From b1f3e35f2027c79072f1b6ca4199164fdf15549e Mon Sep 17 00:00:00 2001 From: Nasr Date: Tue, 5 Nov 2024 16:29:52 -0500 Subject: [PATCH 01/35] feat(torii): model upgrades --- crates/torii/core/src/sql/mod.rs | 91 +++++++++++++++++++++++++++----- 1 file changed, 77 insertions(+), 14 deletions(-) diff --git a/crates/torii/core/src/sql/mod.rs b/crates/torii/core/src/sql/mod.rs index 3c20222a9a..233e857c50 100644 --- a/crates/torii/core/src/sql/mod.rs +++ b/crates/torii/core/src/sql/mod.rs @@ -1016,7 +1016,7 @@ impl Sql { } #[allow(clippy::too_many_arguments)] - fn build_model_query( + async fn build_model_query( &mut self, selector: Felt, path: Vec, @@ -1029,25 +1029,58 @@ impl Sql { let table_id = path.join("$"); let mut indices = Vec::new(); + // Check if table exists using sqlx + let table_exists = sqlx::query_scalar::<_, bool>( + "SELECT EXISTS (SELECT 1 FROM sqlite_master WHERE type='table' AND name = ?)" + ) + .bind(&table_id) + .fetch_one(&self.pool) + .await?; + let mut create_table_query = format!( "CREATE TABLE IF NOT EXISTS [{table_id}] (id TEXT NOT NULL, event_id TEXT NOT NULL, \ entity_id TEXT, event_message_id TEXT, " ); + let mut alter_table_queries = Vec::new(); + if array_idx > 0 { // index columns for i in 0..array_idx { - create_table_query.push_str(&format!("idx_{i} INTEGER NOT NULL, ", i = i)); + let column = format!("idx_{i} INTEGER NOT NULL"); + create_table_query.push_str(&format!("{column}, ")); + + if table_exists { + // For upgrades, add column if it doesn't exist + alter_table_queries.push(format!( + "ALTER TABLE [{table_id}] ADD COLUMN idx_{i} INTEGER NOT NULL DEFAULT 0" + )); + } } // full array id column create_table_query.push_str("full_array_id TEXT NOT NULL UNIQUE, "); + if table_exists { + alter_table_queries.push( + format!("ALTER TABLE [{table_id}] ADD COLUMN full_array_id TEXT NOT NULL UNIQUE DEFAULT ''") + ); + } } let mut build_member = |name: &str, ty: &Ty, options: &mut Option| { if let Ok(cairo_type) = Primitive::from_str(&ty.name()) { - create_table_query - .push_str(&format!("external_{name} {}, ", cairo_type.to_sql_type())); + let sql_type = cairo_type.to_sql_type(); + let column = format!("external_{name} {sql_type}"); + + create_table_query.push_str(&format!("{column}, ")); + + if table_exists { + // Add ALTER TABLE query for upgrades + alter_table_queries.push( + format!("ALTER TABLE [{table_id}] ADD COLUMN external_{name} {sql_type}") + ); + } + indices.push(format!( "CREATE INDEX IF NOT EXISTS [idx_{table_id}_{name}] ON [{table_id}] \ (external_{name});" @@ -1060,12 +1093,19 @@ impl Sql { .collect::>() .join(", "); - create_table_query.push_str(&format!( - "external_{name} TEXT CHECK(external_{name} IN ({all_options})) ", - )); - - // if we're an array, we could have multiple enum options - create_table_query.push_str(if array_idx > 0 { ", " } else { "NOT NULL, " }); + let column = format!( + "external_{name} TEXT CHECK(external_{name} IN ({all_options})) {}", + if array_idx > 0 { "" } else { "NOT NULL" } + ); + + create_table_query.push_str(&format!("{column}, ")); + + if table_exists { + // Add ALTER TABLE query for upgrades + alter_table_queries.push( + format!("ALTER TABLE [{table_id}] ADD COLUMN {column}") + ); + } indices.push(format!( "CREATE INDEX IF NOT EXISTS [idx_{table_id}_{name}] ON [{table_id}] \ @@ -1081,7 +1121,17 @@ impl Sql { .to_string(), )); } else if let Ty::ByteArray(_) = &ty { - create_table_query.push_str(&format!("external_{name} TEXT, ")); + let column = format!("external_{name} TEXT"); + + create_table_query.push_str(&format!("{column}, ")); + + if table_exists { + // Add ALTER TABLE query for upgrades + alter_table_queries.push( + format!("ALTER TABLE [{table_id}] ADD COLUMN {column}") + ); + } + indices.push(format!( "CREATE INDEX IF NOT EXISTS [idx_{table_id}_{name}] ON [{table_id}] \ (external_{name});" @@ -1248,10 +1298,23 @@ impl Sql { create_table_query .push_str("FOREIGN KEY (event_message_id) REFERENCES event_messages(id));"); - self.executor.send(QueryMessage::other(create_table_query, vec![]))?; + // If table doesn't exist, create it with all columns + if !table_exists { + self.executor.send(QueryMessage::other(create_table_query, vec![]))?; + } else { + // If table exists, try to add any missing columns + for alter_query in alter_table_queries { + // We need to wrap each ALTER TABLE in a try-catch since the column might already exist + self.executor.send(QueryMessage::other( + alter_query, + vec![] + ))?; + } + } - for s in indices.iter() { - self.executor.send(QueryMessage::other(s.to_string(), vec![]))?; + // Create indices + for index_query in indices { + self.executor.send(QueryMessage::other(index_query, vec![]))?; } Ok(()) From fa71dbd8435e1160b2aa1006c0d715a84852a898 Mon Sep 17 00:00:00 2001 From: Nasr Date: Tue, 5 Nov 2024 20:00:55 -0500 Subject: [PATCH 02/35] upgrade processor for event and model --- crates/dojo/world/src/contracts/model.rs | 35 ++++++ crates/dojo/world/src/contracts/world.rs | 8 ++ crates/torii/core/src/processors/mod.rs | 2 + .../core/src/processors/register_event.rs | 7 +- .../core/src/processors/register_model.rs | 1 + .../core/src/processors/upgrade_event.rs | 102 ++++++++++++++++++ .../core/src/processors/upgrade_model.rs | 98 +++++++++++++++++ crates/torii/core/src/sql/mod.rs | 93 ++++++---------- 8 files changed, 285 insertions(+), 61 deletions(-) create mode 100644 crates/torii/core/src/processors/upgrade_event.rs create mode 100644 crates/torii/core/src/processors/upgrade_model.rs diff --git a/crates/dojo/world/src/contracts/model.rs b/crates/dojo/world/src/contracts/model.rs index 623b164a64..ff488f519d 100644 --- a/crates/dojo/world/src/contracts/model.rs +++ b/crates/dojo/world/src/contracts/model.rs @@ -117,6 +117,41 @@ where }) } + pub async fn new_with_selector( + selector: Felt, + world: &'a WorldContractReader

