Skip to content

Commit

Permalink
Refactor database
Browse files Browse the repository at this point in the history
  • Loading branch information
tarrencev committed Jun 21, 2023
1 parent b2bb39f commit 84b7736
Show file tree
Hide file tree
Showing 24 changed files with 377 additions and 356 deletions.
94 changes: 94 additions & 0 deletions crates/dojo-core/src/database.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use array::{ArrayTrait, SpanTrait};
use traits::{Into, TryInto};
use serde::Serde;
use hash::LegacyHash;
use poseidon::poseidon_hash_span;

mod index;
mod query;
mod storage;
mod utils;

use dojo_core::database::{query::{Query, QueryTrait}};
use dojo_core::interfaces::{IComponentLibraryDispatcher, IComponentDispatcherTrait};
use dojo_core::serde::SpanSerde;

fn get(
class_hash: starknet::ClassHash, table: felt252, query: Query, offset: u8, length: usize
) -> Option<Span<felt252>> {
let mut length = length;
if length == 0 {
length = IComponentLibraryDispatcher { class_hash: class_hash }.len();
}

let id = query.hash();
let mut keys = ArrayTrait::new();
keys.append('dojo_storage');
keys.append(table);
keys.append(id);
match index::exists(0, table, id) {
bool::False(()) => Option::None(()),
bool::True(()) => Option::Some(storage::get_many(0, keys.span(), offset, length)),
}
}

fn set(
class_hash: starknet::ClassHash, table: felt252, query: Query, offset: u8, value: Span<felt252>
) {
let keys = query.keys();
let id = query.hash();

let length = IComponentLibraryDispatcher { class_hash: class_hash }.len();
assert(value.len() <= length, 'Value too long');

index::create(0, table, id);

let mut keys = ArrayTrait::new();
keys.append('dojo_storage');
keys.append(table);
keys.append(id);
storage::set_many(0, keys.span(), offset, value);
}

fn del(class_hash: starknet::ClassHash, table: felt252, query: Query) {
index::delete(0, table, query.hash());
}

// returns a tuple of spans, first contains the entity IDs,
// second the deserialized entities themselves
fn all(
class_hash: starknet::ClassHash, component: felt252, partition: felt252
) -> (Span<felt252>, Span<Span<felt252>>) {
let table = {
if partition == 0.into() {
component
} else {
let mut serialized = ArrayTrait::new();
component.serialize(ref serialized);
partition.serialize(ref serialized);
let hash = poseidon_hash_span(serialized.span());
hash.into()
}
};

let all_ids = index::get(0, table);
let length = IComponentLibraryDispatcher { class_hash: class_hash }.len();

let mut ids = all_ids.span();
let mut entities: Array<Span<felt252>> = ArrayTrait::new();
loop {
match ids.pop_front() {
Option::Some(id) => {
let mut keys = ArrayTrait::new();
keys.append('dojo_storage');
keys.append(table);
keys.append(*id);
let value: Span<felt252> = storage::get_many(0, keys.span(), 0_u8, length);
entities.append(value);
},
Option::None(_) => {
break (all_ids.span(), entities.span());
}
};
}
}
92 changes: 92 additions & 0 deletions crates/dojo-core/src/database/index.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use array::{ArrayTrait, SpanTrait};
use traits::Into;
use option::OptionTrait;
use poseidon::poseidon_hash_span;
use serde::Serde;

use dojo_core::database::storage;
use dojo_core::serde::SpanSerde;

fn create(address_domain: u32, index: felt252, id: felt252) {
if exists(address_domain, index, id) {
return ();
}

let index_len_key = build_index_len_key(index);
let index_len = storage::get(address_domain, index_len_key);
storage::set(address_domain, build_index_item_key(index, id), index_len + 1);
storage::set(address_domain, index_len_key, index_len + 1);
storage::set(address_domain, build_index_key(index, index_len), id);
}

fn delete(address_domain: u32, index: felt252, id: felt252) {
if !exists(address_domain, index, id) {
return ();
}

let index_len_key = build_index_len_key(index);
let replace_item_idx = storage::get(address_domain, index_len_key) - 1;

let index_item_key = build_index_item_key(index, id);
let delete_item_idx = storage::get(address_domain, index_item_key) - 1;

storage::set(address_domain, index_item_key, 0);
storage::set(address_domain, index_len_key, replace_item_idx);

// Replace the deleted element with the last element.
// NOTE: We leave the last element set as to not produce an unncessary state diff.
let replace_item_value = storage::get(address_domain, build_index_key(index, replace_item_idx));
storage::set(address_domain, build_index_key(index, delete_item_idx), replace_item_value);
}

