diff --git a/Cargo.lock b/Cargo.lock index 34bb135760..f98cb5344d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8475,6 +8475,7 @@ dependencies = [ "base64 0.21.5", "camino", "chrono", + "convert_case 0.6.0", "dojo-test-utils", "dojo-types", "dojo-world", diff --git a/crates/torii/graphql/Cargo.toml b/crates/torii/graphql/Cargo.toml index 242bf96213..2b7854c59a 100644 --- a/crates/torii/graphql/Cargo.toml +++ b/crates/torii/graphql/Cargo.toml @@ -16,6 +16,7 @@ async-recursion = "1.0.5" async-trait.workspace = true base64.workspace = true chrono.workspace = true +convert_case = "0.6.0" dojo-types = { path = "../../dojo-types" } lazy_static.workspace = true scarb-ui.workspace = true @@ -28,8 +29,8 @@ thiserror.workspace = true tokio-stream = "0.1.11" tokio-util = "0.7.7" tokio.workspace = true -torii-core = { path = "../core" } toml.workspace = true +torii-core = { path = "../core" } tracing.workspace = true url.workspace = true warp.workspace = true @@ -39,7 +40,7 @@ camino.workspace = true dojo-test-utils = { path = "../../dojo-test-utils", features = [ "build-examples" ] } dojo-world = { path = "../../dojo-world" } scarb.workspace = true +serial_test = "2.0.0" sozo = { path = "../../sozo" } starknet-crypto.workspace = true starknet.workspace = true -serial_test = "2.0.0" diff --git a/crates/torii/graphql/src/mapping.rs b/crates/torii/graphql/src/mapping.rs index c780369fd9..64c49aa0ab 100644 --- a/crates/torii/graphql/src/mapping.rs +++ b/crates/torii/graphql/src/mapping.rs @@ -11,13 +11,13 @@ lazy_static! { pub static ref ENTITY_TYPE_MAPPING: TypeMapping = IndexMap::from([ (Name::new("id"), TypeData::Simple(TypeRef::named(TypeRef::ID))), (Name::new("keys"), TypeData::Simple(TypeRef::named_list(TypeRef::STRING))), - (Name::new("event_id"), TypeData::Simple(TypeRef::named(TypeRef::STRING))), + (Name::new("eventId"), TypeData::Simple(TypeRef::named(TypeRef::STRING))), ( - Name::new("created_at"), + Name::new("createdAt"), TypeData::Simple(TypeRef::named(GraphqlType::DateTime.to_string())), ), ( - Name::new("updated_at"), + Name::new("updatedAt"), TypeData::Simple(TypeRef::named(GraphqlType::DateTime.to_string())), ), ]); @@ -26,35 +26,35 @@ lazy_static! { (Name::new("keys"), TypeData::Simple(TypeRef::named_list(TypeRef::STRING))), (Name::new("data"), TypeData::Simple(TypeRef::named_list(TypeRef::STRING))), ( - Name::new("created_at"), + Name::new("createdAt"), TypeData::Simple(TypeRef::named(GraphqlType::DateTime.to_string())), ), - (Name::new("transaction_hash"), TypeData::Simple(TypeRef::named(TypeRef::STRING))), + (Name::new("transactionHash"), TypeData::Simple(TypeRef::named(TypeRef::STRING))), ]); pub static ref MODEL_TYPE_MAPPING: TypeMapping = IndexMap::from([ (Name::new("id"), TypeData::Simple(TypeRef::named(TypeRef::ID))), (Name::new("name"), TypeData::Simple(TypeRef::named(TypeRef::STRING))), ( - Name::new("class_hash"), + Name::new("classHash"), TypeData::Simple(TypeRef::named(Primitive::Felt252(None).to_string())), ), ( - Name::new("transaction_hash"), + Name::new("transactionHash"), TypeData::Simple(TypeRef::named(Primitive::Felt252(None).to_string())), ), ( - Name::new("created_at"), + Name::new("createdAt"), TypeData::Simple(TypeRef::named(GraphqlType::DateTime.to_string())), ), ]); pub static ref TRANSACTION_MAPPING: TypeMapping = IndexMap::from([ (Name::new("id"), TypeData::Simple(TypeRef::named(TypeRef::ID))), ( - Name::new("transaction_hash"), + Name::new("transactionHash"), TypeData::Simple(TypeRef::named(Primitive::Felt252(None).to_string())) ), ( - Name::new("sender_address"), + Name::new("senderAddress"), TypeData::Simple(TypeRef::named(Primitive::Felt252(None).to_string())) ), ( @@ -62,7 +62,7 @@ lazy_static! { TypeData::Simple(TypeRef::named_list(Primitive::Felt252(None).to_string())) ), ( - Name::new("max_fee"), + Name::new("maxFee"), TypeData::Simple(TypeRef::named(Primitive::Felt252(None).to_string())) ), ( @@ -74,21 +74,18 @@ lazy_static! { TypeData::Simple(TypeRef::named(Primitive::Felt252(None).to_string())) ), ( - Name::new("created_at"), + Name::new("createdAt"), TypeData::Simple(TypeRef::named(GraphqlType::DateTime.to_string())), ), ]); pub static ref PAGE_INFO_TYPE_MAPPING: TypeMapping = TypeMapping::from([ - (Name::new("has_previous_page"), TypeData::Simple(TypeRef::named(TypeRef::BOOLEAN))), - (Name::new("has_next_page"), TypeData::Simple(TypeRef::named(TypeRef::BOOLEAN))), + (Name::new("hasPreviousPage"), TypeData::Simple(TypeRef::named(TypeRef::BOOLEAN))), + (Name::new("hasNextPage"), TypeData::Simple(TypeRef::named(TypeRef::BOOLEAN))), ( - Name::new("start_cursor"), - TypeData::Simple(TypeRef::named(GraphqlType::Cursor.to_string())), - ), - ( - Name::new("end_cursor"), + Name::new("startCursor"), TypeData::Simple(TypeRef::named(GraphqlType::Cursor.to_string())), ), + (Name::new("endCursor"), TypeData::Simple(TypeRef::named(GraphqlType::Cursor.to_string())),), ]); pub static ref SOCIAL_TYPE_MAPPING: TypeMapping = IndexMap::from([ (Name::new("name"), TypeData::Simple(TypeRef::named(TypeRef::STRING))), @@ -102,6 +99,7 @@ lazy_static! { (Name::new("cover_uri"), TypeData::Simple(TypeRef::named(TypeRef::STRING))), (Name::new("socials"), TypeData::Simple(TypeRef::named_list(SOCIAL_TYPE_NAME))) ]); + // Todo: refactor this to use the same type as the one in dojo-world pub static ref METADATA_TYPE_MAPPING: TypeMapping = IndexMap::from([ (Name::new("id"), TypeData::Simple(TypeRef::named(TypeRef::ID))), (Name::new("uri"), TypeData::Simple(TypeRef::named(TypeRef::STRING))), @@ -109,14 +107,14 @@ lazy_static! { Name::new("content"), TypeData::Nested((TypeRef::named(CONTENT_TYPE_NAME), IndexMap::new())) ), - (Name::new("icon_img"), TypeData::Simple(TypeRef::named(TypeRef::STRING))), - (Name::new("cover_img"), TypeData::Simple(TypeRef::named(TypeRef::STRING))), + (Name::new("iconImg"), TypeData::Simple(TypeRef::named(TypeRef::STRING))), + (Name::new("coverImg"), TypeData::Simple(TypeRef::named(TypeRef::STRING))), ( - Name::new("created_at"), + Name::new("createdAt"), TypeData::Simple(TypeRef::named(GraphqlType::DateTime.to_string())) ), ( - Name::new("updated_at"), + Name::new("updatedAt"), TypeData::Simple(TypeRef::named(GraphqlType::DateTime.to_string())) ), ]); diff --git a/crates/torii/graphql/src/object/connection/mod.rs b/crates/torii/graphql/src/object/connection/mod.rs index 63b796e31b..7785188785 100644 --- a/crates/torii/graphql/src/object/connection/mod.rs +++ b/crates/torii/graphql/src/object/connection/mod.rs @@ -40,9 +40,9 @@ impl ConnectionObject { Name::new("edges"), TypeData::Simple(TypeRef::named_list(format!("{}Edge", type_name))), ), - (Name::new("total_count"), TypeData::Simple(TypeRef::named_nn(TypeRef::INT))), + (Name::new("totalCount"), TypeData::Simple(TypeRef::named_nn(TypeRef::INT))), ( - Name::new("page_info"), + Name::new("pageInfo"), TypeData::Nested((TypeRef::named_nn(PAGE_INFO_TYPE_NAME), IndexMap::new())), ), ]); @@ -141,8 +141,8 @@ pub fn connection_output( .collect::>>(); Ok(ValueMapping::from([ - (Name::new("total_count"), Value::from(total_count)), + (Name::new("totalCount"), Value::from(total_count)), (Name::new("edges"), Value::List(model_edges?)), - (Name::new("page_info"), PageInfoObject::value(page_info)), + (Name::new("pageInfo"), PageInfoObject::value(page_info)), ])) } diff --git a/crates/torii/graphql/src/object/connection/page_info.rs b/crates/torii/graphql/src/object/connection/page_info.rs index 126f00f7aa..7a27b5b98e 100644 --- a/crates/torii/graphql/src/object/connection/page_info.rs +++ b/crates/torii/graphql/src/object/connection/page_info.rs @@ -33,17 +33,17 @@ impl ObjectTrait for PageInfoObject { impl PageInfoObject { pub fn value(page_info: PageInfo) -> Value { Value::Object(IndexMap::from([ - (Name::new("has_previous_page"), Value::from(page_info.has_previous_page)), - (Name::new("has_next_page"), Value::from(page_info.has_next_page)), + (Name::new("hasPreviousPage"), Value::from(page_info.has_previous_page)), + (Name::new("hasNextPage"), Value::from(page_info.has_next_page)), ( - Name::new("start_cursor"), + Name::new("startCursor"), match page_info.start_cursor { Some(val) => Value::from(val), None => Value::Null, }, ), ( - Name::new("end_cursor"), + Name::new("endCursor"), match page_info.end_cursor { Some(val) => Value::from(val), None => Value::Null, diff --git a/crates/torii/graphql/src/object/entity.rs b/crates/torii/graphql/src/object/entity.rs index 898bb5fdbd..aa19481648 100644 --- a/crates/torii/graphql/src/object/entity.rs +++ b/crates/torii/graphql/src/object/entity.rs @@ -115,13 +115,13 @@ impl EntityObject { IndexMap::from([ (Name::new("id"), Value::from(entity.id)), (Name::new("keys"), Value::from(keys)), - (Name::new("event_id"), Value::from(entity.event_id)), + (Name::new("eventId"), Value::from(entity.event_id)), ( - Name::new("created_at"), + Name::new("createdAt"), Value::from(entity.created_at.format("%Y-%m-%d %H:%M:%S").to_string()), ), ( - Name::new("updated_at"), + Name::new("updatedAt"), Value::from(entity.updated_at.format("%Y-%m-%d %H:%M:%S").to_string()), ), ]) @@ -134,6 +134,7 @@ fn model_union_field() -> Field { match ctx.parent_value.try_to_value()? { Value::Object(indexmap) => { let mut conn = ctx.data::>()?.acquire().await?; + let entity_id = extract::(indexmap, "id")?; let model_ids: Vec<(String,)> = sqlx::query_as("SELECT model_id from entity_model WHERE entity_id = ?") diff --git a/crates/torii/graphql/src/object/event.rs b/crates/torii/graphql/src/object/event.rs index 31b660c2b9..7a7e28377f 100644 --- a/crates/torii/graphql/src/object/event.rs +++ b/crates/torii/graphql/src/object/event.rs @@ -102,9 +102,9 @@ impl EventObject { (Name::new("id"), Value::from(event.id)), (Name::new("keys"), Value::from(keys)), (Name::new("data"), Value::from(data)), - (Name::new("transaction_hash"), Value::from(event.transaction_hash)), + (Name::new("transactionHash"), Value::from(event.transaction_hash)), ( - Name::new("created_at"), + Name::new("createdAt"), Value::from(event.created_at.format("%Y-%m-%d %H:%M:%S").to_string()), ), ]) diff --git a/crates/torii/graphql/src/object/metadata/mod.rs b/crates/torii/graphql/src/object/metadata/mod.rs index 4a00b2dd43..94e8171d4a 100644 --- a/crates/torii/graphql/src/object/metadata/mod.rs +++ b/crates/torii/graphql/src/object/metadata/mod.rs @@ -122,9 +122,9 @@ fn metadata_connection_output( .collect::>>(); Ok(ValueMapping::from([ - (Name::new("total_count"), Value::from(total_count)), + (Name::new("totalCount"), Value::from(total_count)), (Name::new("edges"), Value::List(edges?)), - (Name::new("page_info"), PageInfoObject::value(page_info)), + (Name::new("pageInfo"), PageInfoObject::value(page_info)), ])) } diff --git a/crates/torii/graphql/src/object/model.rs b/crates/torii/graphql/src/object/model.rs index a23e8b18a6..402bfe7935 100644 --- a/crates/torii/graphql/src/object/model.rs +++ b/crates/torii/graphql/src/object/model.rs @@ -60,10 +60,10 @@ impl ModelObject { IndexMap::from([ (Name::new("id"), Value::from(model.id)), (Name::new("name"), Value::from(model.name)), - (Name::new("class_hash"), Value::from(model.class_hash)), - (Name::new("transaction_hash"), Value::from(model.transaction_hash)), + (Name::new("classHash"), Value::from(model.class_hash)), + (Name::new("transactionHash"), Value::from(model.transaction_hash)), ( - Name::new("created_at"), + Name::new("createdAt"), Value::from(model.created_at.format("%Y-%m-%d %H:%M:%S").to_string()), ), ]) diff --git a/crates/torii/graphql/src/query/mod.rs b/crates/torii/graphql/src/query/mod.rs index b256164632..140dcc8caa 100644 --- a/crates/torii/graphql/src/query/mod.rs +++ b/crates/torii/graphql/src/query/mod.rs @@ -2,6 +2,7 @@ use std::str::FromStr; use async_graphql::dynamic::TypeRef; use async_graphql::{Name, Value}; +use convert_case::{Case, Casing}; use dojo_types::primitive::{Primitive, SqlType}; use sqlx::pool::PoolConnection; use sqlx::sqlite::SqliteRow; @@ -144,8 +145,11 @@ fn fetch_value( type_name: &str, is_external: bool, ) -> sqlx::Result { - let column_name = - if is_external { format!("external_{}", field_name) } else { field_name.to_string() }; + let column_name = if is_external { + format!("external_{}", field_name) + } else { + field_name.to_string().to_case(Case::Snake) + }; match Primitive::from_str(type_name) { // fetch boolean diff --git a/crates/torii/graphql/src/tests/entities_test.rs b/crates/torii/graphql/src/tests/entities_test.rs index e41da42f32..d2e3f31879 100644 --- a/crates/torii/graphql/src/tests/entities_test.rs +++ b/crates/torii/graphql/src/tests/entities_test.rs @@ -16,18 +16,18 @@ mod tests { r#" {{ entities {} {{ - total_count + totalCount edges {{ cursor node {{ keys }} }} - page_info {{ - has_previous_page - has_next_page - start_cursor - end_cursor + pageInfo {{ + hasPreviousPage + hasNextPage + startCursor + endCursor }} }} }} diff --git a/crates/torii/graphql/src/tests/metadata_test.rs b/crates/torii/graphql/src/tests/metadata_test.rs index d6490421ff..47c16e2949 100644 --- a/crates/torii/graphql/src/tests/metadata_test.rs +++ b/crates/torii/graphql/src/tests/metadata_test.rs @@ -13,13 +13,13 @@ mod tests { const QUERY: &str = r#" { metadatas { - total_count + totalCount edges { cursor node { uri - cover_img - icon_img + coverImg + iconImg content { name description @@ -33,11 +33,11 @@ mod tests { } } } - page_info { - has_previous_page - has_next_page - start_cursor - end_cursor + pageInfo { + hasPreviousPage + hasNextPage + startCursor + endCursor } } } @@ -60,7 +60,6 @@ mod tests { "#, ) .unwrap(); - let world_metadata = dojo_metadata.world.unwrap(); db.update_metadata(&RESOURCE, URI, &world_metadata, &None, &Some(cover_img.to_string())) .await diff --git a/crates/torii/graphql/src/tests/mod.rs b/crates/torii/graphql/src/tests/mod.rs index 4a55f66a3e..927faf3a0a 100644 --- a/crates/torii/graphql/src/tests/mod.rs +++ b/crates/torii/graphql/src/tests/mod.rs @@ -37,6 +37,7 @@ mod subscription_test; use crate::schema::build_schema; #[derive(Deserialize, Debug, PartialEq)] +#[serde(rename_all = "camelCase")] pub struct Connection { pub total_count: i64, pub edges: Vec>, @@ -50,12 +51,14 @@ pub struct Edge { } #[derive(Deserialize, Debug, PartialEq)] +#[serde(rename_all = "camelCase")] pub struct Entity { pub keys: Option>, pub created_at: Option, } #[derive(Deserialize, Debug, PartialEq)] +#[serde(rename_all = "camelCase")] // same as type from `async-graphql` but derive necessary traits // https://docs.rs/async-graphql/6.0.10/async_graphql/types/connection/struct.PageInfo.html pub struct PageInfo { @@ -65,27 +68,6 @@ pub struct PageInfo { pub end_cursor: Option, } -#[derive(Deserialize, Debug)] -pub struct Moves { - pub __typename: String, - pub remaining: u32, - pub last_direction: String, - pub entity: Option, -} - -#[derive(Deserialize, Debug)] -pub struct Vec2 { - pub x: u32, - pub y: u32, -} - -#[derive(Deserialize, Debug)] -pub struct Position { - pub __typename: String, - pub vec: Vec2, - pub entity: Option, -} - #[derive(Deserialize, Debug, PartialEq)] pub struct Record { pub __typename: String, @@ -160,6 +142,7 @@ pub struct Content { } #[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] pub struct Metadata { pub uri: String, pub icon_img: String, @@ -210,7 +193,7 @@ pub async fn model_fixtures(db: &mut Sql) { ty: Ty::Primitive(Primitive::U32(None)), }, Member { - name: "type_u16".to_string(), + name: "typeU16".to_string(), key: false, ty: Ty::Primitive(Primitive::U16(None)), }, @@ -220,7 +203,7 @@ pub async fn model_fixtures(db: &mut Sql) { ty: Ty::Primitive(Primitive::U64(None)), }, Member { - name: "type_bool".to_string(), + name: "typeBool".to_string(), key: false, ty: Ty::Primitive(Primitive::Bool(None)), }, @@ -230,7 +213,7 @@ pub async fn model_fixtures(db: &mut Sql) { ty: Ty::Primitive(Primitive::Felt252(None)), }, Member { - name: "type_contract_address".to_string(), + name: "typeContractAddress".to_string(), key: true, ty: Ty::Primitive(Primitive::ContractAddress(None)), }, diff --git a/crates/torii/graphql/src/tests/models_test.rs b/crates/torii/graphql/src/tests/models_test.rs index b033512071..10d4ef6bbe 100644 --- a/crates/torii/graphql/src/tests/models_test.rs +++ b/crates/torii/graphql/src/tests/models_test.rs @@ -15,7 +15,7 @@ mod tests { r#" {{ recordModels {} {{ - total_count + totalCount edges {{ cursor node {{ @@ -57,11 +57,11 @@ mod tests { }} }} }} - page_info {{ - has_previous_page - has_next_page - start_cursor - end_cursor + pageInfo {{ + hasPreviousPage + hasNextPage + startCursor + endCursor }} }} }} diff --git a/crates/torii/graphql/src/tests/subscription_test.rs b/crates/torii/graphql/src/tests/subscription_test.rs index 89b851674e..879d209dec 100644 --- a/crates/torii/graphql/src/tests/subscription_test.rs +++ b/crates/torii/graphql/src/tests/subscription_test.rs @@ -34,11 +34,11 @@ mod tests { "__typename": model_name, "depth": "Zero", "record_id": 0, - "type_u16": 1, + "typeU16": 1, "type_u64": 1, - "type_bool": true, + "typeBool": true, "type_felt": format!("{:#x}", FieldElement::from(1u128)), - "type_contract_address": format!("{:#x}", FieldElement::ONE) + "typeContractAddress": format!("{:#x}", FieldElement::ONE) }] } }); @@ -73,7 +73,7 @@ mod tests { ty: Ty::Primitive(Primitive::U8(Some(0))), }, Member { - name: "type_u16".to_string(), + name: "typeU16".to_string(), key: false, ty: Ty::Primitive(Primitive::U16(Some(1))), }, @@ -83,7 +83,7 @@ mod tests { ty: Ty::Primitive(Primitive::U64(Some(1))), }, Member { - name: "type_bool".to_string(), + name: "typeBool".to_string(), key: false, ty: Ty::Primitive(Primitive::Bool(Some(true))), }, @@ -93,7 +93,7 @@ mod tests { ty: Ty::Primitive(Primitive::Felt252(Some(FieldElement::from(1u128)))), }, Member { - name: "type_contract_address".to_string(), + name: "typeContractAddress".to_string(), key: true, ty: Ty::Primitive(Primitive::ContractAddress(Some(FieldElement::ONE))), }, @@ -119,11 +119,11 @@ mod tests { ... on Record { depth record_id - type_u16 + typeU16 type_u64 - type_bool + typeBool type_felt - type_contract_address + typeContractAddress } } } @@ -156,7 +156,7 @@ mod tests { "depth": "Zero", "record_id": 0, "type_felt": format!("{:#x}", FieldElement::from(1u128)), - "type_contract_address": format!("{:#x}", FieldElement::ONE) + "typeContractAddress": format!("{:#x}", FieldElement::ONE) }] } }); @@ -196,7 +196,7 @@ mod tests { ty: Ty::Primitive(Primitive::Felt252(Some(FieldElement::from(1u128)))), }, Member { - name: "type_contract_address".to_string(), + name: "typeContractAddress".to_string(), key: true, ty: Ty::Primitive(Primitive::ContractAddress(Some(FieldElement::ONE))), }, @@ -223,7 +223,7 @@ mod tests { depth record_id type_felt - type_contract_address + typeContractAddress } } } @@ -256,7 +256,7 @@ mod tests { let model = Ty::Struct(Struct { name: model_name, children: vec![Member { - name: "subrecord_id".to_string(), + name: "subrecordId".to_string(), key: true, ty: Ty::Primitive(Primitive::U32(None)), }], @@ -369,7 +369,7 @@ mod tests { eventEmitted (keys: ["*", "{:#x}"]) {{ keys data - transaction_hash + transactionHash }} }} "#, @@ -385,7 +385,7 @@ mod tests { ], "data": vec![ format!("{:#x}", FieldElement::from_str("0xc0de").unwrap()), format!("{:#x}", FieldElement::from_str("0xface").unwrap()) - ], "transaction_hash": format!("{:#x}", FieldElement::ZERO)} + ], "transactionHash": format!("{:#x}", FieldElement::ZERO)} }); assert_eq!(response_value, expected_value);