diff --git a/examples/proxy_gluesql_example/Cargo.toml b/examples/proxy_gluesql_example/Cargo.toml new file mode 100644 index 000000000..9e21bee18 --- /dev/null +++ b/examples/proxy_gluesql_example/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "sea-orm-proxy-gluesql-example" +version = "0.1.0" +authors = ["Langyo "] +edition = "2021" +publish = false + +[workspace] + +[dependencies] +async-std = { version = "1.12", features = ["attributes", "tokio1"] } +serde_json = { version = "1" } +serde = { version = "1" } +futures = { version = "0.3" } +async-stream = { version = "0.3" } +futures-util = { version = "0.3" } + +sea-orm = { path = "../../", features = [ + "sqlx-all", + "proxy", + "runtime-async-std-native-tls", + "debug-print", +] } +# Since it's newer version (0.14.0) locked the chrono's version to 0.4.23, +# we need to lock it on older version too. +# Related to https://github.com/gluesql/gluesql/pull/1427 +gluesql = { version = "0.13", default-features = false, features = [ + "memory-storage", +] } diff --git a/examples/proxy_gluesql_example/README.md b/examples/proxy_gluesql_example/README.md new file mode 100644 index 000000000..2269c471e --- /dev/null +++ b/examples/proxy_gluesql_example/README.md @@ -0,0 +1,7 @@ +# SeaORM Proxy Demo for GlueSQL + +Run this demo for [GlueSQL](https://gluesql.org/) with the following command: + +```bash +cargo run +``` diff --git a/examples/proxy_gluesql_example/src/entity/mod.rs b/examples/proxy_gluesql_example/src/entity/mod.rs new file mode 100644 index 000000000..e8b6291ac --- /dev/null +++ b/examples/proxy_gluesql_example/src/entity/mod.rs @@ -0,0 +1 @@ +pub mod post; diff --git a/examples/proxy_gluesql_example/src/entity/post.rs b/examples/proxy_gluesql_example/src/entity/post.rs new file mode 100644 index 000000000..868846046 --- /dev/null +++ b/examples/proxy_gluesql_example/src/entity/post.rs @@ -0,0 +1,17 @@ +use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Deserialize, Serialize)] +#[sea_orm(table_name = "posts")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i64, + + pub title: String, + pub text: String, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/examples/proxy_gluesql_example/src/main.rs b/examples/proxy_gluesql_example/src/main.rs new file mode 100644 index 000000000..942efd462 --- /dev/null +++ b/examples/proxy_gluesql_example/src/main.rs @@ -0,0 +1,138 @@ +//! Proxy connection example. + +#![deny(missing_docs)] + +mod entity; + +use std::{ + collections::BTreeMap, + sync::{Arc, Mutex}, +}; + +use gluesql::{memory_storage::MemoryStorage, prelude::Glue}; +use sea_orm::{ + ActiveValue::Set, Database, DbBackend, DbErr, EntityTrait, ProxyDatabaseTrait, ProxyExecResult, + ProxyRow, Statement, +}; + +use entity::post::{ActiveModel, Entity}; + +struct ProxyDb { + mem: Mutex>, +} + +impl std::fmt::Debug for ProxyDb { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ProxyDb").finish() + } +} + +impl ProxyDatabaseTrait for ProxyDb { + fn query(&self, statement: Statement) -> Result, DbErr> { + println!("SQL query: {:?}", statement); + let sql = statement.sql.clone(); + + let mut ret: Vec = vec![]; + for payload in self.mem.lock().unwrap().execute(sql).unwrap().iter() { + match payload { + gluesql::prelude::Payload::Select { labels, rows } => { + for row in rows.iter() { + let mut map = BTreeMap::new(); + for (label, column) in labels.iter().zip(row.iter()) { + map.insert( + label.to_owned(), + match column { + gluesql::prelude::Value::I64(val) => { + sea_orm::Value::BigInt(Some(*val)) + } + gluesql::prelude::Value::Str(val) => { + sea_orm::Value::String(Some(Box::new(val.to_owned()))) + } + _ => unreachable!("Unsupported value: {:?}", column), + }, + ); + } + ret.push(map.into()); + } + } + _ => unreachable!("Unsupported payload: {:?}", payload), + } + } + + Ok(ret) + } + + fn execute(&self, statement: Statement) -> Result { + if let Some(values) = statement.values { + // Replace all the '?' with the statement values + let mut new_sql = statement.sql.clone(); + let mark_count = new_sql.matches('?').count(); + for (i, v) in values.0.iter().enumerate() { + if i >= mark_count { + break; + } + new_sql = new_sql.replacen('?', &v.to_string(), 1); + } + println!("SQL execute: {}", new_sql); + + self.mem.lock().unwrap().execute(new_sql).unwrap(); + } else { + self.mem.lock().unwrap().execute(statement.sql).unwrap(); + } + + Ok(ProxyExecResult { + last_insert_id: 1, + rows_affected: 1, + }) + } +} + +#[async_std::main] +async fn main() { + let mem = MemoryStorage::default(); + let mut glue = Glue::new(mem); + + glue.execute( + r#" + CREATE TABLE IF NOT EXISTS posts ( + id INTEGER PRIMARY KEY, + title TEXT NOT NULL, + text TEXT NOT NULL + ) + "#, + ) + .unwrap(); + + let db = Database::connect_proxy( + DbBackend::Sqlite, + Arc::new(Mutex::new(Box::new(ProxyDb { + mem: Mutex::new(glue), + }))), + ) + .await + .unwrap(); + + println!("Initialized"); + + let data = ActiveModel { + id: Set(11), + title: Set("Homo".to_owned()), + text: Set("いいよ、来いよ".to_owned()), + }; + Entity::insert(data).exec(&db).await.unwrap(); + let data = ActiveModel { + id: Set(45), + title: Set("Homo".to_owned()), + text: Set("そうだよ".to_owned()), + }; + Entity::insert(data).exec(&db).await.unwrap(); + let data = ActiveModel { + id: Set(14), + title: Set("Homo".to_owned()), + text: Set("悔い改めて".to_owned()), + }; + Entity::insert(data).exec(&db).await.unwrap(); + + let list = Entity::find().all(&db).await.unwrap().to_vec(); + println!("Result: {:?}", list); +}