Explorar o código

Add explicit ID column to each Entity.

Kestrel %!s(int64=2) %!d(string=hai) anos
pai
achega
25ef8ae28a
Modificáronse 4 ficheiros con 24 adicións e 24 borrados
  1. 4 1
      microrm-macros/src/lib.rs
  2. 4 2
      microrm/src/lib.rs
  3. 7 7
      microrm/src/model/create.rs
  4. 9 14
      microrm/src/query.rs

+ 4 - 1
microrm-macros/src/lib.rs

@@ -81,6 +81,7 @@ pub fn derive_entity(tokens: TokenStream) -> TokenStream {
         #[derive(Clone,Copy)]
         #[allow(unused)]
         pub enum #enum_name {
+            ID,
             #variants
         }
 
@@ -112,13 +113,15 @@ pub fn derive_entity(tokens: TokenStream) -> TokenStream {
 
             fn table_name() -> &'static str { #table_name }
             fn column_count() -> usize {
-                #field_count
+                // +1 for ID column
+                #field_count + 1
             }
             fn index(c: Self::Column) -> usize {
                 c as usize
             }
             fn name(c: Self::Column) -> &'static str {
                 match c {
+                    Self::Column::ID => "ID",
                     #field_names
                 }
             }

+ 4 - 2
microrm/src/lib.rs

@@ -171,7 +171,7 @@ impl DB {
                 .map_err(|_| DBError::CreateFailure)?;
         }
 
-        query::add(
+        let add_result = query::add(
             self,
             &meta::Metaschema {
                 key: "schema_hash".to_string(),
@@ -179,6 +179,8 @@ impl DB {
             },
         );
 
+        assert!(add_result.is_some());
+
         let sanity_check = query::get_one_by(self, meta::MetaschemaColumns::Key, "schema_hash");
         assert!(sanity_check.is_some());
         assert_eq!(sanity_check.unwrap().value, self.schema_hash);
@@ -194,7 +196,7 @@ mod test {
     #[derive(serde::Serialize, serde::Deserialize, crate::Entity)]
     #[microrm_internal]
     pub struct S1 {
-        id: i32,
+        an_id: i32,
     }
 
     fn simple_schema() -> super::model::SchemaModel {

+ 7 - 7
microrm/src/model/create.rs

@@ -163,14 +163,14 @@ pub fn sql_for<T: crate::model::Entity>() -> (String, String) {
             <T as crate::model::Entity>::table_name()
         ),
         format!(
-            "CREATE TABLE \"{}\" ({})",
+            "CREATE TABLE \"{}\" (id integer primary key{})",
             <T as crate::model::Entity>::table_name(),
             cd.column_names
                 .iter()
                 .zip(cd.column_types.iter())
-                .map(|(n, t)| format!("\"{}\" {}", n, t))
+                .map(|(n, t)| format!(", \"{}\" {}", n, t))
                 .collect::<Vec<_>>()
-                .join(",")
+                .join("")
         ),
     )
 }
@@ -201,14 +201,14 @@ mod test {
             super::sql_for::<Empty>(),
             (
                 r#"DROP TABLE IF EXISTS "empty""#.to_owned(),
-                r#"CREATE TABLE "empty" ()"#.to_owned()
+                r#"CREATE TABLE "empty" (id integer primary key)"#.to_owned()
             )
         );
         assert_eq!(
             super::sql_for::<Single>(),
             (
                 r#"DROP TABLE IF EXISTS "single""#.to_owned(),
-                r#"CREATE TABLE "single" ("e" integer)"#.to_owned()
+                r#"CREATE TABLE "single" (id integer primary key, "e" integer)"#.to_owned()
             )
         );
 
@@ -216,7 +216,7 @@ mod test {
             super::sql_for::<Reference>(),
             (
                 r#"DROP TABLE IF EXISTS "reference""#.to_owned(),
-                r#"CREATE TABLE "reference" ("e" integer)"#.to_owned()
+                r#"CREATE TABLE "reference" (id integer primary key, "e" integer)"#.to_owned()
             )
         );
     }
@@ -236,7 +236,7 @@ mod test {
             super::sql_for::<UnitNewtype>(),
             (
                 r#"DROP TABLE IF EXISTS "unit_newtype""#.to_owned(),
-                r#"CREATE TABLE "unit_newtype" ("newtype" integer)"#.to_owned()
+                r#"CREATE TABLE "unit_newtype" (id integer primary key, "newtype" integer)"#.to_owned()
             )
         );
     }