fn exists(address_domain: u32, index: felt252, id: felt252) -> bool {
storage::get(address_domain, build_index_item_key(index, id)) != 0
}

fn get(address_domain: u32, index: felt252) -> Array<felt252> {
let mut res = ArrayTrait::new();

let index_len_key = build_index_len_key(index);
let index_len = storage::get(address_domain, index_len_key);
let mut idx = 0;

loop {
if idx == index_len {
break ();
}

res.append(storage::get(address_domain, build_index_key(index, idx)));
idx += 1;
};

res
}

fn index_key_prefix() -> Array<felt252> {
let mut prefix = ArrayTrait::new();
prefix.append('dojo_index');
prefix
}

fn build_index_len_key(index: felt252) -> Span<felt252> {
let mut index_len_key = index_key_prefix();
index_len_key.append('index_lens');
index_len_key.append(index);
index_len_key.span()
}

fn build_index_key(index: felt252, idx: felt252) -> Span<felt252> {
let mut key = index_key_prefix();
key.append('indexes');
key.append(index);
key.append(idx);
key.span()
}

fn build_index_item_key(index: felt252, id: felt252) -> Span<felt252> {
let mut index_len_key = index_key_prefix();
index_len_key.append('index_ids');
index_len_key.append(index);
index_len_key.append(id);
index_len_key.span()
}
File renamed without changes.
63 changes: 63 additions & 0 deletions crates/dojo-core/src/database/storage.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use array::{ArrayTrait, SpanTrait};
use option::OptionTrait;
use starknet::SyscallResultTrait;
use traits::Into;
use poseidon::poseidon_hash_span;
use serde::Serde;
use dojo_core::serde::SpanSerde;

fn get(address_domain: u32, keys: Span<felt252>) -> felt252 {
let base = starknet::storage_base_address_from_felt252(poseidon_hash_span(keys));
starknet::storage_read_syscall(
address_domain, starknet::storage_address_from_base(base)
).unwrap_syscall()
}

fn get_many(address_domain: u32, keys: Span<felt252>, offset: u8, length: usize) -> Span<felt252> {
let base = starknet::storage_base_address_from_felt252(poseidon_hash_span(keys));
let mut value = ArrayTrait::new();

let mut offset = offset;
loop {
if length == offset.into() {
break ();
}

value
.append(
starknet::storage_read_syscall(
address_domain, starknet::storage_address_from_base_and_offset(base, offset)
).unwrap_syscall()
);

offset += 1;
};

value.span()
}

fn set(address_domain: u32, keys: Span<felt252>, value: felt252) {
let base = starknet::storage_base_address_from_felt252(poseidon_hash_span(keys));
starknet::storage_write_syscall(
address_domain, starknet::storage_address_from_base(base), value
);
}

fn set_many(address_domain: u32, keys: Span<felt252>, offset: u8, mut value: Span<felt252>) {
let base = starknet::storage_base_address_from_felt252(poseidon_hash_span(keys));

let mut offset = offset;
loop {
match value.pop_front() {
Option::Some(v) => {
starknet::storage_write_syscall(
address_domain, starknet::storage_address_from_base_and_offset(base, offset), *v
);
offset += 1
},
Option::None(_) => {
break ();
},
};
};
}
File renamed without changes.
2 changes: 1 addition & 1 deletion crates/dojo-core/src/interfaces.cairo
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use dojo_core::{
serde::SpanSerde, storage::query::Query,
serde::SpanSerde, database::query::Query,
auth::systems::Route, auth::components::AuthRole, execution_context::Context
};
use starknet::{ClassHash, ContractAddress};
Expand Down
2 changes: 1 addition & 1 deletion crates/dojo-core/src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ mod executor;
mod execution_context;
mod interfaces;
mod serde;
mod storage;
mod database;
mod world;
mod world_factory;
mod test_utils;
5 changes: 0 additions & 5 deletions crates/dojo-core/src/storage.cairo

This file was deleted.

92 changes: 0 additions & 92 deletions crates/dojo-core/src/storage/db.cairo

This file was deleted.

Loading

0 comments on commit 84b7736

Please sign in to comment.