Skip to content
This repository was archived by the owner on Nov 11, 2024. It is now read-only.

Commit 5386dbd

Browse files
authored
feat: add entity batching (n-02) (#32)
* backport 1 * fix: fix contracts path
1 parent 969004b commit 5386dbd

File tree

12 files changed

+593
-245
lines changed

12 files changed

+593
-245
lines changed

crates/contracts/Scarb.lock

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,3 @@ dependencies = [
1111
[[package]]
1212
name = "dojo_plugin"
1313
version = "2.8.4"
14-
source = "git+https://github.com/dojoengine/dojo?branch=feat%2Fdojo-1-rc0#3bf1276163fe9dbfe0f65775de8363e358510c77"

crates/contracts/Scarb.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ version = "1.0.0-rc.0"
77

88
[dependencies]
99
starknet = "=2.8.4"
10-
dojo_plugin = { git = "https://github.com/dojoengine/dojo", branch = "feat/dojo-1-rc0" }
10+
dojo_plugin = { path = "../contracts" }
11+
#dojo_macros = { path = "../macros" }
1112

1213
[dev-dependencies]
1314
cairo_test = "=2.8.4"

crates/contracts/src/event/event.cairo

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,15 @@ use dojo::meta::introspect::Ty;
44
#[derive(Drop, Serde, Debug, PartialEq)]
55
pub struct EventDefinition {
66
pub name: ByteArray,
7-
pub version: u8,
87
pub layout: Layout,
98
pub schema: Ty
109
}
1110

1211
pub trait Event<T> {
1312
fn name() -> ByteArray;
14-
fn version() -> u8;
1513
fn definition() -> EventDefinition;
1614
fn layout() -> Layout;
1715
fn schema() -> Ty;
18-
fn historical() -> bool;
1916
fn keys(self: @T) -> Span<felt252>;
2017
fn values(self: @T) -> Span<felt252>;
2118
/// Returns the selector of the model computed for the given namespace hash.

crates/contracts/src/event/interface.cairo

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use super::EventDefinition;
66
#[starknet::interface]
77
pub trait IEvent<T> {
88
fn dojo_name(self: @T) -> ByteArray;
9-
fn version(self: @T) -> u8;
109
fn definition(self: @T) -> EventDefinition;
1110
fn layout(self: @T) -> Layout;
1211
fn schema(self: @T) -> Ty;

crates/contracts/src/lib.cairo

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,8 @@ pub mod model {
4747

4848
pub mod storage;
4949
pub use storage::{
50-
ModelStorage, ModelMemberStorage, ModelStorageTest, ModelValueStorage, ModelValueStorageTest
50+
ModelStorage, ModelStorageTest, ModelValueStorage, ModelValueStorageTest, ModelPtr,
5151
};
52-
53-
#[cfg(target: "test")]
54-
pub use model::{ModelTest};
55-
56-
#[cfg(target: "test")]
57-
pub use model_value::{ModelValueTest};
5852
}
5953

6054
pub mod storage {

crates/contracts/src/model/model.cairo

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -119,25 +119,3 @@ pub impl ModelImpl<M, +ModelParser<M>, +ModelDefinition<M>, +Serde<M>> of Model<
119119
}
120120
}
121121
}
122-
123-
/// The `ModelTest` trait.
124-
///
125-
/// It provides a standardized way to interact with models for testing purposes,
126-
/// bypassing the permission checks.
127-
#[cfg(target: "test")]
128-
pub trait ModelTest<S, M> {
129-
fn set_model_test(ref self: S, model: @M);
130-
fn delete_model_test(ref self: S, model: @M);
131-
}
132-
133-
/// The `ModelTestImpl` implementation for testing purposes.
134-
#[cfg(target: "test")]
135-
pub impl ModelTestImpl<S, M, +dojo::model::ModelStorageTest<S, M>, +Model<M>> of ModelTest<S, M> {
136-
fn set_model_test(ref self: S, model: @M) {
137-
dojo::model::ModelStorageTest::<S, M>::write_model_test(ref self, model);
138-
}
139-
140-
fn delete_model_test(ref self: S, model: @M) {
141-
dojo::model::ModelStorageTest::<S, M>::erase_model_test(ref self, model);
142-
}
143-
}

crates/contracts/src/model/model_value.cairo

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub impl ModelValueImpl<V, +Serde<V>, +ModelDefinition<V>, +ModelValueParser<V>>
3434
}
3535

3636
fn from_values(entity_id: felt252, ref values: Span<felt252>) -> Option<V> {
37-
let mut serialized: Array<felt252> = array![entity_id];
37+
let mut serialized: Array<felt252> = array![];
3838
serialized.append_span(values);
3939
let mut span = serialized.span();
4040
Serde::<V>::deserialize(ref span)
@@ -60,27 +60,3 @@ pub impl ModelValueImpl<V, +Serde<V>, +ModelDefinition<V>, +ModelValueParser<V>>
6060
dojo::utils::selector_from_namespace_and_name(namespace_hash, @Self::name())
6161
}
6262
}
63-
64-
65-
/// Test implementation of the `ModelValueTest` trait to bypass permission checks.
66-
#[cfg(target: "test")]
67-
pub trait ModelValueTest<S, V> {
68-
fn update_test(ref self: S, entity_id: felt252, value: @V);
69-
fn delete_test(ref self: S, entity_id: felt252);
70-
}
71-
72-
/// Implementation of the `ModelValueTest` trait for testing purposes, bypassing permission checks.
73-
#[cfg(target: "test")]
74-
pub impl ModelValueTestImpl<
75-
S, V, +super::storage::ModelValueStorageTest<S, V>, +ModelValue<V>
76-
> of ModelValueTest<S, V> {
77-
fn update_test(ref self: S, entity_id: felt252, value: @V) {
78-
super::storage::ModelValueStorageTest::<
79-
S, V
80-
>::write_model_value_test(ref self, entity_id, value)
81-
}
82-
83-
fn delete_test(ref self: S, entity_id: felt252) {
84-
super::storage::ModelValueStorageTest::<S, V>::erase_model_value_test(ref self, entity_id)
85-
}
86-
}
Lines changed: 64 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
use dojo::model::model_value::ModelValueKey;
22

