Skip to content

Commit

Permalink
Add basic diesel sqlite driver
Browse files Browse the repository at this point in the history
  • Loading branch information
Sytten committed Aug 1, 2021
1 parent b893bbf commit bd0f734
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
members = [
".",
"sea-query-derive",
"examples/diesel-sqlite",
"examples/postgres",
"examples/postgres_json",
"examples/rusqlite",
Expand Down Expand Up @@ -56,6 +57,7 @@ rusqlite = [ ]
sqlx-mysql = [ ]
sqlx-postgres = [ ]
sqlx-sqlite = [ ]
diesel-sqlite = [ ]
with-chrono = [ "chrono" ]
with-json = [ "serde_json" ]
with-rust_decimal = [ "rust_decimal" ]
Expand Down
18 changes: 18 additions & 0 deletions examples/diesel-sqlite/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "sea-query-diesel-sqlite-example"
version = "0.1.0"
edition = "2018"

[dependencies]
async-std = { version = "1.8", features = [ "attributes" ] }
sea-query = { path = "../../", features = ["diesel-sqlite"] }
# NOTE: if you are copying this example into your own project, use the following line instead:
# sea-query = { version = "^0.11", features = ["diesel-sqlite"] }

[dependencies.diesel]
git = "https://github.com/diesel-rs/diesel.git"
rev = "90935821477ef8fc80385cd5e608e7a93f531014"
features = [
"sqlite",
"r2d2"
]
147 changes: 147 additions & 0 deletions examples/diesel-sqlite/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
use diesel::deserialize::QueryableByName;
use diesel::r2d2::{ConnectionManager, Pool};
use diesel::sql_types::{BigInt, Integer, Text};
use diesel::sqlite::Sqlite;
use diesel::{sql_query, RunQueryDsl, SqliteConnection};
use sea_query::{Alias, ColumnDef, Expr, Func, Iden, Order, Query, SqliteQueryBuilder, Table};

sea_query::sea_query_driver_diesel_sqlite!();
use sea_query_driver_diesel_sqlite::bind_query;

#[async_std::main]
async fn main() {
let manager = ConnectionManager::<SqliteConnection>::new(":memory:");
let pool = Pool::new(manager).unwrap();
let conn = &mut pool.get().unwrap();

// Schema
let sql = Table::create()
.table(Character::Table)
.if_not_exists()
.col(
ColumnDef::new(Character::Id)
.integer()
.not_null()
.auto_increment()
.primary_key(),
)
.col(ColumnDef::new(Character::FontSize).integer())
.col(ColumnDef::new(Character::Character).string())
.build(SqliteQueryBuilder);

let result = sql_query(&sql).execute(conn);
println!("Create table character: {:?}\n", result);

// Create
let (sql, values) = Query::insert()
.into_table(Character::Table)
.columns(vec![Character::Character, Character::FontSize])
.values_panic(vec!["A".into(), 12.into()])
.build(SqliteQueryBuilder);

//TODO: Implement RETURNING (returning_col) for the Sqlite driver.
let inserted_rows = bind_query(sql_query(&sql).into_boxed::<Sqlite>(), &values)
.execute(conn)
.unwrap();

let id = 1;
println!("Insert into character: inserted_rows = {}\n", inserted_rows);

// Read
let (sql, values) = Query::select()
.columns(vec![
Character::Id,
Character::Character,
Character::FontSize,
])
.from(Character::Table)
.order_by(Character::Id, Order::Desc)
.limit(1)
.build(SqliteQueryBuilder);

let rows = bind_query(sql_query(&sql).into_boxed(), &values)
.get_results::<CharacterStruct>(conn)
.unwrap();
println!("Select one from character:");
for row in rows.iter() {
println!("{:?}", row);
}
println!();

// Update
let (sql, values) = Query::update()
.table(Character::Table)
.values(vec![(Character::FontSize, 24.into())])
.and_where(Expr::col(Character::Id).eq(id))
.build(SqliteQueryBuilder);

let result = bind_query(sql_query(&sql).into_boxed::<Sqlite>(), &values).execute(conn);
println!("Update character: {:?}\n", result);

// Read
let (sql, values) = Query::select()
.columns(vec![
Character::Id,
Character::Character,
Character::FontSize,
])
.from(Character::Table)
.order_by(Character::Id, Order::Desc)
.limit(1)
.build(SqliteQueryBuilder);

let row = bind_query(sql_query(&sql).into_boxed::<Sqlite>(), &values)
.get_result::<CharacterStruct>(conn)
.unwrap();

println!("Select one from character:");
println!("{:?}\n", row);

// Count
let (sql, values) = Query::select()
.from(Character::Table)
.expr_as(Func::count(Expr::col(Character::Id)), Alias::new("count"))
.build(SqliteQueryBuilder);

let row = bind_query(sql_query(&sql).into_boxed::<Sqlite>(), &values)
.get_result::<CharacterCount>(conn)
.unwrap();

println!("Count character: {}\n", row.count);

// Delete
let (sql, values) = Query::delete()
.from_table(Character::Table)
.and_where(Expr::col(Character::Id).eq(id))
.build(SqliteQueryBuilder);

let result = bind_query(sql_query(&sql).into_boxed::<Sqlite>(), &values)
.execute(conn)
.unwrap();

println!("Delete character: {:?}", result);
}

#[derive(Iden)]
enum Character {
Table,
Id,
Character,
FontSize,
}

#[derive(QueryableByName, Debug)]
struct CharacterStruct {
#[sql_type = "Integer"]
id: i32,
#[sql_type = "Text"]
character: String,
#[sql_type = "Integer"]
font_size: i32,
}

#[derive(QueryableByName, Debug)]
struct CharacterCount {
#[sql_type = "BigInt"]
count: i64,
}
69 changes: 69 additions & 0 deletions src/driver/diesel_sqlite.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#[macro_export]
macro_rules! bind_params_diesel {
( $query:expr, $params:expr ) => {{
let mut query = $query;
for value in $params.iter() {
query = match value {
Value::Null => query.bind::<sql_types::Nullable<sql_types::Bool>, _>(None::<bool>),
Value::Bool(v) => query.bind::<sql_types::Bool, _>(v),
Value::TinyInt(v) => query.bind::<sql_types::SmallInt, _>(*v as i16),
Value::SmallInt(v) => query.bind::<sql_types::SmallInt, _>(v),
Value::Int(v) => query.bind::<sql_types::Integer, _>(v),
Value::BigInt(v) => query.bind::<sql_types::BigInt, _>(v),
Value::TinyUnsigned(v) => query.bind::<sql_types::SmallInt, _>(*v as i16),
Value::SmallUnsigned(v) => query.bind::<sql_types::SmallInt, _>(*v as i16),
Value::Unsigned(v) => query.bind::<sql_types::Integer, _>(*v as i32),
Value::BigUnsigned(v) => query.bind::<sql_types::BigInt, _>(*v as i64),
Value::Float(v) => query.bind::<sql_types::Float, _>(v),
Value::Double(v) => query.bind::<sql_types::Double, _>(v),
Value::String(v) => query.bind::<sql_types::Text, _>(v.as_str()),
Value::Bytes(v) => query.bind::<sql_types::Blob, _>(v.as_ref()),
_ => {
if value.is_json() {
#[cfg(feature = "with-json")]
return query.bind::<sql_types::Json, _>(value.as_ref_json());
#[cfg(not(feature = "with-json"))]
unimplemented!();
} else if value.is_date_time() {
#[cfg(feature = "with-chrono")]
return query.bind::<sql_types::Timestamp, _>(value.as_ref_date_time());
#[cfg(not(feature = "with-chrono"))]
unimplemented!();
} else if value.is_decimal() {
#[cfg(feature = "with-rust_decimal")]
return query.bind::<sql_types::Double, _>(value.decimal_to_f64());
#[cfg(not(feature = "with-rust_decimal"))]
unimplemented!();
} else if value.is_uuid() {
#[cfg(feature = "with-uuid")]
return query.bind::<sql_types::Uuid, _>(value.as_ref_uuid());
#[cfg(not(feature = "with-uuid"))]
unimplemented!();
} else {
unimplemented!();
}
}
};
}
query
}};
}

#[macro_export]
macro_rules! sea_query_driver_diesel_sqlite {
() => {
mod sea_query_driver_diesel_sqlite {
use diesel::query_builder::BoxedSqlQuery;
use diesel::sql_types;
use diesel::sqlite::Sqlite;
use $crate::{Value, Values};

pub fn bind_query<'a, Query>(
query: BoxedSqlQuery<'a, Sqlite, Query>,
params: &'a Values,
) -> BoxedSqlQuery<'a, Sqlite, Query> {
$crate::bind_params_diesel!(query, params.0)
}
}
};
}
5 changes: 5 additions & 0 deletions src/driver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,8 @@ pub use sqlx_postgres::*;
mod sqlx_sqlite;
#[cfg(feature = "sqlx-sqlite")]
pub use sqlx_sqlite::*;

#[cfg(feature = "diesel-sqlite")]
mod diesel_sqlite;
#[cfg(feature = "diesel-sqlite")]
pub use diesel_sqlite::*;

0 comments on commit bd0f734

Please sign in to comment.