Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: single relations against wasi branches #9

Merged
merged 2 commits into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@ publish = false

[dependencies]
anyhow = "1"
ceramic-event = { git = "https://github.com/3box/rust-ceramic", branch = "main" }
json-patch = { version = "1.0.0", features = ["diff"] }
ceramic-event = { git = "https://github.com/ceramicnetwork/rust-ceramic", branch = "feat/wasi" }
json-patch = { version = "1.2.0", features = ["diff"] }
reqwest = { version = "0.11.14", features = ["json"], optional = true }
schemars = "0.8.12"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
ssi = { version = "0.7", features = ["ed25519"] }
url = { version = "2.2.2", optional = true }
url = { version = "2.5.0", optional = true }

[features]
default = ["remote"]
remote = ["reqwest", "url"]

[dev-dependencies]
rand = "0.8.5"
test-log = { version = "0.2", default-features = false, features = ["trace"] }
tokio = { version = "1", default-features = false, features = ["macros", "rt"] }
tracing = "0.1"
Expand Down
3 changes: 2 additions & 1 deletion src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,8 @@ pub struct PageInfo {
/// Whether previous page exists
pub has_previous_page: bool,
/// Cursor for next page
pub end_cursor: Base64UrlString,
#[serde(default)]
pub end_cursor: Option<Base64UrlString>,
/// Cursor for previous page
pub start_cursor: Base64UrlString,
}
Expand Down
178 changes: 167 additions & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ mod model_definition;
mod query;

use ceramic_event::{
Base64String, Cid, DagCborEncoded, EventArgs, Jws, MultiBase36String, Signer, StreamId,
Base64String, Cid, DeterministicInitEvent, EventArgs, Jws, MultiBase36String, Signer, StreamId,
StreamIdType,
};
use serde::Serialize;
use std::str::FromStr;

