Skip to content

Commit

Permalink
feat(torii): enum support (#874)
Browse files Browse the repository at this point in the history
* fix(torii): exact key matching issue

* chore(torii): gen sql type mapping at runtime

* fix graphql type

* update ecs example to add enum

* remove obsolete fixtures

* update test manifest

* fix test
  • Loading branch information
broody authored Sep 8, 2023
1 parent 1c15335 commit 35a68c8
Show file tree
Hide file tree
Showing 11 changed files with 135 additions and 141 deletions.
23 changes: 16 additions & 7 deletions crates/dojo-lang/src/manifest_test_data/manifest
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@ test_manifest_file
}
],
"outputs": [],
"class_hash": "0x3459b99fd17b3bf9aeb6c55b610a457520785646f5c80c21d07041403a25315",
"class_hash": "0x205287b11aa6c42e3cef3539607aa250c2b9ffe27f847af8e88f005e1b3525d",
"dependencies": [],
"abi": [
{
Expand Down Expand Up @@ -701,11 +701,11 @@ test_manifest_file
},
{
"name": "direction",
"type": "dojo_examples::systems::move::Direction"
"type": "dojo_examples::components::Direction"
}
],
"outputs": [],
"class_hash": "0x578416d298f2f6c280a229f58fd7b5b2486285700fcfde9ad102c4052d3804e",
"class_hash": "0x501dbe28cf4e7f3a47c9abeee23c85992b97fdaa324c1fcb1e2a638882fc470",
"dependencies": [],
"abi": [
{
Expand All @@ -721,8 +721,12 @@ test_manifest_file
},
{
"type": "enum",
"name": "dojo_examples::systems::move::Direction",
"name": "dojo_examples::components::Direction",
"variants": [
{
"name": "None",
"type": "()"
},
{
"name": "Left",
"type": "()"
Expand Down Expand Up @@ -779,7 +783,7 @@ test_manifest_file
"inputs": [
{
"name": "direction",
"type": "dojo_examples::systems::move::Direction"
"type": "dojo_examples::components::Direction"
},
{
"name": "ctx",
Expand All @@ -801,7 +805,7 @@ test_manifest_file
},
{
"name": "direction",
"type": "dojo_examples::systems::move::Direction",
"type": "dojo_examples::components::Direction",
"kind": "data"
}
]
Expand Down Expand Up @@ -952,9 +956,14 @@ test_manifest_file
"name": "remaining",
"type": "u8",
"key": false
},
{
"name": "last_direction",
"type": "Direction",
"key": false
}
],
"class_hash": "0x74c8a6b2e93b4a34788c23eb3d931da62d5a973ef66ba0a671de41b1607a9a4",
"class_hash": "0x451a367ced4c22bfc661e6a342391faa6087d3162ea53cf4c6cc86c8630de49",
"abi": [
{
"type": "function",
Expand Down
6 changes: 3 additions & 3 deletions crates/torii/client/src/contract/system_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ async fn test_system() {
let component = world.component("Moves", block_id).await.unwrap();
let moves = component.entity(vec![account.address()], block_id).await.unwrap();

assert_eq!(moves, vec![10_u8.into()]);
assert_eq!(moves, vec![10_u8.into(), FieldElement::ZERO]);

let move_system = world.system("move", block_id).await.unwrap();

Expand All @@ -48,11 +48,11 @@ async fn test_system() {

let moves = component.entity(vec![account.address()], block_id).await.unwrap();

assert_eq!(moves, vec![8_u8.into()]);
assert_eq!(moves, vec![8_u8.into(), FieldElement::THREE]);

let position_component = world.component("Position", block_id).await.unwrap();

let position = position_component.entity(vec![account.address()], block_id).await.unwrap();

assert_eq!(position, vec![11_u8.into(), 11_u8.into()]);
assert_eq!(position, vec![9_u8.into(), 9_u8.into()]);
}
87 changes: 54 additions & 33 deletions crates/torii/core/src/sql.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::HashMap;

use anyhow::Result;
use async_trait::async_trait;
use chrono::{DateTime, Utc};
Expand Down Expand Up @@ -27,6 +29,7 @@ pub struct Sql {
world_address: FieldElement,
pool: Pool<Sqlite>,
query_queue: Mutex<Vec<String>>,
sql_types: Mutex<HashMap<String, &'static str>>,
}

impl Sql {
Expand All @@ -50,7 +53,29 @@ impl Sql {

tx.commit().await?;

Ok(Self { pool, world_address, query_queue: Mutex::new(vec![]) })
let sql_types = HashMap::from([
("u8".to_string(), "INTEGER"),
("u16".to_string(), "INTEGER"),
("u32".to_string(), "INTEGER"),
("u64".to_string(), "INTEGER"),
("u128".to_string(), "TEXT"),
("u256".to_string(), "TEXT"),
("usize".to_string(), "INTEGER"),
("bool".to_string(), "INTEGER"),
("Cursor".to_string(), "TEXT"),
("ContractAddress".to_string(), "TEXT"),
("ClassHash".to_string(), "TEXT"),
("DateTime".to_string(), "TEXT"),
("felt252".to_string(), "TEXT"),
("Enum".to_string(), "INTEGER"),
]);

Ok(Self {
pool,
world_address,
query_queue: Mutex::new(vec![]),
sql_types: Mutex::new(sql_types),
})
}
}

Expand Down Expand Up @@ -157,6 +182,8 @@ impl State for Sql {
}

async fn register_component(&self, component: Component) -> Result<()> {
let mut sql_types = self.sql_types.lock().await;

let component_id = component.name.to_lowercase();
let mut queries = vec![format!(
"INSERT INTO components (id, name, class_hash) VALUES ('{}', '{}', '{:#x}') ON \
Expand All @@ -169,12 +196,24 @@ impl State for Sql {
component.name.to_lowercase()
);

for member in component.clone().members {
component_table_query.push_str(&format!(
"external_{} {}, ",
member.name,
sql_type(&member.ty)?
for member in &component.members {
// FIXME: defaults all unknown component types to Enum for now until we support nested
// components
let (sql_type, member_type) = match sql_types.get(&member.ty) {
Some(sql_type) => (*sql_type, member.ty.as_str()),
None => {
sql_types.insert(member.ty.clone(), "INTEGER");
("INTEGER", "Enum")
}
};

queries.push(format!(
"INSERT OR IGNORE INTO component_members (component_id, name, type, key) VALUES \
('{}', '{}', '{}', {})",
component_id, member.name, member_type, member.key,
));

component_table_query.push_str(&format!("external_{} {}, ", member.name, sql_type));
}

component_table_query.push_str(
Expand All @@ -183,15 +222,8 @@ impl State for Sql {
);
queries.push(component_table_query);

for member in component.members {
queries.push(format!(
"INSERT OR IGNORE INTO component_members (component_id, name, type, key) VALUES \
('{}', '{}', '{}', {})",
component_id, member.name, member.ty, member.key,
));
}

self.queue(queries).await;

// Since previous query has not been executed, we have to make sure created_at exists
let created_at: DateTime<Utc> =
match sqlx::query("SELECT created_at FROM components WHERE id = ?")
Expand Down Expand Up @@ -259,7 +291,9 @@ impl State for Sql {
member_values.extend(keys);
member_values.extend(values);

let (names_str, values_str) = format_values(member_names_result, member_values)?;
let sql_types = self.sql_types.lock().await;
let (names_str, values_str) =
format_values(member_names_result, member_values, &sql_types)?;
let insert_components = format!(
"INSERT OR REPLACE INTO external_{} (entity_id {}) VALUES ('{}' {})",
component.to_lowercase(),
Expand Down Expand Up @@ -329,6 +363,7 @@ fn component_names(entity_result: Option<SqliteRow>, new_component: &str) -> Res
fn format_values(
member_results: Vec<SqliteRow>,
values: Vec<FieldElement>,
sql_types: &HashMap<String, &str>,
) -> Result<(String, String)> {
let names: Result<Vec<String>> = member_results
.iter()
Expand All @@ -345,26 +380,12 @@ fn format_values(
let values: Result<Vec<String>> = values
.iter()
.zip(types?.iter())
.map(|(value, ty)| {
if sql_type(ty)? == "INTEGER" {
Ok(format!(",'{}'", value))
} else {
Ok(format!(",'{:#x}'", value))
}
.map(|(value, ty)| match sql_types.get(ty).copied() {
Some("INTEGER") => Ok(format!(",'{}'", value)),
Some("TEXT") => Ok(format!(",'{:#x}'", value)),
_ => Err(anyhow::anyhow!("Unsupported type {}", ty)),
})
.collect();

Ok((names?.join(""), values?.join("")))
}

// NOTE: If adding/removing types, corresponding change needs to be made to torii-graphql
// `src/types.rs`
fn sql_type(member_type: &str) -> Result<&str, anyhow::Error> {
match member_type {
"u8" | "u16" | "u32" | "u64" | "usize" | "bool" => Ok("INTEGER"),
"u128" | "u256" | "Cursor" | "ContractAddress" | "ClassHash" | "DateTime" | "felt252" => {
Ok("TEXT")
}
_ => Err(anyhow::anyhow!("Unknown member type {}", member_type.to_string())),
}
}
57 changes: 0 additions & 57 deletions crates/torii/graphql/src/tests/events_test.rs

This file was deleted.

6 changes: 0 additions & 6 deletions crates/torii/graphql/src/tests/fixtures/events.sql

This file was deleted.

6 changes: 0 additions & 6 deletions crates/torii/graphql/src/tests/fixtures/system_calls.sql

This file was deleted.

6 changes: 0 additions & 6 deletions crates/torii/graphql/src/tests/fixtures/systems.sql

This file was deleted.

1 change: 0 additions & 1 deletion crates/torii/graphql/src/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
mod common;
mod components_test;
mod entities_test;
mod events_test;
mod subscription_test;
5 changes: 5 additions & 0 deletions crates/torii/graphql/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub enum ScalarType {
ClassHash,
DateTime,
Felt252,
Enum,
}

impl fmt::Display for ScalarType {
Expand All @@ -37,6 +38,7 @@ impl fmt::Display for ScalarType {
ScalarType::ClassHash => write!(f, "ClassHash"),
ScalarType::DateTime => write!(f, "DateTime"),
ScalarType::Felt252 => write!(f, "felt252"),
ScalarType::Enum => write!(f, "Enum"),
}
}
}
Expand All @@ -57,6 +59,7 @@ impl ScalarType {
ScalarType::ClassHash,
ScalarType::DateTime,
ScalarType::Felt252,
ScalarType::Enum,
]
.into_iter()
.collect()
Expand All @@ -70,6 +73,7 @@ impl ScalarType {
ScalarType::U64,
ScalarType::USize,
ScalarType::Bool,
ScalarType::Enum,
]
.into_iter()
.collect()
Expand Down Expand Up @@ -114,6 +118,7 @@ impl FromStr for ScalarType {
"ClassHash" => Ok(ScalarType::ClassHash),
"DateTime" => Ok(ScalarType::DateTime),
"felt252" => Ok(ScalarType::Felt252),
"Enum" => Ok(ScalarType::Enum),
_ => Err(anyhow::anyhow!("Unknown type {}", s.to_string())),
}
}
Expand Down
Loading

0 comments on commit 35a68c8

Please sign in to comment.