+ 9 - 14
microrm/src/query.rs

@@ -47,12 +47,6 @@ impl<T: Entity> std::ops::DerefMut for WithID<T> {
     }
 }
 
-/*impl<T: Entity> std::convert::Into<T> for WithID<T> {
-    fn into(self) -> T {
-        self.wrap
-    }
-}*/
-
 /// Search for an entity by a property
 pub fn get_one_by<T: Entity<Column = C>, C: EntityColumns<Entity = T>, V: rusqlite::ToSql>(
     db: &DB,
@@ -61,10 +55,11 @@ pub fn get_one_by<T: Entity<Column = C>, C: EntityColumns<Entity = T>, V: rusqli
 ) -> Option<WithID<T>> {
     let table_name = <T as Entity>::table_name();
     let column_name = <T as Entity>::name(c);
+
     let mut prepared = db
         .conn
         .prepare(&format!(
-            "SELECT rowid, tbl.* FROM \"{}\" tbl WHERE \"{}\" = ?1",
+            "SELECT * FROM \"{}\" WHERE \"{}\" = ?1",
             table_name, column_name
         ))
         .ok()?;
@@ -73,7 +68,7 @@ pub fn get_one_by<T: Entity<Column = C>, C: EntityColumns<Entity = T>, V: rusqli
         let mut deser = crate::model::load::RowDeserializer::from_row(row);
         Ok(WithID::wrap(
             T::deserialize(&mut deser).expect("deserialization works"),
-            row.get(0).expect("can get rowid"),
+            row.get(0).expect("can get id"),
         ))
     });
 
@@ -92,7 +87,7 @@ pub fn get_all_by<T: Entity<Column = C>, C: EntityColumns<Entity = T>, V: rusqli
     let mut prepared = db
         .conn
         .prepare(&format!(
-            "SELECT rowid, tbl.* FROM \"{}\" tbl WHERE \"{}\" = ?1",
+            "SELECT * FROM \"{}\" WHERE \"{}\" = ?1",
             table_name, column_name
         ))
         .ok()?;
@@ -116,7 +111,7 @@ pub fn get_one_by_id<T: Entity>(db: &DB, id: <T as Entity>::ID) -> Option<WithID
     let mut prepared = db
         .conn
         .prepare(&format!(
-            "SELECT rowid, tbl.* FROM \"{}\" tbl WHERE rowid = ?1",
+            "SELECT * FROM \"{}\" WHERE id = ?1",
             table_name
         ))
         .ok()?;
@@ -136,20 +131,20 @@ pub fn get_one_by_id<T: Entity>(db: &DB, id: <T as Entity>::ID) -> Option<WithID
 pub fn add<T: Entity + serde::Serialize>(db: &DB, m: &T) -> Option<<T as Entity>::ID> {
     let row = crate::model::store::serialize_as_row(m);
 
-    let placeholders = (0..<T as Entity>::column_count())
+    let placeholders = (0..(<T as Entity>::column_count()-1))
         .map(|n| format!("?{}", n + 1))
         .collect::<Vec<_>>()
         .join(",");
 
     let res = db.conn.prepare(&format!(
-        "INSERT INTO \"{}\" VALUES ({})",
+        "INSERT INTO \"{}\" VALUES (NULL, {})",
         <T as Entity>::table_name(),
         placeholders
     ));
     let mut prepared = res.ok()?;
 
-    // make sure we bound enough things
-    assert_eq!(row.len(), <T as Entity>::column_count());
+    // make sure we bound enough things (not including ID column here)
+    assert_eq!(row.len(), <T as Entity>::column_count() - 1);
 
     let id = prepared.insert(rusqlite::params_from_iter(row)).ok()?;
     Some(<T as Entity>::ID::from_raw_id(id))