Skip to content

Commit

Permalink
feat: Add a new proxy example which uses GlueSQL.
Browse files Browse the repository at this point in the history
  • Loading branch information
langyo committed Oct 23, 2023
1 parent 2c90866 commit ecbc2f3
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 0 deletions.
29 changes: 29 additions & 0 deletions examples/proxy_gluesql_example/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[package]
name = "sea-orm-proxy-gluesql-example"
version = "0.1.0"
authors = ["Langyo <[email protected]>"]
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",
] }
7 changes: 7 additions & 0 deletions examples/proxy_gluesql_example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# SeaORM Proxy Demo for GlueSQL

Run this demo for [GlueSQL](https://gluesql.org/) with the following command:

```bash
cargo run
```
1 change: 1 addition & 0 deletions examples/proxy_gluesql_example/src/entity/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod post;
17 changes: 17 additions & 0 deletions examples/proxy_gluesql_example/src/entity/post.rs
Original file line number Diff line number Diff line change
@@ -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 {}
138 changes: 138 additions & 0 deletions examples/proxy_gluesql_example/src/main.rs
Original file line number Diff line number Diff line change
@@ -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<Glue<MemoryStorage>>,
}

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<Vec<ProxyRow>, DbErr> {
println!("SQL query: {:?}", statement);
let sql = statement.sql.clone();

let mut ret: Vec<ProxyRow> = 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<ProxyExecResult, DbErr> {
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);
}

0 comments on commit ecbc2f3

Please sign in to comment.