Skip to content

Commit

Permalink
core: delete entity models (#1191)
Browse files Browse the repository at this point in the history
* core: delete entity models

* test: delete entity

* chore: pass layout to delete

* chore: fix manifest test

* Fix records contract address

---------

Co-authored-by: Tarrence van As <[email protected]>
  • Loading branch information
shramee and tarrencev authored Nov 21, 2023
1 parent d6f2772 commit 0fa1b2a
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 45 deletions.
29 changes: 21 additions & 8 deletions crates/dojo-core/src/world.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ trait IWorld<T> {
fn set_executor(ref self: T, contract_address: ContractAddress);
fn executor(self: @T) -> ContractAddress;
fn base(self: @T) -> ClassHash;
fn delete_entity(ref self: T, model: felt252, keys: Span<felt252>);
fn delete_entity(ref self: T, model: felt252, keys: Span<felt252>, layout: Span<u8>);
fn is_owner(self: @T, address: ContractAddress, resource: felt252) -> bool;
fn grant_owner(ref self: T, address: ContractAddress, resource: felt252);
fn revoke_owner(ref self: T, address: ContractAddress, resource: felt252);
Expand Down Expand Up @@ -247,9 +247,7 @@ mod world {
self.metadata_uri.write(i, *item);
i += 1;
},
Option::None(_) => {
break;
}
Option::None(_) => { break; }
};
};
}
Expand Down Expand Up @@ -491,12 +489,27 @@ mod world {
///
/// * `model` - The name of the model to be deleted.
/// * `query` - The query to be used to find the entity.
fn delete_entity(ref self: ContractState, model: felt252, keys: Span<felt252>) {
let system = get_caller_address();
assert(system.is_non_zero(), 'must be called thru system');
assert_can_write(@self, model, system);
fn delete_entity(
ref self: ContractState, model: felt252, keys: Span<felt252>, layout: Span<u8>
) {
assert_can_write(@self, model, get_caller_address());

let model_class_hash = self.models.read(model);

let mut empty_values = ArrayTrait::new();
let mut i = 0;

loop {
if (i == layout.len()) {
break;
}
empty_values.append(0);
i += 1;
};

let key = poseidon::poseidon_hash_span(keys);
database::set(model, key, 0, empty_values.span(), layout);
// this deletes the index
database::del(model, key);

EventEmitter::emit(ref self, StoreDelRecord { table: model, keys });
Expand Down
94 changes: 59 additions & 35 deletions crates/dojo-core/src/world_test.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,13 @@ struct Fizz {
#[starknet::interface]
trait Ibar<TContractState> {
fn set_foo(self: @TContractState, a: felt252, b: u128);
fn delete_foo(self: @TContractState);
fn set_char(self: @TContractState, a: felt252, b: u32);
}

#[starknet::contract]
mod bar {
use super::{Foo, IWorldDispatcher, IWorldDispatcherTrait};
use super::{Foo, IWorldDispatcher, IWorldDispatcherTrait, SchemaIntrospection};
use super::benchmarks::{Character, Abilities, Stats, Weapon, Sword};
use traits::Into;
use starknet::{get_caller_address, ContractAddress};
Expand All @@ -57,6 +58,15 @@ mod bar {
set!(self.world.read(), Foo { caller: get_caller_address(), a, b });
}

fn delete_foo(self: @ContractState) {
let mut layout = array![];
SchemaIntrospection::<Foo>::layout(ref layout);
self
.world
.read()
.delete_entity('Foo', array![get_caller_address().into()].span(), layout.span());
}

fn set_char(self: @ContractState, a: felt252, b: u32) {
set!(
self.world.read(),
Expand All @@ -82,16 +92,12 @@ mod bar {
finished: true,
romances: 0x1234,
},
weapon: Weapon::DualWield((
Sword {
swordsmith: get_caller_address(),
damage: 0x12345678,
},
Sword {
swordsmith: get_caller_address(),
damage: 0x12345678,
}
)),
weapon: Weapon::DualWield(
(
Sword { swordsmith: get_caller_address(), damage: 0x12345678, },
Sword { swordsmith: get_caller_address(), damage: 0x12345678, }
)
),
gold: b,
}
);
Expand All @@ -101,6 +107,19 @@ mod bar {

// Tests

fn deploy_world_and_bar() -> (IWorldDispatcher, IbarDispatcher) {
// Spawn empty world
let world = deploy_world();
world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap());

// System contract
let bar_contract = IbarDispatcher {
contract_address: deploy_with_world_address(bar::TEST_CLASS_HASH, world)
};

(world, bar_contract)
}

#[test]
#[available_gas(2000000)]
fn test_model() {
Expand All @@ -111,14 +130,7 @@ fn test_model() {
#[test]
#[available_gas(6000000)]
fn test_system() {
// Spawn empty world
let world = deploy_world();
world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap());

// System contract
let bar_contract = IbarDispatcher {
contract_address: deploy_with_world_address(bar::TEST_CLASS_HASH, world)
};
let (world, bar_contract) = deploy_world_and_bar();

bar_contract.set_foo(1337, 1337);

Expand All @@ -127,6 +139,24 @@ fn test_system() {
assert(stored.b == 1337, 'data not stored');
}

#[test]
#[available_gas(6000000)]
fn test_delete() {
let (world, bar_contract) = deploy_world_and_bar();

// set model
bar_contract.set_foo(1337, 1337);
let stored: Foo = get!(world, get_caller_address(), Foo);
assert(stored.a == 1337, 'data not stored');
assert(stored.b == 1337, 'data not stored');

// delete model
bar_contract.delete_foo();
let deleted: Foo = get!(world, get_caller_address(), Foo);
assert(deleted.a == 0, 'data not deleted');
assert(deleted.b == 0, 'data not deleted');
}

#[test]
#[available_gas(6000000)]
fn test_model_class_hash_getter() {
Expand All @@ -153,13 +183,7 @@ fn test_emit() {
#[test]
#[available_gas(9000000)]
fn test_set_entity_admin() {
// Spawn empty world
let world = deploy_world();
world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap());

let bar_contract = IbarDispatcher {
contract_address: deploy_with_world_address(bar::TEST_CLASS_HASH, world)
};
let (world, bar_contract) = deploy_world_and_bar();

let alice = starknet::contract_address_const::<0x1337>();
starknet::testing::set_contract_address(alice);
Expand Down Expand Up @@ -267,14 +291,14 @@ fn test_entities() {
let ids = world.entity_ids('Foo');
assert(keys.len() == ids.len(), 'result differs in entity_ids');
assert(keys.len() == 0, 'found value for unindexed');
// query_keys.append(0x1337);
// let (keys, values) = world.entities('Foo', 42, query_keys.span(), 2, layout);
// assert(keys.len() == 1, 'No keys found!');

// let mut query_keys = ArrayTrait::new();
// query_keys.append(0x1338);
// let (keys, values) = world.entities('Foo', 42, query_keys.span(), 2, layout);
// assert(keys.len() == 0, 'Keys found!');
// query_keys.append(0x1337);
// let (keys, values) = world.entities('Foo', 42, query_keys.span(), 2, layout);
// assert(keys.len() == 1, 'No keys found!');

// let mut query_keys = ArrayTrait::new();
// query_keys.append(0x1338);
// let (keys, values) = world.entities('Foo', 42, query_keys.span(), 2, layout);
// assert(keys.len() == 0, 'Keys found!');
}

#[test]
Expand Down Expand Up @@ -486,4 +510,4 @@ fn bench_execute_complex() {
end(gas, 'char get macro');

assert(data.heigth == 1337, 'data not stored');
}
}
6 changes: 5 additions & 1 deletion crates/dojo-lang/src/manifest_test_data/manifest
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ test_manifest_file
"world": {
"name": "world",
"address": null,
"class_hash": "0x6441e7fc96d795ec94fca66634e6d87edf84362e564ef80eb13f459914b8b",
"class_hash": "0x481a9c7b128847a520bb234d93ef8a83b462de03fce7089eb4ed9135d2f31d9",
"abi": [
{
"type": "impl",
Expand Down Expand Up @@ -357,6 +357,10 @@ test_manifest_file
{
"name": "keys",
"type": "core::array::Span::<core::felt252>"
},
{
"name": "layout",
"type": "core::array::Span::<core::integer::u8>"
}
],
"outputs": [],
Expand Down
2 changes: 1 addition & 1 deletion crates/torii/graphql/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ pub async fn spinup_types_test() -> Result<SqlitePool> {
execute_strategy(&ws, &migration, &account, None).await.unwrap();

// Execute `create` and insert 10 records into storage
let records_contract = "0x2753d30656b393ecea156189bf0acf5e1063f3ac978fb5c3cebe7a4570bbc78";
let records_contract = "0x58eaab9779694efb92b43ccad6dc9b40cd8fc69e3efa97137f1c83af69ca8a1";
let InvokeTransactionResult { transaction_hash } = account
.execute(vec![Call {
calldata: vec![FieldElement::from_str("0xa").unwrap()],
Expand Down

0 comments on commit 0fa1b2a

Please sign in to comment.