Browse Source

rustfmt pass, tweak to simple_in_memory bench.

Kestrel 2 years ago
parent
commit
c396883dc0

+ 3 - 2
Cargo.lock

@@ -338,11 +338,12 @@ dependencies = [
 
 [[package]]
 name = "microrm"
-version = "0.3.0"
+version = "0.3.1"
 dependencies = [
  "base64",
  "criterion",
  "lazy_static",
+ "log",
  "microrm-macros",
  "rand",
  "serde",
@@ -355,7 +356,7 @@ dependencies = [
 
 [[package]]
 name = "microrm-macros"
-version = "0.2.3"
+version = "0.2.4"
 dependencies = [
  "convert_case",
  "proc-macro2",

+ 1 - 0
microrm/Cargo.toml

@@ -18,6 +18,7 @@ serde_json = { version = "1.0" }
 lazy_static = { version = "1.4.0" }
 
 microrm-macros = { path = "../microrm-macros", version = "0.2.4" }
+log = "0.4.17"
 
 [dev-dependencies]
 criterion = "0.3"

+ 21 - 13
microrm/benches/simple_in_memory.rs

@@ -1,6 +1,6 @@
 use criterion::{black_box, criterion_group, criterion_main, Criterion};
 
-use microrm::{make_index, Entity};
+use microrm::{make_index, Entity, prelude::*};
 use rand::prelude::*;
 use serde::{Deserialize, Serialize};
 
@@ -12,38 +12,46 @@ pub struct RowIDIndexed {
     val: usize,
 }
 
+const MAX_ID: usize = 100;
+
 fn rowid_indexed(c: &mut Criterion) {
-    let schema = microrm::model::SchemaModel::new().entity::<RowIDIndexed>();
+    let schema = microrm::Schema::new().entity::<RowIDIndexed>();
     let db = microrm::DB::new_in_memory(schema).unwrap();
     let qi = db.query_interface();
 
-    for i in 0..10000 {
-        qi.add(&RowIDIndexed { val: i * i });
+    for i in 0..MAX_ID {
+        qi.add(&RowIDIndexed { val: i * i }).unwrap();
     }
 
     let mut reg = stats_alloc::Region::new(&GLOBAL);
 
-    qi.get_one_by_id(RowIDIndexedID(0));
+    qi.get().by_id(&RowIDIndexedID(1)).exec().unwrap();
 
     println!(
-        "allocations for single get_one_by_id: {}",
+        "allocations for single get by_id: {}",
         reg.change_and_reset().allocations
     );
 
-    c.bench_function("select 0", |b| {
-        b.iter(|| qi.get_one_by_id(RowIDIndexedID(0)))
-    });
-    c.bench_function("select 0 no statement cache", |b| {
-        b.iter(|| db.query_interface().get_one_by_id(RowIDIndexedID(0)))
+    qi.get().by_id(&RowIDIndexedID(1)).exec().unwrap();
+
+    println!(
+        "allocations for second get by_id: {}",
+        reg.change_and_reset().allocations
+    );
+
+    c.bench_function("select 1", |b| {
+        b.iter(|| qi.get().by_id(&RowIDIndexedID(1)).one().unwrap())
     });
 
     fn random_id() -> RowIDIndexedID {
-        let res = RowIDIndexedID((rand::random::<usize>() % 10000) as i64);
+        let res = RowIDIndexedID((rand::random::<usize>() % MAX_ID) as i64 + 1);
         res
     }
 
     c.bench_function("select random", |b| {
-        b.iter(|| qi.get_one_by_id(random_id()))
+        b.iter(|| {
+            qi.get().by_id(&random_id()).one().unwrap();
+        });
     });
 }
 

+ 4 - 9
microrm/src/entity.rs

@@ -11,13 +11,14 @@ pub trait Entity: 'static + for<'de> serde::Deserialize<'de> + serde::Serialize
     fn columns() -> &'static [&'static dyn EntityColumn<Entity = Self>];
     fn id_column() -> Self::IDColumn;
 
-    fn visit_values<E,F: FnMut(&dyn Modelable) -> Result<(),E>>(&self, visit: &mut F) -> Result<(),E>;
+    fn visit_values<E, F: FnMut(&dyn Modelable) -> Result<(), E>>(
+        &self,
+        visit: &mut F,
+    ) -> Result<(), E>;
 
     fn build_from(stmt: &sqlite::Statement) -> sqlite::Result<Self>
     where
         Self: Sized;
-
-    // fn foreign_keys() -> &'static [&'static dyn EntityForeignKey<Local = dyn EntityColumn<Entity = Self>, Foreign = dyn EntityColumn<Entity = ...>>];
 }
 
 /// Trait representing the columns of a database entity
@@ -47,12 +48,6 @@ pub trait EntityID: 'static + std::fmt::Debug + Copy + Modelable {
     fn raw_id(&self) -> i64;
 }
 
-/// Trait for a foreign key relationship
-pub trait EntityForeignKey {
-    type Local: EntityColumn;
-    type Foreign: EntityColumn;
-}
-
 /// Trait for an index over a column
 pub trait Index {
     fn index_name() -> &'static str

+ 1 - 1
microrm/src/error.rs

@@ -5,7 +5,7 @@ pub enum Error {
     StoreError(String),
     EmptyStoreError,
     CreateError,
-    ExecFailure
+    ExecFailure,
 }
 
 impl From<sqlite::Error> for Error {

+ 23 - 10
microrm/src/lib.rs

@@ -13,11 +13,11 @@ use meta::Metaschema;
 pub use microrm_macros::{make_index, Entity, Modelable};
 
 pub use error::Error;
-pub use query::{QueryInterface, WithID, build::CompareOp};
+pub use query::{build::CompareOp, QueryInterface, WithID};
 pub use schema::Schema;
 
 pub mod prelude {
-    pub use crate::query::{Filterable,Resolvable,Settable};
+    pub use crate::query::{Filterable, Resolvable, Settable};
 }
 
 use prelude::*;
@@ -47,7 +47,7 @@ pub enum DBError {
     DropFailure,
     CreateFailure,
     SanityCheckFailure,
-    InternalFailure(crate::Error)
+    InternalFailure(crate::Error),
 }
 
 impl From<crate::Error> for DBError {
@@ -163,7 +163,8 @@ impl DB {
         }
 
         let qi = query::QueryInterface::new(self);
-        let hash: Option<WithID<Metaschema>> = qi.get().by(meta::Metaschema::Key, "schema_hash").one()?;
+        let hash: Option<WithID<Metaschema>> =
+            qi.get().by(meta::Metaschema::Key, "schema_hash").one()?;
 
         if hash.is_none() {
             if mode == CreateMode::MustExist {
@@ -323,7 +324,10 @@ mod test {
         let id = qi.add(&S1 { an_id: -1 }).expect("Can't add S1");
         let child_id = qi.add(&S2 { parent_id: id }).expect("Can't add S2");
 
-        qi.get().by(S2::ID, &child_id).one().expect("Can't get S2 instance");
+        qi.get()
+            .by(S2::ID, &child_id)
+            .one()
+            .expect("Can't get S2 instance");
     }
 
     microrm_macros::make_index_internal!(S2ParentIndex, S2::ParentId);
@@ -360,7 +364,8 @@ mod test2 {
         qi.add(&KVStore {
             key: "a_key".to_string(),
             value: "a_value".to_string(),
-        }).unwrap();
+        })
+        .unwrap();
 
         // because KVStoreIndex indexes key, this is a logarithmic lookup
         let qr = qi.get().by(KVStore::Key, "a_key").one();
@@ -393,18 +398,21 @@ mod delete_test {
         qi.add(&KVStore {
             key: "a".to_string(),
             value: "a_value".to_string(),
-        }).unwrap();
+        })
+        .unwrap();
 
         let insert_two = || {
             qi.add(&KVStore {
                 key: "a".to_string(),
                 value: "a_value".to_string(),
-            }).unwrap();
+            })
+            .unwrap();
 
             qi.add(&KVStore {
                 key: "a".to_string(),
                 value: "another_value".to_string(),
-            }).unwrap();
+            })
+            .unwrap();
         };
 
         assert!(qi.get().by(KVStore::Key, "a").one().is_ok());
@@ -423,7 +431,12 @@ mod delete_test {
         assert!(all.is_ok());
         assert_eq!(all.unwrap().len(), 2);
 
-        assert!(qi.delete().by(KVStore::Key, &"a").by(KVStore::Value, &"another_value").exec().is_ok());
+        assert!(qi
+            .delete()
+            .by(KVStore::Key, &"a")
+            .by(KVStore::Value, &"another_value")
+            .exec()
+            .is_ok());
 
         let one = qi.get().by(KVStore::Key, "a").one().unwrap();
         assert!(one.is_some());

+ 0 - 0
microrm/src/lookup.rs


+ 1 - 1
microrm/src/model/store.rs

@@ -3,7 +3,7 @@ use crate::entity::Entity;
 pub fn serialize_into<T: Entity>(stmt: &mut sqlite::Statement, value: &T) -> sqlite::Result<()> {
     let mut i = 1;
 
-    value.visit_values::<sqlite::Error,_>(&mut |val| {
+    value.visit_values::<sqlite::Error, _>(&mut |val| {
         val.bind_to(stmt, i)?;
         i += 1;
         Ok(())

+ 23 - 14
microrm/src/query.rs

@@ -1,19 +1,17 @@
-use crate::prelude::*;
-use std::hash::{Hash,Hasher};
-
-use crate::entity::{Entity, EntityColumn, EntityID};
-use crate::model::Modelable;
+use crate::{prelude::*, Error};
+use std::hash::{Hash, Hasher};
 
+use crate::entity::{Entity, EntityID};
 
 pub mod build;
-pub mod resolve;
-pub mod filter;
 pub mod delete;
+pub mod filter;
+pub mod resolve;
 pub mod select;
 pub mod update;
 
-pub use resolve::Resolvable;
 pub use filter::Filterable;
+pub use resolve::Resolvable;
 pub use update::Settable;
 
 /// Wraps an entity with its ID, for example as a query result.
@@ -102,7 +100,7 @@ impl<'l> QueryInterface<'l> {
     ) -> Result<Option<T>, crate::Error> {
         let state = stmt.next()?;
         if state != sqlite::State::Row {
-            return Ok(None)
+            return Ok(None);
             // return Err(crate::Error::ExecFailure)
         }
 
@@ -132,7 +130,7 @@ impl<'l> QueryInterface<'l> {
         create: Create,
         mut with: With,
     ) -> Return
-    where {
+where {
         let mut cache = self.cache.lock().expect("Couldn't acquire cache?");
         let query = cache.entry(hash).or_insert_with(create);
         query.reset().expect("Couldn't reset query");
@@ -141,12 +139,18 @@ impl<'l> QueryInterface<'l> {
 }
 
 impl<'l> QueryInterface<'l> {
-    pub fn insert<T: Entity + serde::Serialize>(&self, m: &T) -> Result<<T as Entity>::ID, crate::Error> {
+    pub fn insert<T: Entity + serde::Serialize>(
+        &self,
+        m: &T,
+    ) -> Result<<T as Entity>::ID, crate::Error> {
         self.add(m)
     }
 
     /// Add an entity to its table
-    pub fn add<T: Entity + serde::Serialize>(&self, m: &T) -> Result<<T as Entity>::ID, crate::Error> {
+    pub fn add<T: Entity + serde::Serialize>(
+        &self,
+        m: &T,
+    ) -> Result<<T as Entity>::ID, crate::Error> {
         let mut hasher = std::collections::hash_map::DefaultHasher::new();
         "add".hash(&mut hasher);
         std::any::TypeId::of::<T>().hash(&mut hasher);
@@ -180,6 +184,7 @@ impl<'l> QueryInterface<'l> {
     }
 }
 
+// General query interface
 impl<'l> QueryInterface<'l> {
     pub fn get<'a, 'b, T: Entity>(&'a self) -> select::Select<'b, 'l, T>
     where
@@ -203,13 +208,17 @@ impl<'l> QueryInterface<'l> {
     }
 }
 
+impl<'l> QueryInterface<'l> {
+    pub fn put<T: Entity>(&self, what: &WithID<T>) -> Result<(), Error> {
+        self.update().to(what.as_ref()).by(T::id_column(), &what.id()).exec()
+    }
+}
+
 #[cfg(test)]
 mod test_build {
     use microrm_macros::Entity;
     use serde::{Deserialize, Serialize};
 
-    use crate::QueryInterface;
-
     #[derive(Entity, Serialize, Deserialize)]
     #[microrm_internal]
     pub struct KVStore {

+ 2 - 5
microrm/src/query/build.rs

@@ -3,15 +3,12 @@
 //! Interface:
 //! - `qi.get().by(KVStore::Key, &key).result()`
 
-use crate::{entity::EntityColumn, model::Modelable, Entity, Error};
+use crate::Error;
 use std::{
     collections::HashMap,
     hash::{Hash, Hasher},
-    marker::PhantomData,
 };
 
-use super::{QueryInterface, WithID};
-
 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub enum QueryPart {
     Root,
@@ -59,7 +56,7 @@ impl DerivedQuery {
             }
         };
 
-        println!("{} {} {}", root, set_, where_);
+        log::trace!("built SQL query: {} {} {}", root, set_, where_);
 
         format!("{} {} {}", root, set_, where_)
     }

+ 4 - 4
microrm/src/query/delete.rs

@@ -1,8 +1,8 @@
-use std::marker::PhantomData;
-use std::hash::{Hash,Hasher};
-use crate::{Error,Entity,QueryInterface};
 use super::build::*;
-use super::{Filterable,Resolvable};
+use super::{Filterable, Resolvable};
+use crate::{Entity, Error, QueryInterface};
+use std::hash::{Hash, Hasher};
+use std::marker::PhantomData;
 
 pub struct Delete<'r, 'q, T: Entity> {
     qi: &'r QueryInterface<'q>,

+ 18 - 14
microrm/src/query/filter.rs

@@ -1,9 +1,9 @@
-use std::marker::PhantomData;
-use std::hash::{Hash,Hasher};
-use crate::entity::EntityID;
-use crate::{Entity,entity::EntityColumn,WithID,QueryInterface,model::Modelable};
-use super::{Resolvable,build::CompareOp};
 use super::build::*;
+use super::{build::CompareOp, Resolvable};
+use crate::entity::EntityID;
+use crate::{entity::EntityColumn, model::Modelable, Entity, QueryInterface};
+use std::hash::{Hash, Hasher};
+use std::marker::PhantomData;
 
 /// Any query that can have a WHERE clause attached to it
 pub trait Filterable<'r, 'q>: Resolvable<'r, 'q, Self::Table>
@@ -29,15 +29,19 @@ where
         }
     }
 
-    fn by_id<I: EntityID<Entity = Self::Table>>(self, given: &'r I) -> Filter<'r, 'q, Self, <Self::Table as Entity>::IDColumn, I>
-        where Self: Sized {
-
+    fn by_id<I: EntityID<Entity = Self::Table>>(
+        self,
+        given: &'r I,
+    ) -> Filter<'r, 'q, Self, <Self::Table as Entity>::IDColumn, I>
+    where
+        Self: Sized,
+    {
         Filter {
             wrap: self,
             col: Self::Table::id_column(),
             op: CompareOp::Equals,
             given,
-            _ghost: PhantomData
+            _ghost: PhantomData,
         }
     }
 
@@ -45,7 +49,7 @@ where
         self,
         col: C,
         op: CompareOp,
-        given: &'r G
+        given: &'r G,
     ) -> Filter<'r, 'q, Self, C, G>
     where
         Self: Sized,
@@ -87,9 +91,10 @@ where
     'q: 'r,
 {
     fn derive(&self) -> DerivedQuery {
-        self.wrap
-            .derive()
-            .add(QueryPart::Where, format!("{} {} ?", self.col.name(), self.op.ch()))
+        self.wrap.derive().add(
+            QueryPart::Where,
+            format!("{} {} ?", self.col.name(), self.op.ch()),
+        )
     }
 
     fn contribute<H: Hasher>(&self, hasher: &mut H) {
@@ -126,4 +131,3 @@ where
 {
     type Table = C::Entity;
 }
-

+ 19 - 4
microrm/src/query/resolve.rs

@@ -1,4 +1,4 @@
-use crate::{Entity,WithID,QueryInterface};
+use crate::{Entity, QueryInterface, WithID};
 use std::hash::Hasher;
 
 /// Any query that can be completed/executed
@@ -8,9 +8,24 @@ where
 {
     fn qi(&self) -> &'r QueryInterface<'q>;
 
-    fn exec(self) -> Result<(), crate::Error> where Self: Sized { self.no_result() }
-    fn one(self) -> Result<Option<WithID<T>>, crate::Error> where Self: Sized { self.result() }
-    fn all(self) -> Result<Vec<WithID<T>>, crate::Error> where Self: Sized { self.results() }
+    fn exec(self) -> Result<(), crate::Error>
+    where
+        Self: Sized,
+    {
+        self.no_result()
+    }
+    fn one(self) -> Result<Option<WithID<T>>, crate::Error>
+    where
+        Self: Sized,
+    {
+        self.result()
+    }
+    fn all(self) -> Result<Vec<WithID<T>>, crate::Error>
+    where
+        Self: Sized,
+    {
+        self.results()
+    }
 
     fn no_result(self) -> Result<(), crate::Error>
     where

+ 4 - 4
microrm/src/query/select.rs

@@ -1,8 +1,8 @@
+use super::build::{DerivedQuery, QueryComponent, QueryPart, StaticVersion};
+use super::{Filterable, Resolvable};
+use crate::{Entity, Error, QueryInterface};
+use std::hash::{Hash, Hasher};
 use std::marker::PhantomData;
-use std::hash::{Hash,Hasher};
-use crate::{Entity,QueryInterface,Error};
-use super::build::{QueryComponent,StaticVersion,DerivedQuery,QueryPart};
-use super::{Filterable,Resolvable};
 
 pub struct Select<'r, 'q, T: Entity> {
     qi: &'r QueryInterface<'q>,

+ 70 - 32
microrm/src/query/update.rs

@@ -1,10 +1,10 @@
-use std::marker::PhantomData;
-use std::hash::{Hash,Hasher};
-use crate::{Entity,QueryInterface,Error};
-use super::build::{QueryComponent,StaticVersion,DerivedQuery,QueryPart};
-use super::{Filterable,Resolvable};
+use super::build::{DerivedQuery, QueryComponent, QueryPart, StaticVersion};
+use super::{Filterable, Resolvable};
 use crate::entity::EntityColumn;
 use crate::model::Modelable;
+use crate::{Entity, Error, QueryInterface};
+use std::hash::{Hash, Hasher};
+use std::marker::PhantomData;
 
 pub struct Update<'r, 'q, T: Entity> {
     qi: &'r QueryInterface<'q>,
@@ -20,10 +20,7 @@ impl<'r, 'q, T: Entity> Update<'r, 'q, T> {
     }
 
     pub fn to(self, to: &'r T) -> Entire<'r, 'q, T> {
-        Entire {
-            wrap: self,
-            to,
-        }
+        Entire { wrap: self, to }
     }
 }
 
@@ -40,10 +37,7 @@ impl<'r, 'q, T: Entity> StaticVersion for Update<'r, 'q, T> {
 
 impl<'r, 'q, T: Entity> QueryComponent for Update<'r, 'q, T> {
     fn derive(&self) -> DerivedQuery {
-        DerivedQuery::new().add(
-            QueryPart::Root,
-            format!("UPDATE {}", T::table_name()),
-        )
+        DerivedQuery::new().add(QueryPart::Root, format!("UPDATE {}", T::table_name()))
     }
 
     fn contribute<H: Hasher>(&self, hasher: &mut H) {
@@ -69,7 +63,7 @@ impl<'r, 'q, T: Entity> Resolvable<'r, 'q, T> for Update<'r, 'q, T> {
 
 pub struct Entire<'r, 'q, T: Entity> {
     wrap: Update<'r, 'q, T>,
-    to: &'r T
+    to: &'r T,
 }
 
 impl<'r, 'q, T: Entity> StaticVersion for Entire<'r, 'q, T> {
@@ -96,7 +90,7 @@ impl<'r, 'q, T: Entity> QueryComponent for Entire<'r, 'q, T> {
     fn bind(&self, stmt: &mut sqlite::Statement<'_>) -> Result<usize, Error> {
         let mut ind = self.wrap.bind(stmt)?;
 
-        self.to.visit_values::<Error,_>(&mut |val| {
+        self.to.visit_values::<Error, _>(&mut |val| {
             val.bind_to(stmt, ind)?;
             ind += 1;
             Ok(())
@@ -128,13 +122,13 @@ where
         given: &'r G,
     ) -> Set<'r, 'q, Self, C, G>
     where
-        Self: Sized
+        Self: Sized,
     {
         Set {
             wrap: self,
             col,
             given,
-            _ghost: PhantomData
+            _ghost: PhantomData,
         }
     }
 }
@@ -196,8 +190,8 @@ where
     }
 }
 
-impl<'r, 'q, S: Settable<'r, 'q>, C: EntityColumn, G: Modelable + ?Sized>
-    Settable<'r, 'q> for Set<'r, 'q, S, C, G>
+impl<'r, 'q, S: Settable<'r, 'q>, C: EntityColumn, G: Modelable + ?Sized> Settable<'r, 'q>
+    for Set<'r, 'q, S, C, G>
 where
     <S as StaticVersion>::Is: Settable<'static, 'static>,
     'q: 'r,
@@ -205,8 +199,8 @@ where
     type Table = C::Entity;
 }
 
-impl<'r, 'q, S: Settable<'r, 'q>, C: EntityColumn, G: Modelable + ?Sized>
-    Filterable<'r, 'q> for Set<'r, 'q, S, C, G>
+impl<'r, 'q, S: Settable<'r, 'q>, C: EntityColumn, G: Modelable + ?Sized> Filterable<'r, 'q>
+    for Set<'r, 'q, S, C, G>
 where
     <S as StaticVersion>::Is: Settable<'static, 'static>,
     'q: 'r,
@@ -217,23 +211,55 @@ where
 #[cfg(test)]
 mod test {
     use crate::prelude::*;
-    use crate::test_support::KVStore;
     use crate::query::Resolvable;
+    use crate::test_support::KVStore;
 
     #[test]
     fn simple_update() {
         let db = crate::DB::new_in_memory(crate::Schema::new().entity::<KVStore>()).unwrap();
         let qi = db.query_interface();
 
-        qi.add(&KVStore { key: "key".into(), value: "value".into() }).unwrap();
-        qi.add(&KVStore { key: "key2".into(), value: "value2".into() }).unwrap();
-        qi.add(&KVStore { key: "key2".into(), value: "value2b".into() }).unwrap();
-
-        assert_eq!(qi.get().by(KVStore::Key, "key").one().unwrap().unwrap().value, "value");
+        qi.add(&KVStore {
+            key: "key".into(),
+            value: "value".into(),
+        })
+        .unwrap();
+        qi.add(&KVStore {
+            key: "key2".into(),
+            value: "value2".into(),
+        })
+        .unwrap();
+        qi.add(&KVStore {
+            key: "key2".into(),
+            value: "value2b".into(),
+        })
+        .unwrap();
+
+        assert_eq!(
+            qi.get()
+                .by(KVStore::Key, "key")
+                .one()
+                .unwrap()
+                .unwrap()
+                .value,
+            "value"
+        );
         assert_eq!(qi.get().by(KVStore::Key, "key2").all().unwrap().len(), 2);
 
-        qi.update().update(KVStore::Value, "newvalue").by(KVStore::Key, "key").exec().unwrap();
-        assert_eq!(qi.get().by(KVStore::Key, "key").one().unwrap().unwrap().value, "newvalue");
+        qi.update()
+            .update(KVStore::Value, "newvalue")
+            .by(KVStore::Key, "key")
+            .exec()
+            .unwrap();
+        assert_eq!(
+            qi.get()
+                .by(KVStore::Key, "key")
+                .one()
+                .unwrap()
+                .unwrap()
+                .value,
+            "newvalue"
+        );
     }
 
     #[test]
@@ -241,14 +267,26 @@ mod test {
         let db = crate::DB::new_in_memory(crate::Schema::new().entity::<KVStore>()).unwrap();
         let qi = db.query_interface();
 
-        let id = qi.add(&KVStore { key: "a".into(), value: "b".into() }).unwrap();
+        let id = qi
+            .add(&KVStore {
+                key: "a".into(),
+                value: "b".into(),
+            })
+            .unwrap();
 
         let check = qi.get().by(KVStore::ID, &id).all().unwrap();
         assert_eq!(check.len(), 1);
         assert_eq!(check[0].key, "a");
         assert_eq!(check[0].value, "b");
-        
-        qi.update().to(&KVStore { key: "c".into(), value: "d".into() }).by(KVStore::ID, &id).exec().unwrap();
+
+        qi.update()
+            .to(&KVStore {
+                key: "c".into(),
+                value: "d".into(),
+            })
+            .by(KVStore::ID, &id)
+            .exec()
+            .unwrap();
 
         let check = qi.get().by(KVStore::ID, &id).all().unwrap();
         assert_eq!(check.len(), 1);