use crate::api::ModelData;
pub use ceramic_event;
pub use json_patch;
pub use model_definition::{
GetRootSchema, ModelAccountRelation, ModelDefinition, ModelRelationDefinition,
ModelViewDefinition,
Expand Down Expand Up @@ -146,12 +147,12 @@ impl<S: Signer> CeramicHttpClient<S> {
pub async fn create_single_instance_request(
&self,
model_id: &StreamId,
) -> anyhow::Result<api::CreateRequest<DagCborEncoded>> {
) -> anyhow::Result<api::CreateRequest<DeterministicInitEvent>> {
if !model_id.is_model() {
anyhow::bail!("StreamId was not a model");
}
let args = EventArgs::new_with_parent(&self.signer, model_id);
let commit = args.init()?;
let _commit = args.init()?;
dav1do marked this conversation as resolved.
Show resolved Hide resolved
let controllers: Vec<_> = args.controllers().map(|c| c.id.clone()).collect();
let model = Base64String::from(model_id.to_vec()?);
Ok(api::CreateRequest {
Expand All @@ -164,7 +165,7 @@ impl<S: Signer> CeramicHttpClient<S> {
},
linked_block: None,
jws: None,
data: Some(commit.encoded),
data: None,
cacao_block: None,
},
})
Expand Down Expand Up @@ -587,7 +588,7 @@ pub mod tests {
use crate::model_definition::{GetRootSchema, ModelAccountRelation, ModelDefinition};
use crate::query::{FilterQuery, OperationFilter};
use ceramic_event::{DidDocument, JwkSigner};
use json_patch::ReplaceOperation;
use json_patch::{AddOperation, ReplaceOperation};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
Expand Down Expand Up @@ -629,19 +630,60 @@ pub mod tests {
cli.create_model(&model).await.unwrap()
}

pub async fn create_single_model(cli: &CeramicRemoteHttpClient<JwkSigner>) -> StreamId {
let model = ModelDefinition::new::<Ball>("TestBall", ModelAccountRelation::Single).unwrap();
cli.create_model(&model).await.unwrap()
}

#[tokio::test]
async fn should_create_model() {
let ceramic = CeramicRemoteHttpClient::new(signer().await, ceramic_url());
let model = ModelDefinition::new::<Ball>("TestBall", ModelAccountRelation::List).unwrap();
ceramic.create_model(&model).await.unwrap();
}

// #[tokio::test]
// async fn should_create_single_instance() {
// let ceramic = CeramicRemoteHttpClient::new(did(), &did_private_key(), ceramic_url());
// let model = create_model(&ceramic).await;
// ceramic.create_single_instance(&model).await.unwrap();
// }
#[tokio::test]
async fn should_create_single_instance() {
let ceramic = CeramicRemoteHttpClient::new(signer().await, ceramic_url());
let model = create_single_model(&ceramic).await;
ceramic.create_single_instance(&model).await.unwrap();
}

#[tokio::test]
async fn should_create_and_update_single_instance() {
let ceramic = CeramicRemoteHttpClient::new(signer().await, ceramic_url());
let model = create_single_model(&ceramic).await;
let stream_id = ceramic.create_single_instance(&model).await.unwrap();

tokio::time::sleep(Duration::from_secs(1)).await;

let patch = json_patch::Patch(vec![
json_patch::PatchOperation::Add(AddOperation {
path: "/creator".to_string(),
value: serde_json::Value::String(ceramic.client().signer().id().id.clone()),
}),
json_patch::PatchOperation::Add(AddOperation {
path: "/radius".to_string(),
value: serde_json::Value::Number(serde_json::Number::from(1)),
}),
json_patch::PatchOperation::Add(AddOperation {
path: "/red".to_string(),
value: serde_json::Value::Number(serde_json::Number::from(2)),
}),
json_patch::PatchOperation::Add(AddOperation {
path: "/green".to_string(),
value: serde_json::Value::Number(serde_json::Number::from(3)),
}),
json_patch::PatchOperation::Add(AddOperation {
path: "/blue".to_string(),
value: serde_json::Value::Number(serde_json::Number::from(4)),
}),
]);
let post_resp = ceramic.update(&model, &stream_id, patch).await.unwrap();
assert_eq!(post_resp.stream_id, stream_id);
let post_resp: Ball = serde_json::from_value(post_resp.state.unwrap().content).unwrap();
assert_eq!(post_resp.red, 2);
}

#[tokio::test]
async fn should_create_and_update_list() {
Expand Down Expand Up @@ -795,5 +837,119 @@ pub mod tests {
.await
.unwrap();
assert_eq!(res.edges.len(), 1);
let node = &res.edges[0].node;
let result: Ball = serde_json::from_value(node.content.clone()).unwrap();
assert_eq!(result.blue, 5);
}

#[tokio::test]
async fn should_query_models_after_update() {
let ceramic = CeramicRemoteHttpClient::new(signer().await, ceramic_url());
let model = create_model(&ceramic).await;
ceramic.index_model(&model).await.unwrap();
let _instance1 = ceramic
.create_list_instance(
&model,
&Ball {
creator: ceramic.client().signer().id().id.clone(),
radius: 1,
red: 2,
green: 3,
blue: 4,
},
)
.await
.unwrap();

let instance2 = ceramic
.create_list_instance(
&model,
&Ball {
creator: ceramic.client().signer().id().id.clone(),
radius: 2,
red: 3,
green: 4,
blue: 5,
},
)
.await
.unwrap();

//give anchor time to complete
tokio::time::sleep(Duration::from_secs(1)).await;

let replace = Ball {
creator: ceramic.client().signer().id().id.clone(),
radius: 1,
red: 0,
green: 3,
blue: 10,
};
let post_resp = ceramic.replace(&model, &instance2, &replace).await.unwrap();
assert_eq!(post_resp.stream_id, instance2);

//give anchor time to complete
tokio::time::sleep(Duration::from_secs(1)).await;

let mut where_filter = HashMap::new();
where_filter.insert("blue".to_string(), OperationFilter::EqualTo(10.into()));
let filter = FilterQuery::Where(where_filter);
let res = ceramic
.query(&model, Some(filter), Pagination::default())
.await
.unwrap();
assert_eq!(res.edges.len(), 1);
let node = &res.edges[0].node;
let result: Ball = serde_json::from_value(node.content.clone()).unwrap();
assert_eq!(result.blue, 10);
}

#[tokio::test]
async fn should_create_and_repeatedly_update_list() {
let ceramic = CeramicRemoteHttpClient::new(signer().await, ceramic_url());
let model = create_model(&ceramic).await;
let stream_id = ceramic
.create_list_instance(
&model,
&Ball {
creator: ceramic.client().signer().id().id.clone(),
radius: 1,
red: 2,
green: 3,
blue: 4,
},
)
.await
.unwrap();

for i in 0..100 {
//give anchor time to complete
tokio::time::sleep(Duration::from_millis(100)).await;

let replace_value = rand::random::<i32>() % 10i32;
let patch = json_patch::Patch(vec![json_patch::PatchOperation::Replace(
ReplaceOperation {
path: "/red".to_string(),
value: serde_json::json!(replace_value),
},
)]);
let post_resp = ceramic.update(&model, &stream_id, patch).await.unwrap();
assert_eq!(post_resp.stream_id, stream_id);
let post_resp: Ball = serde_json::from_value(post_resp.state.unwrap().content).unwrap();
assert_eq!(
post_resp.red, replace_value,
"Failed to return expected value on iteration {}",
i
);

let get_resp: Ball = ceramic.get_as(&stream_id).await.unwrap();
assert_eq!(get_resp.red, replace_value);
assert_eq!(get_resp.blue, 4);
assert_eq!(
get_resp, post_resp,
"Failed to retrieve expected value on iteration {}",
i
);
}
}
}
9 changes: 9 additions & 0 deletions src/model_definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,15 @@ impl ModelDefinition {
) -> anyhow::Result<Self> {
let schema = T::root_schema();
let schema = serde_json::to_value(&schema)?;
Self::new_for_value(name, account_relation, schema)
}

/// Create a new definition from schema that is already json
pub fn new_for_value(
name: &str,
account_relation: ModelAccountRelation,
schema: serde_json::Value,
) -> anyhow::Result<Self> {
Ok(Self {
version: "1.0",
name: name.to_string(),
Expand Down
14 changes: 7 additions & 7 deletions src/query.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use serde::Serialize;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// Valid values for operation Filter
#[derive(Clone, Debug, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(untagged)]
pub enum NumberFilter {
/// I64 Value
Expand Down Expand Up @@ -40,7 +40,7 @@ impl From<f32> for NumberFilter {
}

/// Valid values for operation Filter
#[derive(Clone, Debug, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(untagged)]
pub enum ValueFilter {
/// String value
Expand Down Expand Up @@ -86,7 +86,7 @@ impl From<f32> for ValueFilter {
}

/// Valid values for operation Filter
#[derive(Clone, Debug, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(untagged)]
pub enum EqualValueFilter {
/// Boolean value
Expand Down Expand Up @@ -138,7 +138,7 @@ impl From<f32> for EqualValueFilter {
}

/// Operation Filter
#[derive(Clone, Debug, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum OperationFilter {
/// Filter by null or not null
Expand All @@ -162,7 +162,7 @@ pub enum OperationFilter {
}

/// Combination query
#[derive(Clone, Debug, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct CombinationQuery(Vec<FilterQuery>);

impl CombinationQuery {
Expand All @@ -189,7 +189,7 @@ macro_rules! or {
}

/// Filter Query
#[derive(Clone, Debug, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum FilterQuery {
/// Filter by where
#[serde(rename = "where")]
Expand Down
Loading