3+
// TODO: define the right interface for member accesses.
4+
5+
/// A pointer to a model, which can be expressed by an entity id.
6+
/// It's different from `ModelIndex` which is used for low level accesses.
7+
#[derive(Copy, Drop, Serde, Debug, PartialEq)]
8+
pub enum ModelPtr<M> {
9+
// The id of the model.
10+
Id: felt252,
11+
// The keys of the model as span.
12+
Keys: Span<felt252>,
13+
}
14+
315
/// A `ModelStorage` trait that abstracts where the storage is.
416
///
517
/// Currently it's only world storage, but this will be useful when we have other
@@ -8,41 +20,29 @@ pub trait ModelStorage<S, M> {
820
/// Sets a model of type `M`.
921
fn write_model(ref self: S, model: @M);
1022

23+
/// Sets multiple models of type `M`.
24+
fn write_models(ref self: S, models: Span<@M>);
25+
1126
/// Retrieves a model of type `M` using the provided key of type `K`.
1227
fn read_model<K, +Drop<K>, +Serde<K>>(self: @S, key: K) -> M;
1328

29+
/// Retrieves multiple models of type `M` using the provided keys of type `K`.
30+
/// Returnes an array to ensure the user can consume the models, even if the type is not
31+
/// copiable.
32+
fn read_models<K, +Drop<K>, +Serde<K>>(self: @S, keys: Span<K>) -> Array<M>;
33+
1434
/// Deletes a model of type `M`.
1535
fn erase_model(ref self: S, model: @M);
1636

17-
/// Deletes a model of type `M` using the provided key of type `K`.
18-
fn erase_model_from_key<K, +Drop<K>, +Serde<K>>(ref self: S, key: K);
37+
/// Deletes multiple models of type `M`.
38+
fn erase_models(ref self: S, models: Span<@M>);
1939

2040
/// Deletes a model of type `M` using the provided entity id.
21-
fn erase_model_from_id(ref self: S, entity_id: felt252);
22-
23-
/// Retrieves a member of type `T` from a model of type `M` using the provided member id and key
24-
/// of type `K`.
25-
fn read_member<T, K, +ModelMemberStorage<S, M, T>, +Drop<T>, +Drop<K>, +Serde<K>>(
26-
self: @S, key: K, member_id: felt252
27-
) -> T;
28-
29-
/// Updates a member of type `T` within a model of type `M` using the provided member id, key of
30-
/// type `K`, and new value of type `T`.
31-
fn write_member<T, K, +ModelMemberStorage<S, M, T>, +Drop<T>, +Drop<K>, +Serde<K>>(
32-
ref self: S, key: K, member_id: felt252, value: T
33-
);
34-
35-
/// Returns the current namespace hash.
36-
fn namespace_hash(self: @S) -> felt252;
37-
}
38-
39-
/// A `ModelMemberStorage` trait that abstracts where the storage is.
40-
pub trait ModelMemberStorage<S, M, T> {
41-
/// Retrieves a member of type `T` for the given entity id and member id.
42-
fn read_member_from_id(self: @S, entity_id: felt252, member_id: felt252) -> T;
41+
/// The ptr is mostly used for type inferrence.
42+
fn erase_model_ptr(ref self: S, ptr: ModelPtr<M>);
4343

44-
/// Updates a member of type `T` for the given entity id and member id.
45-
fn write_member_from_id(ref self: S, entity_id: felt252, member_id: felt252, value: T);
44+
/// Deletes multiple models of type `M` using the provided entity ids.
45+
fn erase_models_ptrs(ref self: S, ptrs: Span<ModelPtr<M>>);
4646

4747
/// Returns the current namespace hash.
4848
fn namespace_hash(self: @S) -> felt252;
@@ -51,18 +51,32 @@ pub trait ModelMemberStorage<S, M, T> {
5151
/// A `ModelValueStorage` trait that abstracts where the storage is.
5252
pub trait ModelValueStorage<S, V> {
5353
/// Retrieves a model value of type `V` using the provided key of type `K`.
54-
fn read_model_value<K, +Drop<K>, +Serde<K>, +ModelValueKey<V, K>>(self: @S, key: K) -> V;
54+
fn read_value<K, +Drop<K>, +Serde<K>, +ModelValueKey<V, K>>(self: @S, key: K) -> V;
55+
56+
/// Retrieves multiple model values of type `V` using the provided keys of type `K`.
57+
fn read_values<K, +Drop<K>, +Serde<K>, +ModelValueKey<V, K>>(
58+
self: @S, keys: Span<K>
59+
) -> Array<V>;
5560

5661
/// Retrieves a model value of type `V` using the provided entity id.
57-
fn read_model_value_from_id(self: @S, entity_id: felt252) -> V;
62+
fn read_value_from_id(self: @S, entity_id: felt252) -> V;
63+
64+
/// Retrieves multiple model values of type `V` using the provided entity ids.
65+
fn read_values_from_ids(self: @S, entity_ids: Span<felt252>) -> Array<V>;
5866

5967
/// Updates a model value of type `V`.
60-
fn write_model_value<K, +Drop<K>, +Serde<K>, +ModelValueKey<V, K>>(
61-
ref self: S, key: K, value: @V
68+
fn write_value<K, +Drop<K>, +Serde<K>, +ModelValueKey<V, K>>(ref self: S, key: K, value: @V);
69+
70+
/// Updates multiple model values of type `V`.
71+
fn write_values<K, +Drop<K>, +Serde<K>, +ModelValueKey<V, K>>(
72+
ref self: S, keys: Span<K>, values: Span<@V>
6273
);
6374

6475
/// Updates a model value of type `V`.
65-
fn write_model_value_from_id(ref self: S, entity_id: felt252, value: @V);
76+
fn write_value_from_id(ref self: S, entity_id: felt252, value: @V);
77+
78+
/// Updates multiple model values of type `V`.
79+
fn write_values_from_ids(ref self: S, entity_ids: Span<felt252>, values: Span<@V>);
6680
}
6781

6882
/// A `ModelStorage` trait that abstracts where the storage is.
@@ -72,15 +86,31 @@ pub trait ModelValueStorage<S, V> {
7286
pub trait ModelStorageTest<S, M> {
7387
/// Sets a model of type `M`.
7488
fn write_model_test(ref self: S, model: @M);
89+
/// Sets multiple models of type `M`.
90+
fn write_models_test(ref self: S, models: Span<@M>);
7591
/// Deletes a model of type `M`.
7692
fn erase_model_test(ref self: S, model: @M);
93+
/// Deletes multiple models of type `M`.
94+
fn erase_models_test(ref self: S, models: Span<@M>);
95+
/// Deletes a model of type `M` using the provided entity id.
96+
fn erase_model_ptr_test(ref self: S, ptr: ModelPtr<M>);
97+
/// Deletes multiple models of type `M` using the provided entity ids.
98+
fn erase_models_ptrs_test(ref self: S, ptrs: Span<ModelPtr<M>>);
7799
}
78100

79101
/// A `ModelValueStorageTest` trait that abstracts where the storage is and bypass the permission
80102
/// checks.
81103
pub trait ModelValueStorageTest<S, V> {
82104
/// Updates a model value of type `V`.
83-
fn write_model_value_test(ref self: S, entity_id: felt252, value: @V);
84-
/// Deletes a model value of type `V`.
85-
fn erase_model_value_test(ref self: S, entity_id: felt252);
105+
fn write_value_test<K, +Drop<K>, +Serde<K>, +ModelValueKey<V, K>>(
106+
ref self: S, key: K, value: @V
107+
);
108+
/// Updates multiple model values of type `V`.
109+
fn write_values_test<K, +Drop<K>, +Serde<K>, +ModelValueKey<V, K>>(
110+
ref self: S, keys: Span<K>, values: Span<@V>
111+
);
112+
/// Updates a model value of type `V`.
113+
fn write_value_from_id_test(ref self: S, entity_id: felt252, value: @V);
114+
/// Updates multiple model values of type `V`.
115+
fn write_values_from_ids_test(ref self: S, entity_ids: Span<felt252>, values: Span<@V>);
86116
}

crates/contracts/src/world/errors.cairo

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ use starknet::ContractAddress;
22

33
pub const DELETE_ENTITY_MEMBER: felt252 = 'Cannot delete entity member';
44

5+
pub fn lengths_mismatch(a: @ByteArray, b: @ByteArray, context: @ByteArray) -> ByteArray {
6+
format!("Length mismatch: `{a}` and `{b}` in `{context}`")
7+
}
8+
59
pub fn not_writer(contract_tag: @ByteArray, on_type: @ByteArray, on_tag: @ByteArray) -> ByteArray {
610
format!("Caller `{}` has no write access on {} `{}`", contract_tag, on_type, on_tag)
711
}
@@ -63,7 +67,7 @@ pub fn invalid_resource_selector(selector: felt252) -> ByteArray {
6367
}
6468

6569
pub fn resource_conflict(name: @ByteArray, expected_type: @ByteArray) -> ByteArray {
66-
format!("Resource `{}` is registered but not as a {}", name, expected_type)
70+
format!("Resource `{}` is registered but not as {}", name, expected_type)
6771
}
6872

6973
pub fn no_model_write_access(tag: @ByteArray, caller: ContractAddress) -> ByteArray {

crates/contracts/src/world/iworld.cairo

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -126,13 +126,23 @@ pub trait IWorld<T> {
126126
/// * `event_selector` - The selector of the event.
127127
/// * `keys` - The keys of the event.
128128
/// * `values` - The data to be logged by the event.
129-
/// * `historical` - Whether the event should be logged in historical mode.
130129
fn emit_event(
130+
ref self: T, event_selector: felt252, keys: Span<felt252>, values: Span<felt252>,
131+
);
132+
133+
/// Emits multiple events.
134+
/// Permissions are only checked once, then the events are batched.
135+
///
136+
/// # Arguments
137+
///
138+
/// * `event_selector` - The selector of the event.
139+
/// * `keys` - The keys of the event.
140+
/// * `values` - The data to be logged by the event.
141+
fn emit_events(
131142
ref self: T,
132143
event_selector: felt252,
133-
keys: Span<felt252>,
134-
values: Span<felt252>,
135-
historical: bool
144+
keys: Span<Span<felt252>>,
145+
values: Span<Span<felt252>>,
136146
);
137147

138148
/// Gets the values of a model entity/member.
@@ -151,6 +161,17 @@ pub trait IWorld<T> {
151161
self: @T, model_selector: felt252, index: ModelIndex, layout: Layout
152162
) -> Span<felt252>;
153163

164+
/// Gets the model values for the given entities.
165+
///
166+
/// # Arguments
167+
///
168+
/// * `model_selector` - The selector of the model to be retrieved.
169+
/// * `indices` - The indexes of the entities/members to read.
170+
/// * `layout` - The memory layout of the model.
171+
fn entities(
172+
self: @T, model_selector: felt252, indexes: Span<ModelIndex>, layout: Layout
173+
) -> Span<Span<felt252>>;
174+
154175
/// Sets the model value for the given entity/member.
155176
///
156177
/// # Arguments
@@ -167,6 +188,23 @@ pub trait IWorld<T> {
167188
layout: Layout
168189
);
169190

191+
/// Sets the model values for the given entities.
192+
/// The permissions are only checked once, then the writes are batched.
193+
///
194+
/// # Arguments
195+
///
196+
/// * `model_selector` - The selector of the model to be set.
197+
/// * `indexes` - The indexes of the entities/members to write.
198+
/// * `values` - The values to be set, serialized using the model layout format.
199+
/// * `layout` - The memory layout of the model.
200+
fn set_entities(
201+
ref self: T,
202+
model_selector: felt252,
203+
indexes: Span<ModelIndex>,
204+
values: Span<Span<felt252>>,
205+
layout: Layout
206+
);
207+
170208
/// Deletes a model value for the given entity/member.
171209
/// Deleting is setting all the values to 0 in the given layout.
172210
///
@@ -177,6 +215,18 @@ pub trait IWorld<T> {
177215
/// * `layout` - The memory layout of the model.
178216
fn delete_entity(ref self: T, model_selector: felt252, index: ModelIndex, layout: Layout);
179217

218+
/// Deletes the model values for the given entities.
219+
/// The permissions are only checked once, then the deletes are batched.
220+
///
221+
/// # Arguments
222+
///
223+
/// * `model_selector` - The selector of the model to be deleted.
224+
/// * `indexes` - The indexes of the entities/members to delete.
225+
/// * `layout` - The memory layout of the model.
226+
fn delete_entities(
227+
ref self: T, model_selector: felt252, indexes: Span<ModelIndex>, layout: Layout
228+
);
229+
180230
/// Returns true if the provided account has owner permission for the resource, false otherwise.
181231
///
182232
/// # Arguments
@@ -258,11 +308,7 @@ pub trait IWorldTest<T> {
258308
/// Emits a custom event that was previously registered in the world without checking for
259309
/// resource permissions.
260310
fn emit_event_test(
261-
ref self: T,
262-
event_selector: felt252,
263-
keys: Span<felt252>,
264-
values: Span<felt252>,
265-
historical: bool
311+
ref self: T, event_selector: felt252, keys: Span<felt252>, values: Span<felt252>,
266312
);
267313

268314
/// Returns the address of a registered contract, panics otherwise.

0 commit comments

Comments
 (0)