|
@@ -1,4 +1,4 @@
|
|
|
-use crate::{entity::{Entity, EntityDatum, EntityVisitor, EntityPartVisitor, EntityPart}, schema::collect_from_database};
|
|
|
+use crate::{entity::{Entity, EntityDatum, EntityVisitor, EntityPartVisitor, EntityPart}, schema::collect_from_database, query};
|
|
|
|
|
|
pub(crate) type DBConnection = std::sync::Arc<sqlite::ConnectionThreadSafe>;
|
|
|
|
|
@@ -55,54 +55,20 @@ impl<T: Entity> IDMap<T> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ pub(crate) fn conn(&self) -> &DBConnection {
|
|
|
+ &self.conn
|
|
|
+ }
|
|
|
+
|
|
|
+ pub(crate) fn ctx(&self) -> &'static str {
|
|
|
+ self.ctx
|
|
|
+ }
|
|
|
+
|
|
|
pub fn lookup_unique(&self, uniques: &T::Uniques) -> DBResult<T> {
|
|
|
None.into()
|
|
|
}
|
|
|
|
|
|
pub fn insert(&self, value: &T) -> Result<(), DBError> {
|
|
|
- println!("inserting value into IDMap; context is {} and name is {}", self.ctx, T::entity_name());
|
|
|
- let table_name = format!("{}_{}", self.ctx, T::entity_name());
|
|
|
-
|
|
|
- let mut part_names = String::new();
|
|
|
- let mut placeholders = String::new();
|
|
|
- struct PartNameVisitor<'a>(&'a mut String, &'a mut String);
|
|
|
- impl<'a> EntityPartVisitor for PartNameVisitor<'a> {
|
|
|
- fn visit<EP: EntityPart>(&mut self) {
|
|
|
- if self.0.len() != 0 {
|
|
|
- self.0.push_str(", ");
|
|
|
- self.1.push_str(", ");
|
|
|
- }
|
|
|
- self.0.push_str("`");
|
|
|
- self.0.push_str(EP::part_name());
|
|
|
- self.0.push_str("`");
|
|
|
- self.1.push_str("?");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- T::accept_part_visitor(&mut PartNameVisitor(&mut part_names, &mut placeholders));
|
|
|
-
|
|
|
- let query_string = format!("insert into `{}` ({}) values ({})", table_name, part_names, placeholders);
|
|
|
- println!("query_string: {}", query_string);
|
|
|
-
|
|
|
- let mut prepared = self.conn.prepare(query_string).expect("couldn't prepare statement");
|
|
|
- struct PartBinder<'a, 'b>(&'a mut sqlite::Statement<'b>, usize);
|
|
|
- impl<'a, 'b> EntityPartVisitor for PartBinder<'a, 'b> {
|
|
|
- fn visit_datum<EP: EntityPart>(&mut self, _ctx: &'static str, datum: &EP::Datum) {
|
|
|
- datum.bind_to(self.0, self.1);
|
|
|
- self.1 += 1;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- value.accept_part_visitor_ref(&mut PartBinder(&mut prepared, 1));
|
|
|
-
|
|
|
- prepared.next();
|
|
|
-
|
|
|
- // struct BuildQuery
|
|
|
-
|
|
|
- // we're going to do a dumb thing for now
|
|
|
- // TODO: make this better
|
|
|
- // self.conn.execute(format!("insert into {} values ({})
|
|
|
- Ok(())
|
|
|
+ query::insert(self, value)
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -111,28 +77,17 @@ pub struct Index<T: Entity, Key: EntityDatum> {
|
|
|
_ghost: std::marker::PhantomData<(T, Key)>,
|
|
|
}
|
|
|
|
|
|
-/*pub struct Unique<T: EntityDatum> {
|
|
|
- _ghost: std::marker::PhantomData<T>,
|
|
|
-}
|
|
|
-
|
|
|
-impl<T: EntityDatum> EntityDatum for Unique<T> {
|
|
|
- fn sql_type() -> &'static str { T::sql_type() }
|
|
|
- fn is_unique() -> bool { true }
|
|
|
-}*/
|
|
|
-
|
|
|
pub struct AssocSet<T: Entity> {
|
|
|
_ghost: std::marker::PhantomData<T>,
|
|
|
}
|
|
|
|
|
|
impl<T: Entity> EntityDatum for AssocSet<T> {
|
|
|
- // foreign key over IDs
|
|
|
- fn sql_type() -> &'static str { "integer" }
|
|
|
+ fn sql_type() -> &'static str { unreachable!() }
|
|
|
|
|
|
fn accept_entity_visitor(v: &mut impl EntityVisitor) {
|
|
|
v.visit::<T>();
|
|
|
}
|
|
|
|
|
|
-
|
|
|
fn bind_to<'a>(&self, _stmt: &mut sqlite::Statement<'a>, index: usize) {
|
|
|
todo!()
|
|
|
}
|
|
@@ -183,8 +138,6 @@ pub trait Database {
|
|
|
Ok(Self::build(conn))
|
|
|
},
|
|
|
Err(e) => {
|
|
|
- /*std::io::Error::new(std::io::ErrorKind::
|
|
|
- e.message*/
|
|
|
println!("e: {:?}", e);
|
|
|
todo!("connection failed")
|
|
|
},
|
|
@@ -204,13 +157,23 @@ mod simple_tests {
|
|
|
#![allow(unused)]
|
|
|
|
|
|
use super::*;
|
|
|
- use crate::entity::{EntityPart, EntityPartVisitor};
|
|
|
+ use crate::entity::{EntityPart, EntityPartVisitor, EntityID};
|
|
|
// simple hand-built database example
|
|
|
|
|
|
struct SimpleEntity {
|
|
|
name: String,
|
|
|
}
|
|
|
|
|
|
+ #[derive(Clone, Copy, PartialEq, PartialOrd, Debug, Hash)]
|
|
|
+ struct SimpleEntityID(usize);
|
|
|
+
|
|
|
+ impl EntityID for SimpleEntityID {
|
|
|
+ type Entity = SimpleEntity;
|
|
|
+
|
|
|
+ fn from_raw(id: usize) -> Self { Self(id) }
|
|
|
+ fn into_raw(self) -> usize { self.0 }
|
|
|
+ }
|
|
|
+
|
|
|
// normally this would be invisible, but for testing purposes we expose it
|
|
|
impl SimpleEntity {
|
|
|
// pub const Name: SimpleEntityName = SimpleEntityName;
|
|
@@ -226,6 +189,8 @@ mod simple_tests {
|
|
|
|
|
|
impl Entity for SimpleEntity {
|
|
|
type Uniques = String;
|
|
|
+ type ID = SimpleEntityID;
|
|
|
+
|
|
|
fn entity_name() -> &'static str {
|
|
|
"simple_entity"
|
|
|
}
|