Переглянути джерело

Fix tests, add extra use of backquotes, add ID-only queries.

Kestrel 1 рік тому
батько
коміт
bfd6f7b26a

+ 1 - 0
Cargo.toml

@@ -1,2 +1,3 @@
 [workspace]
+resolver = "2"
 members = ["microrm", "microrm-macros"]

+ 1 - 1
microrm/benches/simple_in_memory.rs

@@ -1,6 +1,6 @@
 use criterion::{black_box, criterion_group, criterion_main, Criterion};
 
-use microrm::{make_index, Entity, prelude::*};
+use microrm::{make_index, prelude::*, Entity};
 use rand::prelude::*;
 use serde::{Deserialize, Serialize};
 

+ 44 - 20
microrm/src/lib.rs

@@ -292,7 +292,10 @@ mod test_support {
         let dist = rand::distributions::Uniform::new('a', 'z');
         let mut db_filename = std::env::temp_dir();
         let mut rng = rand::thread_rng();
-        db_filename.push(format!("microrm-{}.db", (0..16).map(|_| dist.sample(&mut rng)).collect::<String>()));
+        db_filename.push(format!(
+            "microrm-{}.db",
+            (0..16).map(|_| dist.sample(&mut rng)).collect::<String>()
+        ));
         db_filename
     }
 }