, + ) -> Result, ModelError> { + // Events are also considered like models from a off-chain perspective. They both have + // introspection and convey type information. + let (contract_address, class_hash) = + match world.resource(&selector).block_id(world.block_id).call().await? { + abigen::world::Resource::Model((address, hash)) => (address, hash), + abigen::world::Resource::Event((address, hash)) => (address, hash), + _ => return Err(ModelError::ModelNotFound), + }; + + // World Cairo contract won't raise an error in case of unknown/unregistered + // model so raise an error here in case of zero address. + if contract_address == ContractAddress(Felt::ZERO) { + return Err(ModelError::ModelNotFound); + } + + let model_reader = ModelContractReader::new(contract_address.into(), world.provider()); + let tag = model_reader.dojo_name().call().await?; + // Safe to unwrap, since it's coming from the chain. + let (namespace, name) = naming::split_tag(&tag.to_string().unwrap()).unwrap(); + + Ok(Self { + namespace: namespace.into(), + name: name.into(), + world_reader: world, + class_hash, + contract_address: contract_address.into(), + selector, + model_reader, + }) + } + pub async fn entity_storage(&self, keys: &[Felt]) -> Result, ModelError> { // As the dojo::model::Layout type has been pasted // in both `model` and `world` ABI by abigen, the compiler sees both types diff --git a/crates/dojo/world/src/contracts/world.rs b/crates/dojo/world/src/contracts/world.rs index 11224da756..dfa05e6b6c 100644 --- a/crates/dojo/world/src/contracts/world.rs +++ b/crates/dojo/world/src/contracts/world.rs @@ -1,6 +1,7 @@ use std::result::Result; use starknet::providers::Provider; +use starknet_crypto::Felt; pub use super::abigen::world::{ ContractRegistered, ContractUpgraded, Event as WorldEvent, ModelRegistered, WorldContract, @@ -33,4 +34,11 @@ where ) -> Result, ModelError> { ModelRPCReader::new(namespace, name, self).await } + + pub async fn model_reader_with_selector( + &self, + selector: Felt, + ) -> Result, ModelError> { + ModelRPCReader::new_with_selector(selector, self).await + } } diff --git a/crates/torii/core/src/processors/mod.rs b/crates/torii/core/src/processors/mod.rs index 58dad65928..68973d400d 100644 --- a/crates/torii/core/src/processors/mod.rs +++ b/crates/torii/core/src/processors/mod.rs @@ -20,6 +20,8 @@ pub mod store_set_record; pub mod store_transaction; pub mod store_update_member; pub mod store_update_record; +pub mod upgrade_model; +pub mod upgrade_event; const MODEL_INDEX: usize = 0; const ENTITY_ID_INDEX: usize = 1; diff --git a/crates/torii/core/src/processors/register_event.rs b/crates/torii/core/src/processors/register_event.rs index 79ab0067f0..c1fbff31d9 100644 --- a/crates/torii/core/src/processors/register_event.rs +++ b/crates/torii/core/src/processors/register_event.rs @@ -21,7 +21,7 @@ where P: Provider + Send + Sync + std::fmt::Debug, { fn event_key(&self) -> String { - "EventRegistered".to_string() + "EventUpgraded".to_string() } // We might not need this anymore, since we don't have fallback and all world events must @@ -71,7 +71,7 @@ where target: LOG_TARGET, namespace = %namespace, name = %name, - "Registered event." + "Upgraded event." ); debug!( @@ -83,7 +83,7 @@ where contract_address = ?event.address, packed_size = %packed_size, unpacked_size = %unpacked_size, - "Registered model content." + "Upgraded event content." ); db.register_model( @@ -95,6 +95,7 @@ where packed_size, unpacked_size, block_timestamp, + true, ) .await?; diff --git a/crates/torii/core/src/processors/register_model.rs b/crates/torii/core/src/processors/register_model.rs index 6f25230b39..10ce03a0b8 100644 --- a/crates/torii/core/src/processors/register_model.rs +++ b/crates/torii/core/src/processors/register_model.rs @@ -92,6 +92,7 @@ where packed_size, unpacked_size, block_timestamp, + false, ) .await?; diff --git a/crates/torii/core/src/processors/upgrade_event.rs b/crates/torii/core/src/processors/upgrade_event.rs new file mode 100644 index 0000000000..3a8d83200e --- /dev/null +++ b/crates/torii/core/src/processors/upgrade_event.rs @@ -0,0 +1,102 @@ +use anyhow::{Error, Ok, Result}; +use async_trait::async_trait; +use dojo_world::contracts::abigen::world::Event as WorldEvent; +use dojo_world::contracts::model::ModelReader; +use dojo_world::contracts::world::WorldContractReader; +use starknet::core::types::Event; +use starknet::providers::Provider; +use tracing::{debug, info}; + +use super::EventProcessor; +use crate::sql::Sql; + +pub(crate) const LOG_TARGET: &str = "torii_core::processors::register_event"; + +#[derive(Default, Debug)] +pub struct RegisterEventProcessor; + +#[async_trait] +impl

EventProcessor

for RegisterEventProcessor +where + P: Provider + Send + Sync + std::fmt::Debug, +{ + fn event_key(&self) -> String { + "EventUpgraded".to_string() + } + + // We might not need this anymore, since we don't have fallback and all world events must + // be handled. + fn validate(&self, _event: &Event) -> bool { + true + } + + async fn process( + &self, + world: &WorldContractReader

, + db: &mut Sql, + _block_number: u64, + block_timestamp: u64, + _event_id: &str, + event: &Event, + ) -> Result<(), Error> { + // Torii version is coupled to the world version, so we can expect the event to be well + // formed. + let event = match WorldEvent::try_from(event).unwrap_or_else(|_| { + panic!( + "Expected {} event to be well formed.", + >::event_key(self) + ) + }) { + WorldEvent::EventUpgraded(e) => e, + _ => { + unreachable!() + } + }; + + // Called model here by language, but it's an event. Torii rework will make clear + // distinction. + let model = world.model_reader_with_selector(event.selector).await?; + let namespace = model.namespace(); + let name = model.name(); + let schema = model.schema().await?; + let layout = model.layout().await?; + + // Events are never stored onchain, hence no packing or unpacking. + let unpacked_size: u32 = 0; + let packed_size: u32 = 0; + + info!( + target: LOG_TARGET, + namespace = %namespace, + name = %name, + "Registered event." + ); + + debug!( + target: LOG_TARGET, + name, + schema = ?schema, + layout = ?layout, + class_hash = ?event.class_hash, + contract_address = ?event.address, + packed_size = %packed_size, + unpacked_size = %unpacked_size, + "Registered model content." + ); + + db.register_model( + &namespace, + schema, + layout, + event.class_hash.into(), + event.address.into(), + packed_size, + unpacked_size, + block_timestamp, + false, + ) + .await?; + + Ok(()) + } +} diff --git a/crates/torii/core/src/processors/upgrade_model.rs b/crates/torii/core/src/processors/upgrade_model.rs new file mode 100644 index 0000000000..9c26953516 --- /dev/null +++ b/crates/torii/core/src/processors/upgrade_model.rs @@ -0,0 +1,98 @@ +use anyhow::{Error, Ok, Result}; +use async_trait::async_trait; +use dojo_world::contracts::{abigen::world::Event as WorldEvent, model::ModelReader}; +use dojo_world::contracts::world::WorldContractReader; +use starknet::core::types::Event; +use starknet::providers::Provider; +use tracing::{debug, info}; + +use super::EventProcessor; +use crate::sql::Sql; + +pub(crate) const LOG_TARGET: &str = "torii_core::processors::register_model"; + +#[derive(Default, Debug)] +pub struct RegisterModelProcessor; + +#[async_trait] +impl

EventProcessor

for RegisterModelProcessor +where + P: Provider + Send + Sync + std::fmt::Debug, +{ + fn event_key(&self) -> String { + "ModelUpgraded".to_string() + } + + // We might not need this anymore, since we don't have fallback and all world events must + // be handled. + fn validate(&self, _event: &Event) -> bool { + true + } + + async fn process( + &self, + world: &WorldContractReader

, + db: &mut Sql, + _block_number: u64, + block_timestamp: u64, + _event_id: &str, + event: &Event, + ) -> Result<(), Error> { + // Torii version is coupled to the world version, so we can expect the event to be well + // formed. + let event = match WorldEvent::try_from(event).unwrap_or_else(|_| { + panic!( + "Expected {} event to be well formed.", + >::event_key(self) + ) + }) { + WorldEvent::ModelUpgraded(e) => e, + _ => { + unreachable!() + } + }; + + let model = world.model_reader_with_selector(event.selector).await?; + let namespace = model.namespace(); + let name = model.name(); + let schema = model.schema().await?; + let layout = model.layout().await?; + + let unpacked_size: u32 = model.unpacked_size().await?; + let packed_size: u32 = model.packed_size().await?; + + info!( + target: LOG_TARGET, + namespace = %namespace, + name = %name, + "Upgraded model." + ); + + debug!( + target: LOG_TARGET, + name = %name, + schema = ?schema, + layout = ?layout, + class_hash = ?event.class_hash, + contract_address = ?event.address, + packed_size = %packed_size, + unpacked_size = %unpacked_size, + "Upgraded model content." + ); + + db.register_model( + &namespace, + schema, + layout, + event.class_hash.into(), + event.address.into(), + packed_size, + unpacked_size, + block_timestamp, + true, + ) + .await?; + + Ok(()) + } +} diff --git a/crates/torii/core/src/sql/mod.rs b/crates/torii/core/src/sql/mod.rs index 233e857c50..50065a3941 100644 --- a/crates/torii/core/src/sql/mod.rs +++ b/crates/torii/core/src/sql/mod.rs @@ -261,6 +261,7 @@ impl Sql { packed_size: u32, unpacked_size: u32, block_timestamp: u64, + is_upgrade: bool, ) -> Result<()> { let selector = compute_selector_from_names(namespace, &model.name()); let namespaced_name = format!("{}-{}", namespace, model.name()); @@ -298,6 +299,7 @@ impl Sql { block_timestamp, &mut 0, &mut 0, + is_upgrade, )?; // we set the model in the cache directly @@ -633,6 +635,7 @@ impl Sql { block_timestamp: u64, array_idx: &mut usize, parent_array_idx: &mut usize, + is_upgrade: bool, ) -> Result<()> { if let Ty::Enum(e) = model { if e.options.iter().all(|o| if let Ty::Tuple(t) = &o.ty { t.is_empty() } else { false }) @@ -649,6 +652,7 @@ impl Sql { block_timestamp, *array_idx, *parent_array_idx, + is_upgrade, )?; let mut build_member = |pathname: &str, member: &Ty| -> Result<()> { @@ -669,6 +673,7 @@ impl Sql { block_timestamp, &mut (*array_idx + if let Ty::Array(_) = member { 1 } else { 0 }), &mut (*parent_array_idx + if let Ty::Array(_) = model { 1 } else { 0 }), + is_upgrade, )?; Ok(()) @@ -828,7 +833,11 @@ impl Sql { Ty::Enum(e) => { if e.options.iter().all( |o| { - if let Ty::Tuple(t) = &o.ty { t.is_empty() } else { false } + if let Ty::Tuple(t) = &o.ty { + t.is_empty() + } else { + false + } }, ) { return Ok(()); @@ -1016,7 +1025,7 @@ impl Sql { } #[allow(clippy::too_many_arguments)] - async fn build_model_query( + fn build_model_query( &mut self, selector: Felt, path: Vec, @@ -1025,18 +1034,11 @@ impl Sql { block_timestamp: u64, array_idx: usize, parent_array_idx: usize, + is_upgrade: bool, ) -> Result<()> { let table_id = path.join("$"); let mut indices = Vec::new(); - // Check if table exists using sqlx - let table_exists = sqlx::query_scalar::<_, bool>( - "SELECT EXISTS (SELECT 1 FROM sqlite_master WHERE type='table' AND name = ?)" - ) - .bind(&table_id) - .fetch_one(&self.pool) - .await?; - let mut create_table_query = format!( "CREATE TABLE IF NOT EXISTS [{table_id}] (id TEXT NOT NULL, event_id TEXT NOT NULL, \ entity_id TEXT, event_message_id TEXT, " @@ -1049,38 +1051,30 @@ impl Sql { for i in 0..array_idx { let column = format!("idx_{i} INTEGER NOT NULL"); create_table_query.push_str(&format!("{column}, ")); - - if table_exists { - // For upgrades, add column if it doesn't exist - alter_table_queries.push(format!( - "ALTER TABLE [{table_id}] ADD COLUMN idx_{i} INTEGER NOT NULL DEFAULT 0" - )); - } + + alter_table_queries.push(format!( + "ALTER TABLE [{table_id}] ADD COLUMN idx_{i} INTEGER NOT NULL DEFAULT 0" + )); } // full array id column create_table_query.push_str("full_array_id TEXT NOT NULL UNIQUE, "); - if table_exists { - alter_table_queries.push( - format!("ALTER TABLE [{table_id}] ADD COLUMN full_array_id TEXT NOT NULL UNIQUE DEFAULT ''") - ); - } + alter_table_queries.push(format!( + "ALTER TABLE [{table_id}] ADD COLUMN full_array_id TEXT NOT NULL UNIQUE DEFAULT ''" + )); } let mut build_member = |name: &str, ty: &Ty, options: &mut Option| { if let Ok(cairo_type) = Primitive::from_str(&ty.name()) { let sql_type = cairo_type.to_sql_type(); let column = format!("external_{name} {sql_type}"); - + create_table_query.push_str(&format!("{column}, ")); - - if table_exists { - // Add ALTER TABLE query for upgrades - alter_table_queries.push( - format!("ALTER TABLE [{table_id}] ADD COLUMN external_{name} {sql_type}") - ); - } - + + alter_table_queries.push(format!( + "ALTER TABLE [{table_id}] ADD COLUMN external_{name} {sql_type}" + )); + indices.push(format!( "CREATE INDEX IF NOT EXISTS [idx_{table_id}_{name}] ON [{table_id}] \ (external_{name});" @@ -1097,15 +1091,10 @@ impl Sql { "external_{name} TEXT CHECK(external_{name} IN ({all_options})) {}", if array_idx > 0 { "" } else { "NOT NULL" } ); - + create_table_query.push_str(&format!("{column}, ")); - - if table_exists { - // Add ALTER TABLE query for upgrades - alter_table_queries.push( - format!("ALTER TABLE [{table_id}] ADD COLUMN {column}") - ); - } + + alter_table_queries.push(format!("ALTER TABLE [{table_id}] ADD COLUMN {column}")); indices.push(format!( "CREATE INDEX IF NOT EXISTS [idx_{table_id}_{name}] ON [{table_id}] \ @@ -1122,15 +1111,10 @@ impl Sql { )); } else if let Ty::ByteArray(_) = &ty { let column = format!("external_{name} TEXT"); - + create_table_query.push_str(&format!("{column}, ")); - - if table_exists { - // Add ALTER TABLE query for upgrades - alter_table_queries.push( - format!("ALTER TABLE [{table_id}] ADD COLUMN {column}") - ); - } + + alter_table_queries.push(format!("ALTER TABLE [{table_id}] ADD COLUMN {column}")); indices.push(format!( "CREATE INDEX IF NOT EXISTS [idx_{table_id}_{name}] ON [{table_id}] \ @@ -1298,21 +1282,14 @@ impl Sql { create_table_query .push_str("FOREIGN KEY (event_message_id) REFERENCES event_messages(id));"); - // If table doesn't exist, create it with all columns - if !table_exists { - self.executor.send(QueryMessage::other(create_table_query, vec![]))?; - } else { - // If table exists, try to add any missing columns + if is_upgrade { for alter_query in alter_table_queries { - // We need to wrap each ALTER TABLE in a try-catch since the column might already exist - self.executor.send(QueryMessage::other( - alter_query, - vec![] - ))?; + self.executor.send(QueryMessage::other(alter_query, vec![]))?; } + } else { + self.executor.send(QueryMessage::other(create_table_query, vec![]))?; } - // Create indices for index_query in indices { self.executor.send(QueryMessage::other(index_query, vec![]))?; } From 62750f6e39c10aa1def5d07dc6e3fbaa4bbd2bec Mon Sep 17 00:00:00 2001 From: Nasr Date: Tue, 5 Nov 2024 22:36:21 -0500 Subject: [PATCH 03/35] fix processors --- crates/dojo/world/src/contracts/model.rs | 37 +------------------ crates/dojo/world/src/contracts/world.rs | 8 ---- crates/torii/core/src/engine.rs | 4 ++ .../core/src/processors/register_event.rs | 8 ++-- .../core/src/processors/upgrade_event.rs | 22 ++++++----- .../core/src/processors/upgrade_model.rs | 16 ++++---- 6 files changed, 30 insertions(+), 65 deletions(-) diff --git a/crates/dojo/world/src/contracts/model.rs b/crates/dojo/world/src/contracts/model.rs index ff488f519d..5108ca634e 100644 --- a/crates/dojo/world/src/contracts/model.rs +++ b/crates/dojo/world/src/contracts/model.rs @@ -117,41 +117,6 @@ where }) } - pub async fn new_with_selector( - selector: Felt, - world: &'a WorldContractReader

, - ) -> Result, ModelError> { - // Events are also considered like models from a off-chain perspective. They both have - // introspection and convey type information. - let (contract_address, class_hash) = - match world.resource(&selector).block_id(world.block_id).call().await? { - abigen::world::Resource::Model((address, hash)) => (address, hash), - abigen::world::Resource::Event((address, hash)) => (address, hash), - _ => return Err(ModelError::ModelNotFound), - }; - - // World Cairo contract won't raise an error in case of unknown/unregistered - // model so raise an error here in case of zero address. - if contract_address == ContractAddress(Felt::ZERO) { - return Err(ModelError::ModelNotFound); - } - - let model_reader = ModelContractReader::new(contract_address.into(), world.provider()); - let tag = model_reader.dojo_name().call().await?; - // Safe to unwrap, since it's coming from the chain. - let (namespace, name) = naming::split_tag(&tag.to_string().unwrap()).unwrap(); - - Ok(Self { - namespace: namespace.into(), - name: name.into(), - world_reader: world, - class_hash, - contract_address: contract_address.into(), - selector, - model_reader, - }) - } - pub async fn entity_storage(&self, keys: &[Felt]) -> Result, ModelError> { // As the dojo::model::Layout type has been pasted // in both `model` and `world` ABI by abigen, the compiler sees both types @@ -211,7 +176,7 @@ where parse_schema(&abigen::model::Ty::Struct(res)).map_err(ModelError::Parse) } - // For non fixed layouts, packed and unpacked sizes are None. + // For non fixed layouts, packed and unpacked sizes are None. // Therefore we return 0 in this case. async fn packed_size(&self) -> Result { Ok(self.model_reader.packed_size().call().await?.unwrap_or(0)) diff --git a/crates/dojo/world/src/contracts/world.rs b/crates/dojo/world/src/contracts/world.rs index dfa05e6b6c..11224da756 100644 --- a/crates/dojo/world/src/contracts/world.rs +++ b/crates/dojo/world/src/contracts/world.rs @@ -1,7 +1,6 @@ use std::result::Result; use starknet::providers::Provider; -use starknet_crypto::Felt; pub use super::abigen::world::{ ContractRegistered, ContractUpgraded, Event as WorldEvent, ModelRegistered, WorldContract, @@ -34,11 +33,4 @@ where ) -> Result, ModelError> { ModelRPCReader::new(namespace, name, self).await } - - pub async fn model_reader_with_selector( - &self, - selector: Felt, - ) -> Result, ModelError> { - ModelRPCReader::new_with_selector(selector, self).await - } } diff --git a/crates/torii/core/src/engine.rs b/crates/torii/core/src/engine.rs index f060500f89..67402f53a1 100644 --- a/crates/torii/core/src/engine.rs +++ b/crates/torii/core/src/engine.rs @@ -37,6 +37,8 @@ use crate::processors::store_del_record::StoreDelRecordProcessor; use crate::processors::store_set_record::StoreSetRecordProcessor; use crate::processors::store_update_member::StoreUpdateMemberProcessor; use crate::processors::store_update_record::StoreUpdateRecordProcessor; +use crate::processors::upgrade_event::UpgradeEventProcessor; +use crate::processors::upgrade_model::UpgradeModelProcessor; use crate::processors::{BlockProcessor, EventProcessor, TransactionProcessor}; use crate::sql::{Cursors, Sql}; use crate::types::ContractType; @@ -74,6 +76,8 @@ impl Processors

{ vec![ Box::new(RegisterModelProcessor) as Box>, Box::new(RegisterEventProcessor) as Box>, + Box::new(UpgradeModelProcessor) as Box>, + Box::new(UpgradeEventProcessor) as Box>, Box::new(StoreSetRecordProcessor), Box::new(StoreDelRecordProcessor), Box::new(StoreUpdateRecordProcessor), diff --git a/crates/torii/core/src/processors/register_event.rs b/crates/torii/core/src/processors/register_event.rs index c1fbff31d9..975cc78ea8 100644 --- a/crates/torii/core/src/processors/register_event.rs +++ b/crates/torii/core/src/processors/register_event.rs @@ -21,7 +21,7 @@ where P: Provider + Send + Sync + std::fmt::Debug, { fn event_key(&self) -> String { - "EventUpgraded".to_string() + "EventRegistered".to_string() } // We might not need this anymore, since we don't have fallback and all world events must @@ -71,7 +71,7 @@ where target: LOG_TARGET, namespace = %namespace, name = %name, - "Upgraded event." + "Registered event." ); debug!( @@ -83,7 +83,7 @@ where contract_address = ?event.address, packed_size = %packed_size, unpacked_size = %unpacked_size, - "Upgraded event content." + "Registered event content." ); db.register_model( @@ -95,7 +95,7 @@ where packed_size, unpacked_size, block_timestamp, - true, + false, ) .await?; diff --git a/crates/torii/core/src/processors/upgrade_event.rs b/crates/torii/core/src/processors/upgrade_event.rs index 3a8d83200e..75312d3a9c 100644 --- a/crates/torii/core/src/processors/upgrade_event.rs +++ b/crates/torii/core/src/processors/upgrade_event.rs @@ -10,13 +10,13 @@ use tracing::{debug, info}; use super::EventProcessor; use crate::sql::Sql; -pub(crate) const LOG_TARGET: &str = "torii_core::processors::register_event"; +pub(crate) const LOG_TARGET: &str = "torii_core::processors::upgrade_event"; #[derive(Default, Debug)] -pub struct RegisterEventProcessor; +pub struct UpgradeEventProcessor; #[async_trait] -impl

EventProcessor

for RegisterEventProcessor +impl

EventProcessor

for UpgradeEventProcessor where P: Provider + Send + Sync + std::fmt::Debug, { @@ -44,7 +44,7 @@ where let event = match WorldEvent::try_from(event).unwrap_or_else(|_| { panic!( "Expected {} event to be well formed.", - >::event_key(self) + >::event_key(self) ) }) { WorldEvent::EventUpgraded(e) => e, @@ -55,9 +55,11 @@ where // Called model here by language, but it's an event. Torii rework will make clear // distinction. - let model = world.model_reader_with_selector(event.selector).await?; - let namespace = model.namespace(); - let name = model.name(); + let model = db.model(event.selector).await?; + let name = model.name; + let namespace = model.namespace; + + let model = world.model_reader(&namespace, &name).await?; let schema = model.schema().await?; let layout = model.layout().await?; @@ -69,7 +71,7 @@ where target: LOG_TARGET, namespace = %namespace, name = %name, - "Registered event." + "Upgraded event." ); debug!( @@ -81,7 +83,7 @@ where contract_address = ?event.address, packed_size = %packed_size, unpacked_size = %unpacked_size, - "Registered model content." + "Upgraded event content." ); db.register_model( @@ -93,7 +95,7 @@ where packed_size, unpacked_size, block_timestamp, - false, + true, ) .await?; diff --git a/crates/torii/core/src/processors/upgrade_model.rs b/crates/torii/core/src/processors/upgrade_model.rs index 9c26953516..06f3336232 100644 --- a/crates/torii/core/src/processors/upgrade_model.rs +++ b/crates/torii/core/src/processors/upgrade_model.rs @@ -9,13 +9,13 @@ use tracing::{debug, info}; use super::EventProcessor; use crate::sql::Sql; -pub(crate) const LOG_TARGET: &str = "torii_core::processors::register_model"; +pub(crate) const LOG_TARGET: &str = "torii_core::processors::upgrade_model"; #[derive(Default, Debug)] -pub struct RegisterModelProcessor; +pub struct UpgradeModelProcessor; #[async_trait] -impl

EventProcessor

for RegisterModelProcessor +impl

EventProcessor

for UpgradeModelProcessor where P: Provider + Send + Sync + std::fmt::Debug, { @@ -43,7 +43,7 @@ where let event = match WorldEvent::try_from(event).unwrap_or_else(|_| { panic!( "Expected {} event to be well formed.", - >::event_key(self) + >::event_key(self) ) }) { WorldEvent::ModelUpgraded(e) => e, @@ -52,9 +52,11 @@ where } }; - let model = world.model_reader_with_selector(event.selector).await?; - let namespace = model.namespace(); - let name = model.name(); + let model = db.model(event.selector).await?; + let name = model.name; + let namespace = model.namespace; + + let model = world.model_reader(&namespace, &name).await?; let schema = model.schema().await?; let layout = model.layout().await?; From 6313f44e101656a57d76369d1093b2d51d4c854a Mon Sep 17 00:00:00 2001 From: Nasr Date: Wed, 6 Nov 2024 12:53:04 -0500 Subject: [PATCH 04/35] fix: model upgrade --- crates/dojo/types/src/schema.rs | 167 ++++++++++++++++++ .../core/src/processors/upgrade_event.rs | 24 ++- .../core/src/processors/upgrade_model.rs | 23 ++- crates/torii/core/src/sql/mod.rs | 3 +- 4 files changed, 210 insertions(+), 7 deletions(-) diff --git a/crates/dojo/types/src/schema.rs b/crates/dojo/types/src/schema.rs index 943996d7ef..c7ac85caf4 100644 --- a/crates/dojo/types/src/schema.rs +++ b/crates/dojo/types/src/schema.rs @@ -224,6 +224,87 @@ impl Ty { } Ok(()) } + + /// Returns a new Ty containing only the differences between self and other + pub fn diff(&self, other: &Ty) -> Option { + match (self, other) { + (Ty::Struct(s1), Ty::Struct(s2)) if s1.name == s2.name => { + // Find members that exist in s1 but not in s2, or are different + let diff_children: Vec = s1.children + .iter() + .filter(|m1| { + s2.children + .iter() + .find(|m2| m2.name == m1.name) + .map_or(true, |m2| *m1 != m2) + }) + .cloned() + .collect(); + + if diff_children.is_empty() { + None + } else { + Some(Ty::Struct(Struct { + name: s1.name.clone(), + children: diff_children, + })) + } + } + (Ty::Enum(e1), Ty::Enum(e2)) if e1.name == e2.name => { + // Find options that exist in e1 but not in e2, or are different + let diff_options: Vec = e1.options + .iter() + .filter(|o1| { + e2.options + .iter() + .find(|o2| o2.name == o1.name) + .map_or(true, |o2| *o1 != o2) + }) + .cloned() + .collect(); + + if diff_options.is_empty() { + None + } else { + Some(Ty::Enum(Enum { + name: e1.name.clone(), + option: e1.option, + options: diff_options, + })) + } + } + (Ty::Array(a1), Ty::Array(a2)) => { + if a1 == a2 { + None + } else { + Some(Ty::Array(a1.clone())) + } + } + (Ty::Tuple(t1), Ty::Tuple(t2)) => { + if t1 == t2 { + None + } else { + Some(Ty::Tuple(t1.clone())) + } + } + (Ty::ByteArray(b1), Ty::ByteArray(b2)) => { + if b1 == b2 { + None + } else { + Some(Ty::ByteArray(b1.clone())) + } + } + (Ty::Primitive(p1), Ty::Primitive(p2)) => { + if p1 == p2 { + None + } else { + Some(Ty::Primitive(p1.clone())) + } + } + // Different types entirely - return the new type + _ => Some(self.clone()), + } + } } #[derive(Debug)] @@ -597,4 +678,90 @@ mod tests { assert_eq!(format_member(&member), expected); } } + + #[test] + fn test_ty_diff() { + // Test struct diff + let struct1 = Ty::Struct(Struct { + name: "TestStruct".to_string(), + children: vec![ + Member { + name: "field1".to_string(), + ty: Ty::Primitive(Primitive::U32(None)), + key: false, + }, + Member { + name: "field2".to_string(), + ty: Ty::Primitive(Primitive::U32(None)), + key: false, + }, + Member { + name: "field3".to_string(), + ty: Ty::Primitive(Primitive::U32(None)), + key: false, + }, + ], + }); + + let struct2 = Ty::Struct(Struct { + name: "TestStruct".to_string(), + children: vec![ + Member { + name: "field1".to_string(), + ty: Ty::Primitive(Primitive::U32(None)), + key: false, + }, + ], + }); + + // Should show only field2 and field3 as differences + let diff = struct1.diff(&struct2).unwrap(); + if let Ty::Struct(s) = diff { + assert_eq!(s.children.len(), 2); + assert_eq!(s.children[0].name, "field2"); + assert_eq!(s.children[1].name, "field3"); + } else { + panic!("Expected Struct diff"); + } + + // Test enum diff + let enum1 = Ty::Enum(Enum { + name: "TestEnum".to_string(), + option: None, + options: vec![ + EnumOption { + name: "Option1".to_string(), + ty: Ty::Tuple(vec![]), + }, + EnumOption { + name: "Option2".to_string(), + ty: Ty::Tuple(vec![]), + }, + ], + }); + + let enum2 = Ty::Enum(Enum { + name: "TestEnum".to_string(), + option: None, + options: vec![ + EnumOption { + name: "Option1".to_string(), + ty: Ty::Tuple(vec![]), + }, + ], + }); + + // Should show only Option2 as difference + let diff = enum1.diff(&enum2).unwrap(); + if let Ty::Enum(e) = diff { + assert_eq!(e.options.len(), 1); + assert_eq!(e.options[0].name, "Option2"); + } else { + panic!("Expected Enum diff"); + } + + // Test no differences + let same_struct = struct2.diff(&struct2); + assert!(same_struct.is_none()); + } } diff --git a/crates/torii/core/src/processors/upgrade_event.rs b/crates/torii/core/src/processors/upgrade_event.rs index 75312d3a9c..c907de3fc5 100644 --- a/crates/torii/core/src/processors/upgrade_event.rs +++ b/crates/torii/core/src/processors/upgrade_event.rs @@ -1,5 +1,6 @@ use anyhow::{Error, Ok, Result}; use async_trait::async_trait; +use dojo_types::schema::Ty; use dojo_world::contracts::abigen::world::Event as WorldEvent; use dojo_world::contracts::model::ModelReader; use dojo_world::contracts::world::WorldContractReader; @@ -58,9 +59,26 @@ where let model = db.model(event.selector).await?; let name = model.name; let namespace = model.namespace; + let prev_schema = model.schema; let model = world.model_reader(&namespace, &name).await?; - let schema = model.schema().await?; + let mut new_schema = model.schema().await?; + match &mut new_schema { + Ty::Struct(s) => { + s.name = format!("{}-{}", namespace, name); + } + _ => unreachable!(), + } + + let schema_diff = new_schema.diff(&prev_schema); + // No changes to the schema. This can happen if torii is re-run with a fresh database. + // As the register model fetches the latest schema from the chain. + if schema_diff.is_none() { + return Ok(()); + } + + + let schema_diff = schema_diff.unwrap(); let layout = model.layout().await?; // Events are never stored onchain, hence no packing or unpacking. @@ -77,7 +95,7 @@ where debug!( target: LOG_TARGET, name, - schema = ?schema, + diff = ?schema_diff, layout = ?layout, class_hash = ?event.class_hash, contract_address = ?event.address, @@ -88,7 +106,7 @@ where db.register_model( &namespace, - schema, + schema_diff, layout, event.class_hash.into(), event.address.into(), diff --git a/crates/torii/core/src/processors/upgrade_model.rs b/crates/torii/core/src/processors/upgrade_model.rs index 06f3336232..2ef71baf13 100644 --- a/crates/torii/core/src/processors/upgrade_model.rs +++ b/crates/torii/core/src/processors/upgrade_model.rs @@ -1,5 +1,6 @@ use anyhow::{Error, Ok, Result}; use async_trait::async_trait; +use dojo_types::schema::Ty; use dojo_world::contracts::{abigen::world::Event as WorldEvent, model::ModelReader}; use dojo_world::contracts::world::WorldContractReader; use starknet::core::types::Event; @@ -55,9 +56,25 @@ where let model = db.model(event.selector).await?; let name = model.name; let namespace = model.namespace; + let prev_schema = model.schema; let model = world.model_reader(&namespace, &name).await?; - let schema = model.schema().await?; + let mut new_schema = model.schema().await?; + match &mut new_schema { + Ty::Struct(s) => { + s.name = format!("{}-{}", namespace, name); + } + _ => unreachable!(), + } + + let schema_diff = new_schema.diff(&prev_schema); + // No changes to the schema. This can happen if torii is re-run with a fresh database. + // As the register model fetches the latest schema from the chain. + if schema_diff.is_none() { + return Ok(()); + } + + let schema_diff = schema_diff.unwrap(); let layout = model.layout().await?; let unpacked_size: u32 = model.unpacked_size().await?; @@ -73,7 +90,7 @@ where debug!( target: LOG_TARGET, name = %name, - schema = ?schema, + diff = ?schema_diff, layout = ?layout, class_hash = ?event.class_hash, contract_address = ?event.address, @@ -84,7 +101,7 @@ where db.register_model( &namespace, - schema, + schema_diff, layout, event.class_hash.into(), event.address.into(), diff --git a/crates/torii/core/src/sql/mod.rs b/crates/torii/core/src/sql/mod.rs index 50065a3941..92191d7ed6 100644 --- a/crates/torii/core/src/sql/mod.rs +++ b/crates/torii/core/src/sql/mod.rs @@ -673,7 +673,8 @@ impl Sql { block_timestamp, &mut (*array_idx + if let Ty::Array(_) = member { 1 } else { 0 }), &mut (*parent_array_idx + if let Ty::Array(_) = model { 1 } else { 0 }), - is_upgrade, + // nested members are not upgrades + false, )?; Ok(()) From f7fd6aea574bf32400479f3784e86e36c69cca64 Mon Sep 17 00:00:00 2001 From: Nasr Date: Wed, 6 Nov 2024 13:31:10 -0500 Subject: [PATCH 05/35] wrap up model upgrade --- crates/torii/core/src/processors/upgrade_event.rs | 11 +++++------ crates/torii/core/src/processors/upgrade_model.rs | 11 +++++------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/crates/torii/core/src/processors/upgrade_event.rs b/crates/torii/core/src/processors/upgrade_event.rs index c907de3fc5..8c25f9eb6e 100644 --- a/crates/torii/core/src/processors/upgrade_event.rs +++ b/crates/torii/core/src/processors/upgrade_event.rs @@ -59,17 +59,16 @@ where let model = db.model(event.selector).await?; let name = model.name; let namespace = model.namespace; - let prev_schema = model.schema; - - let model = world.model_reader(&namespace, &name).await?; - let mut new_schema = model.schema().await?; - match &mut new_schema { + let mut prev_schema = model.schema; + match &mut prev_schema { Ty::Struct(s) => { - s.name = format!("{}-{}", namespace, name); + s.name = name.clone(); } _ => unreachable!(), } + let model = world.model_reader(&namespace, &name).await?; + let new_schema = model.schema().await?; let schema_diff = new_schema.diff(&prev_schema); // No changes to the schema. This can happen if torii is re-run with a fresh database. // As the register model fetches the latest schema from the chain. diff --git a/crates/torii/core/src/processors/upgrade_model.rs b/crates/torii/core/src/processors/upgrade_model.rs index 2ef71baf13..47474032b1 100644 --- a/crates/torii/core/src/processors/upgrade_model.rs +++ b/crates/torii/core/src/processors/upgrade_model.rs @@ -56,17 +56,16 @@ where let model = db.model(event.selector).await?; let name = model.name; let namespace = model.namespace; - let prev_schema = model.schema; - - let model = world.model_reader(&namespace, &name).await?; - let mut new_schema = model.schema().await?; - match &mut new_schema { + let mut prev_schema = model.schema; + match &mut prev_schema { Ty::Struct(s) => { - s.name = format!("{}-{}", namespace, name); + s.name = name.clone(); } _ => unreachable!(), } + let model = world.model_reader(&namespace, &name).await?; + let new_schema = model.schema().await?; let schema_diff = new_schema.diff(&prev_schema); // No changes to the schema. This can happen if torii is re-run with a fresh database. // As the register model fetches the latest schema from the chain. From e85bdd09ba4c0c29743ca26f70d3d30f8c720d64 Mon Sep 17 00:00:00 2001 From: Nasr Date: Wed, 6 Nov 2024 13:31:25 -0500 Subject: [PATCH 06/35] ftm --- crates/dojo/types/src/schema.rs | 45 ++++++------------- crates/torii/core/src/processors/mod.rs | 2 +- .../core/src/processors/upgrade_event.rs | 1 - .../core/src/processors/upgrade_model.rs | 3 +- crates/torii/core/src/sql/mod.rs | 6 +-- 5 files changed, 18 insertions(+), 39 deletions(-) diff --git a/crates/dojo/types/src/schema.rs b/crates/dojo/types/src/schema.rs index c7ac85caf4..362bc56706 100644 --- a/crates/dojo/types/src/schema.rs +++ b/crates/dojo/types/src/schema.rs @@ -230,7 +230,8 @@ impl Ty { match (self, other) { (Ty::Struct(s1), Ty::Struct(s2)) if s1.name == s2.name => { // Find members that exist in s1 but not in s2, or are different - let diff_children: Vec = s1.children + let diff_children: Vec = s1 + .children .iter() .filter(|m1| { s2.children @@ -244,21 +245,16 @@ impl Ty { if diff_children.is_empty() { None } else { - Some(Ty::Struct(Struct { - name: s1.name.clone(), - children: diff_children, - })) + Some(Ty::Struct(Struct { name: s1.name.clone(), children: diff_children })) } } (Ty::Enum(e1), Ty::Enum(e2)) if e1.name == e2.name => { // Find options that exist in e1 but not in e2, or are different - let diff_options: Vec = e1.options + let diff_options: Vec = e1 + .options .iter() .filter(|o1| { - e2.options - .iter() - .find(|o2| o2.name == o1.name) - .map_or(true, |o2| *o1 != o2) + e2.options.iter().find(|o2| o2.name == o1.name).map_or(true, |o2| *o1 != o2) }) .cloned() .collect(); @@ -705,13 +701,11 @@ mod tests { let struct2 = Ty::Struct(Struct { name: "TestStruct".to_string(), - children: vec![ - Member { - name: "field1".to_string(), - ty: Ty::Primitive(Primitive::U32(None)), - key: false, - }, - ], + children: vec![Member { + name: "field1".to_string(), + ty: Ty::Primitive(Primitive::U32(None)), + key: false, + }], }); // Should show only field2 and field3 as differences @@ -729,26 +723,15 @@ mod tests { name: "TestEnum".to_string(), option: None, options: vec![ - EnumOption { - name: "Option1".to_string(), - ty: Ty::Tuple(vec![]), - }, - EnumOption { - name: "Option2".to_string(), - ty: Ty::Tuple(vec![]), - }, + EnumOption { name: "Option1".to_string(), ty: Ty::Tuple(vec![]) }, + EnumOption { name: "Option2".to_string(), ty: Ty::Tuple(vec![]) }, ], }); let enum2 = Ty::Enum(Enum { name: "TestEnum".to_string(), option: None, - options: vec![ - EnumOption { - name: "Option1".to_string(), - ty: Ty::Tuple(vec![]), - }, - ], + options: vec![EnumOption { name: "Option1".to_string(), ty: Ty::Tuple(vec![]) }], }); // Should show only Option2 as difference diff --git a/crates/torii/core/src/processors/mod.rs b/crates/torii/core/src/processors/mod.rs index 68973d400d..55ef7d41c8 100644 --- a/crates/torii/core/src/processors/mod.rs +++ b/crates/torii/core/src/processors/mod.rs @@ -20,8 +20,8 @@ pub mod store_set_record; pub mod store_transaction; pub mod store_update_member; pub mod store_update_record; -pub mod upgrade_model; pub mod upgrade_event; +pub mod upgrade_model; const MODEL_INDEX: usize = 0; const ENTITY_ID_INDEX: usize = 1; diff --git a/crates/torii/core/src/processors/upgrade_event.rs b/crates/torii/core/src/processors/upgrade_event.rs index 8c25f9eb6e..c77e48f1c2 100644 --- a/crates/torii/core/src/processors/upgrade_event.rs +++ b/crates/torii/core/src/processors/upgrade_event.rs @@ -76,7 +76,6 @@ where return Ok(()); } - let schema_diff = schema_diff.unwrap(); let layout = model.layout().await?; diff --git a/crates/torii/core/src/processors/upgrade_model.rs b/crates/torii/core/src/processors/upgrade_model.rs index 47474032b1..8cae4aab8e 100644 --- a/crates/torii/core/src/processors/upgrade_model.rs +++ b/crates/torii/core/src/processors/upgrade_model.rs @@ -1,7 +1,8 @@ use anyhow::{Error, Ok, Result}; use async_trait::async_trait; use dojo_types::schema::Ty; -use dojo_world::contracts::{abigen::world::Event as WorldEvent, model::ModelReader}; +use dojo_world::contracts::abigen::world::Event as WorldEvent; +use dojo_world::contracts::model::ModelReader; use dojo_world::contracts::world::WorldContractReader; use starknet::core::types::Event; use starknet::providers::Provider; diff --git a/crates/torii/core/src/sql/mod.rs b/crates/torii/core/src/sql/mod.rs index 92191d7ed6..53884e15da 100644 --- a/crates/torii/core/src/sql/mod.rs +++ b/crates/torii/core/src/sql/mod.rs @@ -834,11 +834,7 @@ impl Sql { Ty::Enum(e) => { if e.options.iter().all( |o| { - if let Ty::Tuple(t) = &o.ty { - t.is_empty() - } else { - false - } + if let Ty::Tuple(t) = &o.ty { t.is_empty() } else { false } }, ) { return Ok(()); From d641ba021ddc55634124f7dad4d6d128d64c0bf4 Mon Sep 17 00:00:00 2001 From: Nasr Date: Wed, 6 Nov 2024 13:46:24 -0500 Subject: [PATCH 07/35] clippy --- crates/dojo/types/src/schema.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/dojo/types/src/schema.rs b/crates/dojo/types/src/schema.rs index 362bc56706..fc7f72b27a 100644 --- a/crates/dojo/types/src/schema.rs +++ b/crates/dojo/types/src/schema.rs @@ -294,7 +294,7 @@ impl Ty { if p1 == p2 { None } else { - Some(Ty::Primitive(p1.clone())) + Some(Ty::Primitive(*p1)) } } // Different types entirely - return the new type From 3336c4a27f8f90fa32bda757ecdb18272d3ef120 Mon Sep 17 00:00:00 2001 From: Nasr Date: Wed, 6 Nov 2024 15:59:06 -0500 Subject: [PATCH 08/35] fmt --- crates/torii/graphql/src/tests/mod.rs | 1 + crates/torii/graphql/src/tests/subscription_test.rs | 2 ++ crates/torii/libp2p/src/tests.rs | 1 + 3 files changed, 4 insertions(+) diff --git a/crates/torii/graphql/src/tests/mod.rs b/crates/torii/graphql/src/tests/mod.rs index 7a54dcce72..22bda2faf0 100644 --- a/crates/torii/graphql/src/tests/mod.rs +++ b/crates/torii/graphql/src/tests/mod.rs @@ -266,6 +266,7 @@ pub async fn model_fixtures(db: &mut Sql) { 0, 0, 1710754478_u64, + false, ) .await .unwrap(); diff --git a/crates/torii/graphql/src/tests/subscription_test.rs b/crates/torii/graphql/src/tests/subscription_test.rs index 11ef4585eb..6a87b697e1 100644 --- a/crates/torii/graphql/src/tests/subscription_test.rs +++ b/crates/torii/graphql/src/tests/subscription_test.rs @@ -337,6 +337,7 @@ mod tests { 0, 0, block_timestamp, + false, ) .await .unwrap(); @@ -410,6 +411,7 @@ mod tests { 0, 0, block_timestamp, + false, ) .await .unwrap(); diff --git a/crates/torii/libp2p/src/tests.rs b/crates/torii/libp2p/src/tests.rs index e033d6c5fb..91859441bf 100644 --- a/crates/torii/libp2p/src/tests.rs +++ b/crates/torii/libp2p/src/tests.rs @@ -607,6 +607,7 @@ mod test { 0, 0, 0, + false, ) .await .unwrap(); From 37426760315fe3482a3853c053f72ffd8fac2e1b Mon Sep 17 00:00:00 2001 From: Nasr Date: Thu, 7 Nov 2024 11:40:35 -0500 Subject: [PATCH 09/35] refactor: diff --- crates/dojo/types/src/schema.rs | 12 ++++++++---- crates/torii/core/src/processors/upgrade_event.rs | 9 +-------- crates/torii/core/src/processors/upgrade_model.rs | 9 +-------- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/crates/dojo/types/src/schema.rs b/crates/dojo/types/src/schema.rs index fc7f72b27a..c413a41169 100644 --- a/crates/dojo/types/src/schema.rs +++ b/crates/dojo/types/src/schema.rs @@ -228,7 +228,7 @@ impl Ty { /// Returns a new Ty containing only the differences between self and other pub fn diff(&self, other: &Ty) -> Option { match (self, other) { - (Ty::Struct(s1), Ty::Struct(s2)) if s1.name == s2.name => { + (Ty::Struct(s1), Ty::Struct(s2)) => { // Find members that exist in s1 but not in s2, or are different let diff_children: Vec = s1 .children @@ -248,7 +248,7 @@ impl Ty { Some(Ty::Struct(Struct { name: s1.name.clone(), children: diff_children })) } } - (Ty::Enum(e1), Ty::Enum(e2)) if e1.name == e2.name => { + (Ty::Enum(e1), Ty::Enum(e2)) => { // Find options that exist in e1 but not in e2, or are different let diff_options: Vec = e1 .options @@ -297,8 +297,12 @@ impl Ty { Some(Ty::Primitive(*p1)) } } - // Different types entirely - return the new type - _ => Some(self.clone()), + // Different types entirely - we cannot diff them + _ => panic!( + "Type mismatch between self {:?} and other {:?}", + self.name(), + other.name() + ), } } } diff --git a/crates/torii/core/src/processors/upgrade_event.rs b/crates/torii/core/src/processors/upgrade_event.rs index c77e48f1c2..2869bb86da 100644 --- a/crates/torii/core/src/processors/upgrade_event.rs +++ b/crates/torii/core/src/processors/upgrade_event.rs @@ -1,6 +1,5 @@ use anyhow::{Error, Ok, Result}; use async_trait::async_trait; -use dojo_types::schema::Ty; use dojo_world::contracts::abigen::world::Event as WorldEvent; use dojo_world::contracts::model::ModelReader; use dojo_world::contracts::world::WorldContractReader; @@ -59,13 +58,7 @@ where let model = db.model(event.selector).await?; let name = model.name; let namespace = model.namespace; - let mut prev_schema = model.schema; - match &mut prev_schema { - Ty::Struct(s) => { - s.name = name.clone(); - } - _ => unreachable!(), - } + let prev_schema = model.schema; let model = world.model_reader(&namespace, &name).await?; let new_schema = model.schema().await?; diff --git a/crates/torii/core/src/processors/upgrade_model.rs b/crates/torii/core/src/processors/upgrade_model.rs index 8cae4aab8e..55c90312ae 100644 --- a/crates/torii/core/src/processors/upgrade_model.rs +++ b/crates/torii/core/src/processors/upgrade_model.rs @@ -1,6 +1,5 @@ use anyhow::{Error, Ok, Result}; use async_trait::async_trait; -use dojo_types::schema::Ty; use dojo_world::contracts::abigen::world::Event as WorldEvent; use dojo_world::contracts::model::ModelReader; use dojo_world::contracts::world::WorldContractReader; @@ -57,13 +56,7 @@ where let model = db.model(event.selector).await?; let name = model.name; let namespace = model.namespace; - let mut prev_schema = model.schema; - match &mut prev_schema { - Ty::Struct(s) => { - s.name = name.clone(); - } - _ => unreachable!(), - } + let prev_schema = model.schema; let model = world.model_reader(&namespace, &name).await?; let new_schema = model.schema().await?; From b3ee1098dda03019f69342bbfd294ec5f33da9a1 Mon Sep 17 00:00:00 2001 From: Nasr Date: Thu, 7 Nov 2024 12:03:34 -0500 Subject: [PATCH 10/35] fmtg --- crates/dojo/types/src/schema.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/crates/dojo/types/src/schema.rs b/crates/dojo/types/src/schema.rs index c413a41169..63b7c512f2 100644 --- a/crates/dojo/types/src/schema.rs +++ b/crates/dojo/types/src/schema.rs @@ -298,11 +298,9 @@ impl Ty { } } // Different types entirely - we cannot diff them - _ => panic!( - "Type mismatch between self {:?} and other {:?}", - self.name(), - other.name() - ), + _ => { + panic!("Type mismatch between self {:?} and other {:?}", self.name(), other.name()) + } } } } From 0d26d435aadacd1dea34795436c6b02031256e57 Mon Sep 17 00:00:00 2001 From: Nasr Date: Thu, 7 Nov 2024 12:32:07 -0500 Subject: [PATCH 11/35] fix: set model cache --- crates/torii/core/src/processors/register_event.rs | 2 +- crates/torii/core/src/processors/register_model.rs | 2 +- crates/torii/core/src/processors/upgrade_event.rs | 4 ++-- crates/torii/core/src/processors/upgrade_model.rs | 4 ++-- crates/torii/core/src/sql/mod.rs | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/torii/core/src/processors/register_event.rs b/crates/torii/core/src/processors/register_event.rs index 975cc78ea8..974b61a6fe 100644 --- a/crates/torii/core/src/processors/register_event.rs +++ b/crates/torii/core/src/processors/register_event.rs @@ -95,7 +95,7 @@ where packed_size, unpacked_size, block_timestamp, - false, + None, ) .await?; diff --git a/crates/torii/core/src/processors/register_model.rs b/crates/torii/core/src/processors/register_model.rs index 10ce03a0b8..e15fb7fc1e 100644 --- a/crates/torii/core/src/processors/register_model.rs +++ b/crates/torii/core/src/processors/register_model.rs @@ -92,7 +92,7 @@ where packed_size, unpacked_size, block_timestamp, - false, + None, ) .await?; diff --git a/crates/torii/core/src/processors/upgrade_event.rs b/crates/torii/core/src/processors/upgrade_event.rs index 2869bb86da..7bdd732b44 100644 --- a/crates/torii/core/src/processors/upgrade_event.rs +++ b/crates/torii/core/src/processors/upgrade_event.rs @@ -97,14 +97,14 @@ where db.register_model( &namespace, - schema_diff, + new_schema, layout, event.class_hash.into(), event.address.into(), packed_size, unpacked_size, block_timestamp, - true, + Some(schema_diff), ) .await?; diff --git a/crates/torii/core/src/processors/upgrade_model.rs b/crates/torii/core/src/processors/upgrade_model.rs index 55c90312ae..e66bfbf52c 100644 --- a/crates/torii/core/src/processors/upgrade_model.rs +++ b/crates/torii/core/src/processors/upgrade_model.rs @@ -94,14 +94,14 @@ where db.register_model( &namespace, - schema_diff, + new_schema, layout, event.class_hash.into(), event.address.into(), packed_size, unpacked_size, block_timestamp, - true, + Some(schema_diff), ) .await?; diff --git a/crates/torii/core/src/sql/mod.rs b/crates/torii/core/src/sql/mod.rs index 53884e15da..4f646655b4 100644 --- a/crates/torii/core/src/sql/mod.rs +++ b/crates/torii/core/src/sql/mod.rs @@ -261,7 +261,7 @@ impl Sql { packed_size: u32, unpacked_size: u32, block_timestamp: u64, - is_upgrade: bool, + upgrade_diff: Option, ) -> Result<()> { let selector = compute_selector_from_names(namespace, &model.name()); let namespaced_name = format!("{}-{}", namespace, model.name()); @@ -293,13 +293,13 @@ impl Sql { let mut model_idx = 0_i64; self.build_register_queries_recursive( selector, - &model, + upgrade_diff.as_ref().unwrap_or(&model), vec![namespaced_name.clone()], &mut model_idx, block_timestamp, &mut 0, &mut 0, - is_upgrade, + upgrade_diff.is_some(), )?; // we set the model in the cache directly From cbc39c7ee2f6a101642579e922b926c5f0fc9165 Mon Sep 17 00:00:00 2001 From: Nasr Date: Thu, 7 Nov 2024 14:56:44 -0500 Subject: [PATCH 12/35] fix add model members --- .../core/src/processors/register_event.rs | 2 +- .../core/src/processors/register_model.rs | 2 +- .../core/src/processors/upgrade_event.rs | 4 +-- .../core/src/processors/upgrade_model.rs | 4 +-- crates/torii/core/src/sql/mod.rs | 28 +++++++++++++------ 5 files changed, 26 insertions(+), 14 deletions(-) diff --git a/crates/torii/core/src/processors/register_event.rs b/crates/torii/core/src/processors/register_event.rs index 974b61a6fe..855e2e8389 100644 --- a/crates/torii/core/src/processors/register_event.rs +++ b/crates/torii/core/src/processors/register_event.rs @@ -88,7 +88,7 @@ where db.register_model( &namespace, - schema, + &schema, layout, event.class_hash.into(), event.address.into(), diff --git a/crates/torii/core/src/processors/register_model.rs b/crates/torii/core/src/processors/register_model.rs index e15fb7fc1e..a8027a242d 100644 --- a/crates/torii/core/src/processors/register_model.rs +++ b/crates/torii/core/src/processors/register_model.rs @@ -85,7 +85,7 @@ where db.register_model( &namespace, - schema, + &schema, layout, event.class_hash.into(), event.address.into(), diff --git a/crates/torii/core/src/processors/upgrade_event.rs b/crates/torii/core/src/processors/upgrade_event.rs index 7bdd732b44..0d5efff07e 100644 --- a/crates/torii/core/src/processors/upgrade_event.rs +++ b/crates/torii/core/src/processors/upgrade_event.rs @@ -97,14 +97,14 @@ where db.register_model( &namespace, - new_schema, + &new_schema, layout, event.class_hash.into(), event.address.into(), packed_size, unpacked_size, block_timestamp, - Some(schema_diff), + Some(&schema_diff), ) .await?; diff --git a/crates/torii/core/src/processors/upgrade_model.rs b/crates/torii/core/src/processors/upgrade_model.rs index e66bfbf52c..dde5618ba7 100644 --- a/crates/torii/core/src/processors/upgrade_model.rs +++ b/crates/torii/core/src/processors/upgrade_model.rs @@ -94,14 +94,14 @@ where db.register_model( &namespace, - new_schema, + &new_schema, layout, event.class_hash.into(), event.address.into(), packed_size, unpacked_size, block_timestamp, - Some(schema_diff), + Some(&schema_diff), ) .await?; diff --git a/crates/torii/core/src/sql/mod.rs b/crates/torii/core/src/sql/mod.rs index 4f646655b4..77f833d1c3 100644 --- a/crates/torii/core/src/sql/mod.rs +++ b/crates/torii/core/src/sql/mod.rs @@ -254,14 +254,14 @@ impl Sql { pub async fn register_model( &mut self, namespace: &str, - model: Ty, + model: &Ty, layout: Layout, class_hash: Felt, contract_address: Felt, packed_size: u32, unpacked_size: u32, block_timestamp: u64, - upgrade_diff: Option, + upgrade_diff: Option<&Ty>, ) -> Result<()> { let selector = compute_selector_from_names(namespace, &model.name()); let namespaced_name = format!("{}-{}", namespace, model.name()); @@ -299,7 +299,7 @@ impl Sql { block_timestamp, &mut 0, &mut 0, - upgrade_diff.is_some(), + upgrade_diff, )?; // we set the model in the cache directly @@ -635,7 +635,7 @@ impl Sql { block_timestamp: u64, array_idx: &mut usize, parent_array_idx: &mut usize, - is_upgrade: bool, + upgrade_diff: Option<&Ty>, ) -> Result<()> { if let Ty::Enum(e) = model { if e.options.iter().all(|o| if let Ty::Tuple(t) = &o.ty { t.is_empty() } else { false }) @@ -652,7 +652,7 @@ impl Sql { block_timestamp, *array_idx, *parent_array_idx, - is_upgrade, + upgrade_diff, )?; let mut build_member = |pathname: &str, member: &Ty| -> Result<()> { @@ -674,7 +674,7 @@ impl Sql { &mut (*array_idx + if let Ty::Array(_) = member { 1 } else { 0 }), &mut (*parent_array_idx + if let Ty::Array(_) = model { 1 } else { 0 }), // nested members are not upgrades - false, + None, )?; Ok(()) @@ -1031,7 +1031,7 @@ impl Sql { block_timestamp: u64, array_idx: usize, parent_array_idx: usize, - is_upgrade: bool, + upgrade_diff: Option<&Ty>, ) -> Result<()> { let table_id = path.join("$"); let mut indices = Vec::new(); @@ -1123,6 +1123,18 @@ impl Sql { match model { Ty::Struct(s) => { for (member_idx, member) in s.children.iter().enumerate() { + if let Some(upgrade_diff) = upgrade_diff { + if !upgrade_diff + .as_struct() + .unwrap() + .children + .iter() + .any(|m| m.name == member.name) + { + continue; + } + } + let name = member.name.clone(); let mut options = None; // TEMP: doesnt support complex enums yet @@ -1279,7 +1291,7 @@ impl Sql { create_table_query .push_str("FOREIGN KEY (event_message_id) REFERENCES event_messages(id));"); - if is_upgrade { + if upgrade_diff.is_some() { for alter_query in alter_table_queries { self.executor.send(QueryMessage::other(alter_query, vec![]))?; } From 14ffc8ec13ce393c808053f855e0a7ff3803cb1f Mon Sep 17 00:00:00 2001 From: Nasr Date: Thu, 7 Nov 2024 15:03:39 -0500 Subject: [PATCH 13/35] fix --- crates/torii/core/src/sql/mod.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/torii/core/src/sql/mod.rs b/crates/torii/core/src/sql/mod.rs index 77f833d1c3..4e946a82b7 100644 --- a/crates/torii/core/src/sql/mod.rs +++ b/crates/torii/core/src/sql/mod.rs @@ -293,7 +293,7 @@ impl Sql { let mut model_idx = 0_i64; self.build_register_queries_recursive( selector, - upgrade_diff.as_ref().unwrap_or(&model), + model, vec![namespaced_name.clone()], &mut model_idx, block_timestamp, @@ -834,7 +834,11 @@ impl Sql { Ty::Enum(e) => { if e.options.iter().all( |o| { - if let Ty::Tuple(t) = &o.ty { t.is_empty() } else { false } + if let Ty::Tuple(t) = &o.ty { + t.is_empty() + } else { + false + } }, ) { return Ok(()); From ddd992134a517eabcfcc80b59213ef8455947441 Mon Sep 17 00:00:00 2001 From: Nasr Date: Fri, 8 Nov 2024 11:08:32 -0500 Subject: [PATCH 14/35] feat: shared cache between grpc & engine and fix partial deser --- bin/torii/src/main.rs | 6 +- crates/dojo/types/src/primitive.rs | 55 +++++++------------ crates/dojo/types/src/schema.rs | 5 ++ crates/dojo/world/src/contracts/model.rs | 16 +++++- crates/dojo/world/src/contracts/world.rs | 10 ++++ .../core/src/processors/register_event.rs | 6 +- .../core/src/processors/register_model.rs | 6 +- crates/torii/core/src/sql/mod.rs | 7 ++- crates/torii/grpc/src/server/mod.rs | 10 ++-- 9 files changed, 68 insertions(+), 53 deletions(-) diff --git a/bin/torii/src/main.rs b/bin/torii/src/main.rs index c55da2f464..e8b7c5e305 100644 --- a/bin/torii/src/main.rs +++ b/bin/torii/src/main.rs @@ -38,6 +38,7 @@ use torii_core::engine::{Engine, EngineConfig, IndexingFlags, Processors}; use torii_core::executor::Executor; use torii_core::processors::store_transaction::StoreTransactionProcessor; use torii_core::simple_broker::SimpleBroker; +use torii_core::sql::cache::ModelCache; use torii_core::sql::Sql; use torii_core::types::{Contract, ContractType, Model, ToriiConfig}; use torii_server::proxy::Proxy; @@ -218,7 +219,8 @@ async fn main() -> anyhow::Result<()> { executor.run().await.unwrap(); }); - let db = Sql::new(pool.clone(), sender.clone(), &contracts).await?; + let model_cache = Arc::new(ModelCache::new(pool.clone())); + let db = Sql::new(pool.clone(), sender.clone(), &contracts, model_cache.clone()).await?; let processors = Processors { transaction: vec![Box::new(StoreTransactionProcessor)], @@ -256,7 +258,7 @@ async fn main() -> anyhow::Result<()> { let shutdown_rx = shutdown_tx.subscribe(); let (grpc_addr, grpc_server) = - torii_grpc::server::new(shutdown_rx, &pool, block_rx, world_address, Arc::clone(&provider)) + torii_grpc::server::new(shutdown_rx, &pool, block_rx, world_address, Arc::clone(&provider), model_cache) .await?; let mut libp2p_relay_server = torii_relay::server::Relay::new( diff --git a/crates/dojo/types/src/primitive.rs b/crates/dojo/types/src/primitive.rs index 0c43e653ee..9fd0a41563 100644 --- a/crates/dojo/types/src/primitive.rs +++ b/crates/dojo/types/src/primitive.rs @@ -190,46 +190,29 @@ impl Primitive { } } - pub fn to_sql_value(&self) -> Result { - let value = self.serialize()?; - - if value.is_empty() { - return Err(PrimitiveError::MissingFieldElement); - } - + pub fn to_sql_value(&self) -> String { match self { // Integers - Primitive::I8(_) => Ok(format!("{}", try_from_felt::(value[0])?)), - Primitive::I16(_) => Ok(format!("{}", try_from_felt::(value[0])?)), - Primitive::I32(_) => Ok(format!("{}", try_from_felt::(value[0])?)), - Primitive::I64(_) => Ok(format!("{}", try_from_felt::(value[0])?)), + Primitive::I8(i8) => format!("{}", i8.unwrap_or_default()), + Primitive::I16(i16) => format!("{}", i16.unwrap_or_default()), + Primitive::I32(i32) => format!("{}", i32.unwrap_or_default()), + Primitive::I64(i64) => format!("{}", i64.unwrap_or_default()), - Primitive::U8(_) - | Primitive::U16(_) - | Primitive::U32(_) - | Primitive::USize(_) - | Primitive::Bool(_) => Ok(format!("{}", value[0])), + Primitive::U8(u8) => format!("{}", u8.unwrap_or_default()), + Primitive::U16(u16) => format!("{}", u16.unwrap_or_default()), + Primitive::U32(u32) => format!("{}", u32.unwrap_or_default()), + Primitive::USize(u32) => format!("{}", u32.unwrap_or_default()), + Primitive::Bool(bool) => format!("{}", bool.unwrap_or_default()), // Hex string - Primitive::I128(_) => Ok(format!("{:#064x}", try_from_felt::(value[0])?)), - Primitive::ContractAddress(_) - | Primitive::ClassHash(_) - | Primitive::Felt252(_) - | Primitive::U128(_) - | Primitive::U64(_) => Ok(format!("{:#064x}", value[0])), - - Primitive::U256(_) => { - if value.len() < 2 { - Err(PrimitiveError::NotEnoughFieldElements) - } else { - let mut buffer = [0u8; 32]; - let value0_bytes = value[0].to_bytes_be(); - let value1_bytes = value[1].to_bytes_be(); - buffer[16..].copy_from_slice(&value0_bytes[16..]); - buffer[..16].copy_from_slice(&value1_bytes[16..]); - Ok(format!("0x{}", hex::encode(buffer))) - } - } + Primitive::I128(i128) => format!("{:#064x}", i128.unwrap_or_default()), + Primitive::ContractAddress(felt) => format!("{:#064x}", felt.unwrap_or_default()), + Primitive::ClassHash(felt) => format!("{:#064x}", felt.unwrap_or_default()), + Primitive::Felt252(felt) => format!("{:#064x}", felt.unwrap_or_default()), + Primitive::U128(u128) => format!("{:#064x}", u128.unwrap_or_default()), + Primitive::U64(u64) => format!("{:#064x}", u64.unwrap_or_default()), + + Primitive::U256(u256) => format!("0x{:064x}", u256.unwrap_or_default()), } } @@ -436,7 +419,7 @@ mod tests { let primitive = Primitive::U256(Some(U256::from_be_hex( "aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbccccccccccccccccdddddddddddddddd", ))); - let sql_value = primitive.to_sql_value().unwrap(); + let sql_value = primitive.to_sql_value(); let serialized = primitive.serialize().unwrap(); let mut deserialized = primitive; diff --git a/crates/dojo/types/src/schema.rs b/crates/dojo/types/src/schema.rs index 63b7c512f2..a8585ba0d3 100644 --- a/crates/dojo/types/src/schema.rs +++ b/crates/dojo/types/src/schema.rs @@ -173,6 +173,11 @@ impl Ty { } pub fn deserialize(&mut self, felts: &mut Vec) -> Result<(), PrimitiveError> { + if felts.is_empty() { + // return early if there are no felts to deserialize + return Ok(()); + } + match self { Ty::Primitive(c) => { c.deserialize(felts)?; diff --git a/crates/dojo/world/src/contracts/model.rs b/crates/dojo/world/src/contracts/model.rs index 5108ca634e..7753767e8a 100644 --- a/crates/dojo/world/src/contracts/model.rs +++ b/crates/dojo/world/src/contracts/model.rs @@ -5,7 +5,7 @@ use cainome::cairo_serde::{CairoSerde as _, ContractAddress, Error as CainomeErr use dojo_types::packing::{PackingError, ParseError}; use dojo_types::primitive::{Primitive, PrimitiveError}; use dojo_types::schema::{Enum, EnumOption, Member, Struct, Ty}; -use starknet::core::types::Felt; +use starknet::core::types::{BlockId, Felt}; use starknet::core::utils::{ cairo_short_string_to_felt, parse_cairo_short_string, CairoShortStringToFeltError, NonAsciiNameError, ParseCairoShortStringError, @@ -86,13 +86,22 @@ where namespace: &str, name: &str, world: &'a WorldContractReader

, + ) -> Result, ModelError> { + Self::new_with_block(namespace, name, world, world.block_id).await + } + + pub async fn new_with_block( + namespace: &str, + name: &str, + world: &'a WorldContractReader

, + block_id: BlockId, ) -> Result, ModelError> { let model_selector = naming::compute_selector_from_names(namespace, name); // Events are also considered like models from a off-chain perspective. They both have // introspection and convey type information. let (contract_address, class_hash) = - match world.resource(&model_selector).block_id(world.block_id).call().await? { + match world.resource(&model_selector).block_id(block_id).call().await? { abigen::world::Resource::Model((address, hash)) => (address, hash), abigen::world::Resource::Event((address, hash)) => (address, hash), _ => return Err(ModelError::ModelNotFound), @@ -104,7 +113,8 @@ where return Err(ModelError::ModelNotFound); } - let model_reader = ModelContractReader::new(contract_address.into(), world.provider()); + let mut model_reader = ModelContractReader::new(contract_address.into(), world.provider()); + model_reader.set_block(block_id); Ok(Self { namespace: namespace.into(), diff --git a/crates/dojo/world/src/contracts/world.rs b/crates/dojo/world/src/contracts/world.rs index 11224da756..4508c5db07 100644 --- a/crates/dojo/world/src/contracts/world.rs +++ b/crates/dojo/world/src/contracts/world.rs @@ -1,5 +1,6 @@ use std::result::Result; +use starknet::core::types::BlockId; use starknet::providers::Provider; pub use super::abigen::world::{ @@ -33,4 +34,13 @@ where ) -> Result, ModelError> { ModelRPCReader::new(namespace, name, self).await } + + pub async fn model_reader_with_block( + &self, + namespace: &str, + name: &str, + block_id: BlockId, + ) -> Result, ModelError> { + ModelRPCReader::new_with_block(namespace, name, self, block_id).await + } } diff --git a/crates/torii/core/src/processors/register_event.rs b/crates/torii/core/src/processors/register_event.rs index 855e2e8389..8cebcde01f 100644 --- a/crates/torii/core/src/processors/register_event.rs +++ b/crates/torii/core/src/processors/register_event.rs @@ -3,7 +3,7 @@ use async_trait::async_trait; use dojo_world::contracts::abigen::world::Event as WorldEvent; use dojo_world::contracts::model::ModelReader; use dojo_world::contracts::world::WorldContractReader; -use starknet::core::types::Event; +use starknet::core::types::{BlockId, Event}; use starknet::providers::Provider; use tracing::{debug, info}; @@ -34,7 +34,7 @@ where &self, world: &WorldContractReader

, db: &mut Sql, - _block_number: u64, + block_number: u64, block_timestamp: u64, _event_id: &str, event: &Event, @@ -59,7 +59,7 @@ where // Called model here by language, but it's an event. Torii rework will make clear // distinction. - let model = world.model_reader(&namespace, &name).await?; + let model = world.model_reader_with_block(&namespace, &name, BlockId::Number(block_number)).await?; let schema = model.schema().await?; let layout = model.layout().await?; diff --git a/crates/torii/core/src/processors/register_model.rs b/crates/torii/core/src/processors/register_model.rs index a8027a242d..d7e50b9641 100644 --- a/crates/torii/core/src/processors/register_model.rs +++ b/crates/torii/core/src/processors/register_model.rs @@ -3,7 +3,7 @@ use async_trait::async_trait; use dojo_world::contracts::abigen::world::Event as WorldEvent; use dojo_world::contracts::model::ModelReader; use dojo_world::contracts::world::WorldContractReader; -use starknet::core::types::Event; +use starknet::core::types::{BlockId, Event}; use starknet::providers::Provider; use tracing::{debug, info}; @@ -34,7 +34,7 @@ where &self, world: &WorldContractReader

, db: &mut Sql, - _block_number: u64, + block_number: u64, block_timestamp: u64, _event_id: &str, event: &Event, @@ -57,7 +57,7 @@ where let namespace = event.namespace.to_string().unwrap(); let name = event.name.to_string().unwrap(); - let model = world.model_reader(&namespace, &name).await?; + let model = world.model_reader_with_block(&namespace, &name, BlockId::Number(block_number)).await?; let schema = model.schema().await?; let layout = model.layout().await?; diff --git a/crates/torii/core/src/sql/mod.rs b/crates/torii/core/src/sql/mod.rs index 4e946a82b7..90a474f0d5 100644 --- a/crates/torii/core/src/sql/mod.rs +++ b/crates/torii/core/src/sql/mod.rs @@ -60,6 +60,7 @@ impl Sql { pool: Pool, executor: UnboundedSender, contracts: &HashMap, + model_cache: Arc, ) -> Result { for contract in contracts { executor.send(QueryMessage::other( @@ -78,7 +79,7 @@ impl Sql { let db = Self { pool: pool.clone(), executor, - model_cache: Arc::new(ModelCache::new(pool.clone())), + model_cache, local_cache, }; @@ -325,6 +326,8 @@ impl Sql { ) .await; + println!("selector: {:?}", selector); + println!("set model cache: {:?}", model); Ok(()) } @@ -768,7 +771,7 @@ impl Sql { match &member.ty { Ty::Primitive(ty) => { columns.push(format!("external_{}", &member.name)); - arguments.push(Argument::String(ty.to_sql_value().unwrap())); + arguments.push(Argument::String(ty.to_sql_value())); } Ty::Enum(e) => { columns.push(format!("external_{}", &member.name)); diff --git a/crates/torii/grpc/src/server/mod.rs b/crates/torii/grpc/src/server/mod.rs index 4e710713e7..e0e3d15460 100644 --- a/crates/torii/grpc/src/server/mod.rs +++ b/crates/torii/grpc/src/server/mod.rs @@ -105,8 +105,8 @@ impl DojoWorld { block_rx: Receiver, world_address: Felt, provider: Arc>, + model_cache: Arc, ) -> Self { - let model_cache = Arc::new(ModelCache::new(pool.clone())); let entity_manager = Arc::new(EntityManager::default()); let event_message_manager = Arc::new(EventMessageManager::default()); let event_manager = Arc::new(EventManager::default()); @@ -624,7 +624,7 @@ impl DojoWorld { Some(ValueType::String(value)) => value, Some(ValueType::Primitive(value)) => { let primitive: Primitive = value.try_into()?; - primitive.to_sql_value()? + primitive.to_sql_value() } None => return Err(QueryError::MissingParam("value_type".into()).into()), }; @@ -969,6 +969,7 @@ fn map_row_to_entity( schemas: &[Ty], dont_include_hashed_keys: bool, ) -> Result { + println!("schemas: {:?}", schemas); let hashed_keys = Felt::from_str(&row.get::("id")).map_err(ParseError::FromStr)?; let models = schemas .iter() @@ -1060,7 +1061,7 @@ fn build_composite_clause( Some(ValueType::String(value)) => value, Some(ValueType::Primitive(value)) => { let primitive: Primitive = value.try_into()?; - primitive.to_sql_value()? + primitive.to_sql_value() } None => return Err(QueryError::MissingParam("value_type".into()).into()), }; @@ -1368,6 +1369,7 @@ pub async fn new( block_rx: Receiver, world_address: Felt, provider: Arc>, + model_cache: Arc, ) -> Result< (SocketAddr, impl Future> + 'static), std::io::Error, @@ -1380,7 +1382,7 @@ pub async fn new( .build() .unwrap(); - let world = DojoWorld::new(pool.clone(), block_rx, world_address, provider); + let world = DojoWorld::new(pool.clone(), block_rx, world_address, provider, model_cache); let server = WorldServer::new(world) .accept_compressed(CompressionEncoding::Gzip) .send_compressed(CompressionEncoding::Gzip); From cf9c45c579d9bf628654f9b6a44635745a72c579 Mon Sep 17 00:00:00 2001 From: Nasr Date: Fri, 8 Nov 2024 11:52:51 -0500 Subject: [PATCH 15/35] fix: test and fmt --- bin/torii/src/main.rs | 12 ++- crates/sozo/ops/src/model.rs | 2 +- crates/torii/core/src/model.rs | 25 +++--- .../core/src/processors/register_event.rs | 3 +- .../core/src/processors/register_model.rs | 3 +- crates/torii/core/src/sql/mod.rs | 13 +-- crates/torii/core/src/sql/test.rs | 7 ++ .../torii/graphql/src/tests/metadata_test.rs | 29 +++++-- crates/torii/graphql/src/tests/mod.rs | 18 +++-- .../graphql/src/tests/subscription_test.rs | 80 +++++++++++++------ .../grpc/src/server/tests/entities_test.rs | 17 +++- crates/torii/libp2p/src/tests.rs | 20 +++-- 12 files changed, 152 insertions(+), 77 deletions(-) diff --git a/bin/torii/src/main.rs b/bin/torii/src/main.rs index e8b7c5e305..41a10c2b23 100644 --- a/bin/torii/src/main.rs +++ b/bin/torii/src/main.rs @@ -257,9 +257,15 @@ async fn main() -> anyhow::Result<()> { ); let shutdown_rx = shutdown_tx.subscribe(); - let (grpc_addr, grpc_server) = - torii_grpc::server::new(shutdown_rx, &pool, block_rx, world_address, Arc::clone(&provider), model_cache) - .await?; + let (grpc_addr, grpc_server) = torii_grpc::server::new( + shutdown_rx, + &pool, + block_rx, + world_address, + Arc::clone(&provider), + model_cache, + ) + .await?; let mut libp2p_relay_server = torii_relay::server::Relay::new( db, diff --git a/crates/sozo/ops/src/model.rs b/crates/sozo/ops/src/model.rs index d4d471eeb9..38cdfabe5d 100644 --- a/crates/sozo/ops/src/model.rs +++ b/crates/sozo/ops/src/model.rs @@ -412,7 +412,7 @@ fn format_primitive( let mut _p = *p; let _ = _p.deserialize(values); - format!("{}{}", _start_indent(level, start_indent), _p.to_sql_value().unwrap()) + format!("{}{}", _start_indent(level, start_indent), _p.to_sql_value()) } fn format_byte_array(values: &mut Vec, level: usize, start_indent: bool) -> String { diff --git a/crates/torii/core/src/model.rs b/crates/torii/core/src/model.rs index 6660bba4fb..5a38e60c2e 100644 --- a/crates/torii/core/src/model.rs +++ b/crates/torii/core/src/model.rs @@ -238,7 +238,7 @@ pub fn build_sql_query( struct TableInfo { table_name: String, parent_table: Option, - is_optional: bool, + // is_optional: bool, depth: usize, // Track nesting depth for proper ordering } @@ -250,7 +250,7 @@ pub fn build_sql_query( selections: &mut Vec, tables: &mut Vec, arrays_queries: &mut HashMap, Vec)>, - parent_is_optional: bool, + _parent_is_optional: bool, depth: usize, ) { match &ty { @@ -261,7 +261,7 @@ pub fn build_sql_query( tables.push(TableInfo { table_name: table_name.clone(), parent_table: if path.is_empty() { None } else { Some(path.to_string()) }, - is_optional: parent_is_optional, + // is_optional: parent_is_optional, depth, }); @@ -273,7 +273,7 @@ pub fn build_sql_query( selections, tables, arrays_queries, - parent_is_optional, + _parent_is_optional, depth + 1, ); } @@ -284,7 +284,7 @@ pub fn build_sql_query( tables.push(TableInfo { table_name: table_name.clone(), parent_table: Some(path.to_string()), - is_optional: parent_is_optional, + // is_optional: parent_is_optional, depth, }); @@ -296,7 +296,7 @@ pub fn build_sql_query( selections, tables, arrays_queries, - parent_is_optional, + _parent_is_optional, depth + 1, ); } @@ -309,7 +309,7 @@ pub fn build_sql_query( let mut array_tables = vec![TableInfo { table_name: table_name.clone(), parent_table: Some(path.to_string()), - is_optional: true, + // is_optional: true, depth, }]; @@ -356,7 +356,7 @@ pub fn build_sql_query( tables.push(TableInfo { table_name, parent_table: Some(path.to_string()), - is_optional: parent_is_optional || is_optional, + // is_optional: parent_is_optional || is_optional, depth, }); } @@ -395,10 +395,9 @@ pub fn build_sql_query( let join_clause = global_tables .iter() .map(|table| { - let join_type = if table.is_optional { "LEFT JOIN" } else { "JOIN" }; let join_condition = format!("{entities_table}.id = [{}].{entity_relation_column}", table.table_name); - format!(" {join_type} [{}] ON {join_condition}", table.table_name) + format!(" LEFT JOIN [{}] ON {join_condition}", table.table_name) }) .collect::>() .join(" "); @@ -420,13 +419,13 @@ pub fn build_sql_query( .map(|(i, table)| { if i == 0 { format!( - " JOIN [{}] ON {entities_table}.id = [{}].{entity_relation_column}", + " LEFT JOIN [{}] ON {entities_table}.id = \ + [{}].{entity_relation_column}", table.table_name, table.table_name ) } else { - let join_type = if table.is_optional { "LEFT JOIN" } else { "JOIN" }; format!( - " {join_type} [{}] ON [{}].full_array_id = [{}].full_array_id", + " LEFT JOIN [{}] ON [{}].full_array_id = [{}].full_array_id", table.table_name, table.table_name, table.parent_table.as_ref().unwrap() diff --git a/crates/torii/core/src/processors/register_event.rs b/crates/torii/core/src/processors/register_event.rs index 8cebcde01f..1c1cd419ab 100644 --- a/crates/torii/core/src/processors/register_event.rs +++ b/crates/torii/core/src/processors/register_event.rs @@ -59,7 +59,8 @@ where // Called model here by language, but it's an event. Torii rework will make clear // distinction. - let model = world.model_reader_with_block(&namespace, &name, BlockId::Number(block_number)).await?; + let model = + world.model_reader_with_block(&namespace, &name, BlockId::Number(block_number)).await?; let schema = model.schema().await?; let layout = model.layout().await?; diff --git a/crates/torii/core/src/processors/register_model.rs b/crates/torii/core/src/processors/register_model.rs index d7e50b9641..3b486780dd 100644 --- a/crates/torii/core/src/processors/register_model.rs +++ b/crates/torii/core/src/processors/register_model.rs @@ -57,7 +57,8 @@ where let namespace = event.namespace.to_string().unwrap(); let name = event.name.to_string().unwrap(); - let model = world.model_reader_with_block(&namespace, &name, BlockId::Number(block_number)).await?; + let model = + world.model_reader_with_block(&namespace, &name, BlockId::Number(block_number)).await?; let schema = model.schema().await?; let layout = model.layout().await?; diff --git a/crates/torii/core/src/sql/mod.rs b/crates/torii/core/src/sql/mod.rs index 90a474f0d5..e145c58a52 100644 --- a/crates/torii/core/src/sql/mod.rs +++ b/crates/torii/core/src/sql/mod.rs @@ -76,12 +76,7 @@ impl Sql { } let local_cache = LocalCache::new(pool.clone()).await; - let db = Self { - pool: pool.clone(), - executor, - model_cache, - local_cache, - }; + let db = Self { pool: pool.clone(), executor, model_cache, local_cache }; db.execute().await?; @@ -837,11 +832,7 @@ impl Sql { Ty::Enum(e) => { if e.options.iter().all( |o| { - if let Ty::Tuple(t) = &o.ty { - t.is_empty() - } else { - false - } + if let Ty::Tuple(t) = &o.ty { t.is_empty() } else { false } }, ) { return Ok(()); diff --git a/crates/torii/core/src/sql/test.rs b/crates/torii/core/src/sql/test.rs index fd1539b49c..43804a6f4c 100644 --- a/crates/torii/core/src/sql/test.rs +++ b/crates/torii/core/src/sql/test.rs @@ -23,6 +23,7 @@ use tokio::sync::broadcast; use crate::engine::{Engine, EngineConfig, Processors}; use crate::executor::Executor; +use crate::sql::cache::ModelCache; use crate::sql::Sql; use crate::types::ContractType; @@ -124,10 +125,12 @@ async fn test_load_from_remote(sequencer: &RunnerCtx) { executor.run().await.unwrap(); }); + let model_cache = Arc::new(ModelCache::new(pool.clone())); let db = Sql::new( pool.clone(), sender.clone(), &HashMap::from([(world_reader.address, ContractType::WORLD)]), + model_cache.clone(), ) .await .unwrap(); @@ -282,10 +285,12 @@ async fn test_load_from_remote_del(sequencer: &RunnerCtx) { executor.run().await.unwrap(); }); + let model_cache = Arc::new(ModelCache::new(pool.clone())); let db = Sql::new( pool.clone(), sender.clone(), &HashMap::from([(world_reader.address, ContractType::WORLD)]), + model_cache.clone(), ) .await .unwrap(); @@ -368,10 +373,12 @@ async fn test_update_with_set_record(sequencer: &RunnerCtx) { executor.run().await.unwrap(); }); + let model_cache = Arc::new(ModelCache::new(pool.clone())); let db = Sql::new( pool.clone(), sender.clone(), &HashMap::from([(world_reader.address, ContractType::WORLD)]), + model_cache.clone(), ) .await .unwrap(); diff --git a/crates/torii/graphql/src/tests/metadata_test.rs b/crates/torii/graphql/src/tests/metadata_test.rs index d92cca5854..0c8e3ab803 100644 --- a/crates/torii/graphql/src/tests/metadata_test.rs +++ b/crates/torii/graphql/src/tests/metadata_test.rs @@ -1,12 +1,14 @@ #[cfg(test)] mod tests { use std::collections::HashMap; + use std::sync::Arc; use dojo_world::config::{ProfileConfig, WorldMetadata}; use sqlx::SqlitePool; use starknet::core::types::Felt; use tokio::sync::broadcast; use torii_core::executor::Executor; + use torii_core::sql::cache::ModelCache; use torii_core::sql::Sql; use torii_core::types::ContractType; @@ -58,10 +60,15 @@ mod tests { tokio::spawn(async move { executor.run().await.unwrap(); }); - let mut db = - Sql::new(pool.clone(), sender, &HashMap::from([(Felt::ZERO, ContractType::WORLD)])) - .await - .unwrap(); + let model_cache = Arc::new(ModelCache::new(pool.clone())); + let mut db = Sql::new( + pool.clone(), + sender, + &HashMap::from([(Felt::ZERO, ContractType::WORLD)]), + model_cache, + ) + .await + .unwrap(); let schema = build_schema(&pool).await.unwrap(); let cover_img = "QWxsIHlvdXIgYmFzZSBiZWxvbmcgdG8gdXM="; @@ -119,10 +126,16 @@ mod tests { tokio::spawn(async move { executor.run().await.unwrap(); }); - let mut db = - Sql::new(pool.clone(), sender, &HashMap::from([(Felt::ZERO, ContractType::WORLD)])) - .await - .unwrap(); + + let model_cache = Arc::new(ModelCache::new(pool.clone())); + let mut db = Sql::new( + pool.clone(), + sender, + &HashMap::from([(Felt::ZERO, ContractType::WORLD)]), + model_cache, + ) + .await + .unwrap(); let schema = build_schema(&pool).await.unwrap(); db.set_metadata(&RESOURCE, URI, BLOCK_TIMESTAMP).unwrap(); diff --git a/crates/torii/graphql/src/tests/mod.rs b/crates/torii/graphql/src/tests/mod.rs index 22bda2faf0..f08426bcfa 100644 --- a/crates/torii/graphql/src/tests/mod.rs +++ b/crates/torii/graphql/src/tests/mod.rs @@ -29,6 +29,7 @@ use tokio::sync::broadcast; use tokio_stream::StreamExt; use torii_core::engine::{Engine, EngineConfig, Processors}; use torii_core::executor::Executor; +use torii_core::sql::cache::ModelCache; use torii_core::sql::Sql; use torii_core::types::ContractType; @@ -211,7 +212,7 @@ pub async fn run_graphql_subscription( pub async fn model_fixtures(db: &mut Sql) { db.register_model( "types_test", - Ty::Struct(Struct { + &Ty::Struct(Struct { name: "Record".to_string(), children: vec![ Member { @@ -266,7 +267,7 @@ pub async fn model_fixtures(db: &mut Sql) { 0, 0, 1710754478_u64, - false, + None, ) .await .unwrap(); @@ -346,9 +347,16 @@ pub async fn spinup_types_test(path: &str) -> Result { tokio::spawn(async move { executor.run().await.unwrap(); }); - let db = Sql::new(pool.clone(), sender, &HashMap::from([(world_address, ContractType::WORLD)])) - .await - .unwrap(); + + let model_cache = Arc::new(ModelCache::new(pool.clone())); + let db = Sql::new( + pool.clone(), + sender, + &HashMap::from([(world_address, ContractType::WORLD)]), + model_cache, + ) + .await + .unwrap(); let (shutdown_tx, _) = broadcast::channel(1); let mut engine = Engine::new( diff --git a/crates/torii/graphql/src/tests/subscription_test.rs b/crates/torii/graphql/src/tests/subscription_test.rs index 6a87b697e1..860364f774 100644 --- a/crates/torii/graphql/src/tests/subscription_test.rs +++ b/crates/torii/graphql/src/tests/subscription_test.rs @@ -2,6 +2,7 @@ mod tests { use std::collections::HashMap; use std::str::FromStr; + use std::sync::Arc; use std::time::Duration; use async_graphql::value; @@ -15,6 +16,7 @@ mod tests { use starknet_crypto::{poseidon_hash_many, Felt}; use tokio::sync::{broadcast, mpsc}; use torii_core::executor::Executor; + use torii_core::sql::cache::ModelCache; use torii_core::sql::utils::felts_to_sql_string; use torii_core::sql::Sql; use torii_core::types::ContractType; @@ -31,10 +33,16 @@ mod tests { tokio::spawn(async move { executor.run().await.unwrap(); }); - let mut db = - Sql::new(pool.clone(), sender, &HashMap::from([(Felt::ZERO, ContractType::WORLD)])) - .await - .unwrap(); + + let model_cache = Arc::new(ModelCache::new(pool.clone())); + let mut db = Sql::new( + pool.clone(), + sender, + &HashMap::from([(Felt::ZERO, ContractType::WORLD)]), + model_cache, + ) + .await + .unwrap(); model_fixtures(&mut db).await; // 0. Preprocess expected entity value @@ -175,10 +183,16 @@ mod tests { tokio::spawn(async move { executor.run().await.unwrap(); }); - let mut db = - Sql::new(pool.clone(), sender, &HashMap::from([(Felt::ZERO, ContractType::WORLD)])) - .await - .unwrap(); + + let model_cache = Arc::new(ModelCache::new(pool.clone())); + let mut db = Sql::new( + pool.clone(), + sender, + &HashMap::from([(Felt::ZERO, ContractType::WORLD)]), + model_cache, + ) + .await + .unwrap(); model_fixtures(&mut db).await; // 0. Preprocess expected entity value @@ -299,10 +313,16 @@ mod tests { tokio::spawn(async move { executor.run().await.unwrap(); }); - let mut db = - Sql::new(pool.clone(), sender, &HashMap::from([(Felt::ZERO, ContractType::WORLD)])) - .await - .unwrap(); + + let model_cache = Arc::new(ModelCache::new(pool.clone())); + let mut db = Sql::new( + pool.clone(), + sender, + &HashMap::from([(Felt::ZERO, ContractType::WORLD)]), + model_cache, + ) + .await + .unwrap(); // 0. Preprocess model value let namespace = "types_test".to_string(); let model_name = "Subrecord".to_string(); @@ -330,14 +350,14 @@ mod tests { }); db.register_model( &namespace, - model, + &model, Layout::Fixed(vec![]), class_hash, contract_address, 0, 0, block_timestamp, - false, + None, ) .await .unwrap(); @@ -374,10 +394,16 @@ mod tests { tokio::spawn(async move { executor.run().await.unwrap(); }); - let mut db = - Sql::new(pool.clone(), sender, &HashMap::from([(Felt::ZERO, ContractType::WORLD)])) - .await - .unwrap(); + + let model_cache = Arc::new(ModelCache::new(pool.clone())); + let mut db = Sql::new( + pool.clone(), + sender, + &HashMap::from([(Felt::ZERO, ContractType::WORLD)]), + model_cache, + ) + .await + .unwrap(); // 0. Preprocess model value let namespace = "types_test".to_string(); let model_name = "Subrecord".to_string(); @@ -404,14 +430,14 @@ mod tests { }); db.register_model( &namespace, - model, + &model, Layout::Fixed(vec![]), class_hash, contract_address, 0, 0, block_timestamp, - false, + None, ) .await .unwrap(); @@ -450,10 +476,16 @@ mod tests { tokio::spawn(async move { executor.run().await.unwrap(); }); - let mut db = - Sql::new(pool.clone(), sender, &HashMap::from([(Felt::ZERO, ContractType::WORLD)])) - .await - .unwrap(); + + let model_cache = Arc::new(ModelCache::new(pool.clone())); + let mut db = Sql::new( + pool.clone(), + sender, + &HashMap::from([(Felt::ZERO, ContractType::WORLD)]), + model_cache, + ) + .await + .unwrap(); let block_timestamp: u64 = 1710754478_u64; let (tx, mut rx) = mpsc::channel(7); tokio::spawn(async move { diff --git a/crates/torii/grpc/src/server/tests/entities_test.rs b/crates/torii/grpc/src/server/tests/entities_test.rs index e7996092e9..2430063fc6 100644 --- a/crates/torii/grpc/src/server/tests/entities_test.rs +++ b/crates/torii/grpc/src/server/tests/entities_test.rs @@ -24,6 +24,7 @@ use tempfile::NamedTempFile; use tokio::sync::broadcast; use torii_core::engine::{Engine, EngineConfig, Processors}; use torii_core::executor::Executor; +use torii_core::sql::cache::ModelCache; use torii_core::sql::Sql; use torii_core::types::ContractType; @@ -92,9 +93,16 @@ async fn test_entities_queries(sequencer: &RunnerCtx) { tokio::spawn(async move { executor.run().await.unwrap(); }); - let db = Sql::new(pool.clone(), sender, &HashMap::from([(world_address, ContractType::WORLD)])) - .await - .unwrap(); + + let model_cache = Arc::new(ModelCache::new(pool.clone())); + let db = Sql::new( + pool.clone(), + sender, + &HashMap::from([(world_address, ContractType::WORLD)]), + model_cache, + ) + .await + .unwrap(); let (shutdown_tx, _) = broadcast::channel(1); let mut engine = Engine::new( @@ -115,7 +123,8 @@ async fn test_entities_queries(sequencer: &RunnerCtx) { db.execute().await.unwrap(); let (_, receiver) = tokio::sync::mpsc::channel(1); - let grpc = DojoWorld::new(db.pool, receiver, world_address, provider.clone()); + let model_cache = Arc::new(ModelCache::new(pool.clone())); + let grpc = DojoWorld::new(db.pool, receiver, world_address, provider.clone(), model_cache); let entities = grpc .query_by_keys( diff --git a/crates/torii/libp2p/src/tests.rs b/crates/torii/libp2p/src/tests.rs index 91859441bf..017467bc17 100644 --- a/crates/torii/libp2p/src/tests.rs +++ b/crates/torii/libp2p/src/tests.rs @@ -525,6 +525,7 @@ mod test { #[tokio::test] async fn test_client_messaging() -> Result<(), Box> { use std::collections::HashMap; + use std::sync::Arc; use std::time::Duration; use dojo_types::schema::{Member, Struct, Ty}; @@ -540,6 +541,7 @@ mod test { use tokio::sync::broadcast; use tokio::time::sleep; use torii_core::executor::Executor; + use torii_core::sql::cache::ModelCache; use torii_core::sql::Sql; use torii_core::types::ContractType; @@ -578,15 +580,21 @@ mod test { tokio::spawn(async move { executor.run().await.unwrap(); }); - let mut db = - Sql::new(pool.clone(), sender, &HashMap::from([(Felt::ZERO, ContractType::WORLD)])) - .await - .unwrap(); + + let model_cache = Arc::new(ModelCache::new(pool.clone())); + let mut db = Sql::new( + pool.clone(), + sender, + &HashMap::from([(Felt::ZERO, ContractType::WORLD)]), + model_cache, + ) + .await + .unwrap(); // Register the model of our Message db.register_model( "types_test", - Ty::Struct(Struct { + &Ty::Struct(Struct { name: "Message".to_string(), children: vec![ Member { @@ -607,7 +615,7 @@ mod test { 0, 0, 0, - false, + None, ) .await .unwrap(); From ae8bf42cff6776ed09ca9aa0d95bb1fa182b781c Mon Sep 17 00:00:00 2001 From: Nasr Date: Sat, 9 Nov 2024 19:37:28 -0500 Subject: [PATCH 16/35] fix --- bin/torii/src/main.rs | 2 +- crates/torii/core/src/engine.rs | 4 +++- crates/torii/core/src/processors/upgrade_event.rs | 3 ++- crates/torii/core/src/processors/upgrade_model.rs | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/bin/torii/src/main.rs b/bin/torii/src/main.rs index 99e248cbd8..2c2fc8a48f 100644 --- a/bin/torii/src/main.rs +++ b/bin/torii/src/main.rs @@ -223,7 +223,7 @@ async fn main() -> anyhow::Result<()> { }); let model_cache = Arc::new(ModelCache::new(pool.clone())); - let db = Sql::new(pool.clone(), sender.clone(), &contracts, &args.model_cache.clone()).await?; + let db = Sql::new(pool.clone(), sender.clone(), &args.contracts, model_cache.clone()).await?; let processors = Processors { transaction: vec![Box::new(StoreTransactionProcessor)], diff --git a/crates/torii/core/src/engine.rs b/crates/torii/core/src/engine.rs index 8a68c7f58a..ccac372feb 100644 --- a/crates/torii/core/src/engine.rs +++ b/crates/torii/core/src/engine.rs @@ -39,7 +39,9 @@ use crate::processors::store_update_member::StoreUpdateMemberProcessor; use crate::processors::store_update_record::StoreUpdateRecordProcessor; use crate::processors::upgrade_event::UpgradeEventProcessor; use crate::processors::upgrade_model::UpgradeModelProcessor; -use crate::processors::{BlockProcessor, EventProcessor, TransactionProcessor, EventProcessorConfig}; +use crate::processors::{ + BlockProcessor, EventProcessor, EventProcessorConfig, TransactionProcessor, +}; use crate::sql::{Cursors, Sql}; use crate::types::{Contract, ContractType}; diff --git a/crates/torii/core/src/processors/upgrade_event.rs b/crates/torii/core/src/processors/upgrade_event.rs index 0d5efff07e..8479d9ab05 100644 --- a/crates/torii/core/src/processors/upgrade_event.rs +++ b/crates/torii/core/src/processors/upgrade_event.rs @@ -7,7 +7,7 @@ use starknet::core::types::Event; use starknet::providers::Provider; use tracing::{debug, info}; -use super::EventProcessor; +use super::{EventProcessor, EventProcessorConfig}; use crate::sql::Sql; pub(crate) const LOG_TARGET: &str = "torii_core::processors::upgrade_event"; @@ -38,6 +38,7 @@ where block_timestamp: u64, _event_id: &str, event: &Event, + _config: &EventProcessorConfig, ) -> Result<(), Error> { // Torii version is coupled to the world version, so we can expect the event to be well // formed. diff --git a/crates/torii/core/src/processors/upgrade_model.rs b/crates/torii/core/src/processors/upgrade_model.rs index dde5618ba7..403e1e17fd 100644 --- a/crates/torii/core/src/processors/upgrade_model.rs +++ b/crates/torii/core/src/processors/upgrade_model.rs @@ -7,7 +7,7 @@ use starknet::core::types::Event; use starknet::providers::Provider; use tracing::{debug, info}; -use super::EventProcessor; +use super::{EventProcessor, EventProcessorConfig}; use crate::sql::Sql; pub(crate) const LOG_TARGET: &str = "torii_core::processors::upgrade_model"; @@ -38,6 +38,7 @@ where block_timestamp: u64, _event_id: &str, event: &Event, + _config: &EventProcessorConfig, ) -> Result<(), Error> { // Torii version is coupled to the world version, so we can expect the event to be well // formed. From 210ac315d54eeef6b6ae6a397c65f69ffba2d3cc Mon Sep 17 00:00:00 2001 From: Nasr Date: Tue, 12 Nov 2024 15:08:33 +0700 Subject: [PATCH 17/35] primitives not option --- crates/dojo/types/src/packing.rs | 2 +- crates/dojo/types/src/primitive.rs | 310 +++++++++++++---------------- crates/dojo/types/src/schema.rs | 108 ++++------ crates/dojo/types/tests/json.rs | 8 +- crates/torii/core/src/model.rs | 44 ++-- 5 files changed, 201 insertions(+), 271 deletions(-) diff --git a/crates/dojo/types/src/packing.rs b/crates/dojo/types/src/packing.rs index 6817bb5447..f2d7fa1aed 100644 --- a/crates/dojo/types/src/packing.rs +++ b/crates/dojo/types/src/packing.rs @@ -321,7 +321,7 @@ mod tests { #[test] fn parse_simple_with_valid_value() { let data = [cairo_short_string_to_felt("u8").unwrap()]; - assert_eq!(parse_simple(&data).unwrap(), Ty::Primitive(Primitive::U8(None))); + assert_eq!(parse_simple(&data).unwrap(), Ty::Primitive(Primitive::U8(0))); } #[test] diff --git a/crates/dojo/types/src/primitive.rs b/crates/dojo/types/src/primitive.rs index 9fd0a41563..ce29063d23 100644 --- a/crates/dojo/types/src/primitive.rs +++ b/crates/dojo/types/src/primitive.rs @@ -27,24 +27,24 @@ use super::primitive_conversion::try_from_felt; #[strum(serialize_all = "lowercase")] #[serde(rename_all = "lowercase")] pub enum Primitive { - I8(Option), - I16(Option), - I32(Option), - I64(Option), - I128(Option), - U8(Option), - U16(Option), - U32(Option), - U64(Option), - U128(Option), - U256(Option), - USize(Option), - Bool(Option), - Felt252(Option), + I8(i8), + I16(i16), + I32(i32), + I64(i64), + I128(i128), + U8(u8), + U16(u16), + U32(u32), + U64(u64), + U128(u128), + U256(U256), + USize(u32), + Bool(bool), + Felt252(Felt), #[strum(serialize = "ClassHash")] - ClassHash(Option), + ClassHash(Felt), #[strum(serialize = "ContractAddress")] - ContractAddress(Option), + ContractAddress(Felt), } #[derive(Debug, thiserror::Error)] @@ -80,7 +80,7 @@ pub enum SqlType { macro_rules! set_primitive { ($method_name:ident, $variant:ident, $type:ty) => { /// Sets the inner value of the `Primitive` enum if variant matches. - pub fn $method_name(&mut self, value: Option<$type>) -> Result<(), PrimitiveError> { + pub fn $method_name(&mut self, value: $type) -> Result<(), PrimitiveError> { match self { Primitive::$variant(_) => { *self = Primitive::$variant(value); @@ -99,7 +99,7 @@ macro_rules! as_primitive { /// `None` otherwise. pub fn $method_name(&self) -> Option<$type> { match self { - Primitive::$variant(value) => *value, + Primitive::$variant(value) => Some(*value), _ => None, } } @@ -193,26 +193,26 @@ impl Primitive { pub fn to_sql_value(&self) -> String { match self { // Integers - Primitive::I8(i8) => format!("{}", i8.unwrap_or_default()), - Primitive::I16(i16) => format!("{}", i16.unwrap_or_default()), - Primitive::I32(i32) => format!("{}", i32.unwrap_or_default()), - Primitive::I64(i64) => format!("{}", i64.unwrap_or_default()), + Primitive::I8(i8) => format!("{}", i8), + Primitive::I16(i16) => format!("{}", i16), + Primitive::I32(i32) => format!("{}", i32), + Primitive::I64(i64) => format!("{}", i64), - Primitive::U8(u8) => format!("{}", u8.unwrap_or_default()), - Primitive::U16(u16) => format!("{}", u16.unwrap_or_default()), - Primitive::U32(u32) => format!("{}", u32.unwrap_or_default()), - Primitive::USize(u32) => format!("{}", u32.unwrap_or_default()), - Primitive::Bool(bool) => format!("{}", bool.unwrap_or_default()), + Primitive::U8(u8) => format!("{}", u8), + Primitive::U16(u16) => format!("{}", u16), + Primitive::U32(u32) => format!("{}", u32), + Primitive::USize(u32) => format!("{}", u32), + Primitive::Bool(bool) => format!("{}", bool), // Hex string - Primitive::I128(i128) => format!("{:#064x}", i128.unwrap_or_default()), - Primitive::ContractAddress(felt) => format!("{:#064x}", felt.unwrap_or_default()), - Primitive::ClassHash(felt) => format!("{:#064x}", felt.unwrap_or_default()), - Primitive::Felt252(felt) => format!("{:#064x}", felt.unwrap_or_default()), - Primitive::U128(u128) => format!("{:#064x}", u128.unwrap_or_default()), - Primitive::U64(u64) => format!("{:#064x}", u64.unwrap_or_default()), - - Primitive::U256(u256) => format!("0x{:064x}", u256.unwrap_or_default()), + Primitive::I128(i128) => format!("{:#064x}", i128), + Primitive::ContractAddress(felt) => format!("{:#064x}", felt), + Primitive::ClassHash(felt) => format!("{:#064x}", felt), + Primitive::Felt252(felt) => format!("{:#064x}", felt), + Primitive::U128(u128) => format!("{:#064x}", u128), + Primitive::U64(u64) => format!("{:#064x}", u64), + + Primitive::U256(u256) => format!("0x{:064x}", u256), } } @@ -224,77 +224,77 @@ impl Primitive { match self { Primitive::I8(ref mut value) => { let felt = felts.remove(0); - *value = Some(try_from_felt::(felt).map_err(|_| { + *value = try_from_felt::(felt).map_err(|_| { PrimitiveError::ValueOutOfRange { r#type: type_name::(), value: felt } - })?); + })?; } Primitive::I16(ref mut value) => { let felt = felts.remove(0); - *value = Some(try_from_felt::(felt).map_err(|_| { + *value = try_from_felt::(felt).map_err(|_| { PrimitiveError::ValueOutOfRange { r#type: type_name::(), value: felt } - })?); + })?; } Primitive::I32(ref mut value) => { let felt = felts.remove(0); - *value = Some(try_from_felt::(felt).map_err(|_| { + *value = try_from_felt::(felt).map_err(|_| { PrimitiveError::ValueOutOfRange { r#type: type_name::(), value: felt } - })?); + })?; } Primitive::I64(ref mut value) => { let felt = felts.remove(0); - *value = Some(try_from_felt::(felt).map_err(|_| { + *value = try_from_felt::(felt).map_err(|_| { PrimitiveError::ValueOutOfRange { r#type: type_name::(), value: felt } - })?); + })?; } Primitive::I128(ref mut value) => { let felt = felts.remove(0); - *value = Some(try_from_felt::(felt).map_err(|_| { + *value = try_from_felt::(felt).map_err(|_| { PrimitiveError::ValueOutOfRange { r#type: type_name::(), value: felt } - })?); + })?; } Primitive::U8(ref mut value) => { let felt = felts.remove(0); - *value = Some(felt.to_u8().ok_or_else(|| PrimitiveError::ValueOutOfRange { + *value = felt.to_u8().ok_or_else(|| PrimitiveError::ValueOutOfRange { r#type: type_name::(), value: felt, - })?); + })?; } Primitive::U16(ref mut value) => { let felt = felts.remove(0); - *value = Some(felt.to_u16().ok_or_else(|| PrimitiveError::ValueOutOfRange { + *value = felt.to_u16().ok_or_else(|| PrimitiveError::ValueOutOfRange { r#type: type_name::(), value: felt, - })?); + })?; } Primitive::U32(ref mut value) => { let felt = felts.remove(0); - *value = Some(felt.to_u32().ok_or_else(|| PrimitiveError::ValueOutOfRange { + *value = felt.to_u32().ok_or_else(|| PrimitiveError::ValueOutOfRange { r#type: type_name::(), value: felt, - })?); + })?; } Primitive::U64(ref mut value) => { let felt = felts.remove(0); - *value = Some(felt.to_u64().ok_or_else(|| PrimitiveError::ValueOutOfRange { + *value = felt.to_u64().ok_or_else(|| PrimitiveError::ValueOutOfRange { r#type: type_name::(), value: felt, - })?); + })?; } Primitive::U128(ref mut value) => { let felt = felts.remove(0); - *value = Some(felt.to_u128().ok_or_else(|| PrimitiveError::ValueOutOfRange { + *value = felt.to_u128().ok_or_else(|| PrimitiveError::ValueOutOfRange { r#type: type_name::(), value: felt, - })?); + })?; } Primitive::U256(ref mut value) => { @@ -308,99 +308,67 @@ impl Primitive { let mut bytes = [0u8; 32]; bytes[16..].copy_from_slice(&value0_bytes[16..]); bytes[..16].copy_from_slice(&value1_bytes[16..]); - *value = Some(U256::from_be_bytes(bytes)); + *value = U256::from_be_bytes(bytes); } Primitive::USize(ref mut value) => { let felt = felts.remove(0); - *value = Some(felt.to_u32().ok_or_else(|| PrimitiveError::ValueOutOfRange { + *value = felt.to_u32().ok_or_else(|| PrimitiveError::ValueOutOfRange { r#type: type_name::(), value: felt, - })?); + })?; } Primitive::Bool(ref mut value) => { let raw = felts.remove(0); - *value = Some(raw == Felt::ONE); + *value = raw == Felt::ONE; } Primitive::ContractAddress(ref mut value) => { - *value = Some(felts.remove(0)); + *value = felts.remove(0); } Primitive::ClassHash(ref mut value) => { - *value = Some(felts.remove(0)); + *value = felts.remove(0); } Primitive::Felt252(ref mut value) => { - *value = Some(felts.remove(0)); + *value = felts.remove(0); } } Ok(()) } - pub fn serialize(&self) -> Result, PrimitiveError> { + pub fn serialize(&self) -> Vec { match self { - Primitive::I8(value) => value - .map(|v| Ok(vec![Felt::from(v)])) - .unwrap_or(Err(PrimitiveError::MissingFieldElement)), - Primitive::I16(value) => value - .map(|v| Ok(vec![Felt::from(v)])) - .unwrap_or(Err(PrimitiveError::MissingFieldElement)), - Primitive::I32(value) => value - .map(|v| Ok(vec![Felt::from(v)])) - .unwrap_or(Err(PrimitiveError::MissingFieldElement)), - Primitive::I64(value) => value - .map(|v| Ok(vec![Felt::from(v)])) - .unwrap_or(Err(PrimitiveError::MissingFieldElement)), - Primitive::I128(value) => value - .map(|v| Ok(vec![Felt::from(v)])) - .unwrap_or(Err(PrimitiveError::MissingFieldElement)), - Primitive::U8(value) => value - .map(|v| Ok(vec![Felt::from(v)])) - .unwrap_or(Err(PrimitiveError::MissingFieldElement)), - Primitive::U16(value) => value - .map(|v| Ok(vec![Felt::from(v)])) - .unwrap_or(Err(PrimitiveError::MissingFieldElement)), - Primitive::U32(value) => value - .map(|v| Ok(vec![Felt::from(v)])) - .unwrap_or(Err(PrimitiveError::MissingFieldElement)), - Primitive::U64(value) => value - .map(|v| Ok(vec![Felt::from(v)])) - .unwrap_or(Err(PrimitiveError::MissingFieldElement)), - Primitive::U128(value) => value - .map(|v| Ok(vec![Felt::from(v)])) - .unwrap_or(Err(PrimitiveError::MissingFieldElement)), - Primitive::U256(value) => value - .map(|v| { - let bytes: [u8; 32] = v.to_be_bytes(); - let value0_slice = &bytes[16..]; - let value1_slice = &bytes[..16]; - let mut value0_array = [0u8; 32]; - let mut value1_array = [0u8; 32]; - value0_array[16..].copy_from_slice(value0_slice); - value1_array[16..].copy_from_slice(value1_slice); - let value0 = Felt::from_bytes_be(&value0_array); - let value1 = Felt::from_bytes_be(&value1_array); - Ok(vec![value0, value1]) - }) - .unwrap_or(Err(PrimitiveError::MissingFieldElement)), - Primitive::USize(value) => value - .map(|v| Ok(vec![Felt::from(v)])) - .unwrap_or(Err(PrimitiveError::MissingFieldElement)), - Primitive::Bool(value) => value - .map(|v| Ok(vec![if v { Felt::ONE } else { Felt::ZERO }])) - .unwrap_or(Err(PrimitiveError::MissingFieldElement)), - Primitive::ContractAddress(value) => { - value.map(|v| Ok(vec![v])).unwrap_or(Err(PrimitiveError::MissingFieldElement)) - } - Primitive::ClassHash(value) => { - value.map(|v| Ok(vec![v])).unwrap_or(Err(PrimitiveError::MissingFieldElement)) - } - Primitive::Felt252(value) => { - value.map(|v| Ok(vec![v])).unwrap_or(Err(PrimitiveError::MissingFieldElement)) + Primitive::I8(value) => vec![Felt::from(*value)], + Primitive::I16(value) => vec![Felt::from(*value)], + Primitive::I32(value) => vec![Felt::from(*value)], + Primitive::I64(value) => vec![Felt::from(*value)], + Primitive::I128(value) => vec![Felt::from(*value)], + Primitive::U8(value) => vec![Felt::from(*value)], + Primitive::U16(value) => vec![Felt::from(*value)], + Primitive::U32(value) => vec![Felt::from(*value)], + Primitive::U64(value) => vec![Felt::from(*value)], + Primitive::U128(value) => vec![Felt::from(*value)], + Primitive::U256(value) => { + let bytes: [u8; 32] = value.to_be_bytes(); + let value0_slice = &bytes[16..]; + let value1_slice = &bytes[..16]; + let mut value0_array = [0u8; 32]; + let mut value1_array = [0u8; 32]; + value0_array[16..].copy_from_slice(value0_slice); + value1_array[16..].copy_from_slice(value1_slice); + let value0 = Felt::from_bytes_be(&value0_array); + let value1 = Felt::from_bytes_be(&value1_array); + vec![value0, value1] } + Primitive::USize(value) => vec![Felt::from(*value)], + Primitive::Bool(value) => vec![if *value { Felt::ONE } else { Felt::ZERO }], + Primitive::ContractAddress(value) => vec![Felt::from(*value)], + Primitive::ClassHash(value) => vec![Felt::from(*value)], + Primitive::Felt252(value) => vec![Felt::from(*value)] } } } @@ -416,11 +384,11 @@ mod tests { #[test] fn test_u256() { - let primitive = Primitive::U256(Some(U256::from_be_hex( + let primitive = Primitive::U256(U256::from_be_hex( "aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbccccccccccccccccdddddddddddddddd", - ))); + )); let sql_value = primitive.to_sql_value(); - let serialized = primitive.serialize().unwrap(); + let serialized = primitive.serialize(); let mut deserialized = primitive; deserialized.deserialize(&mut serialized.clone()).unwrap(); @@ -438,79 +406,79 @@ mod tests { #[test] fn inner_value_getter_setter() { - let mut primitive = Primitive::I8(None); - primitive.set_i8(Some(-1i8)).unwrap(); + let mut primitive = Primitive::I8(0); + primitive.set_i8(-1).unwrap(); assert_eq!(primitive.as_i8(), Some(-1i8)); - let mut primitive = Primitive::I16(None); - primitive.set_i16(Some(-1i16)).unwrap(); + let mut primitive = Primitive::I16(0); + primitive.set_i16(-1i16).unwrap(); assert_eq!(primitive.as_i16(), Some(-1i16)); - let mut primitive = Primitive::I32(None); - primitive.set_i32(Some(-1i32)).unwrap(); + let mut primitive = Primitive::I32(0); + primitive.set_i32(-1i32).unwrap(); assert_eq!(primitive.as_i32(), Some(-1i32)); - let mut primitive = Primitive::I64(None); - primitive.set_i64(Some(-1i64)).unwrap(); + let mut primitive = Primitive::I64(0); + primitive.set_i64(-1i64).unwrap(); assert_eq!(primitive.as_i64(), Some(-1i64)); - let mut primitive = Primitive::I128(None); - primitive.set_i128(Some(-1i128)).unwrap(); + let mut primitive = Primitive::I128(0); + primitive.set_i128(-1i128).unwrap(); assert_eq!(primitive.as_i128(), Some(-1i128)); - let mut primitive = Primitive::U8(None); - primitive.set_u8(Some(1u8)).unwrap(); + let mut primitive = Primitive::U8(0); + primitive.set_u8(1u8).unwrap(); assert_eq!(primitive.as_u8(), Some(1u8)); - let mut primitive = Primitive::U16(None); - primitive.set_u16(Some(1u16)).unwrap(); + let mut primitive = Primitive::U16(0); + primitive.set_u16(1u16).unwrap(); assert_eq!(primitive.as_u16(), Some(1u16)); - let mut primitive = Primitive::U32(None); - primitive.set_u32(Some(1u32)).unwrap(); + let mut primitive = Primitive::U32(0); + primitive.set_u32(1u32).unwrap(); assert_eq!(primitive.as_u32(), Some(1u32)); - let mut primitive = Primitive::U64(None); - primitive.set_u64(Some(1u64)).unwrap(); + let mut primitive = Primitive::U64(0); + primitive.set_u64(1u64).unwrap(); assert_eq!(primitive.as_u64(), Some(1u64)); - let mut primitive = Primitive::U128(None); - primitive.set_u128(Some(1u128)).unwrap(); + let mut primitive = Primitive::U128(0); + primitive.set_u128(1u128).unwrap(); assert_eq!(primitive.as_u128(), Some(1u128)); - let mut primitive = Primitive::U256(None); - primitive.set_u256(Some(U256::from(1u128))).unwrap(); + let mut primitive = Primitive::U256(U256::ZERO); + primitive.set_u256(U256::from(1u128)).unwrap(); assert_eq!(primitive.as_u256(), Some(U256::from(1u128))); - let mut primitive = Primitive::USize(None); - primitive.set_usize(Some(1u32)).unwrap(); + let mut primitive = Primitive::USize(0); + primitive.set_usize(1u32).unwrap(); assert_eq!(primitive.as_usize(), Some(1u32)); - let mut primitive = Primitive::Bool(None); - primitive.set_bool(Some(true)).unwrap(); + let mut primitive = Primitive::Bool(false); + primitive.set_bool(true).unwrap(); assert_eq!(primitive.as_bool(), Some(true)); - let mut primitive = Primitive::Felt252(None); - primitive.set_felt252(Some(Felt::from(1u128))).unwrap(); + let mut primitive = Primitive::Felt252(Felt::ZERO); + primitive.set_felt252(Felt::from(1u128)).unwrap(); assert_eq!(primitive.as_felt252(), Some(Felt::from(1u128))); - let mut primitive = Primitive::ClassHash(None); - primitive.set_class_hash(Some(Felt::from(1u128))).unwrap(); + let mut primitive = Primitive::ClassHash(Felt::ZERO); + primitive.set_class_hash(Felt::from(1u128)).unwrap(); assert_eq!(primitive.as_class_hash(), Some(Felt::from(1u128))); - let mut primitive = Primitive::ContractAddress(None); - primitive.set_contract_address(Some(Felt::from(1u128))).unwrap(); + let mut primitive = Primitive::ContractAddress(Felt::ZERO); + primitive.set_contract_address(Felt::from(1u128)).unwrap(); assert_eq!(primitive.as_contract_address(), Some(Felt::from(1u128))); } #[test] fn test_primitive_deserialization() { let test_cases = vec![ - (vec![Felt::from(-42i8)], Primitive::I8(Some(-42))), - (vec![Felt::from(-1000i16)], Primitive::I16(Some(-1000))), - (vec![Felt::from(-100000i32)], Primitive::I32(Some(-100000))), - (vec![Felt::from(-1000000000i64)], Primitive::I64(Some(-1000000000))), + (vec![Felt::from(-42i8)], Primitive::I8(-42)), + (vec![Felt::from(-1000i16)], Primitive::I16(-1000)), + (vec![Felt::from(-100000i32)], Primitive::I32(-100000)), + (vec![Felt::from(-1000000000i64)], Primitive::I64(-1000000000)), ( vec![Felt::from(-1000000000000000000i128)], - Primitive::I128(Some(-1000000000000000000)), + Primitive::I128(-1000000000000000000), ), - (vec![Felt::from(42u8)], Primitive::U8(Some(42))), - (vec![Felt::from(1000u16)], Primitive::U16(Some(1000))), - (vec![Felt::from(100000u32)], Primitive::U32(Some(100000))), - (vec![Felt::from(1000000000u64)], Primitive::U64(Some(1000000000))), - (vec![Felt::from(1000000000000000000u128)], Primitive::U128(Some(1000000000000000000))), - (vec![Felt::from(42u32)], Primitive::USize(Some(42))), - (vec![Felt::from(1u8)], Primitive::Bool(Some(true))), - (vec![Felt::from(123456789u128)], Primitive::Felt252(Some(Felt::from(123456789)))), - (vec![Felt::from(987654321u128)], Primitive::ClassHash(Some(Felt::from(987654321)))), + (vec![Felt::from(42u8)], Primitive::U8(42)), + (vec![Felt::from(1000u16)], Primitive::U16(1000)), + (vec![Felt::from(100000u32)], Primitive::U32(100000)), + (vec![Felt::from(1000000000u64)], Primitive::U64(1000000000)), + (vec![Felt::from(1000000000000000000u128)], Primitive::U128(1000000000000000000)), + (vec![Felt::from(42u32)], Primitive::USize(42)), + (vec![Felt::from(1u8)], Primitive::Bool(true)), + (vec![Felt::from(123456789u128)], Primitive::Felt252(Felt::from(123456789))), + (vec![Felt::from(987654321u128)], Primitive::ClassHash(Felt::from(987654321))), ( vec![Felt::from(123456789u128)], - Primitive::ContractAddress(Some(Felt::from(123456789))), + Primitive::ContractAddress(Felt::from(123456789)), ), ]; diff --git a/crates/dojo/types/src/schema.rs b/crates/dojo/types/src/schema.rs index a8585ba0d3..b3a2bc2016 100644 --- a/crates/dojo/types/src/schema.rs +++ b/crates/dojo/types/src/schema.rs @@ -126,7 +126,7 @@ impl Ty { fn serialize_inner(ty: &Ty, felts: &mut Vec) -> Result<(), PrimitiveError> { match ty { Ty::Primitive(c) => { - felts.extend(c.serialize()?); + felts.extend(c.serialize()); } Ty::Struct(s) => { for child in &s.children { @@ -151,7 +151,7 @@ impl Ty { } Ty::Array(items_ty) => { let _ = serialize_inner( - &Ty::Primitive(Primitive::U32(Some(items_ty.len().try_into().unwrap()))), + &Ty::Primitive(Primitive::U32(items_ty.len().try_into().unwrap())), felts, ); for item_ty in items_ty { @@ -400,7 +400,7 @@ pub enum EnumError { #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Hash, Eq)] pub struct Enum { pub name: String, - pub option: Option, + pub option: u8, pub options: Vec, } @@ -450,84 +450,52 @@ fn format_member(m: &Member) -> String { if let Ty::Primitive(ty) = &m.ty { match ty { Primitive::I8(value) => { - if let Some(value) = value { - str.push_str(&format!(" = {}", value)); - } + str.push_str(&format!(" = {}", value)); } Primitive::I16(value) => { - if let Some(value) = value { - str.push_str(&format!(" = {}", value)); - } + str.push_str(&format!(" = {}", value)); } Primitive::I32(value) => { - if let Some(value) = value { - str.push_str(&format!(" = {}", value)); - } + str.push_str(&format!(" = {}", value)); } Primitive::I64(value) => { - if let Some(value) = value { - str.push_str(&format!(" = {}", value)); - } + str.push_str(&format!(" = {}", value)); } Primitive::I128(value) => { - if let Some(value) = value { - str.push_str(&format!(" = {}", value)); - } + str.push_str(&format!(" = {}", value)); } Primitive::U8(value) => { - if let Some(value) = value { - str.push_str(&format!(" = {}", value)); - } + str.push_str(&format!(" = {}", value)); } Primitive::U16(value) => { - if let Some(value) = value { - str.push_str(&format!(" = {}", value)); - } + str.push_str(&format!(" = {}", value)); } Primitive::U32(value) => { - if let Some(value) = value { - str.push_str(&format!(" = {}", value)); - } + str.push_str(&format!(" = {}", value)); } Primitive::U64(value) => { - if let Some(value) = value { - str.push_str(&format!(" = {}", value)); - } + str.push_str(&format!(" = {}", value)); } Primitive::U128(value) => { - if let Some(value) = value { - str.push_str(&format!(" = {}", value)); - } + str.push_str(&format!(" = {}", value)); } Primitive::U256(value) => { - if let Some(value) = value { - str.push_str(&format!(" = {}", value)); - } + str.push_str(&format!(" = {}", value)); } Primitive::USize(value) => { - if let Some(value) = value { - str.push_str(&format!(" = {}", value)); - } + str.push_str(&format!(" = {}", value)); } Primitive::Bool(value) => { - if let Some(value) = value { - str.push_str(&format!(" = {}", value)); - } + str.push_str(&format!(" = {}", value)); } Primitive::Felt252(value) => { - if let Some(value) = value { - str.push_str(&format!(" = {:#x}", value)); - } + str.push_str(&format!(" = {:#x}", value)); } Primitive::ClassHash(value) => { - if let Some(value) = value { - str.push_str(&format!(" = {:#x}", value)); - } + str.push_str(&format!(" = {:#x}", value)); } Primitive::ContractAddress(value) => { - if let Some(value) = value { - str.push_str(&format!(" = {:#x}", value)); - } + str.push_str(&format!(" = {:#x}", value)); } } } else if let Ty::Enum(e) = &m.ty { @@ -554,7 +522,7 @@ mod tests { ( Member { name: "i8_field".to_string(), - ty: Ty::Primitive(Primitive::I8(Some(-42))), + ty: Ty::Primitive(Primitive::I8(-42)), key: false, }, " i8_field: i8 = -42", @@ -562,7 +530,7 @@ mod tests { ( Member { name: "i16_field".to_string(), - ty: Ty::Primitive(Primitive::I16(Some(-1000))), + ty: Ty::Primitive(Primitive::I16(-1000)), key: false, }, " i16_field: i16 = -1000", @@ -570,7 +538,7 @@ mod tests { ( Member { name: "i32_field".to_string(), - ty: Ty::Primitive(Primitive::I32(Some(-100000))), + ty: Ty::Primitive(Primitive::I32(-100000)), key: false, }, " i32_field: i32 = -100000", @@ -578,7 +546,7 @@ mod tests { ( Member { name: "i64_field".to_string(), - ty: Ty::Primitive(Primitive::I64(Some(-1000000000))), + ty: Ty::Primitive(Primitive::I64(-1000000000)), key: false, }, " i64_field: i64 = -1000000000", @@ -586,7 +554,7 @@ mod tests { ( Member { name: "i128_field".to_string(), - ty: Ty::Primitive(Primitive::I128(Some(-1000000000000000000))), + ty: Ty::Primitive(Primitive::I128(-1000000000000000000)), key: false, }, " i128_field: i128 = -1000000000000000000", @@ -594,7 +562,7 @@ mod tests { ( Member { name: "u8_field".to_string(), - ty: Ty::Primitive(Primitive::U8(Some(255))), + ty: Ty::Primitive(Primitive::U8(255)), key: false, }, " u8_field: u8 = 255", @@ -602,7 +570,7 @@ mod tests { ( Member { name: "u16_field".to_string(), - ty: Ty::Primitive(Primitive::U16(Some(65535))), + ty: Ty::Primitive(Primitive::U16(65535)), key: false, }, " u16_field: u16 = 65535", @@ -610,7 +578,7 @@ mod tests { ( Member { name: "u32_field".to_string(), - ty: Ty::Primitive(Primitive::U32(Some(4294967295))), + ty: Ty::Primitive(Primitive::U32(4294967295)), key: false, }, " u32_field: u32 = 4294967295", @@ -618,7 +586,7 @@ mod tests { ( Member { name: "u64_field".to_string(), - ty: Ty::Primitive(Primitive::U64(Some(18446744073709551615))), + ty: Ty::Primitive(Primitive::U64(18446744073709551615)), key: false, }, " u64_field: u64 = 18446744073709551615", @@ -626,9 +594,7 @@ mod tests { ( Member { name: "u128_field".to_string(), - ty: Ty::Primitive(Primitive::U128(Some( - 340282366920938463463374607431768211455, - ))), + ty: Ty::Primitive(Primitive::U128(340282366920938463463374607431768211455)), key: false, }, " u128_field: u128 = 340282366920938463463374607431768211455", @@ -636,7 +602,7 @@ mod tests { ( Member { name: "u256_field".to_string(), - ty: Ty::Primitive(Primitive::U256(Some(U256::from_u128(123456789_u128)))), + ty: Ty::Primitive(Primitive::U256(U256::from_u128(123456789_u128))), key: false, }, " u256_field: u256 = \ @@ -645,7 +611,7 @@ mod tests { ( Member { name: "bool_field".to_string(), - ty: Ty::Primitive(Primitive::Bool(Some(true))), + ty: Ty::Primitive(Primitive::Bool(true)), key: false, }, " bool_field: bool = true", @@ -653,9 +619,7 @@ mod tests { ( Member { name: "felt252_field".to_string(), - ty: Ty::Primitive(Primitive::Felt252(Some( - Felt::from_hex("0x123abc").unwrap(), - ))), + ty: Ty::Primitive(Primitive::Felt252(Felt::from_hex("0x123abc").unwrap())), key: false, }, " felt252_field: felt252 = 0x123abc", @@ -690,17 +654,17 @@ mod tests { children: vec![ Member { name: "field1".to_string(), - ty: Ty::Primitive(Primitive::U32(None)), + ty: Ty::Primitive(Primitive::U32(0)), key: false, }, Member { name: "field2".to_string(), - ty: Ty::Primitive(Primitive::U32(None)), + ty: Ty::Primitive(Primitive::U32(0)), key: false, }, Member { name: "field3".to_string(), - ty: Ty::Primitive(Primitive::U32(None)), + ty: Ty::Primitive(Primitive::U32(0)), key: false, }, ], @@ -710,7 +674,7 @@ mod tests { name: "TestStruct".to_string(), children: vec![Member { name: "field1".to_string(), - ty: Ty::Primitive(Primitive::U32(None)), + ty: Ty::Primitive(Primitive::U32(0)), key: false, }], }); diff --git a/crates/dojo/types/tests/json.rs b/crates/dojo/types/tests/json.rs index 61a6579c73..ddea135a26 100644 --- a/crates/dojo/types/tests/json.rs +++ b/crates/dojo/types/tests/json.rs @@ -7,8 +7,8 @@ fn serialize_ty_to_json() { let ty = Ty::Struct(Struct { name: "Position".into(), children: vec![ - Member { name: "x".into(), key: false, ty: Ty::Primitive(Primitive::U8(Some(128))) }, - Member { name: "y".into(), key: false, ty: Ty::Primitive(Primitive::U64(Some(2048))) }, + Member { name: "x".into(), key: false, ty: Ty::Primitive(Primitive::U8(128)) }, + Member { name: "y".into(), key: false, ty: Ty::Primitive(Primitive::U64(2048)) }, Member { name: "kind".into(), key: false, @@ -149,8 +149,8 @@ fn deserialize_ty_from_json() { let expected_value = Ty::Struct(Struct { name: "Position".into(), children: vec![ - Member { name: "x".into(), key: false, ty: Ty::Primitive(Primitive::U8(Some(128))) }, - Member { name: "y".into(), key: false, ty: Ty::Primitive(Primitive::U64(Some(2048))) }, + Member { name: "x".into(), key: false, ty: Ty::Primitive(Primitive::U8(128)) }, + Member { name: "y".into(), key: false, ty: Ty::Primitive(Primitive::U64(2048)) }, Member { name: "kind".into(), key: false, diff --git a/crates/torii/core/src/model.rs b/crates/torii/core/src/model.rs index 5a38e60c2e..9219fe4344 100644 --- a/crates/torii/core/src/model.rs +++ b/crates/torii/core/src/model.rs @@ -494,82 +494,80 @@ pub fn map_row_to_ty( match &primitive { Primitive::I8(_) => { let value = row.try_get::(&column_name)?; - primitive.set_i8(Some(value))?; + primitive.set_i8(value)?; } Primitive::I16(_) => { let value = row.try_get::(&column_name)?; - primitive.set_i16(Some(value))?; + primitive.set_i16(value)?; } Primitive::I32(_) => { let value = row.try_get::(&column_name)?; - primitive.set_i32(Some(value))?; + primitive.set_i32(value)?; } Primitive::I64(_) => { let value = row.try_get::(&column_name)?; - primitive.set_i64(Some(value))?; + primitive.set_i64(value)?; } Primitive::I128(_) => { let value = row.try_get::(&column_name)?; let hex_str = value.trim_start_matches("0x"); - primitive.set_i128(Some( + primitive.set_i128( i128::from_str_radix(hex_str, 16).map_err(ParseError::ParseIntError)?, - ))?; + )?; } Primitive::U8(_) => { let value = row.try_get::(&column_name)?; - primitive.set_u8(Some(value))?; + primitive.set_u8(value)?; } Primitive::U16(_) => { let value = row.try_get::(&column_name)?; - primitive.set_u16(Some(value))?; + primitive.set_u16(value)?; } Primitive::U32(_) => { let value = row.try_get::(&column_name)?; - primitive.set_u32(Some(value))?; + primitive.set_u32(value)?; } Primitive::U64(_) => { let value = row.try_get::(&column_name)?; let hex_str = value.trim_start_matches("0x"); - primitive.set_u64(Some( + primitive.set_u64( u64::from_str_radix(hex_str, 16).map_err(ParseError::ParseIntError)?, - ))?; + )?; } Primitive::U128(_) => { let value = row.try_get::(&column_name)?; let hex_str = value.trim_start_matches("0x"); - primitive.set_u128(Some( + primitive.set_u128( u128::from_str_radix(hex_str, 16).map_err(ParseError::ParseIntError)?, - ))?; + )?; } Primitive::U256(_) => { let value = row.try_get::(&column_name)?; let hex_str = value.trim_start_matches("0x"); - primitive.set_u256(Some(U256::from_be_hex(hex_str)))?; + primitive.set_u256(U256::from_be_hex(hex_str))?; } Primitive::USize(_) => { let value = row.try_get::(&column_name)?; - primitive.set_usize(Some(value))?; + primitive.set_usize(value)?; } Primitive::Bool(_) => { let value = row.try_get::(&column_name)?; - primitive.set_bool(Some(value))?; + primitive.set_bool(value)?; } Primitive::Felt252(_) => { let value = row.try_get::(&column_name)?; - primitive - .set_felt252(Some(Felt::from_str(&value).map_err(ParseError::FromStr)?))?; + primitive.set_felt252(Felt::from_str(&value).map_err(ParseError::FromStr)?)?; } Primitive::ClassHash(_) => { let value = row.try_get::(&column_name)?; - primitive.set_class_hash(Some( - Felt::from_str(&value).map_err(ParseError::FromStr)?, - ))?; + primitive + .set_class_hash(Felt::from_str(&value).map_err(ParseError::FromStr)?)?; } Primitive::ContractAddress(_) => { let value = row.try_get::(&column_name)?; - primitive.set_contract_address(Some( + primitive.set_contract_address( Felt::from_str(&value).map_err(ParseError::FromStr)?, - ))?; + )?; } }; } From d86fcc4fe5220a7301725a2b2d7abf3476955856 Mon Sep 17 00:00:00 2001 From: Nasr Date: Wed, 13 Nov 2024 08:32:09 +0700 Subject: [PATCH 18/35] fix: enums --- crates/dojo/types/src/packing.rs | 2 +- crates/dojo/types/src/schema.rs | 32 +++++++++++--------------------- 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/crates/dojo/types/src/packing.rs b/crates/dojo/types/src/packing.rs index f2d7fa1aed..3b1c7b2b3a 100644 --- a/crates/dojo/types/src/packing.rs +++ b/crates/dojo/types/src/packing.rs @@ -251,7 +251,7 @@ fn parse_enum(data: &[Felt]) -> Result { offset += len as usize + 2; } - Ok(Ty::Enum(schema::Enum { name, option: None, options: values })) + Ok(Ty::Enum(schema::Enum { name, option: 0, options: values })) } fn parse_tuple(data: &[Felt]) -> Result { diff --git a/crates/dojo/types/src/schema.rs b/crates/dojo/types/src/schema.rs index b3a2bc2016..c60f339de8 100644 --- a/crates/dojo/types/src/schema.rs +++ b/crates/dojo/types/src/schema.rs @@ -134,11 +134,7 @@ impl Ty { } } Ty::Enum(e) => { - let option = e - .option - .map(|v| Ok(vec![Felt::from(v)])) - .unwrap_or(Err(PrimitiveError::MissingFieldElement))?; - felts.extend(option); + felts.extend(vec![Felt::from(e.option)]); for EnumOption { ty, .. } in &e.options { serialize_inner(ty, felts)?; @@ -189,16 +185,16 @@ impl Ty { } Ty::Enum(e) => { let value = felts.remove(0); - e.option = Some(value.to_u8().ok_or_else(|| PrimitiveError::ValueOutOfRange { + e.option = value.to_u8().ok_or_else(|| PrimitiveError::ValueOutOfRange { r#type: type_name::(), value, - })?); + })?; - match &e.options[e.option.unwrap() as usize].ty { + match &e.options[e.option as usize].ty { // Skip deserializing the enum option if it has no type - unit type Ty::Tuple(tuple) if tuple.is_empty() => {} _ => { - e.options[e.option.unwrap() as usize].ty.deserialize(felts)?; + e.options[e.option as usize].ty.deserialize(felts)?; } } } @@ -412,23 +408,17 @@ pub struct EnumOption { impl Enum { pub fn option(&self) -> Result<&EnumOption, EnumError> { - let option: usize = if let Some(option) = self.option { - option as usize - } else { - return Err(EnumError::OptionNotSet); - }; - - if option >= self.options.len() { + if self.option as usize >= self.options.len() { return Err(EnumError::OptionInvalid); } - Ok(&self.options[option]) + Ok(&self.options[self.option as usize]) } pub fn set_option(&mut self, name: &str) -> Result<(), EnumError> { match self.options.iter().position(|option| option.name == name) { Some(index) => { - self.option = Some(index as u8); + self.option = index as u8; Ok(()) } None => Err(EnumError::OptionInvalid), @@ -629,7 +619,7 @@ mod tests { name: "enum_field".to_string(), ty: Ty::Enum(Enum { name: "TestEnum".to_string(), - option: Some(1), + option: 1, options: vec![ EnumOption { name: "OptionA".to_string(), ty: Ty::Tuple(vec![]) }, EnumOption { name: "OptionB".to_string(), ty: Ty::Tuple(vec![]) }, @@ -692,7 +682,7 @@ mod tests { // Test enum diff let enum1 = Ty::Enum(Enum { name: "TestEnum".to_string(), - option: None, + option: 0, options: vec![ EnumOption { name: "Option1".to_string(), ty: Ty::Tuple(vec![]) }, EnumOption { name: "Option2".to_string(), ty: Ty::Tuple(vec![]) }, @@ -701,7 +691,7 @@ mod tests { let enum2 = Ty::Enum(Enum { name: "TestEnum".to_string(), - option: None, + option: 0, options: vec![EnumOption { name: "Option1".to_string(), ty: Ty::Tuple(vec![]) }], }); From ab855ddaff52f84dc1950a0317abacce7fa8ac00 Mon Sep 17 00:00:00 2001 From: Nasr Date: Wed, 13 Nov 2024 08:45:38 +0700 Subject: [PATCH 19/35] Revert "fix: enums" This reverts commit d86fcc4fe5220a7301725a2b2d7abf3476955856. --- crates/dojo/types/src/packing.rs | 2 +- crates/dojo/types/src/schema.rs | 32 +++++++++++++++++++++----------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/crates/dojo/types/src/packing.rs b/crates/dojo/types/src/packing.rs index 3b1c7b2b3a..f2d7fa1aed 100644 --- a/crates/dojo/types/src/packing.rs +++ b/crates/dojo/types/src/packing.rs @@ -251,7 +251,7 @@ fn parse_enum(data: &[Felt]) -> Result { offset += len as usize + 2; } - Ok(Ty::Enum(schema::Enum { name, option: 0, options: values })) + Ok(Ty::Enum(schema::Enum { name, option: None, options: values })) } fn parse_tuple(data: &[Felt]) -> Result { diff --git a/crates/dojo/types/src/schema.rs b/crates/dojo/types/src/schema.rs index c60f339de8..b3a2bc2016 100644 --- a/crates/dojo/types/src/schema.rs +++ b/crates/dojo/types/src/schema.rs @@ -134,7 +134,11 @@ impl Ty { } } Ty::Enum(e) => { - felts.extend(vec![Felt::from(e.option)]); + let option = e + .option + .map(|v| Ok(vec![Felt::from(v)])) + .unwrap_or(Err(PrimitiveError::MissingFieldElement))?; + felts.extend(option); for EnumOption { ty, .. } in &e.options { serialize_inner(ty, felts)?; @@ -185,16 +189,16 @@ impl Ty { } Ty::Enum(e) => { let value = felts.remove(0); - e.option = value.to_u8().ok_or_else(|| PrimitiveError::ValueOutOfRange { + e.option = Some(value.to_u8().ok_or_else(|| PrimitiveError::ValueOutOfRange { r#type: type_name::(), value, - })?; + })?); - match &e.options[e.option as usize].ty { + match &e.options[e.option.unwrap() as usize].ty { // Skip deserializing the enum option if it has no type - unit type Ty::Tuple(tuple) if tuple.is_empty() => {} _ => { - e.options[e.option as usize].ty.deserialize(felts)?; + e.options[e.option.unwrap() as usize].ty.deserialize(felts)?; } } } @@ -408,17 +412,23 @@ pub struct EnumOption { impl Enum { pub fn option(&self) -> Result<&EnumOption, EnumError> { - if self.option as usize >= self.options.len() { + let option: usize = if let Some(option) = self.option { + option as usize + } else { + return Err(EnumError::OptionNotSet); + }; + + if option >= self.options.len() { return Err(EnumError::OptionInvalid); } - Ok(&self.options[self.option as usize]) + Ok(&self.options[option]) } pub fn set_option(&mut self, name: &str) -> Result<(), EnumError> { match self.options.iter().position(|option| option.name == name) { Some(index) => { - self.option = index as u8; + self.option = Some(index as u8); Ok(()) } None => Err(EnumError::OptionInvalid), @@ -619,7 +629,7 @@ mod tests { name: "enum_field".to_string(), ty: Ty::Enum(Enum { name: "TestEnum".to_string(), - option: 1, + option: Some(1), options: vec![ EnumOption { name: "OptionA".to_string(), ty: Ty::Tuple(vec![]) }, EnumOption { name: "OptionB".to_string(), ty: Ty::Tuple(vec![]) }, @@ -682,7 +692,7 @@ mod tests { // Test enum diff let enum1 = Ty::Enum(Enum { name: "TestEnum".to_string(), - option: 0, + option: None, options: vec![ EnumOption { name: "Option1".to_string(), ty: Ty::Tuple(vec![]) }, EnumOption { name: "Option2".to_string(), ty: Ty::Tuple(vec![]) }, @@ -691,7 +701,7 @@ mod tests { let enum2 = Ty::Enum(Enum { name: "TestEnum".to_string(), - option: 0, + option: None, options: vec![EnumOption { name: "Option1".to_string(), ty: Ty::Tuple(vec![]) }], }); From 5d57e6d6ae02e6f7913a6ad120c5fb796326cbe3 Mon Sep 17 00:00:00 2001 From: Nasr Date: Wed, 13 Nov 2024 08:45:46 +0700 Subject: [PATCH 20/35] Revert "primitives not option" This reverts commit 210ac315d54eeef6b6ae6a397c65f69ffba2d3cc. --- crates/dojo/types/src/packing.rs | 2 +- crates/dojo/types/src/primitive.rs | 310 ++++++++++++++++------------- crates/dojo/types/src/schema.rs | 108 ++++++---- crates/dojo/types/tests/json.rs | 8 +- crates/torii/core/src/model.rs | 44 ++-- 5 files changed, 271 insertions(+), 201 deletions(-) diff --git a/crates/dojo/types/src/packing.rs b/crates/dojo/types/src/packing.rs index f2d7fa1aed..6817bb5447 100644 --- a/crates/dojo/types/src/packing.rs +++ b/crates/dojo/types/src/packing.rs @@ -321,7 +321,7 @@ mod tests { #[test] fn parse_simple_with_valid_value() { let data = [cairo_short_string_to_felt("u8").unwrap()]; - assert_eq!(parse_simple(&data).unwrap(), Ty::Primitive(Primitive::U8(0))); + assert_eq!(parse_simple(&data).unwrap(), Ty::Primitive(Primitive::U8(None))); } #[test] diff --git a/crates/dojo/types/src/primitive.rs b/crates/dojo/types/src/primitive.rs index ce29063d23..9fd0a41563 100644 --- a/crates/dojo/types/src/primitive.rs +++ b/crates/dojo/types/src/primitive.rs @@ -27,24 +27,24 @@ use super::primitive_conversion::try_from_felt; #[strum(serialize_all = "lowercase")] #[serde(rename_all = "lowercase")] pub enum Primitive { - I8(i8), - I16(i16), - I32(i32), - I64(i64), - I128(i128), - U8(u8), - U16(u16), - U32(u32), - U64(u64), - U128(u128), - U256(U256), - USize(u32), - Bool(bool), - Felt252(Felt), + I8(Option), + I16(Option), + I32(Option), + I64(Option), + I128(Option), + U8(Option), + U16(Option), + U32(Option), + U64(Option), + U128(Option), + U256(Option), + USize(Option), + Bool(Option), + Felt252(Option), #[strum(serialize = "ClassHash")] - ClassHash(Felt), + ClassHash(Option), #[strum(serialize = "ContractAddress")] - ContractAddress(Felt), + ContractAddress(Option), } #[derive(Debug, thiserror::Error)] @@ -80,7 +80,7 @@ pub enum SqlType { macro_rules! set_primitive { ($method_name:ident, $variant:ident, $type:ty) => { /// Sets the inner value of the `Primitive` enum if variant matches. - pub fn $method_name(&mut self, value: $type) -> Result<(), PrimitiveError> { + pub fn $method_name(&mut self, value: Option<$type>) -> Result<(), PrimitiveError> { match self { Primitive::$variant(_) => { *self = Primitive::$variant(value); @@ -99,7 +99,7 @@ macro_rules! as_primitive { /// `None` otherwise. pub fn $method_name(&self) -> Option<$type> { match self { - Primitive::$variant(value) => Some(*value), + Primitive::$variant(value) => *value, _ => None, } } @@ -193,26 +193,26 @@ impl Primitive { pub fn to_sql_value(&self) -> String { match self { // Integers - Primitive::I8(i8) => format!("{}", i8), - Primitive::I16(i16) => format!("{}", i16), - Primitive::I32(i32) => format!("{}", i32), - Primitive::I64(i64) => format!("{}", i64), + Primitive::I8(i8) => format!("{}", i8.unwrap_or_default()), + Primitive::I16(i16) => format!("{}", i16.unwrap_or_default()), + Primitive::I32(i32) => format!("{}", i32.unwrap_or_default()), + Primitive::I64(i64) => format!("{}", i64.unwrap_or_default()), - Primitive::U8(u8) => format!("{}", u8), - Primitive::U16(u16) => format!("{}", u16), - Primitive::U32(u32) => format!("{}", u32), - Primitive::USize(u32) => format!("{}", u32), - Primitive::Bool(bool) => format!("{}", bool), + Primitive::U8(u8) => format!("{}", u8.unwrap_or_default()), + Primitive::U16(u16) => format!("{}", u16.unwrap_or_default()), + Primitive::U32(u32) => format!("{}", u32.unwrap_or_default()), + Primitive::USize(u32) => format!("{}", u32.unwrap_or_default()), + Primitive::Bool(bool) => format!("{}", bool.unwrap_or_default()), // Hex string - Primitive::I128(i128) => format!("{:#064x}", i128), - Primitive::ContractAddress(felt) => format!("{:#064x}", felt), - Primitive::ClassHash(felt) => format!("{:#064x}", felt), - Primitive::Felt252(felt) => format!("{:#064x}", felt), - Primitive::U128(u128) => format!("{:#064x}", u128), - Primitive::U64(u64) => format!("{:#064x}", u64), - - Primitive::U256(u256) => format!("0x{:064x}", u256), + Primitive::I128(i128) => format!("{:#064x}", i128.unwrap_or_default()), + Primitive::ContractAddress(felt) => format!("{:#064x}", felt.unwrap_or_default()), + Primitive::ClassHash(felt) => format!("{:#064x}", felt.unwrap_or_default()), + Primitive::Felt252(felt) => format!("{:#064x}", felt.unwrap_or_default()), + Primitive::U128(u128) => format!("{:#064x}", u128.unwrap_or_default()), + Primitive::U64(u64) => format!("{:#064x}", u64.unwrap_or_default()), + + Primitive::U256(u256) => format!("0x{:064x}", u256.unwrap_or_default()), } } @@ -224,77 +224,77 @@ impl Primitive { match self { Primitive::I8(ref mut value) => { let felt = felts.remove(0); - *value = try_from_felt::(felt).map_err(|_| { + *value = Some(try_from_felt::(felt).map_err(|_| { PrimitiveError::ValueOutOfRange { r#type: type_name::(), value: felt } - })?; + })?); } Primitive::I16(ref mut value) => { let felt = felts.remove(0); - *value = try_from_felt::(felt).map_err(|_| { + *value = Some(try_from_felt::(felt).map_err(|_| { PrimitiveError::ValueOutOfRange { r#type: type_name::(), value: felt } - })?; + })?); } Primitive::I32(ref mut value) => { let felt = felts.remove(0); - *value = try_from_felt::(felt).map_err(|_| { + *value = Some(try_from_felt::(felt).map_err(|_| { PrimitiveError::ValueOutOfRange { r#type: type_name::(), value: felt } - })?; + })?); } Primitive::I64(ref mut value) => { let felt = felts.remove(0); - *value = try_from_felt::(felt).map_err(|_| { + *value = Some(try_from_felt::(felt).map_err(|_| { PrimitiveError::ValueOutOfRange { r#type: type_name::(), value: felt } - })?; + })?); } Primitive::I128(ref mut value) => { let felt = felts.remove(0); - *value = try_from_felt::(felt).map_err(|_| { + *value = Some(try_from_felt::(felt).map_err(|_| { PrimitiveError::ValueOutOfRange { r#type: type_name::(), value: felt } - })?; + })?); } Primitive::U8(ref mut value) => { let felt = felts.remove(0); - *value = felt.to_u8().ok_or_else(|| PrimitiveError::ValueOutOfRange { + *value = Some(felt.to_u8().ok_or_else(|| PrimitiveError::ValueOutOfRange { r#type: type_name::(), value: felt, - })?; + })?); } Primitive::U16(ref mut value) => { let felt = felts.remove(0); - *value = felt.to_u16().ok_or_else(|| PrimitiveError::ValueOutOfRange { + *value = Some(felt.to_u16().ok_or_else(|| PrimitiveError::ValueOutOfRange { r#type: type_name::(), value: felt, - })?; + })?); } Primitive::U32(ref mut value) => { let felt = felts.remove(0); - *value = felt.to_u32().ok_or_else(|| PrimitiveError::ValueOutOfRange { + *value = Some(felt.to_u32().ok_or_else(|| PrimitiveError::ValueOutOfRange { r#type: type_name::(), value: felt, - })?; + })?); } Primitive::U64(ref mut value) => { let felt = felts.remove(0); - *value = felt.to_u64().ok_or_else(|| PrimitiveError::ValueOutOfRange { + *value = Some(felt.to_u64().ok_or_else(|| PrimitiveError::ValueOutOfRange { r#type: type_name::(), value: felt, - })?; + })?); } Primitive::U128(ref mut value) => { let felt = felts.remove(0); - *value = felt.to_u128().ok_or_else(|| PrimitiveError::ValueOutOfRange { + *value = Some(felt.to_u128().ok_or_else(|| PrimitiveError::ValueOutOfRange { r#type: type_name::(), value: felt, - })?; + })?); } Primitive::U256(ref mut value) => { @@ -308,67 +308,99 @@ impl Primitive { let mut bytes = [0u8; 32]; bytes[16..].copy_from_slice(&value0_bytes[16..]); bytes[..16].copy_from_slice(&value1_bytes[16..]); - *value = U256::from_be_bytes(bytes); + *value = Some(U256::from_be_bytes(bytes)); } Primitive::USize(ref mut value) => { let felt = felts.remove(0); - *value = felt.to_u32().ok_or_else(|| PrimitiveError::ValueOutOfRange { + *value = Some(felt.to_u32().ok_or_else(|| PrimitiveError::ValueOutOfRange { r#type: type_name::(), value: felt, - })?; + })?); } Primitive::Bool(ref mut value) => { let raw = felts.remove(0); - *value = raw == Felt::ONE; + *value = Some(raw == Felt::ONE); } Primitive::ContractAddress(ref mut value) => { - *value = felts.remove(0); + *value = Some(felts.remove(0)); } Primitive::ClassHash(ref mut value) => { - *value = felts.remove(0); + *value = Some(felts.remove(0)); } Primitive::Felt252(ref mut value) => { - *value = felts.remove(0); + *value = Some(felts.remove(0)); } } Ok(()) } - pub fn serialize(&self) -> Vec { + pub fn serialize(&self) -> Result, PrimitiveError> { match self { - Primitive::I8(value) => vec![Felt::from(*value)], - Primitive::I16(value) => vec![Felt::from(*value)], - Primitive::I32(value) => vec![Felt::from(*value)], - Primitive::I64(value) => vec![Felt::from(*value)], - Primitive::I128(value) => vec![Felt::from(*value)], - Primitive::U8(value) => vec![Felt::from(*value)], - Primitive::U16(value) => vec![Felt::from(*value)], - Primitive::U32(value) => vec![Felt::from(*value)], - Primitive::U64(value) => vec![Felt::from(*value)], - Primitive::U128(value) => vec![Felt::from(*value)], - Primitive::U256(value) => { - let bytes: [u8; 32] = value.to_be_bytes(); - let value0_slice = &bytes[16..]; - let value1_slice = &bytes[..16]; - let mut value0_array = [0u8; 32]; - let mut value1_array = [0u8; 32]; - value0_array[16..].copy_from_slice(value0_slice); - value1_array[16..].copy_from_slice(value1_slice); - let value0 = Felt::from_bytes_be(&value0_array); - let value1 = Felt::from_bytes_be(&value1_array); - vec![value0, value1] + Primitive::I8(value) => value + .map(|v| Ok(vec![Felt::from(v)])) + .unwrap_or(Err(PrimitiveError::MissingFieldElement)), + Primitive::I16(value) => value + .map(|v| Ok(vec![Felt::from(v)])) + .unwrap_or(Err(PrimitiveError::MissingFieldElement)), + Primitive::I32(value) => value + .map(|v| Ok(vec![Felt::from(v)])) + .unwrap_or(Err(PrimitiveError::MissingFieldElement)), + Primitive::I64(value) => value + .map(|v| Ok(vec![Felt::from(v)])) + .unwrap_or(Err(PrimitiveError::MissingFieldElement)), + Primitive::I128(value) => value + .map(|v| Ok(vec![Felt::from(v)])) + .unwrap_or(Err(PrimitiveError::MissingFieldElement)), + Primitive::U8(value) => value + .map(|v| Ok(vec![Felt::from(v)])) + .unwrap_or(Err(PrimitiveError::MissingFieldElement)), + Primitive::U16(value) => value + .map(|v| Ok(vec![Felt::from(v)])) + .unwrap_or(Err(PrimitiveError::MissingFieldElement)), + Primitive::U32(value) => value + .map(|v| Ok(vec![Felt::from(v)])) + .unwrap_or(Err(PrimitiveError::MissingFieldElement)), + Primitive::U64(value) => value + .map(|v| Ok(vec![Felt::from(v)])) + .unwrap_or(Err(PrimitiveError::MissingFieldElement)), + Primitive::U128(value) => value + .map(|v| Ok(vec![Felt::from(v)])) + .unwrap_or(Err(PrimitiveError::MissingFieldElement)), + Primitive::U256(value) => value + .map(|v| { + let bytes: [u8; 32] = v.to_be_bytes(); + let value0_slice = &bytes[16..]; + let value1_slice = &bytes[..16]; + let mut value0_array = [0u8; 32]; + let mut value1_array = [0u8; 32]; + value0_array[16..].copy_from_slice(value0_slice); + value1_array[16..].copy_from_slice(value1_slice); + let value0 = Felt::from_bytes_be(&value0_array); + let value1 = Felt::from_bytes_be(&value1_array); + Ok(vec![value0, value1]) + }) + .unwrap_or(Err(PrimitiveError::MissingFieldElement)), + Primitive::USize(value) => value + .map(|v| Ok(vec![Felt::from(v)])) + .unwrap_or(Err(PrimitiveError::MissingFieldElement)), + Primitive::Bool(value) => value + .map(|v| Ok(vec![if v { Felt::ONE } else { Felt::ZERO }])) + .unwrap_or(Err(PrimitiveError::MissingFieldElement)), + Primitive::ContractAddress(value) => { + value.map(|v| Ok(vec![v])).unwrap_or(Err(PrimitiveError::MissingFieldElement)) + } + Primitive::ClassHash(value) => { + value.map(|v| Ok(vec![v])).unwrap_or(Err(PrimitiveError::MissingFieldElement)) + } + Primitive::Felt252(value) => { + value.map(|v| Ok(vec![v])).unwrap_or(Err(PrimitiveError::MissingFieldElement)) } - Primitive::USize(value) => vec![Felt::from(*value)], - Primitive::Bool(value) => vec![if *value { Felt::ONE } else { Felt::ZERO }], - Primitive::ContractAddress(value) => vec![Felt::from(*value)], - Primitive::ClassHash(value) => vec![Felt::from(*value)], - Primitive::Felt252(value) => vec![Felt::from(*value)] } } } @@ -384,11 +416,11 @@ mod tests { #[test] fn test_u256() { - let primitive = Primitive::U256(U256::from_be_hex( + let primitive = Primitive::U256(Some(U256::from_be_hex( "aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbccccccccccccccccdddddddddddddddd", - )); + ))); let sql_value = primitive.to_sql_value(); - let serialized = primitive.serialize(); + let serialized = primitive.serialize().unwrap(); let mut deserialized = primitive; deserialized.deserialize(&mut serialized.clone()).unwrap(); @@ -406,79 +438,79 @@ mod tests { #[test] fn inner_value_getter_setter() { - let mut primitive = Primitive::I8(0); - primitive.set_i8(-1).unwrap(); + let mut primitive = Primitive::I8(None); + primitive.set_i8(Some(-1i8)).unwrap(); assert_eq!(primitive.as_i8(), Some(-1i8)); - let mut primitive = Primitive::I16(0); - primitive.set_i16(-1i16).unwrap(); + let mut primitive = Primitive::I16(None); + primitive.set_i16(Some(-1i16)).unwrap(); assert_eq!(primitive.as_i16(), Some(-1i16)); - let mut primitive = Primitive::I32(0); - primitive.set_i32(-1i32).unwrap(); + let mut primitive = Primitive::I32(None); + primitive.set_i32(Some(-1i32)).unwrap(); assert_eq!(primitive.as_i32(), Some(-1i32)); - let mut primitive = Primitive::I64(0); - primitive.set_i64(-1i64).unwrap(); + let mut primitive = Primitive::I64(None); + primitive.set_i64(Some(-1i64)).unwrap(); assert_eq!(primitive.as_i64(), Some(-1i64)); - let mut primitive = Primitive::I128(0); - primitive.set_i128(-1i128).unwrap(); + let mut primitive = Primitive::I128(None); + primitive.set_i128(Some(-1i128)).unwrap(); assert_eq!(primitive.as_i128(), Some(-1i128)); - let mut primitive = Primitive::U8(0); - primitive.set_u8(1u8).unwrap(); + let mut primitive = Primitive::U8(None); + primitive.set_u8(Some(1u8)).unwrap(); assert_eq!(primitive.as_u8(), Some(1u8)); - let mut primitive = Primitive::U16(0); - primitive.set_u16(1u16).unwrap(); + let mut primitive = Primitive::U16(None); + primitive.set_u16(Some(1u16)).unwrap(); assert_eq!(primitive.as_u16(), Some(1u16)); - let mut primitive = Primitive::U32(0); - primitive.set_u32(1u32).unwrap(); + let mut primitive = Primitive::U32(None); + primitive.set_u32(Some(1u32)).unwrap(); assert_eq!(primitive.as_u32(), Some(1u32)); - let mut primitive = Primitive::U64(0); - primitive.set_u64(1u64).unwrap(); + let mut primitive = Primitive::U64(None); + primitive.set_u64(Some(1u64)).unwrap(); assert_eq!(primitive.as_u64(), Some(1u64)); - let mut primitive = Primitive::U128(0); - primitive.set_u128(1u128).unwrap(); + let mut primitive = Primitive::U128(None); + primitive.set_u128(Some(1u128)).unwrap(); assert_eq!(primitive.as_u128(), Some(1u128)); - let mut primitive = Primitive::U256(U256::ZERO); - primitive.set_u256(U256::from(1u128)).unwrap(); + let mut primitive = Primitive::U256(None); + primitive.set_u256(Some(U256::from(1u128))).unwrap(); assert_eq!(primitive.as_u256(), Some(U256::from(1u128))); - let mut primitive = Primitive::USize(0); - primitive.set_usize(1u32).unwrap(); + let mut primitive = Primitive::USize(None); + primitive.set_usize(Some(1u32)).unwrap(); assert_eq!(primitive.as_usize(), Some(1u32)); - let mut primitive = Primitive::Bool(false); - primitive.set_bool(true).unwrap(); + let mut primitive = Primitive::Bool(None); + primitive.set_bool(Some(true)).unwrap(); assert_eq!(primitive.as_bool(), Some(true)); - let mut primitive = Primitive::Felt252(Felt::ZERO); - primitive.set_felt252(Felt::from(1u128)).unwrap(); + let mut primitive = Primitive::Felt252(None); + primitive.set_felt252(Some(Felt::from(1u128))).unwrap(); assert_eq!(primitive.as_felt252(), Some(Felt::from(1u128))); - let mut primitive = Primitive::ClassHash(Felt::ZERO); - primitive.set_class_hash(Felt::from(1u128)).unwrap(); + let mut primitive = Primitive::ClassHash(None); + primitive.set_class_hash(Some(Felt::from(1u128))).unwrap(); assert_eq!(primitive.as_class_hash(), Some(Felt::from(1u128))); - let mut primitive = Primitive::ContractAddress(Felt::ZERO); - primitive.set_contract_address(Felt::from(1u128)).unwrap(); + let mut primitive = Primitive::ContractAddress(None); + primitive.set_contract_address(Some(Felt::from(1u128))).unwrap(); assert_eq!(primitive.as_contract_address(), Some(Felt::from(1u128))); } #[test] fn test_primitive_deserialization() { let test_cases = vec![ - (vec![Felt::from(-42i8)], Primitive::I8(-42)), - (vec![Felt::from(-1000i16)], Primitive::I16(-1000)), - (vec![Felt::from(-100000i32)], Primitive::I32(-100000)), - (vec![Felt::from(-1000000000i64)], Primitive::I64(-1000000000)), + (vec![Felt::from(-42i8)], Primitive::I8(Some(-42))), + (vec![Felt::from(-1000i16)], Primitive::I16(Some(-1000))), + (vec![Felt::from(-100000i32)], Primitive::I32(Some(-100000))), + (vec![Felt::from(-1000000000i64)], Primitive::I64(Some(-1000000000))), ( vec![Felt::from(-1000000000000000000i128)], - Primitive::I128(-1000000000000000000), + Primitive::I128(Some(-1000000000000000000)), ), - (vec![Felt::from(42u8)], Primitive::U8(42)), - (vec![Felt::from(1000u16)], Primitive::U16(1000)), - (vec![Felt::from(100000u32)], Primitive::U32(100000)), - (vec![Felt::from(1000000000u64)], Primitive::U64(1000000000)), - (vec![Felt::from(1000000000000000000u128)], Primitive::U128(1000000000000000000)), - (vec![Felt::from(42u32)], Primitive::USize(42)), - (vec![Felt::from(1u8)], Primitive::Bool(true)), - (vec![Felt::from(123456789u128)], Primitive::Felt252(Felt::from(123456789))), - (vec![Felt::from(987654321u128)], Primitive::ClassHash(Felt::from(987654321))), + (vec![Felt::from(42u8)], Primitive::U8(Some(42))), + (vec![Felt::from(1000u16)], Primitive::U16(Some(1000))), + (vec![Felt::from(100000u32)], Primitive::U32(Some(100000))), + (vec![Felt::from(1000000000u64)], Primitive::U64(Some(1000000000))), + (vec![Felt::from(1000000000000000000u128)], Primitive::U128(Some(1000000000000000000))), + (vec![Felt::from(42u32)], Primitive::USize(Some(42))), + (vec![Felt::from(1u8)], Primitive::Bool(Some(true))), + (vec![Felt::from(123456789u128)], Primitive::Felt252(Some(Felt::from(123456789)))), + (vec![Felt::from(987654321u128)], Primitive::ClassHash(Some(Felt::from(987654321)))), ( vec![Felt::from(123456789u128)], - Primitive::ContractAddress(Felt::from(123456789)), + Primitive::ContractAddress(Some(Felt::from(123456789))), ), ]; diff --git a/crates/dojo/types/src/schema.rs b/crates/dojo/types/src/schema.rs index b3a2bc2016..a8585ba0d3 100644 --- a/crates/dojo/types/src/schema.rs +++ b/crates/dojo/types/src/schema.rs @@ -126,7 +126,7 @@ impl Ty { fn serialize_inner(ty: &Ty, felts: &mut Vec) -> Result<(), PrimitiveError> { match ty { Ty::Primitive(c) => { - felts.extend(c.serialize()); + felts.extend(c.serialize()?); } Ty::Struct(s) => { for child in &s.children { @@ -151,7 +151,7 @@ impl Ty { } Ty::Array(items_ty) => { let _ = serialize_inner( - &Ty::Primitive(Primitive::U32(items_ty.len().try_into().unwrap())), + &Ty::Primitive(Primitive::U32(Some(items_ty.len().try_into().unwrap()))), felts, ); for item_ty in items_ty { @@ -400,7 +400,7 @@ pub enum EnumError { #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Hash, Eq)] pub struct Enum { pub name: String, - pub option: u8, + pub option: Option, pub options: Vec, } @@ -450,52 +450,84 @@ fn format_member(m: &Member) -> String { if let Ty::Primitive(ty) = &m.ty { match ty { Primitive::I8(value) => { - str.push_str(&format!(" = {}", value)); + if let Some(value) = value { + str.push_str(&format!(" = {}", value)); + } } Primitive::I16(value) => { - str.push_str(&format!(" = {}", value)); + if let Some(value) = value { + str.push_str(&format!(" = {}", value)); + } } Primitive::I32(value) => { - str.push_str(&format!(" = {}", value)); + if let Some(value) = value { + str.push_str(&format!(" = {}", value)); + } } Primitive::I64(value) => { - str.push_str(&format!(" = {}", value)); + if let Some(value) = value { + str.push_str(&format!(" = {}", value)); + } } Primitive::I128(value) => { - str.push_str(&format!(" = {}", value)); + if let Some(value) = value { + str.push_str(&format!(" = {}", value)); + } } Primitive::U8(value) => { - str.push_str(&format!(" = {}", value)); + if let Some(value) = value { + str.push_str(&format!(" = {}", value)); + } } Primitive::U16(value) => { - str.push_str(&format!(" = {}", value)); + if let Some(value) = value { + str.push_str(&format!(" = {}", value)); + } } Primitive::U32(value) => { - str.push_str(&format!(" = {}", value)); + if let Some(value) = value { + str.push_str(&format!(" = {}", value)); + } } Primitive::U64(value) => { - str.push_str(&format!(" = {}", value)); + if let Some(value) = value { + str.push_str(&format!(" = {}", value)); + } } Primitive::U128(value) => { - str.push_str(&format!(" = {}", value)); + if let Some(value) = value { + str.push_str(&format!(" = {}", value)); + } } Primitive::U256(value) => { - str.push_str(&format!(" = {}", value)); + if let Some(value) = value { + str.push_str(&format!(" = {}", value)); + } } Primitive::USize(value) => { - str.push_str(&format!(" = {}", value)); + if let Some(value) = value { + str.push_str(&format!(" = {}", value)); + } } Primitive::Bool(value) => { - str.push_str(&format!(" = {}", value)); + if let Some(value) = value { + str.push_str(&format!(" = {}", value)); + } } Primitive::Felt252(value) => { - str.push_str(&format!(" = {:#x}", value)); + if let Some(value) = value { + str.push_str(&format!(" = {:#x}", value)); + } } Primitive::ClassHash(value) => { - str.push_str(&format!(" = {:#x}", value)); + if let Some(value) = value { + str.push_str(&format!(" = {:#x}", value)); + } } Primitive::ContractAddress(value) => { - str.push_str(&format!(" = {:#x}", value)); + if let Some(value) = value { + str.push_str(&format!(" = {:#x}", value)); + } } } } else if let Ty::Enum(e) = &m.ty { @@ -522,7 +554,7 @@ mod tests { ( Member { name: "i8_field".to_string(), - ty: Ty::Primitive(Primitive::I8(-42)), + ty: Ty::Primitive(Primitive::I8(Some(-42))), key: false, }, " i8_field: i8 = -42", @@ -530,7 +562,7 @@ mod tests { ( Member { name: "i16_field".to_string(), - ty: Ty::Primitive(Primitive::I16(-1000)), + ty: Ty::Primitive(Primitive::I16(Some(-1000))), key: false, }, " i16_field: i16 = -1000", @@ -538,7 +570,7 @@ mod tests { ( Member { name: "i32_field".to_string(), - ty: Ty::Primitive(Primitive::I32(-100000)), + ty: Ty::Primitive(Primitive::I32(Some(-100000))), key: false, }, " i32_field: i32 = -100000", @@ -546,7 +578,7 @@ mod tests { ( Member { name: "i64_field".to_string(), - ty: Ty::Primitive(Primitive::I64(-1000000000)), + ty: Ty::Primitive(Primitive::I64(Some(-1000000000))), key: false, }, " i64_field: i64 = -1000000000", @@ -554,7 +586,7 @@ mod tests { ( Member { name: "i128_field".to_string(), - ty: Ty::Primitive(Primitive::I128(-1000000000000000000)), + ty: Ty::Primitive(Primitive::I128(Some(-1000000000000000000))), key: false, }, " i128_field: i128 = -1000000000000000000", @@ -562,7 +594,7 @@ mod tests { ( Member { name: "u8_field".to_string(), - ty: Ty::Primitive(Primitive::U8(255)), + ty: Ty::Primitive(Primitive::U8(Some(255))), key: false, }, " u8_field: u8 = 255", @@ -570,7 +602,7 @@ mod tests { ( Member { name: "u16_field".to_string(), - ty: Ty::Primitive(Primitive::U16(65535)), + ty: Ty::Primitive(Primitive::U16(Some(65535))), key: false, }, " u16_field: u16 = 65535", @@ -578,7 +610,7 @@ mod tests { ( Member { name: "u32_field".to_string(), - ty: Ty::Primitive(Primitive::U32(4294967295)), + ty: Ty::Primitive(Primitive::U32(Some(4294967295))), key: false, }, " u32_field: u32 = 4294967295", @@ -586,7 +618,7 @@ mod tests { ( Member { name: "u64_field".to_string(), - ty: Ty::Primitive(Primitive::U64(18446744073709551615)), + ty: Ty::Primitive(Primitive::U64(Some(18446744073709551615))), key: false, }, " u64_field: u64 = 18446744073709551615", @@ -594,7 +626,9 @@ mod tests { ( Member { name: "u128_field".to_string(), - ty: Ty::Primitive(Primitive::U128(340282366920938463463374607431768211455)), + ty: Ty::Primitive(Primitive::U128(Some( + 340282366920938463463374607431768211455, + ))), key: false, }, " u128_field: u128 = 340282366920938463463374607431768211455", @@ -602,7 +636,7 @@ mod tests { ( Member { name: "u256_field".to_string(), - ty: Ty::Primitive(Primitive::U256(U256::from_u128(123456789_u128))), + ty: Ty::Primitive(Primitive::U256(Some(U256::from_u128(123456789_u128)))), key: false, }, " u256_field: u256 = \ @@ -611,7 +645,7 @@ mod tests { ( Member { name: "bool_field".to_string(), - ty: Ty::Primitive(Primitive::Bool(true)), + ty: Ty::Primitive(Primitive::Bool(Some(true))), key: false, }, " bool_field: bool = true", @@ -619,7 +653,9 @@ mod tests { ( Member { name: "felt252_field".to_string(), - ty: Ty::Primitive(Primitive::Felt252(Felt::from_hex("0x123abc").unwrap())), + ty: Ty::Primitive(Primitive::Felt252(Some( + Felt::from_hex("0x123abc").unwrap(), + ))), key: false, }, " felt252_field: felt252 = 0x123abc", @@ -654,17 +690,17 @@ mod tests { children: vec![ Member { name: "field1".to_string(), - ty: Ty::Primitive(Primitive::U32(0)), + ty: Ty::Primitive(Primitive::U32(None)), key: false, }, Member { name: "field2".to_string(), - ty: Ty::Primitive(Primitive::U32(0)), + ty: Ty::Primitive(Primitive::U32(None)), key: false, }, Member { name: "field3".to_string(), - ty: Ty::Primitive(Primitive::U32(0)), + ty: Ty::Primitive(Primitive::U32(None)), key: false, }, ], @@ -674,7 +710,7 @@ mod tests { name: "TestStruct".to_string(), children: vec![Member { name: "field1".to_string(), - ty: Ty::Primitive(Primitive::U32(0)), + ty: Ty::Primitive(Primitive::U32(None)), key: false, }], }); diff --git a/crates/dojo/types/tests/json.rs b/crates/dojo/types/tests/json.rs index ddea135a26..61a6579c73 100644 --- a/crates/dojo/types/tests/json.rs +++ b/crates/dojo/types/tests/json.rs @@ -7,8 +7,8 @@ fn serialize_ty_to_json() { let ty = Ty::Struct(Struct { name: "Position".into(), children: vec![ - Member { name: "x".into(), key: false, ty: Ty::Primitive(Primitive::U8(128)) }, - Member { name: "y".into(), key: false, ty: Ty::Primitive(Primitive::U64(2048)) }, + Member { name: "x".into(), key: false, ty: Ty::Primitive(Primitive::U8(Some(128))) }, + Member { name: "y".into(), key: false, ty: Ty::Primitive(Primitive::U64(Some(2048))) }, Member { name: "kind".into(), key: false, @@ -149,8 +149,8 @@ fn deserialize_ty_from_json() { let expected_value = Ty::Struct(Struct { name: "Position".into(), children: vec![ - Member { name: "x".into(), key: false, ty: Ty::Primitive(Primitive::U8(128)) }, - Member { name: "y".into(), key: false, ty: Ty::Primitive(Primitive::U64(2048)) }, + Member { name: "x".into(), key: false, ty: Ty::Primitive(Primitive::U8(Some(128))) }, + Member { name: "y".into(), key: false, ty: Ty::Primitive(Primitive::U64(Some(2048))) }, Member { name: "kind".into(), key: false, diff --git a/crates/torii/core/src/model.rs b/crates/torii/core/src/model.rs index 9219fe4344..5a38e60c2e 100644 --- a/crates/torii/core/src/model.rs +++ b/crates/torii/core/src/model.rs @@ -494,80 +494,82 @@ pub fn map_row_to_ty( match &primitive { Primitive::I8(_) => { let value = row.try_get::(&column_name)?; - primitive.set_i8(value)?; + primitive.set_i8(Some(value))?; } Primitive::I16(_) => { let value = row.try_get::(&column_name)?; - primitive.set_i16(value)?; + primitive.set_i16(Some(value))?; } Primitive::I32(_) => { let value = row.try_get::(&column_name)?; - primitive.set_i32(value)?; + primitive.set_i32(Some(value))?; } Primitive::I64(_) => { let value = row.try_get::(&column_name)?; - primitive.set_i64(value)?; + primitive.set_i64(Some(value))?; } Primitive::I128(_) => { let value = row.try_get::(&column_name)?; let hex_str = value.trim_start_matches("0x"); - primitive.set_i128( + primitive.set_i128(Some( i128::from_str_radix(hex_str, 16).map_err(ParseError::ParseIntError)?, - )?; + ))?; } Primitive::U8(_) => { let value = row.try_get::(&column_name)?; - primitive.set_u8(value)?; + primitive.set_u8(Some(value))?; } Primitive::U16(_) => { let value = row.try_get::(&column_name)?; - primitive.set_u16(value)?; + primitive.set_u16(Some(value))?; } Primitive::U32(_) => { let value = row.try_get::(&column_name)?; - primitive.set_u32(value)?; + primitive.set_u32(Some(value))?; } Primitive::U64(_) => { let value = row.try_get::(&column_name)?; let hex_str = value.trim_start_matches("0x"); - primitive.set_u64( + primitive.set_u64(Some( u64::from_str_radix(hex_str, 16).map_err(ParseError::ParseIntError)?, - )?; + ))?; } Primitive::U128(_) => { let value = row.try_get::(&column_name)?; let hex_str = value.trim_start_matches("0x"); - primitive.set_u128( + primitive.set_u128(Some( u128::from_str_radix(hex_str, 16).map_err(ParseError::ParseIntError)?, - )?; + ))?; } Primitive::U256(_) => { let value = row.try_get::(&column_name)?; let hex_str = value.trim_start_matches("0x"); - primitive.set_u256(U256::from_be_hex(hex_str))?; + primitive.set_u256(Some(U256::from_be_hex(hex_str)))?; } Primitive::USize(_) => { let value = row.try_get::(&column_name)?; - primitive.set_usize(value)?; + primitive.set_usize(Some(value))?; } Primitive::Bool(_) => { let value = row.try_get::(&column_name)?; - primitive.set_bool(value)?; + primitive.set_bool(Some(value))?; } Primitive::Felt252(_) => { let value = row.try_get::(&column_name)?; - primitive.set_felt252(Felt::from_str(&value).map_err(ParseError::FromStr)?)?; + primitive + .set_felt252(Some(Felt::from_str(&value).map_err(ParseError::FromStr)?))?; } Primitive::ClassHash(_) => { let value = row.try_get::(&column_name)?; - primitive - .set_class_hash(Felt::from_str(&value).map_err(ParseError::FromStr)?)?; + primitive.set_class_hash(Some( + Felt::from_str(&value).map_err(ParseError::FromStr)?, + ))?; } Primitive::ContractAddress(_) => { let value = row.try_get::(&column_name)?; - primitive.set_contract_address( + primitive.set_contract_address(Some( Felt::from_str(&value).map_err(ParseError::FromStr)?, - )?; + ))?; } }; } From b04e848801c4853c7178c0e8d3a650fd79d5421d Mon Sep 17 00:00:00 2001 From: Nasr Date: Wed, 13 Nov 2024 08:50:41 +0700 Subject: [PATCH 21/35] fix enum sql value --- crates/dojo/types/src/schema.rs | 4 ++-- crates/torii/core/src/sql/mod.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/dojo/types/src/schema.rs b/crates/dojo/types/src/schema.rs index a8585ba0d3..5ebaea0d42 100644 --- a/crates/dojo/types/src/schema.rs +++ b/crates/dojo/types/src/schema.rs @@ -435,8 +435,8 @@ impl Enum { } } - pub fn to_sql_value(&self) -> Result { - self.option().map(|option| option.name.clone()) + pub fn to_sql_value(&self) -> String { + self.option().unwrap_or(&self.options[0]).name.clone() } } diff --git a/crates/torii/core/src/sql/mod.rs b/crates/torii/core/src/sql/mod.rs index 8b003bea71..48a6e3b7cc 100644 --- a/crates/torii/core/src/sql/mod.rs +++ b/crates/torii/core/src/sql/mod.rs @@ -770,7 +770,7 @@ impl Sql { } Ty::Enum(e) => { columns.push(format!("external_{}", &member.name)); - arguments.push(Argument::String(e.to_sql_value().unwrap())); + arguments.push(Argument::String(e.to_sql_value())); } Ty::ByteArray(b) => { columns.push(format!("external_{}", &member.name)); From b7f3264afb7e901edbe67e8c39e359ddd0d311af Mon Sep 17 00:00:00 2001 From: Nasr Date: Wed, 13 Nov 2024 10:31:59 +0700 Subject: [PATCH 22/35] main --- bin/torii/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/torii/src/main.rs b/bin/torii/src/main.rs index c0a2887d3d..ba8f743f7f 100644 --- a/bin/torii/src/main.rs +++ b/bin/torii/src/main.rs @@ -245,7 +245,7 @@ async fn main() -> anyhow::Result<()> { }); let model_cache = Arc::new(ModelCache::new(pool.clone())); - let db = Sql::new(pool.clone(), sender.clone(), &args.contracts, model_cache.clone()).await?; + let db = Sql::new(pool.clone(), sender.clone(), &args.indexing.contracts, model_cache.clone()).await?; let processors = Processors { transaction: vec![Box::new(StoreTransactionProcessor)], From 87857c2d5c1f02f4e756cee3c555068fa4ba5c60 Mon Sep 17 00:00:00 2001 From: Nasr Date: Wed, 13 Nov 2024 10:55:28 +0700 Subject: [PATCH 23/35] remove prints & format --- bin/torii/src/main.rs | 3 ++- crates/torii/core/src/sql/mod.rs | 2 -- crates/torii/grpc/src/server/mod.rs | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/bin/torii/src/main.rs b/bin/torii/src/main.rs index ba8f743f7f..af3fba18c6 100644 --- a/bin/torii/src/main.rs +++ b/bin/torii/src/main.rs @@ -245,7 +245,8 @@ async fn main() -> anyhow::Result<()> { }); let model_cache = Arc::new(ModelCache::new(pool.clone())); - let db = Sql::new(pool.clone(), sender.clone(), &args.indexing.contracts, model_cache.clone()).await?; + let db = Sql::new(pool.clone(), sender.clone(), &args.indexing.contracts, model_cache.clone()) + .await?; let processors = Processors { transaction: vec![Box::new(StoreTransactionProcessor)], diff --git a/crates/torii/core/src/sql/mod.rs b/crates/torii/core/src/sql/mod.rs index 48a6e3b7cc..06151aacb2 100644 --- a/crates/torii/core/src/sql/mod.rs +++ b/crates/torii/core/src/sql/mod.rs @@ -321,8 +321,6 @@ impl Sql { ) .await; - println!("selector: {:?}", selector); - println!("set model cache: {:?}", model); Ok(()) } diff --git a/crates/torii/grpc/src/server/mod.rs b/crates/torii/grpc/src/server/mod.rs index e0e3d15460..858c4c523c 100644 --- a/crates/torii/grpc/src/server/mod.rs +++ b/crates/torii/grpc/src/server/mod.rs @@ -969,7 +969,6 @@ fn map_row_to_entity( schemas: &[Ty], dont_include_hashed_keys: bool, ) -> Result { - println!("schemas: {:?}", schemas); let hashed_keys = Felt::from_str(&row.get::("id")).map_err(ParseError::FromStr)?; let models = schemas .iter() From 9b5d624cb9639755a972189abb12c5e7f24dedcd Mon Sep 17 00:00:00 2001 From: Nasr Date: Wed, 13 Nov 2024 11:45:55 +0700 Subject: [PATCH 24/35] fix quer ytest --- crates/torii/core/src/model.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/torii/core/src/model.rs b/crates/torii/core/src/model.rs index 5a38e60c2e..2a54950382 100644 --- a/crates/torii/core/src/model.rs +++ b/crates/torii/core/src/model.rs @@ -1069,12 +1069,12 @@ mod tests { [Test-Position$vec].external_y AS \"Test-Position$vec.y\", \ [Test-PlayerConfig$favorite_item].external_Some AS \ \"Test-PlayerConfig$favorite_item.Some\", [Test-PlayerConfig].external_favorite_item \ - AS \"Test-PlayerConfig.favorite_item\" FROM entities JOIN [Test-Position] ON \ - entities.id = [Test-Position].entity_id JOIN [Test-PlayerConfig] ON entities.id = \ - [Test-PlayerConfig].entity_id JOIN [Test-Position$vec] ON entities.id = \ - [Test-Position$vec].entity_id LEFT JOIN [Test-PlayerConfig$favorite_item] ON \ - entities.id = [Test-PlayerConfig$favorite_item].entity_id ORDER BY entities.event_id \ - DESC"; + AS \"Test-PlayerConfig.favorite_item\" FROM entities LEFT JOIN [Test-Position] ON \ + entities.id = [Test-Position].entity_id LEFT JOIN [Test-PlayerConfig] ON \ + entities.id = [Test-PlayerConfig].entity_id LEFT JOIN [Test-Position$vec] ON \ + entities.id = [Test-Position$vec].entity_id LEFT JOIN \ + [Test-PlayerConfig$favorite_item] ON entities.id = \ + [Test-PlayerConfig$favorite_item].entity_id ORDER BY entities.event_id DESC"; // todo: completely tests arrays assert_eq!(query.0, expected_query); } From 9ac0d2176ca2696a78e9cbad434e6f8e50c24dfb Mon Sep 17 00:00:00 2001 From: Nasr Date: Thu, 14 Nov 2024 09:38:59 +0700 Subject: [PATCH 25/35] fix: bool --- crates/dojo/types/src/primitive.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/dojo/types/src/primitive.rs b/crates/dojo/types/src/primitive.rs index 9fd0a41563..997613d1b6 100644 --- a/crates/dojo/types/src/primitive.rs +++ b/crates/dojo/types/src/primitive.rs @@ -202,7 +202,7 @@ impl Primitive { Primitive::U16(u16) => format!("{}", u16.unwrap_or_default()), Primitive::U32(u32) => format!("{}", u32.unwrap_or_default()), Primitive::USize(u32) => format!("{}", u32.unwrap_or_default()), - Primitive::Bool(bool) => format!("{}", bool.unwrap_or_default()), + Primitive::Bool(bool) => format!("{}", bool.unwrap_or_default() as i32), // Hex string Primitive::I128(i128) => format!("{:#064x}", i128.unwrap_or_default()), From a8d673710fdc75a19fae87d28a5cb59ba94a9b77 Mon Sep 17 00:00:00 2001 From: Nasr Date: Thu, 14 Nov 2024 09:40:48 +0700 Subject: [PATCH 26/35] fix: ararys --- crates/torii/core/src/model.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/torii/core/src/model.rs b/crates/torii/core/src/model.rs index 2a54950382..2ff96d73d6 100644 --- a/crates/torii/core/src/model.rs +++ b/crates/torii/core/src/model.rs @@ -419,7 +419,7 @@ pub fn build_sql_query( .map(|(i, table)| { if i == 0 { format!( - " LEFT JOIN [{}] ON {entities_table}.id = \ + " JOIN [{}] ON {entities_table}.id = \ [{}].{entity_relation_column}", table.table_name, table.table_name ) From d2c769617601b2553c39a10ba0a1add52dc6dca8 Mon Sep 17 00:00:00 2001 From: Nasr Date: Thu, 14 Nov 2024 09:41:06 +0700 Subject: [PATCH 27/35] fmt --- crates/torii/core/src/model.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/torii/core/src/model.rs b/crates/torii/core/src/model.rs index 2ff96d73d6..92897bc632 100644 --- a/crates/torii/core/src/model.rs +++ b/crates/torii/core/src/model.rs @@ -419,8 +419,7 @@ pub fn build_sql_query( .map(|(i, table)| { if i == 0 { format!( - " JOIN [{}] ON {entities_table}.id = \ - [{}].{entity_relation_column}", + " JOIN [{}] ON {entities_table}.id = [{}].{entity_relation_column}", table.table_name, table.table_name ) } else { From 255d4fb149e8118605c5d7982d81616883a47853 Mon Sep 17 00:00:00 2001 From: Nasr Date: Thu, 14 Nov 2024 10:55:32 +0700 Subject: [PATCH 28/35] fix: map row to ty --- crates/torii/core/src/model.rs | 54 ++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/crates/torii/core/src/model.rs b/crates/torii/core/src/model.rs index 92897bc632..141b7bd113 100644 --- a/crates/torii/core/src/model.rs +++ b/crates/torii/core/src/model.rs @@ -510,9 +510,12 @@ pub fn map_row_to_ty( Primitive::I128(_) => { let value = row.try_get::(&column_name)?; let hex_str = value.trim_start_matches("0x"); - primitive.set_i128(Some( - i128::from_str_radix(hex_str, 16).map_err(ParseError::ParseIntError)?, - ))?; + + if !hex_str.is_empty() { + primitive.set_i128(Some( + i128::from_str_radix(hex_str, 16).map_err(ParseError::ParseIntError)?, + ))?; + } } Primitive::U8(_) => { let value = row.try_get::(&column_name)?; @@ -529,21 +532,30 @@ pub fn map_row_to_ty( Primitive::U64(_) => { let value = row.try_get::(&column_name)?; let hex_str = value.trim_start_matches("0x"); - primitive.set_u64(Some( - u64::from_str_radix(hex_str, 16).map_err(ParseError::ParseIntError)?, - ))?; + + if !hex_str.is_empty() { + primitive.set_u64(Some( + u64::from_str_radix(hex_str, 16).map_err(ParseError::ParseIntError)?, + ))?; + } } Primitive::U128(_) => { let value = row.try_get::(&column_name)?; let hex_str = value.trim_start_matches("0x"); - primitive.set_u128(Some( - u128::from_str_radix(hex_str, 16).map_err(ParseError::ParseIntError)?, - ))?; + + if !hex_str.is_empty() { + primitive.set_u128(Some( + u128::from_str_radix(hex_str, 16).map_err(ParseError::ParseIntError)?, + ))?; + } } Primitive::U256(_) => { let value = row.try_get::(&column_name)?; let hex_str = value.trim_start_matches("0x"); - primitive.set_u256(Some(U256::from_be_hex(hex_str)))?; + + if !hex_str.is_empty() { + primitive.set_u256(Some(U256::from_be_hex(hex_str)))?; + } } Primitive::USize(_) => { let value = row.try_get::(&column_name)?; @@ -555,20 +567,26 @@ pub fn map_row_to_ty( } Primitive::Felt252(_) => { let value = row.try_get::(&column_name)?; - primitive - .set_felt252(Some(Felt::from_str(&value).map_err(ParseError::FromStr)?))?; + if !value.is_empty() { + primitive + .set_felt252(Some(Felt::from_str(&value).map_err(ParseError::FromStr)?))?; + } } Primitive::ClassHash(_) => { let value = row.try_get::(&column_name)?; - primitive.set_class_hash(Some( - Felt::from_str(&value).map_err(ParseError::FromStr)?, - ))?; + if !value.is_empty() { + primitive.set_class_hash(Some( + Felt::from_str(&value).map_err(ParseError::FromStr)?, + ))?; + } } Primitive::ContractAddress(_) => { let value = row.try_get::(&column_name)?; - primitive.set_contract_address(Some( - Felt::from_str(&value).map_err(ParseError::FromStr)?, - ))?; + if !value.is_empty() { + primitive.set_contract_address(Some( + Felt::from_str(&value).map_err(ParseError::FromStr)?, + ))?; + } } }; } From 62350804ebf0ff31dfe461559165276a4fde28f1 Mon Sep 17 00:00:00 2001 From: Nasr Date: Thu, 14 Nov 2024 10:58:15 +0700 Subject: [PATCH 29/35] fix: enum --- crates/torii/core/src/sql/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/torii/core/src/sql/mod.rs b/crates/torii/core/src/sql/mod.rs index 06151aacb2..b56ca41390 100644 --- a/crates/torii/core/src/sql/mod.rs +++ b/crates/torii/core/src/sql/mod.rs @@ -1081,8 +1081,7 @@ impl Sql { .join(", "); let column = format!( - "external_{name} TEXT CHECK(external_{name} IN ({all_options})) {}", - if array_idx > 0 { "" } else { "NOT NULL" } + "external_{name} TEXT CHECK(external_{name} IN ({all_options}))", ); create_table_query.push_str(&format!("{column}, ")); From 612fc4b71ae8143ddcb76f35d13941c07a88a264 Mon Sep 17 00:00:00 2001 From: Nasr Date: Thu, 14 Nov 2024 11:01:04 +0700 Subject: [PATCH 30/35] fix: enum --- crates/torii/core/src/model.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/torii/core/src/model.rs b/crates/torii/core/src/model.rs index 141b7bd113..e56b5a5321 100644 --- a/crates/torii/core/src/model.rs +++ b/crates/torii/core/src/model.rs @@ -592,7 +592,9 @@ pub fn map_row_to_ty( } Ty::Enum(enum_ty) => { let option_name = row.try_get::(&column_name)?; - enum_ty.set_option(&option_name)?; + if !option_name.is_empty() { + enum_ty.set_option(&option_name)?; + } let path = [path, name].join("$"); for option in &mut enum_ty.options { From 0dbec7e379124f48502e8960787c473d5df1439a Mon Sep 17 00:00:00 2001 From: Nasr Date: Thu, 14 Nov 2024 11:01:22 +0700 Subject: [PATCH 31/35] fmt --- crates/torii/core/src/model.rs | 7 ++++--- crates/torii/core/src/sql/mod.rs | 5 ++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/torii/core/src/model.rs b/crates/torii/core/src/model.rs index e56b5a5321..e2d06c10c8 100644 --- a/crates/torii/core/src/model.rs +++ b/crates/torii/core/src/model.rs @@ -532,7 +532,7 @@ pub fn map_row_to_ty( Primitive::U64(_) => { let value = row.try_get::(&column_name)?; let hex_str = value.trim_start_matches("0x"); - + if !hex_str.is_empty() { primitive.set_u64(Some( u64::from_str_radix(hex_str, 16).map_err(ParseError::ParseIntError)?, @@ -568,8 +568,9 @@ pub fn map_row_to_ty( Primitive::Felt252(_) => { let value = row.try_get::(&column_name)?; if !value.is_empty() { - primitive - .set_felt252(Some(Felt::from_str(&value).map_err(ParseError::FromStr)?))?; + primitive.set_felt252(Some( + Felt::from_str(&value).map_err(ParseError::FromStr)?, + ))?; } } Primitive::ClassHash(_) => { diff --git a/crates/torii/core/src/sql/mod.rs b/crates/torii/core/src/sql/mod.rs index b56ca41390..8c6302447d 100644 --- a/crates/torii/core/src/sql/mod.rs +++ b/crates/torii/core/src/sql/mod.rs @@ -1080,9 +1080,8 @@ impl Sql { .collect::>() .join(", "); - let column = format!( - "external_{name} TEXT CHECK(external_{name} IN ({all_options}))", - ); + let column = + format!("external_{name} TEXT CHECK(external_{name} IN ({all_options}))",); create_table_query.push_str(&format!("{column}, ")); From 551c6bd6fff5432cdb93e9d178e1f8183a33a7ed Mon Sep 17 00:00:00 2001 From: Nasr Date: Thu, 14 Nov 2024 11:11:01 +0700 Subject: [PATCH 32/35] fix: primitive len --- crates/dojo/types/src/primitive.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/dojo/types/src/primitive.rs b/crates/dojo/types/src/primitive.rs index 997613d1b6..5c803ed614 100644 --- a/crates/dojo/types/src/primitive.rs +++ b/crates/dojo/types/src/primitive.rs @@ -205,12 +205,12 @@ impl Primitive { Primitive::Bool(bool) => format!("{}", bool.unwrap_or_default() as i32), // Hex string - Primitive::I128(i128) => format!("{:#064x}", i128.unwrap_or_default()), - Primitive::ContractAddress(felt) => format!("{:#064x}", felt.unwrap_or_default()), - Primitive::ClassHash(felt) => format!("{:#064x}", felt.unwrap_or_default()), - Primitive::Felt252(felt) => format!("{:#064x}", felt.unwrap_or_default()), - Primitive::U128(u128) => format!("{:#064x}", u128.unwrap_or_default()), - Primitive::U64(u64) => format!("{:#064x}", u64.unwrap_or_default()), + Primitive::I128(i128) => format!("0x{:064x}", i128.unwrap_or_default()), + Primitive::ContractAddress(felt) => format!("0x{:064x}", felt.unwrap_or_default()), + Primitive::ClassHash(felt) => format!("0x{:064x}", felt.unwrap_or_default()), + Primitive::Felt252(felt) => format!("0x{:064x}", felt.unwrap_or_default()), + Primitive::U128(u128) => format!("0x{:064x}", u128.unwrap_or_default()), + Primitive::U64(u64) => format!("0x{:064x}", u64.unwrap_or_default()), Primitive::U256(u256) => format!("0x{:064x}", u256.unwrap_or_default()), } From cea81026c96ceceee1650ecbdb0e9c7940982326 Mon Sep 17 00:00:00 2001 From: Nasr Date: Thu, 14 Nov 2024 11:12:55 +0700 Subject: [PATCH 33/35] Revert "fix: primitive len" This reverts commit 551c6bd6fff5432cdb93e9d178e1f8183a33a7ed. --- crates/dojo/types/src/primitive.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/dojo/types/src/primitive.rs b/crates/dojo/types/src/primitive.rs index 5c803ed614..997613d1b6 100644 --- a/crates/dojo/types/src/primitive.rs +++ b/crates/dojo/types/src/primitive.rs @@ -205,12 +205,12 @@ impl Primitive { Primitive::Bool(bool) => format!("{}", bool.unwrap_or_default() as i32), // Hex string - Primitive::I128(i128) => format!("0x{:064x}", i128.unwrap_or_default()), - Primitive::ContractAddress(felt) => format!("0x{:064x}", felt.unwrap_or_default()), - Primitive::ClassHash(felt) => format!("0x{:064x}", felt.unwrap_or_default()), - Primitive::Felt252(felt) => format!("0x{:064x}", felt.unwrap_or_default()), - Primitive::U128(u128) => format!("0x{:064x}", u128.unwrap_or_default()), - Primitive::U64(u64) => format!("0x{:064x}", u64.unwrap_or_default()), + Primitive::I128(i128) => format!("{:#064x}", i128.unwrap_or_default()), + Primitive::ContractAddress(felt) => format!("{:#064x}", felt.unwrap_or_default()), + Primitive::ClassHash(felt) => format!("{:#064x}", felt.unwrap_or_default()), + Primitive::Felt252(felt) => format!("{:#064x}", felt.unwrap_or_default()), + Primitive::U128(u128) => format!("{:#064x}", u128.unwrap_or_default()), + Primitive::U64(u64) => format!("{:#064x}", u64.unwrap_or_default()), Primitive::U256(u256) => format!("0x{:064x}", u256.unwrap_or_default()), } From 155033d275e244e921ba1709ec9cd3c65846364c Mon Sep 17 00:00:00 2001 From: Nasr Date: Thu, 14 Nov 2024 12:03:11 +0700 Subject: [PATCH 34/35] refactotr: dont use modelr eader block --- crates/torii/core/src/processors/register_event.rs | 7 +++---- crates/torii/core/src/processors/register_model.rs | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/crates/torii/core/src/processors/register_event.rs b/crates/torii/core/src/processors/register_event.rs index b0d8b9e959..b026ef3770 100644 --- a/crates/torii/core/src/processors/register_event.rs +++ b/crates/torii/core/src/processors/register_event.rs @@ -3,7 +3,7 @@ use async_trait::async_trait; use dojo_world::contracts::abigen::world::Event as WorldEvent; use dojo_world::contracts::model::ModelReader; use dojo_world::contracts::world::WorldContractReader; -use starknet::core::types::{BlockId, Event}; +use starknet::core::types::Event; use starknet::providers::Provider; use tracing::{debug, info}; @@ -34,7 +34,7 @@ where &self, world: &WorldContractReader

, db: &mut Sql, - block_number: u64, + _block_number: u64, block_timestamp: u64, _event_id: &str, event: &Event, @@ -60,8 +60,7 @@ where // Called model here by language, but it's an event. Torii rework will make clear // distinction. - let model = - world.model_reader_with_block(&namespace, &name, BlockId::Number(block_number)).await?; + let model = world.model_reader(&namespace, &name).await?; let schema = model.schema().await?; let layout = model.layout().await?; diff --git a/crates/torii/core/src/processors/register_model.rs b/crates/torii/core/src/processors/register_model.rs index c5a495b076..b994313d08 100644 --- a/crates/torii/core/src/processors/register_model.rs +++ b/crates/torii/core/src/processors/register_model.rs @@ -3,7 +3,7 @@ use async_trait::async_trait; use dojo_world::contracts::abigen::world::Event as WorldEvent; use dojo_world::contracts::model::ModelReader; use dojo_world::contracts::world::WorldContractReader; -use starknet::core::types::{BlockId, Event}; +use starknet::core::types::Event; use starknet::providers::Provider; use tracing::{debug, info}; @@ -34,7 +34,7 @@ where &self, world: &WorldContractReader

, db: &mut Sql, - block_number: u64, + _block_number: u64, block_timestamp: u64, _event_id: &str, event: &Event, @@ -58,8 +58,7 @@ where let namespace = event.namespace.to_string().unwrap(); let name = event.name.to_string().unwrap(); - let model = - world.model_reader_with_block(&namespace, &name, BlockId::Number(block_number)).await?; + let model = world.model_reader(&namespace, &name).await?; let schema = model.schema().await?; let layout = model.layout().await?; From 4e921c3b5c47de289aae3f2f42b904836b4ea8e7 Mon Sep 17 00:00:00 2001 From: Nasr Date: Thu, 14 Nov 2024 13:34:16 +0700 Subject: [PATCH 35/35] Revert "Revert "fix: primitive len"" This reverts commit cea81026c96ceceee1650ecbdb0e9c7940982326. --- crates/dojo/types/src/primitive.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/dojo/types/src/primitive.rs b/crates/dojo/types/src/primitive.rs index 997613d1b6..5c803ed614 100644 --- a/crates/dojo/types/src/primitive.rs +++ b/crates/dojo/types/src/primitive.rs @@ -205,12 +205,12 @@ impl Primitive { Primitive::Bool(bool) => format!("{}", bool.unwrap_or_default() as i32), // Hex string - Primitive::I128(i128) => format!("{:#064x}", i128.unwrap_or_default()), - Primitive::ContractAddress(felt) => format!("{:#064x}", felt.unwrap_or_default()), - Primitive::ClassHash(felt) => format!("{:#064x}", felt.unwrap_or_default()), - Primitive::Felt252(felt) => format!("{:#064x}", felt.unwrap_or_default()), - Primitive::U128(u128) => format!("{:#064x}", u128.unwrap_or_default()), - Primitive::U64(u64) => format!("{:#064x}", u64.unwrap_or_default()), + Primitive::I128(i128) => format!("0x{:064x}", i128.unwrap_or_default()), + Primitive::ContractAddress(felt) => format!("0x{:064x}", felt.unwrap_or_default()), + Primitive::ClassHash(felt) => format!("0x{:064x}", felt.unwrap_or_default()), + Primitive::Felt252(felt) => format!("0x{:064x}", felt.unwrap_or_default()), + Primitive::U128(u128) => format!("0x{:064x}", u128.unwrap_or_default()), + Primitive::U64(u64) => format!("0x{:064x}", u64.unwrap_or_default()), Primitive::U256(u256) => format!("0x{:064x}", u256.unwrap_or_default()), }