feat: with toggle item
Some checks failed
continuous-integration/drone/push Build is failing

Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
Kasper Juul Hermansen 2024-05-15 15:05:26 +02:00
parent 364f3992bb
commit 4a91a564bf
Signed by: kjuulh
GPG Key ID: 57B6E1465221F912
6 changed files with 192 additions and 5 deletions

View File

@ -36,6 +36,7 @@ service Graph {
rpc CreateRoot(CreateRootRequest) returns (CreateRootResponse);
rpc CreateItem(CreateItemRequest) returns (CreateItemResponse);
rpc UpdateItem(UpdateItemRequest) returns (UpdateItemResponse);
rpc ToggleItem(ToggleItemRequest) returns (ToggleItemResponse);
// Queriers
rpc GetAvailableRoots(GetAvailableRootsRequest) returns (GetAvailableRootsResponse);
@ -69,6 +70,12 @@ message UpdateItemRequest {
}
message UpdateItemResponse {}
message ToggleItemRequest {
string root = 1;
repeated string path = 2;
}
message ToggleItemResponse {}
// Queries
message GetAvailableRootsRequest {}
message GetAvailableRootsResponse {

View File

@ -5,6 +5,7 @@ use crate::{
create_item::{self, CreateItem, CreateItemExt},
create_root::{self, CreateRoot, CreateRootExt},
create_section::{self, CreateSection, CreateSectionExt},
toggle_item::{ToggleItem, ToggleItemExt},
update_item::{UpdateItem, UpdateItemExt},
},
state::SharedState,
@ -50,6 +51,7 @@ pub struct Commander {
create_section: CreateSection,
create_item: CreateItem,
update_item: UpdateItem,
toggle_item: ToggleItem,
}
impl Commander {
@ -58,12 +60,14 @@ impl Commander {
create_section: CreateSection,
create_item: CreateItem,
update_item: UpdateItem,
toggle_item: ToggleItem,
) -> Self {
Self {
create_root,
create_section,
create_item,
update_item,
toggle_item,
}
}
@ -121,7 +125,13 @@ impl Commander {
Ok(())
}
Command::ToggleItem { root, path } => todo!(),
Command::ToggleItem { root, path } => {
self.toggle_item
.execute(crate::services::toggle_item::Request { root, path })
.await?;
Ok(())
}
Command::Move { root, src, dest } => todo!(),
}
}
@ -138,6 +148,7 @@ impl CommanderExt for SharedState {
self.create_section_service(),
self.create_item_service(),
self.update_item_service(),
self.toggle_item_service(),
)
}
}

View File

@ -320,6 +320,66 @@ impl Graph for Server {
Ok(Response::new(UpdateItemResponse {}))
}
async fn toggle_item(
&self,
request: tonic::Request<ToggleItemRequest>,
) -> std::result::Result<tonic::Response<ToggleItemResponse>, tonic::Status> {
let req = request.into_inner();
tracing::trace!("update item: req({:?})", req);
if req.root.is_empty() {
return Err(tonic::Status::new(
tonic::Code::InvalidArgument,
"root cannot be empty".to_string(),
));
}
if req.path.is_empty() {
return Err(tonic::Status::new(
tonic::Code::InvalidArgument,
"path cannot be empty".to_string(),
));
}
if req
.path
.iter()
.filter(|item| item.is_empty())
.collect::<Vec<_>>()
.first()
.is_some()
{
return Err(tonic::Status::new(
tonic::Code::InvalidArgument,
"path cannot contain empty paths".to_string(),
));
}
if req
.path
.iter()
.filter(|item| item.contains("."))
.collect::<Vec<_>>()
.first()
.is_some()
{
return Err(tonic::Status::new(
tonic::Code::InvalidArgument,
"path cannot contain `.`".to_string(),
));
}
self.commander
.execute(Command::ToggleItem {
root: req.root,
path: req.path,
})
.await
.map_err(to_tonic_err)?;
Ok(Response::new(ToggleItemResponse {}))
}
}
fn to_native(from: &hyperlog_core::log::GraphItem) -> anyhow::Result<GraphItem> {

View File

@ -1,6 +1,7 @@
pub mod create_item;
pub mod create_root;
pub mod create_section;
pub mod toggle_item;
pub mod update_item;
pub mod get_available_roots;

View File

@ -0,0 +1,105 @@
use hyperlog_core::log::ItemState;
use sqlx::types::Json;
use crate::state::SharedState;
#[derive(Clone)]
pub struct ToggleItem {
db: sqlx::PgPool,
}
pub struct Request {
pub root: String,
pub path: Vec<String>,
}
pub struct Response {}
#[derive(serde::Serialize, serde::Deserialize)]
struct ItemContent {
pub title: String,
pub description: String,
pub state: ItemState,
}
#[derive(sqlx::FromRow)]
struct Root {
id: uuid::Uuid,
}
#[derive(sqlx::FromRow)]
struct Node {
id: uuid::Uuid,
item_content: Option<Json<ItemContent>>,
}
impl ToggleItem {
pub fn new(db: sqlx::PgPool) -> Self {
Self { db }
}
pub async fn execute(&self, req: Request) -> anyhow::Result<Response> {
let Root { id: root_id, .. } =
sqlx::query_as(r#"SELECT * FROM roots WHERE root_name = $1"#)
.bind(req.root)
.fetch_one(&self.db)
.await?;
let Node {
id: node_id,
mut item_content,
} = sqlx::query_as(
r#"
SELECT
*
FROM
nodes
WHERE
root_id = $1
AND path = $2
AND item_type = $3
"#,
)
.bind(root_id)
.bind(req.path.join("."))
.bind("ITEM")
.fetch_one(&self.db)
.await?;
if let Some(ref mut content) = item_content {
content.state = match content.state {
ItemState::NotDone => ItemState::Done,
ItemState::Done => ItemState::NotDone,
}
}
let res = sqlx::query(
r#"
UPDATE
nodes
SET
item_content = $1
WHERE
id = $2
"#,
)
.bind(item_content)
.bind(node_id)
.execute(&self.db)
.await?;
if res.rows_affected() != 1 {
anyhow::bail!("failed to update item");
}
Ok(Response {})
}
}
pub trait ToggleItemExt {
fn toggle_item_service(&self) -> ToggleItem;
}
impl ToggleItemExt for SharedState {
fn toggle_item_service(&self) -> ToggleItem {
ToggleItem::new(self.db.clone())
}
}

View File

@ -92,10 +92,13 @@ impl Commander {
// )?
}
Command::ToggleItem { root, path } => {
todo!()
// self
// .engine
// .toggle_item(&root, &path.iter().map(|p| p.as_str()).collect::<Vec<_>>())?
let channel = self.channel.clone();
let mut client = GraphClient::new(channel);
let request = tonic::Request::new(ToggleItemRequest { root, path });
let response = client.toggle_item(request).await?;
let res = response.into_inner();
}
Command::UpdateItem {
root,