Skip to content

Commit

Permalink
Uuid/Json types, Postgres support, better defaults
Browse files Browse the repository at this point in the history
  • Loading branch information
m1guelpf authored Sep 3, 2023
1 parent 22cf0c1 commit 01cd5eb
Show file tree
Hide file tree
Showing 31 changed files with 1,577 additions and 199 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions ensemble/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ fastdate = "0.1.39"
itertools = "0.11.0"
Inflector = "0.11.4"
thiserror = "1.0.44"
serde_json = "1.0.105"
async-trait = "0.1.73"
schemars = { version = "0.8.13", optional = true }
validator = { version = "0.16.1", optional = true }
serde_json = { version = "1.0.105", optional = true }
ensemble_derive = { version = "0", path = "../ensemble_derive" }
uuid = { version = "1.4.1", features = ["serde", "v4"], optional = true }
rbdc-pg = { version = "4.3.12", default-features = false, optional = true }
rbdc-mysql = { version = "4.3.12", default-features = false, optional = true }
rbatis = { version = "4.3.12", default-features = false, features = [
Expand All @@ -31,16 +32,15 @@ rbatis = { version = "4.3.12", default-features = false, features = [

[dev-dependencies]
axum = "0.6.20"
uuid = { version = "1.4.1", features = ["serde"] }


[features]
default = ["native-tls", "json", "schema"]
default = ["native-tls", "json", "schema", "uuid"]

schema = ["dep:schemars"]
mysql = ["dep:rbdc-mysql"]
postgres = ["dep:rbdc-pg"]
json = ["dep:serde_json", "ensemble_derive/json"]
json = ["ensemble_derive/json"]
uuid = ["dep:uuid", "schemars?/uuid1"]
rustls = ["rbatis/tls-rustls", "rbdc-pg?/tls-rustls", "rbdc-mysql?/tls-rustls"]
native-tls = [
"rbatis/tls-native-tls",
Expand Down
6 changes: 4 additions & 2 deletions ensemble/docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,16 @@ Like we've said, Ensemble requires each model to have at least one uniquely iden

Instead of using auto-incrementing integers as your Ensemble model's primary keys, you may choose to use UUIDs instead. UUIDs are universally unique alpha-numeric identifiers that are 36 characters long.

If you would like a model to use a UUID key instead of an auto-incrementing integer key, you may use the `uuid::Uuid` type on the model's primary key, and mark it with the `#[model(uuid)]` attribute:
If you would like a model to use a UUID key instead of an auto-incrementing integer key, you may use the `ensemble::types::Uuid` type on the model's primary key, and mark it with the `#[model(uuid)]` attribute:

```rust
use ensemble::types::Uuid;
# use ensemble::Model;

#[derive(Debug, Model)]
struct Flight {
#[model(uuid)]
pub id: uuid::Uuid,
pub id: Uuid,
pub name: String,
}
```
Expand Down
17 changes: 8 additions & 9 deletions ensemble/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,7 @@ use std::{
fmt::Display,
};

use crate::{
connection,
query::Error,
value::{self, to_value},
Model,
};
use crate::{connection, query::Error, value, Model};

/// The Query Builder.
#[derive(Debug)]
Expand Down Expand Up @@ -44,6 +39,10 @@ impl Builder {
}

/// Add a basic where clause to the query.
///
/// # Panics
///
/// Panics if the provided value cannot be serialized.
#[must_use]
pub fn r#where<T, Op>(mut self, column: &str, operator: Op, value: T) -> Self
where
Expand All @@ -54,7 +53,7 @@ impl Builder {
boolean: Boolean::And,
operator: operator.into(),
column: column.to_string(),
value: Some(to_value(value)),
value: Some(value::for_db(value).unwrap()),
}));

self
Expand Down Expand Up @@ -475,7 +474,7 @@ impl<T: Serialize> From<Vec<(&str, T)>> for Columns {
Self(
values
.iter()
.map(|(column, value)| ((*column).to_string(), to_value(value)))
.map(|(column, value)| ((*column).to_string(), value::for_db(value).unwrap()))
.collect(),
)
}
Expand All @@ -485,7 +484,7 @@ impl<T: Serialize> From<&[(&str, T)]> for Columns {
Self(
values
.iter()
.map(|(column, value)| ((*column).to_string(), to_value(value)))
.map(|(column, value)| ((*column).to_string(), value::for_db(value).unwrap()))
.collect(),
)
}
Expand Down
6 changes: 5 additions & 1 deletion ensemble/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,11 @@ pub trait Model: DeserializeOwned + Serialize + Sized + Send + Sync + Debug + De
/// Returns an error if the model cannot be deleted, or if a connection to the database cannot be established.
async fn delete(mut self) -> Result<(), query::Error> {
let rows_affected = Self::query()
.r#where(Self::PRIMARY_KEY, "=", value::to_value(self.primary_key()))
.r#where(
Self::PRIMARY_KEY,
"=",
value::for_db(self.primary_key()).unwrap(),
)
.delete()
.await?;

Expand Down
8 changes: 4 additions & 4 deletions ensemble/src/migrations/migrator.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use std::collections::HashMap;

use rbs::from_value;
use rbs::{from_value, Value};
use tokio::sync::Mutex;

use super::{Error, Migration};
use crate::{
connection::{self, Connection},
value::to_value,
value,
};

pub static MIGRATE_CONN: Mutex<Option<Connection>> = Mutex::const_new(None);
Expand Down Expand Up @@ -120,7 +120,7 @@ impl Migrator {
self.connection
.exec(
"insert into migrations (migration, batch) values (?, ?)",
vec![to_value(&name), to_value(&self.batch)],
vec![value::for_db(&name)?, value::for_db(&self.batch)?],
)
.await
.map_err(|e| Error::Database(e.to_string()))?;
Expand Down Expand Up @@ -194,7 +194,7 @@ impl Migrator {
self.connection
.exec(
"delete from migrations where id = ?",
vec![to_value(&record.id)],
vec![Value::U64(record.id)],
)
.await
.map_err(|e| Error::Database(e.to_string()))?;
Expand Down
4 changes: 2 additions & 2 deletions ensemble/src/migrations/schema/column.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use rbs::Value;
use std::{fmt::Display, sync::mpsc};

use super::Schemable;
use crate::{connection, value::to_value};
use crate::{connection, value};

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Type {
Expand Down Expand Up @@ -102,7 +102,7 @@ impl Column {
let value = if self.r#type == Type::Json {
Value::String(serde_json::to_string(&default).unwrap())
} else {
to_value(default)
value::for_db(default).unwrap()
};

#[cfg(feature = "mysql")]
Expand Down
8 changes: 6 additions & 2 deletions ensemble/src/migrations/schema/mod.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use inflector::Inflector;
use itertools::{Either, Itertools};
use rbs::Value;
use std::{any::type_name, sync::mpsc};

use self::{
column::{Column, Type},
command::{Command, ForeignIndex},
};
use super::{migrator::MIGRATE_CONN, Error};
use crate::{connection, value::to_value, Model};
use crate::{connection, Model};

mod column;
mod command;
Expand Down Expand Up @@ -74,7 +75,10 @@ impl Schema {
let mut conn_lock = MIGRATE_CONN.try_lock().map_err(|_| Error::Lock)?;
let mut conn = conn_lock.take().ok_or(Error::Lock)?;

let (sql, bindings) = (format!("DROP TABLE ?"), vec![to_value(table_name)]);
let (sql, bindings) = (
format!("DROP TABLE ?"),
vec![Value::String(table_name.to_string())],
);

tracing::debug!(sql = sql.as_str(), bindings = ?bindings, "Running DROP TABLE SQL query");
let query_result = conn.exec(&sql, bindings).await;
Expand Down
10 changes: 5 additions & 5 deletions ensemble/src/relationships/belongs_to.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use rbs::Value;
use serde::Serialize;
use std::{collections::HashMap, fmt::Debug};

use super::{find_related, Relationship};
use super::{find_related, Relationship, Status};
use crate::{builder::Builder, query::Error, Model};

/// ## A Belongs To relationship.
Expand Down Expand Up @@ -36,7 +36,7 @@ use crate::{builder::Builder, query::Error, Model};
#[derive(Clone, Default)]
pub struct BelongsTo<Local: Model, Related: Model> {
local_key: String,
relation: Option<Related>,
relation: Status<Related>,
_local: std::marker::PhantomData<Local>,
/// The value of the local model's related key.
pub value: Related::PrimaryKey,
Expand All @@ -54,7 +54,7 @@ impl<Local: Model, Related: Model> Relationship for BelongsTo<Local, Related> {
Self {
value,
local_key,
relation: None,
relation: Status::Initial,
_local: std::marker::PhantomData,
}
}
Expand Down Expand Up @@ -84,7 +84,7 @@ impl<Local: Model, Related: Model> Relationship for BelongsTo<Local, Related> {
if self.relation.is_none() {
let relation = self.query().first().await?.ok_or(Error::NotFound)?;

self.relation = Some(relation);
self.relation = Status::Fetched(Some(relation));
}

Ok(self.relation.as_ref().unwrap())
Expand All @@ -93,7 +93,7 @@ impl<Local: Model, Related: Model> Relationship for BelongsTo<Local, Related> {
fn r#match(&mut self, related: &[HashMap<String, Value>]) -> Result<(), Error> {
let related = find_related(related, &self.local_key, &self.value, true)?;

self.relation = related.into_iter().next();
self.relation = Status::Fetched(related.into_iter().next());

Ok(())
}
Expand Down
10 changes: 5 additions & 5 deletions ensemble/src/relationships/belongs_to_many.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use rbs::Value;
use serde::Serialize;
use std::{collections::HashMap, fmt::Debug};

use super::{find_related, Relationship};
use super::{find_related, Relationship, Status};
use crate::{builder::Builder, query::Error, Model};

/// ## A Many to Many relationship.
Expand Down Expand Up @@ -37,7 +37,7 @@ pub struct BelongsToMany<Local: Model, Related: Model> {
local_key: String,
foreign_key: String,
pivot_table: String,
relation: Option<Vec<Related>>,
relation: Status<Vec<Related>>,
_local: std::marker::PhantomData<Local>,
/// The value of the local model's primary key.
pub value: Related::PrimaryKey,
Expand Down Expand Up @@ -69,7 +69,7 @@ impl<Local: Model, Related: Model> Relationship for BelongsToMany<Local, Related
local_key,
foreign_key,
pivot_table,
relation: None,
relation: Status::Initial,
_local: std::marker::PhantomData,
}
}
Expand Down Expand Up @@ -111,7 +111,7 @@ impl<Local: Model, Related: Model> Relationship for BelongsToMany<Local, Related
if self.relation.is_none() {
let relation = self.query().get().await?;

self.relation = Some(relation);
self.relation = Status::Fetched(Some(relation));
}

Ok(self.relation.as_ref().unwrap())
Expand All @@ -121,7 +121,7 @@ impl<Local: Model, Related: Model> Relationship for BelongsToMany<Local, Related
let related = find_related(related, &self.foreign_key, &self.value, false)?;

if !related.is_empty() {
self.relation = Some(related);
self.relation = Status::Fetched(Some(related));
}

Ok(())
Expand Down
18 changes: 9 additions & 9 deletions ensemble/src/relationships/has_many.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use inflector::Inflector;
use rbs::{to_value, Value};
use rbs::Value;
use serde::Serialize;
use std::{collections::HashMap, fmt::Debug};

use super::{find_related, Relationship};
use super::{find_related, Relationship, Status};
use crate::{builder::Builder, query::Error, value, Model};

/// ## A One to Many relationship.
Expand Down Expand Up @@ -38,7 +38,7 @@ use crate::{builder::Builder, query::Error, value, Model};
#[derive(Clone, Default)]
pub struct HasMany<Local: Model, Related: Model> {
foreign_key: String,
relation: Option<Vec<Related>>,
relation: Status<Vec<Related>>,
/// The value of the local model's primary key.
pub value: Local::PrimaryKey,
}
Expand All @@ -57,7 +57,7 @@ impl<Local: Model, Related: Model> Relationship for HasMany<Local, Related> {
Self {
value,
foreign_key,
relation: None,
relation: Status::Initial,
}
}

Expand Down Expand Up @@ -86,7 +86,7 @@ impl<Local: Model, Related: Model> Relationship for HasMany<Local, Related> {
if self.relation.is_none() {
let relation = self.query().get().await?;

self.relation = Some(relation);
self.relation = Status::Fetched(Some(relation));
}

Ok(self.relation.as_ref().unwrap())
Expand All @@ -96,7 +96,7 @@ impl<Local: Model, Related: Model> Relationship for HasMany<Local, Related> {
let related = find_related(related, &self.foreign_key, &self.value, false)?;

if !related.is_empty() {
self.relation = Some(related);
self.relation = Status::Fetched(Some(related));
}

Ok(())
Expand Down Expand Up @@ -145,12 +145,12 @@ impl<Local: Model, Related: Model> HasMany<Local, Related> {

value.insert(
Value::String(self.foreign_key.clone()),
to_value(&self.value)?,
value::for_db(&self.value)?,
);

let result = Related::create(value::from(Value::Map(value))?).await?;
let result = Related::create(rbs::from_value(Value::Map(value))?).await?;

if let Some(relation) = &mut self.relation {
if let Status::Fetched(Some(relation)) = &mut self.relation {
relation.push(result.clone());
}

Expand Down
Loading

0 comments on commit 01cd5eb

Please sign in to comment.