@@ -459,7 +462,7 @@ mod delete_test {
 mod datatypes {
     use crate::prelude::*;
 
-    #[derive(crate::Entity,serde::Serialize,serde::Deserialize,PartialEq,Debug)]
+    #[derive(crate::Entity, serde::Serialize, serde::Deserialize, PartialEq, Debug)]
     #[microrm_internal]
     pub struct ValueStore {
         pub b: bool,
@@ -475,7 +478,6 @@ mod datatypes {
         pub f_64: f64,
     }
 
-
     #[test]
     fn store_load_datatypes() {
         let schema = crate::Schema::new().entity::<ValueStore>();
@@ -493,12 +495,20 @@ mod datatypes {
             u_64: 3u64 << 62,
             s: "this is a test".to_string(),
             // e**pi
-            f_64: 23.140692632779263f64
+            f_64: 23.140692632779263f64,
         };
 
-        let id = db.query_interface().add(&test_values).expect("failed to add ValueStore");
-
-        let all = db.query_interface().get().by_id(&id).all().expect("failed to get by id");
+        let id = db
+            .query_interface()
+            .add(&test_values)
+            .expect("failed to add ValueStore");
+
+        let all = db
+            .query_interface()
+            .get()
+            .by_id(&id)
+            .all()
+            .expect("failed to get by id");
         assert_eq!(all.len(), 1);
         assert_eq!(all[0].as_ref(), &test_values);
     }
@@ -516,19 +526,26 @@ mod disk_tests {
 
         {
             let schema = crate::Schema::new().entity::<crate::test_support::KVStore>();
-            let db = crate::DB::new(schema, &path_str, crate::CreateMode::AllowNewDatabase).unwrap();
-
-            db.query_interface().add(&crate::test_support::KVStore {
-                key: "key".into(),
-                value: "val".into()
-            }).expect("couldn't add");
+            let db =
+                crate::DB::new(schema, &path_str, crate::CreateMode::AllowNewDatabase).unwrap();
+
+            db.query_interface()
+                .add(&crate::test_support::KVStore {
+                    key: "key".into(),
+                    value: "val".into(),
+                })
+                .expect("couldn't add");
         }
 
         {
             let schema = crate::Schema::new().entity::<crate::test_support::KVStore>();
             let db = crate::DB::new(schema, &path_str, crate::CreateMode::MustExist).unwrap();
 
-            let all = db.query_interface().get::<crate::test_support::KVStore>().all().expect("couldn't get all kv");
+            let all = db
+                .query_interface()
+                .get::<crate::test_support::KVStore>()
+                .all()
+                .expect("couldn't get all kv");
 
             assert_eq!(all.len(), 1);
         }
@@ -543,13 +560,16 @@ mod disk_tests {
 
         {
             let schema = crate::Schema::new().entity::<crate::test_support::KVStore>();
-            let db = crate::DB::new(schema, &path_str, crate::CreateMode::AllowNewDatabase).unwrap();
+            let db =
+                crate::DB::new(schema, &path_str, crate::CreateMode::AllowNewDatabase).unwrap();
             let dbp = crate::DBPool::new(&db);
 
-            dbp.query_interface().add(&crate::test_support::KVStore {
-                key: "key".into(),
-                value: "val".into()
-            }).expect("couldn't add");
+            dbp.query_interface()
+                .add(&crate::test_support::KVStore {
+                    key: "key".into(),
+                    value: "val".into(),
+                })
+                .expect("couldn't add");
         }
 
         {
@@ -557,7 +577,11 @@ mod disk_tests {
             let db = crate::DB::new(schema, &path_str, crate::CreateMode::MustExist).unwrap();
             let dbp = crate::DBPool::new(&db);
 
-            let all = dbp.query_interface().get::<crate::test_support::KVStore>().all().expect("couldn't get all kv");
+            let all = dbp
+                .query_interface()
+                .get::<crate::test_support::KVStore>()
+                .all()
+                .expect("couldn't get all kv");
 
             assert_eq!(all.len(), 1);
         }

+ 1 - 1
microrm/src/model.rs

@@ -1,8 +1,8 @@
 pub(crate) mod store;
 
 // Modelable implementations
-mod modelable;
 mod json;
+mod modelable;
 
 pub use json::JsonWrapper;
 

+ 19 - 9
microrm/src/model/json.rs

@@ -1,15 +1,19 @@
 /// Wrapper struct to store a serializable object as JSON transparently in a text column
 pub struct JsonWrapper<T: serde::Serialize + serde::de::DeserializeOwned + 'static> {
-    wrap: T
+    wrap: T,
 }
 
-impl<T: serde::Serialize + serde::de::DeserializeOwned + 'static> serde::Serialize for JsonWrapper<T> {
+impl<T: serde::Serialize + serde::de::DeserializeOwned + 'static> serde::Serialize
+    for JsonWrapper<T>
+{
     fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
         self.wrap.serialize(serializer)
     }
 }
 
-impl<'de, T: serde::Serialize + serde::de::DeserializeOwned + 'static> serde::Deserialize<'de> for JsonWrapper<T> {
+impl<'de, T: serde::Serialize + serde::de::DeserializeOwned + 'static> serde::Deserialize<'de>
+    for JsonWrapper<T>
+{
     fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
         Ok(Self::wrap(T::deserialize(deserializer)?))
     }
@@ -43,9 +47,13 @@ impl<T: serde::Serialize + serde::de::DeserializeOwned + 'static> From<T> for Js
     }
 }
 
-impl<T: serde::Serialize + serde::de::DeserializeOwned + 'static> super::Modelable for JsonWrapper<T> {
+impl<T: serde::Serialize + serde::de::DeserializeOwned + 'static> super::Modelable
+    for JsonWrapper<T>
+{
     fn bind_to(&self, stmt: &mut sqlite::Statement, col: usize) -> sqlite::Result<()> {
-        serde_json::to_string(&self.wrap).unwrap().bind_to(stmt, col)
+        serde_json::to_string(&self.wrap)
+            .unwrap()
+            .bind_to(stmt, col)
     }
     fn build_from(stmt: &sqlite::Statement, col_offset: usize) -> sqlite::Result<(Self, usize)>
     where
@@ -53,10 +61,12 @@ impl<T: serde::Serialize + serde::de::DeserializeOwned + 'static> super::Modelab
     {
         let s = String::build_from(stmt, col_offset)?;
         Ok((
-            Self::wrap(serde_json::from_str::<T>(s.0.as_str()).map_err(|e| sqlite::Error {
-                code: None,
-                message: Some(e.to_string()),
-            })?),
+            Self::wrap(
+                serde_json::from_str::<T>(s.0.as_str()).map_err(|e| sqlite::Error {
+                    code: None,
+                    message: Some(e.to_string()),
+                })?,
+            ),
             1,
         ))
     }

+ 4 - 10
microrm/src/model/modelable.rs

@@ -64,7 +64,7 @@ impl Modelable for bool {
     where
         Self: Sized,
     {
-        stmt.read(col_offset).map(|x: i64| (x != 0,1))
+        stmt.read(col_offset).map(|x: i64| (x != 0, 1))
     }
     fn column_type() -> &'static str
     where
@@ -155,14 +155,9 @@ impl<'a, T: Modelable> Modelable for &'a T {
 
 impl<T: Modelable> Modelable for Option<T> {
     fn bind_to(&self, stmt: &mut sqlite::Statement, col: usize) -> sqlite::Result<()> {
-
         match self.as_ref() {
-            Some(val) => {
-                val.bind_to(stmt, col)
-            }
-            None => {
-                stmt.bind(col, &sqlite::Value::Null)
-            }
+            Some(val) => val.bind_to(stmt, col),
+            None => stmt.bind(col, &sqlite::Value::Null),
         }
     }
     fn build_from(stmt: &sqlite::Statement, col_offset: usize) -> sqlite::Result<(Self, usize)>
@@ -173,8 +168,7 @@ impl<T: Modelable> Modelable for Option<T> {
         let val = stmt.read::<sqlite::Value>(col_offset)?;
         if val.kind() == sqlite::Type::Null {
             Ok((None, 1))
-        }
-        else {
+        } else {
             let (val, size) = T::build_from(stmt, col_offset)?;
             Ok((Some(val), size))
         }

+ 23 - 2
microrm/src/query.rs

@@ -160,7 +160,7 @@ impl<'l> QueryInterface<'l> {
         std::any::TypeId::of::<T>().hash(&mut hasher);
         self.with_cache(
             hasher.finish(),
-            &|| {
+            || {
                 let placeholders = (0..(<T as Entity>::column_count() - 1))
                     .map(|_| "?".to_string())
                     .collect::<Vec<_>>()
@@ -218,7 +218,10 @@ impl<'l> QueryInterface<'l> {
 impl<'l> QueryInterface<'l> {
     /// Update an entity in its table, aka perform an `UPDATE` query, for all columns.
     pub fn put<T: Entity>(&self, what: &WithID<T>) -> Result<(), Error> {
-        self.update().to(what.as_ref()).by(T::id_column(), &what.id()).exec()
+        self.update()
+            .to(what.as_ref())
+            .by(T::id_column(), &what.id())
+            .exec()
     }
 }
 
@@ -242,4 +245,22 @@ mod test_build {
 
         assert!(qi.get().by(KVStore::Key, "abc").result().is_ok());
     }
+
+    #[test]
+    fn get_only_id() {
+        use super::*;
+        let db = crate::DB::new_in_memory(crate::Schema::new().entity::<KVStore>()).unwrap();
+        let qi = db.query_interface();
+
+        let id = qi
+            .add(&KVStore {
+                key: "abc".to_string(),
+                value: "def".to_string(),
+            })
+            .unwrap();
+
+        let search_result = qi.get().only_ids().by(KVStore::Key, "abc").id_result();
+        assert!(search_result.is_ok());
+        assert_eq!(search_result.unwrap(), Some(id));
+    }
 }

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

@@ -25,7 +25,7 @@ impl DerivedQuery {
     }
 
     pub(crate) fn add(mut self, to: QueryPart, what: String) -> Self {
-        self.0.entry(to).or_insert_with(Vec::new).push(what);
+        self.0.entry(to).or_default().push(what);
         self
     }
 
@@ -89,7 +89,7 @@ pub enum CompareOp {
     Equals,
     AtLeast,
     MoreThan,
-    NotEqual
+    NotEqual,
 }
 
 impl CompareOp {

+ 8 - 2
microrm/src/query/delete.rs

@@ -24,7 +24,10 @@ impl<'r, 'q, T: Entity> StaticVersion for Delete<'r, 'q, T> {
 
 impl<'r, 'q, T: Entity> QueryComponent for Delete<'r, 'q, T> {
     fn derive(&self) -> DerivedQuery {
-        DerivedQuery::new().add(QueryPart::Root, format!("DELETE FROM `{}`", T::table_name()))
+        DerivedQuery::new().add(
+            QueryPart::Root,
+            format!("DELETE FROM `{}`", T::table_name()),
+        )
     }
 
     fn contribute<H: Hasher>(&self, hasher: &mut H) {
@@ -39,10 +42,13 @@ impl<'r, 'q, T: Entity> QueryComponent for Delete<'r, 'q, T> {
 }
 
 impl<'r, 'q, T: Entity> Filterable<'r, 'q> for Delete<'r, 'q, T> {
+    type Output = ();
     type Table = T;
 }
 
-impl<'r, 'q, T: Entity> Resolvable<'r, 'q, T> for Delete<'r, 'q, T> {
+impl<'r, 'q, T: Entity> Resolvable<'r, 'q> for Delete<'r, 'q, T> {
+    type Output = ();
+
     fn qi(&self) -> &'r QueryInterface<'q> {
         self.qi
     }

+ 9 - 5
microrm/src/query/filter.rs

@@ -6,11 +6,12 @@ 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>
+pub trait Filterable<'r, 'q>: Resolvable<'r, 'q>
 where
     'q: 'r,
 {
     type Table: Entity;
+    type Output;
 
     fn by<C: EntityColumn<Entity = Self::Table>, G: Modelable + ?Sized>(
         self,
@@ -112,22 +113,25 @@ where
     }
 }
 
-impl<'r, 'q, F: Filterable<'r, 'q>, C: EntityColumn, G: Modelable + ?Sized>
-    Resolvable<'r, 'q, C::Entity> for Filter<'r, 'q, F, C, G>
+impl<'r, 'q, O, F: Filterable<'r, 'q, Output = O>, C: EntityColumn, G: Modelable + ?Sized>
+    Resolvable<'r, 'q> for Filter<'r, 'q, F, C, G>
 where
     <F as StaticVersion>::Is: Filterable<'static, 'static>,
     'q: 'r,
 {
+    type Output = O;
+
     fn qi(&self) -> &'r QueryInterface<'q> {
         self.wrap.qi()
     }
 }
 
-impl<'r, 'q, F: Filterable<'r, 'q>, C: EntityColumn, G: Modelable + ?Sized> Filterable<'r, 'q>
-    for Filter<'r, 'q, F, C, G>
+impl<'r, 'q, O, F: Filterable<'r, 'q, Output = O>, C: EntityColumn, G: Modelable + ?Sized>
+    Filterable<'r, 'q> for Filter<'r, 'q, F, C, G>
 where
     <F as StaticVersion>::Is: Filterable<'static, 'static>,
     'q: 'r,
 {
+    type Output = O;
     type Table = C::Entity;
 }

+ 81 - 8
microrm/src/query/resolve.rs

@@ -1,11 +1,13 @@
-use crate::{Entity, QueryInterface, WithID};
+use crate::{entity::EntityID, Entity, QueryInterface, WithID};
 use std::hash::Hasher;
 
 /// Any query that can be completed/executed
-pub trait Resolvable<'r, 'q, T: Entity>: super::build::QueryComponent
+pub trait Resolvable<'r, 'q>: super::build::QueryComponent
 where
     'q: 'r,
 {
+    type Output;
+
     fn qi(&self) -> &'r QueryInterface<'q>;
 
     fn exec(self) -> Result<(), crate::Error>
@@ -14,18 +16,34 @@ where
     {
         self.no_result()
     }
-    fn one(self) -> Result<Option<WithID<T>>, crate::Error>
+    fn one(self) -> Result<Option<WithID<Self::Output>>, crate::Error>
     where
         Self: Sized,
+        Self::Output: Entity,
     {
         self.result()
     }
-    fn all(self) -> Result<Vec<WithID<T>>, crate::Error>
+    fn one_id(self) -> Result<Option<Self::Output>, crate::Error>
     where
         Self: Sized,
+        Self::Output: EntityID,
+    {
+        self.id_result()
+    }
+    fn all(self) -> Result<Vec<WithID<Self::Output>>, crate::Error>
+    where
+        Self: Sized,
+        Self::Output: Entity,
     {
         self.results()
     }
+    fn all_ids(self) -> Result<Vec<Self::Output>, crate::Error>
+    where
+        Self: Sized,
+        Self::Output: EntityID,
+    {
+        self.id_results()
+    }
 
     fn no_result(self) -> Result<(), crate::Error>
     where
@@ -45,9 +63,34 @@ where
         )
     }
 
-    fn result(self) -> Result<Option<WithID<T>>, crate::Error>
+    fn result(self) -> Result<Option<WithID<Self::Output>>, crate::Error>
+    where
+        Self: Sized,
+        Self::Output: Entity,
+    {
+        let mut hasher = std::collections::hash_map::DefaultHasher::new();
+        self.contribute(&mut hasher);
+        self.qi().with_cache(
+            hasher.finish(),
+            || {
+                let query = self.derive().assemble();
+                self.qi().db.conn.prepare(query).unwrap()
+            },
+            |stmt| {
+                self.bind(stmt)?;
+
+                self.qi().expect_one_result(stmt, &mut |stmt| {
+                    let id: i64 = stmt.read(0)?;
+                    Ok(WithID::wrap(Self::Output::build_from(stmt)?, id))
+                })
+            },
+        )
+    }
+
+    fn id_result(self) -> Result<Option<Self::Output>, crate::Error>
     where
         Self: Sized,
+        Self::Output: EntityID,
     {
         let mut hasher = std::collections::hash_map::DefaultHasher::new();
         self.contribute(&mut hasher);
@@ -62,15 +105,45 @@ where
 
                 self.qi().expect_one_result(stmt, &mut |stmt| {
                     let id: i64 = stmt.read(0)?;
-                    Ok(WithID::wrap(T::build_from(stmt)?, id))
+                    Ok(Self::Output::from_raw_id(id))
                 })
             },
         )
     }
 
-    fn results(self) -> Result<Vec<WithID<T>>, crate::Error>
+    fn results(self) -> Result<Vec<WithID<Self::Output>>, crate::Error>
+    where
+        Self: Sized,
+        Self::Output: Entity,
+    {
+        let mut hasher = std::collections::hash_map::DefaultHasher::new();
+        self.contribute(&mut hasher);
+        self.qi().with_cache(
+            hasher.finish(),
+            || self.qi().db.conn.prepare(self.derive().assemble()).unwrap(),
+            |stmt| {
+                self.bind(stmt)?;
+
+                let mut res = Vec::new();
+                loop {
+                    let state = stmt.next()?;
+                    if state == sqlite::State::Done {
+                        break;
+                    }
+
+                    let id: i64 = stmt.read(0)?;
+                    res.push(WithID::wrap(Self::Output::build_from(stmt)?, id));
+                }
+
+                Ok(res)
+            },
+        )
+    }
+
+    fn id_results(self) -> Result<Vec<Self::Output>, crate::Error>
     where
         Self: Sized,
+        Self::Output: EntityID,
     {
         let mut hasher = std::collections::hash_map::DefaultHasher::new();
         self.contribute(&mut hasher);
@@ -88,7 +161,7 @@ where
                     }
 
                     let id: i64 = stmt.read(0)?;
-                    res.push(WithID::wrap(T::build_from(stmt)?, id));
+                    res.push(Self::Output::from_raw_id(id));
                 }
 
                 Ok(res)

+ 59 - 1
microrm/src/query/select.rs

@@ -16,6 +16,13 @@ impl<'r, 'q, T: Entity> Select<'r, 'q, T> {
             _ghost: std::marker::PhantomData,
         }
     }
+
+    pub fn only_ids(self) -> SelectID<'r, 'q, T> {
+        SelectID {
+            qi: self.qi,
+            _ghost: Default::default(),
+        }
+    }
 }
 
 impl<'r, 'q, T: Entity> StaticVersion for Select<'r, 'q, T> {
@@ -42,10 +49,61 @@ impl<'r, 'q, T: Entity> QueryComponent for Select<'r, 'q, T> {
 }
 
 impl<'r, 'q, T: Entity> Filterable<'r, 'q> for Select<'r, 'q, T> {
+    type Output = T;
+    type Table = T;
+}
+
+impl<'r, 'q, T: Entity> Resolvable<'r, 'q> for Select<'r, 'q, T> {
+    type Output = T;
+    fn qi(&self) -> &'r QueryInterface<'q> {
+        self.qi
+    }
+}
+
+pub struct SelectID<'r, 'q, T: Entity> {
+    qi: &'r QueryInterface<'q>,
+    _ghost: PhantomData<T>,
+}
+
+impl<'r, 'q, T: Entity> SelectID<'r, 'q, T> {
+    pub fn new(qi: &'r QueryInterface<'q>) -> Self {
+        Self {
+            qi,
+            _ghost: std::marker::PhantomData,
+        }
+    }
+}
+
+impl<'r, 'q, T: Entity> StaticVersion for SelectID<'r, 'q, T> {
+    type Is = SelectID<'static, 'static, T>;
+}
+
+impl<'r, 'q, T: Entity> QueryComponent for SelectID<'r, 'q, T> {
+    fn derive(&self) -> DerivedQuery {
+        DerivedQuery::new().add(
+            QueryPart::Root,
+            format!("SELECT `id` FROM `{}`", T::table_name()),
+        )
+    }
+
+    fn contribute<H: Hasher>(&self, hasher: &mut H) {
+        "select_id".hash(hasher);
+        std::any::TypeId::of::<T>().hash(hasher);
+    }
+
+    // next binding point is the first
+    fn bind(&self, _stmt: &mut sqlite::Statement<'_>) -> Result<usize, Error> {
+        Ok(1)
+    }
+}
+
+impl<'r, 'q, T: Entity> Filterable<'r, 'q> for SelectID<'r, 'q, T> {
+    type Output = T::ID;
     type Table = T;
 }
 
-impl<'r, 'q, T: Entity> Resolvable<'r, 'q, T> for Select<'r, 'q, T> {
+impl<'r, 'q, T: Entity> Resolvable<'r, 'q> for SelectID<'r, 'q, T> {
+    type Output = T::ID;
     fn qi(&self) -> &'r QueryInterface<'q> {
         self.qi
     }

+ 14 - 5
microrm/src/query/update.rs

@@ -52,10 +52,13 @@ impl<'r, 'q, T: Entity> QueryComponent for Update<'r, 'q, T> {
 }
 
 impl<'r, 'q, T: Entity> Filterable<'r, 'q> for Update<'r, 'q, T> {
+    type Output = ();
     type Table = T;
 }
 
-impl<'r, 'q, T: Entity> Resolvable<'r, 'q, T> for Update<'r, 'q, T> {
+impl<'r, 'q, T: Entity> Resolvable<'r, 'q> for Update<'r, 'q, T> {
+    type Output = ();
+
     fn qi(&self) -> &'r QueryInterface<'q> {
         self.qi
     }
@@ -100,17 +103,20 @@ impl<'r, 'q, T: Entity> QueryComponent for Entire<'r, 'q, T> {
     }
 }
 
-impl<'r, 'q, T: Entity> Resolvable<'r, 'q, T> for Entire<'r, 'q, T> {
+impl<'r, 'q, T: Entity> Resolvable<'r, 'q> for Entire<'r, 'q, T> {
+    type Output = ();
+
     fn qi(&self) -> &'r QueryInterface<'q> {
         self.wrap.qi
     }
 }
 
 impl<'r, 'q, T: Entity> Filterable<'r, 'q> for Entire<'r, 'q, T> {
+    type Output = ();
     type Table = T;
 }
 
-pub trait Settable<'r, 'q>: Resolvable<'r, 'q, Self::Table>
+pub trait Settable<'r, 'q>: Resolvable<'r, 'q>
 where
     'q: 'r,
 {
@@ -179,12 +185,14 @@ where
     }
 }
 
-impl<'r, 'q, S: Settable<'r, 'q>, C: EntityColumn, G: Modelable + ?Sized>
-    Resolvable<'r, 'q, C::Entity> for Set<'r, 'q, S, C, G>
+impl<'r, 'q, S: Settable<'r, 'q>, C: EntityColumn, G: Modelable + ?Sized> Resolvable<'r, 'q>
+    for Set<'r, 'q, S, C, G>
 where
     <S as StaticVersion>::Is: Settable<'static, 'static>,
     'q: 'r,
 {
+    type Output = ();
+
     fn qi(&self) -> &'r QueryInterface<'q> {
         self.wrap.qi()
     }
@@ -205,6 +213,7 @@ where
     <S as StaticVersion>::Is: Settable<'static, 'static>,
     'q: 'r,
 {
+    type Output = ();
     type Table = C::Entity;
 }
 

+ 24 - 24
microrm/src/schema/create.rs

@@ -3,17 +3,17 @@ use crate::entity::{Entity, Index};
 pub fn sql_for_table<T: Entity>() -> (String, String) {
     let all_columns = T::columns();
 
-    let mut columns = vec!["id integer primary key".to_owned()];
+    let mut columns = vec!["`id` integer primary key".to_owned()];
 
     // skip the id column type
     for col in all_columns.iter().skip(1) {
         columns.push(format!(
-            "\"{}\" {}{}",
+            "`{}` {}{}",
             col.name(),
             col.sql_type(),
             if col.fk_table_name().is_some() {
                 format!(
-                    " REFERENCES \"{}\"(\"{}\") ON DELETE CASCADE",
+                    " REFERENCES `{}`(`{}`) ON DELETE CASCADE",
                     col.fk_table_name().unwrap(),
                     col.fk_column_name().unwrap()
                 )
@@ -35,15 +35,15 @@ pub fn sql_for_table<T: Entity>() -> (String, String) {
 
 pub fn sql_for_index<I: Index>() -> (String, String) {
     (
-        format!("DROP INDEX IF EXISTS \"{}\"", I::index_name()),
+        format!("DROP INDEX IF EXISTS `{}`", I::index_name()),
         format!(
-            "CREATE {}INDEX \"{}\" ON \"{}\" ({})",
+            "CREATE {}INDEX `{}` ON `{}` ({})",
             if I::unique() { "UNIQUE " } else { "" },
             I::index_name(),
             I::table_name(),
             I::column_names()
                 .iter()
-                .map(|x| format!("\"{}\"", x))
+                .map(|x| format!("`{}`", x))
                 .collect::<Vec<_>>()
                 .join(",")
         ),
@@ -73,15 +73,15 @@ mod test {
         assert_eq!(
             super::sql_for_table::<Empty>(),
             (
-                r#"DROP TABLE IF EXISTS "empty""#.to_owned(),
-                r#"CREATE TABLE IF NOT EXISTS "empty" (id integer primary key)"#.to_owned()
+                r#"DROP TABLE IF EXISTS `empty`"#.to_owned(),
+                r#"CREATE TABLE IF NOT EXISTS `empty` (`id` integer primary key)"#.to_owned()
             )
         );
         assert_eq!(
             super::sql_for_table::<Single>(),
             (
-                r#"DROP TABLE IF EXISTS "single""#.to_owned(),
-                r#"CREATE TABLE IF NOT EXISTS "single" (id integer primary key,"e" integer)"#
+                r#"DROP TABLE IF EXISTS `single`"#.to_owned(),
+                r#"CREATE TABLE IF NOT EXISTS `single` (`id` integer primary key,`e` integer)"#
                     .to_owned()
             )
         );
@@ -89,8 +89,8 @@ mod test {
         assert_eq!(
             super::sql_for_table::<Reference>(),
             (
-                r#"DROP TABLE IF EXISTS "reference""#.to_owned(),
-                r#"CREATE TABLE IF NOT EXISTS "reference" (id integer primary key,"e" integer)"#
+                r#"DROP TABLE IF EXISTS `reference`"#.to_owned(),
+                r#"CREATE TABLE IF NOT EXISTS `reference` (`id` integer primary key,`e` integer)"#
                     .to_owned()
             )
         );
@@ -110,8 +110,8 @@ mod test {
         assert_eq!(
             super::sql_for_table::<UnitNewtype>(),
             (
-                r#"DROP TABLE IF EXISTS "unit_newtype""#.to_owned(),
-                r#"CREATE TABLE IF NOT EXISTS "unit_newtype" (id integer primary key,"newtype" integer)"#
+                r#"DROP TABLE IF EXISTS `unit_newtype`"#.to_owned(),
+                r#"CREATE TABLE IF NOT EXISTS `unit_newtype` (`id` integer primary key,`newtype` integer)"#
                     .to_owned()
             )
         );
@@ -131,8 +131,8 @@ mod test {
         assert_eq!(
             super::sql_for_table::<NonUnitNewtype>(),
             (
-                r#"DROP TABLE IF EXISTS "non_unit_newtype""#.to_owned(),
-                r#"CREATE TABLE IF NOT EXISTS "non_unit_newtype" (id integer primary key,"newtype" blob)"#.to_owned()
+                r#"DROP TABLE IF EXISTS `non_unit_newtype`"#.to_owned(),
+                r#"CREATE TABLE IF NOT EXISTS `non_unit_newtype` (`id` integer primary key,`newtype` blob)"#.to_owned()
             )
         )
     }
@@ -149,8 +149,8 @@ mod test {
         assert_eq!(
             super::sql_for_table::<Child>(),
             (
-                r#"DROP TABLE IF EXISTS "child""#.to_owned(),
-                r#"CREATE TABLE IF NOT EXISTS "child" (id integer primary key,"parent_id" integer REFERENCES "single"("id") ON DELETE CASCADE)"#.to_owned()
+                r#"DROP TABLE IF EXISTS `child`"#.to_owned(),
+                r#"CREATE TABLE IF NOT EXISTS `child` (`id` integer primary key,`parent_id` integer REFERENCES `single`(`id`) ON DELETE CASCADE)"#.to_owned()
             )
         );
     }
@@ -170,15 +170,15 @@ mod test {
         assert_eq!(
             super::sql_for_index::<ValueIndex>(),
             (
-                r#"DROP INDEX IF EXISTS "value_index""#.to_owned(),
-                r#"CREATE INDEX "value_index" ON "key_value" ("value")"#.to_owned()
+                r#"DROP INDEX IF EXISTS `value_index`"#.to_owned(),
+                r#"CREATE INDEX `value_index` ON `key_value` (`value`)"#.to_owned()
             )
         );
         assert_eq!(
             super::sql_for_index::<UniqueValueIndex>(),
             (
-                r#"DROP INDEX IF EXISTS "unique_value_index""#.to_owned(),
-                r#"CREATE UNIQUE INDEX "unique_value_index" ON "key_value" ("value")"#.to_owned()
+                r#"DROP INDEX IF EXISTS `unique_value_index`"#.to_owned(),
+                r#"CREATE UNIQUE INDEX `unique_value_index` ON `key_value` (`value`)"#.to_owned()
             )
         )
     }
@@ -194,7 +194,7 @@ mod test {
     fn test_vec() {
         assert_eq!(
             super::sql_for_table::<VecTest>().1,
-            r#"CREATE TABLE IF NOT EXISTS "vec_test" (id integer primary key,"e" integer,"test" blob)"#.to_owned()
+            r#"CREATE TABLE IF NOT EXISTS `vec_test` (`id` integer primary key,`e` integer,`test` blob)"#.to_owned()
         );
     }
 
@@ -218,7 +218,7 @@ mod test {
     fn test_enum() {
         assert_eq!(
             super::sql_for_table::<EnumContainer>().1,
-            r#"CREATE TABLE IF NOT EXISTS "enum_container" (id integer primary key,"before" integer,"e" text,"after" integer)"#.to_owned()
+            r#"CREATE TABLE IF NOT EXISTS `enum_container` (`id` integer primary key,`before` integer,`e` text,`after` integer)"#.to_owned()
         )
     }
 }