Ver Fonte

Added way of updating entire Entity at once.

Kestrel há 2 anos atrás
pai
commit
2084306e08

+ 1 - 18
Cargo.lock

@@ -355,31 +355,14 @@ dependencies = [
 
 [[package]]
 name = "microrm-macros"
-version = "0.2.1"
+version = "0.2.3"
 dependencies = [
  "convert_case",
- "nom",
  "proc-macro2",
  "quote",
  "syn",
 ]
 
-[[package]]
-name = "minimal-lexical"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
-
-[[package]]
-name = "nom"
-version = "7.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
-dependencies = [
- "memchr",
- "minimal-lexical",
-]
-
 [[package]]
 name = "num-traits"
 version = "0.2.15"

+ 1 - 1
microrm-macros/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = "microrm-macros"
-version = "0.2.2"
+version = "0.2.3"
 edition = "2021"
 license = "BSD-4-Clause"
 authors = ["Kestrel <kestrel@flying-kestrel.ca>"]

+ 1 - 1
microrm-macros/src/entity.rs

@@ -95,7 +95,7 @@ fn derive_columns<'a, I: Iterator<Item = &'a syn::Field>>(
         #(#column_impls)*
 
         impl #struct_name {
-            const ID : #columns_name::ID = #columns_name::ID();
+            pub const ID : #columns_name::ID = #columns_name::ID();
             #(#column_consts)*
         }
 

+ 1 - 1
microrm/Cargo.toml

@@ -17,7 +17,7 @@ serde_bytes = { version = "0.11.6" }
 serde_json = { version = "1.0" }
 lazy_static = { version = "1.4.0" }
 
-microrm-macros = { path = "../microrm-macros", version = "0.2.2" }
+microrm-macros = { path = "../microrm-macros", version = "0.2.3" }
 
 [dev-dependencies]
 criterion = "0.3"

+ 1 - 0
microrm/src/entity.rs

@@ -9,6 +9,7 @@ pub trait Entity: 'static + for<'de> serde::Deserialize<'de> + serde::Serialize
         Self: Sized;
     fn columns() -> &'static [&'static dyn EntityColumn<Entity = Self>];
     fn values(&self) -> Vec<&dyn Modelable>;
+    // TODO: visit_values() to avoid heap allocation
 
     fn build_from(stmt: &sqlite::Statement) -> sqlite::Result<Self>
     where

+ 81 - 2
microrm/src/query/update.rs

@@ -19,6 +19,13 @@ impl<'r, 'q, T: Entity> Update<'r, 'q, T> {
         }
     }
 
+    // pub fn entire(&self, to: &T) -> Entire<'r, 'q, T>impl Filterable<'r, 'q, Table = T> {
+    pub fn to(self, to: &'r T) -> Entire<'r, 'q, T> {
+        Entire {
+            wrap: self,
+            to,
+        }
+    }
 }
 
 impl<'r, 'q, T: Entity> Settable<'r, 'q> for Update<'r, 'q, T>
@@ -45,7 +52,7 @@ impl<'r, 'q, T: Entity> QueryComponent for Update<'r, 'q, T> {
         std::any::TypeId::of::<T>().hash(hasher);
     }
 
-    // next binding point is the first
+    // next binding point is the first, we do nothing here
     fn bind(&self, _stmt: &mut sqlite::Statement<'_>) -> Result<usize, Error> {
         Ok(1)
     }
@@ -61,6 +68,58 @@ 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
+}
+
+impl<'r, 'q, T: Entity> StaticVersion for Entire<'r, 'q, T> {
+    type Is = Entire<'static, 'static, T>;
+}
+
+impl<'r, 'q, T: Entity> QueryComponent for Entire<'r, 'q, T> {
+    fn derive(&self) -> DerivedQuery {
+        let mut dq = self.wrap.derive();
+
+        // skip ID column
+        let cols = T::columns();
+        for column in &cols[1..] {
+            dq = dq.add(QueryPart::Set, format!("{} = ?", column.name()));
+        }
+        dq
+    }
+
+    fn contribute<H: Hasher>(&self, hasher: &mut H) {
+        self.wrap.contribute(hasher);
+        std::any::TypeId::of::<Self::Is>().hash(hasher);
+    }
+
+    fn bind(&self, stmt: &mut sqlite::Statement<'_>) -> Result<usize, Error> {
+        let ind = self.wrap.bind(stmt)?;
+
+        let values = self.to.values();
+
+        // skip ID
+        for col in 0..T::column_count()-1 {
+            println!("col: {}", col);
+            values[col].bind_to(stmt, ind + col)?;
+        }
+
+        println!("bound!");
+        Ok(ind + T::column_count() - 1)
+    }
+}
+
+impl<'r, 'q, T: Entity> Resolvable<'r, 'q, T> for Entire<'r, 'q, T> {
+    fn qi(&self) -> &'r QueryInterface<'q> {
+        self.wrap.qi
+    }
+}
+
+impl<'r, 'q, T: Entity> Filterable<'r, 'q> for Entire<'r, 'q, T> {
+    type Table = T;
+}
+
 pub trait Settable<'r, 'q>: Resolvable<'r, 'q, Self::Table>
 where
     'q: 'r,
@@ -84,7 +143,6 @@ where
     }
 }
 
-
 /// A concrete SET clause
 pub struct Set<'r, 'q, S: Settable<'r, 'q>, C: EntityColumn, G: Modelable + ?Sized>
 where
@@ -164,6 +222,7 @@ where
 mod test {
     use crate::prelude::*;
     use crate::test_support::KVStore;
+    use crate::query::Resolvable;
 
     #[test]
     fn simple_update() {
@@ -180,4 +239,24 @@ mod test {
         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]
+    fn swapout() {
+        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 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();
+
+        let check = qi.get().by(KVStore::ID, &id).all().unwrap();
+        assert_eq!(check.len(), 1);
+        assert_eq!(check[0].key, "c");
+        assert_eq!(check[0].value, "d");
+    }
 }