Jelajahi Sumber

Escape table and column names in generated SQL.

Kestrel 2 tahun lalu
induk
melakukan
0c11845ce4
4 mengubah file dengan 31 tambahan dan 27 penghapusan
  1. 4 2
      microrm/src/lib.rs
  2. 11 8
      microrm/src/model/create.rs
  3. 7 1
      microrm/src/model/load.rs
  4. 9 16
      microrm/src/query.rs

+ 4 - 2
microrm/src/lib.rs

@@ -32,6 +32,10 @@ impl DB {
         )
     }
 
+    pub fn recreate_schema(&self) -> Result<(), &'static str> {
+        self.create_schema()
+    }
+
     fn from_connection(
         conn: rusqlite::Connection,
         schema: model::SchemaModel,
@@ -72,9 +76,7 @@ impl DB {
             if !allow_recreate {
                 return Err("No schema version in database, and not allowed to create!")
             }
-            println!("Failed to retrieve schema; probably is empty database");
             self.create_schema();
-
         }
 
         Ok(())

+ 11 - 8
microrm/src/model/create.rs

@@ -64,7 +64,10 @@ impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut CreateDeserializer<'de> {
         fields: &'static [&'static str],
         v: V,
     ) -> Result<V::Value, Self::Error> {
-        self.column_name_stack.extend(fields.iter().map(|x| x.to_string()).rev());
+        // we may not have a prefix if this is the root struct
+        // but if we do, it means we're serializing a sub-structure
+        let prefix = self.column_name_stack.pop().map(|x| x + "_").unwrap_or("".to_string());
+        self.column_name_stack.extend(fields.iter().map(|x| prefix.clone() + x).rev());
         v.visit_seq(self)
     }
 
@@ -100,16 +103,16 @@ pub fn sql_for<T: crate::model::Entity>() -> (String, String) {
 
     (
         format!(
-            "DROP TABLE IF EXISTS {}",
+            "DROP TABLE IF EXISTS \"{}\"",
             <T as crate::model::Entity>::table_name()
         ),
         format!(
-            "CREATE TABLE {} ({})",
+            "CREATE TABLE \"{}\" ({})",
             <T as crate::model::Entity>::table_name(),
             cd.column_names
                 .iter()
                 .zip(cd.column_types.iter())
-                .map(|(n, t)| n.to_string() + " " + t)
+                .map(|(n, t)| format!("\"{}\" {}", n, t))
                 .collect::<Vec<_>>()
                 .join(",")
         ),
@@ -131,15 +134,15 @@ mod test {
         assert_eq!(
             super::sql_for::<Empty>(),
             (
-                "DROP TABLE IF EXISTS empty".to_owned(),
-                "CREATE TABLE empty ()".to_owned()
+                r#"DROP TABLE IF EXISTS "empty"#.to_owned(),
+                r#"CREATE TABLE "empty" ()"#.to_owned()
             )
         );
         assert_eq!(
             super::sql_for::<Single>(),
             (
-                "DROP TABLE IF EXISTS single".to_owned(),
-                "CREATE TABLE single (e integer)".to_owned()
+                r#"DROP TABLE IF EXISTS "single""#.to_owned(),
+                r#"CREATE TABLE "single" ("e" integer)"#.to_owned()
             )
         );
     }

+ 7 - 1
microrm/src/model/load.rs

@@ -57,6 +57,12 @@ impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut RowDeserializer<'de> {
         res
     }
 
+    fn deserialize_byte_buf<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Self::Error> {
+        let res = v.visit_byte_buf(self.row.get(self.col_index)?);
+        self.col_index += 1;
+        res
+    }
+
     fn deserialize_struct<V: Visitor<'de>>(
         self,
         _name: &'static str,
@@ -68,7 +74,7 @@ impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut RowDeserializer<'de> {
 
     serde::forward_to_deserialize_any! {
         i128 u8 u16 u32 u64 u128 f32 f64 char str
-        bytes byte_buf option unit unit_struct newtype_struct seq tuple
+        bytes option unit unit_struct newtype_struct seq tuple
         tuple_struct map enum identifier ignored_any
     }
 }

+ 9 - 16
microrm/src/query.rs

@@ -2,14 +2,7 @@ use crate::DB;
 
 pub mod condition;
 
-#[derive(Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
-pub struct ID { id: i64 }
-
-impl rusqlite::ToSql for ID {
-    fn to_sql(&self) -> Result<rusqlite::types::ToSqlOutput<'_>, rusqlite::Error> {
-        self.id.to_sql()
-    }
-}
+pub type ID = i64;
 
 #[derive(Debug)]
 pub struct WithID<T: crate::model::Entity> {
@@ -21,7 +14,7 @@ impl<T: crate::model::Entity> WithID<T> {
     fn wrap(what: T, raw_id: i64) -> Self {
         Self {
             wrap: what,
-            id: ID { id: raw_id }
+            id: raw_id
         }
     }
 }
@@ -62,7 +55,7 @@ pub fn get_one_by<T: crate::model::Entity<Column = C>, C: crate::model::EntityCo
     let mut prepared = db
         .conn
         .prepare(&format!(
-            "SELECT rowid, tbl.* FROM {} tbl WHERE {} = ?1",
+            "SELECT rowid, tbl.* FROM \"{}\" tbl WHERE \"{}\" = ?1",
             table_name, column_name
         ))
         .ok()?;
@@ -86,13 +79,13 @@ pub fn get_all_by<T: crate::model::Entity<Column = C>, C: crate::model::EntityCo
 
     let table_name = <T as crate::model::Entity>::table_name();
     let column_name = <T as crate::model::Entity>::name(c);
+
     let mut prepared = db
         .conn
         .prepare(&format!(
-            "SELECT rowid, tbl.* FROM {} tbl WHERE {} = ?1",
+            "SELECT rowid, tbl.* FROM \"{}\" tbl WHERE \"{}\" = ?1",
             table_name, column_name
-        ))
-        .ok()?;
+        )).ok()?;
 
     let rows = prepared.query_map([&val], |row| {
         let mut deser = crate::model::load::RowDeserializer::from_row(row);
@@ -114,7 +107,7 @@ pub fn get_one_by_id<T: crate::model::Entity>(
     let mut prepared = db
         .conn
         .prepare(&format!(
-            "SELECT rowid, tbl.* FROM {} tbl WHERE rowid = ?1",
+            "SELECT rowid, tbl.* FROM \"{}\" tbl WHERE rowid = ?1",
             table_name
         ))
         .ok()?;
@@ -140,7 +133,7 @@ pub fn add<T: crate::model::Entity + serde::Serialize>(db: &DB, m: &T) -> Option
         .join(",");
 
     let res = db.conn.prepare(&format!(
-        "INSERT INTO {} VALUES ({})",
+        "INSERT INTO \"{}\" VALUES ({})",
         <T as crate::model::Entity>::table_name(),
         placeholders
     ));
@@ -150,5 +143,5 @@ pub fn add<T: crate::model::Entity + serde::Serialize>(db: &DB, m: &T) -> Option
     assert_eq!(row.len(), <T as crate::model::Entity>::column_count());
 
     let id = prepared.insert(rusqlite::params_from_iter(row)).ok()?;
-    Some(ID {id})
+    Some(id)
 }