Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pull] master from SeaQL:master #6

Merged
merged 5 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 14 additions & 12 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -226,24 +226,26 @@ jobs:
- uses: dtolnay/rust-toolchain@stable
- run: cargo install --path sea-orm-cli --debug

examples-matrix:
name: Examples Matrix
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- id: set-matrix
run: echo "path_matrix=$(find examples -mindepth 1 -maxdepth 1 -type d -not -path 'examples/rocket_okapi_example' -printf '%P\0' | jq -Rc '[ split("\u0000") | .[] | "examples/\(.)" ]')" >> $GITHUB_OUTPUT
outputs:
path_matrix: ${{ steps.set-matrix.outputs.path_matrix }}

examples:
name: Examples
runs-on: ubuntu-latest
needs: examples-matrix
strategy:
fail-fast: false
matrix:
path: ${{ fromJson(needs.examples-matrix.outputs.path_matrix) }}
path: [
examples/actix_example,
examples/actix3_example,
# examples/rocket_okapi_example,
examples/jsonrpsee_example,
examples/basic,
examples/salvo_example,
examples/rocket_example,
examples/axum_example,
examples/tonic_example,
examples/seaography_example,
examples/graphql_example,
examples/poem_example,
]
steps:
- uses: actions/checkout@v3
- if: ${{ contains(matrix.path, 'tonic_example') }}
Expand Down
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ keywords = ["async", "orm", "mysql", "postgres", "sqlite"]
rust-version = "1.65"

[package.metadata.docs.rs]
features = ["default", "sqlx-all", "mock", "runtime-async-std-native-tls", "postgres-array", "sea-orm-internal"]
features = ["default", "sqlx-all", "mock", "proxy", "runtime-async-std-native-tls", "postgres-array", "sea-orm-internal"]
rustdoc-args = ["--cfg", "docsrs"]

[lib]
Expand Down Expand Up @@ -76,6 +76,7 @@ default = [
]
macros = ["sea-orm-macros/derive"]
mock = []
proxy = ["serde_json"]
with-json = ["serde_json", "sea-query/with-json", "chrono?/serde", "time?/serde", "uuid?/serde", "sea-query-binder?/with-json", "sqlx?/json"]
with-chrono = ["chrono", "sea-query/with-chrono", "sea-query-binder?/with-chrono", "sqlx?/chrono"]
with-rust_decimal = ["rust_decimal", "sea-query/with-rust_decimal", "sea-query-binder?/with-rust_decimal", "sqlx?/rust_decimal"]
Expand Down
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 <langyo.china@gmail.com>"]
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" }

sqlparser = "0.40"
sea-orm = { path = "../../", features = [
"proxy",
"debug-print",
] }
gluesql = { version = "0.15", default-features = false, features = [
"memory-storage",
] }

[dev-dependencies]
smol = { version = "1.2" }
smol-potat = { version = "1.1" }
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 {}
190 changes: 190 additions & 0 deletions examples/proxy_gluesql_example/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
//! 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![];
async_std::task::block_on(async {
for payload in self.mem.lock().unwrap().execute(sql).await.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> {
let sql = if let Some(values) = statement.values {
// Replace all the '?' with the statement values
use sqlparser::ast::{Expr, Value};
use sqlparser::dialect::GenericDialect;
use sqlparser::parser::Parser;

let dialect = GenericDialect {};
let mut ast = Parser::parse_sql(&dialect, statement.sql.as_str()).unwrap();
match &mut ast[0] {
sqlparser::ast::Statement::Insert {
columns, source, ..
} => {
for item in columns.iter_mut() {
item.quote_style = Some('"');
}

if let Some(obj) = source {
match &mut *obj.body {
sqlparser::ast::SetExpr::Values(obj) => {
for (mut item, val) in obj.rows[0].iter_mut().zip(values.0.iter()) {
match &mut item {
Expr::Value(item) => {
*item = match val {
sea_orm::Value::String(val) => {
Value::SingleQuotedString(match val {
Some(val) => val.to_string(),
None => "".to_string(),
})
}
sea_orm::Value::BigInt(val) => Value::Number(
val.unwrap_or(0).to_string(),
false,
),
_ => todo!(),
};
}
_ => todo!(),
}
}
}
_ => todo!(),
}
}
}
_ => todo!(),
}

let statement = &ast[0];
statement.to_string()
} else {
statement.sql
};

println!("SQL execute: {}", sql);
async_std::task::block_on(async {
self.mem.lock().unwrap().execute(sql).await.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
)
"#,
)
.await
.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);
}

#[cfg(test)]
mod tests {
#[smol_potat::test]
async fn try_run() {
crate::main()
}
}
1 change: 1 addition & 0 deletions sea-orm-macros/src/derives/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub mod derive_attr {
pub relation: Option<syn::Ident>,
pub schema_name: Option<syn::Lit>,
pub table_name: Option<syn::Lit>,
pub comment: Option<syn::Lit>,
pub table_iden: Option<()>,
}
}
Expand Down
17 changes: 16 additions & 1 deletion sea-orm-macros/src/derives/entity_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,18 @@ use syn::{
pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> syn::Result<TokenStream> {
// if #[sea_orm(table_name = "foo", schema_name = "bar")] specified, create Entity struct
let mut table_name = None;
let mut comment = quote! {None};
let mut schema_name = quote! { None };
let mut table_iden = false;
attrs
.iter()
.filter(|attr| attr.path().is_ident("sea_orm"))
.try_for_each(|attr| {
attr.parse_nested_meta(|meta| {
if meta.path.is_ident("table_name") {
if meta.path.is_ident("comment") {
let name: Lit = meta.value()?.parse()?;
comment = quote! { Some(#name) };
} else if meta.path.is_ident("table_name") {
table_name = Some(meta.value()?.parse::<Lit>()?);
} else if meta.path.is_ident("schema_name") {
let name: Lit = meta.value()?.parse()?;
Expand Down Expand Up @@ -51,6 +55,10 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> syn::Res
fn table_name(&self) -> &str {
#table_name
}

fn comment(&self) -> Option<&str> {
#comment
}
}
}
})
Expand Down Expand Up @@ -90,6 +98,7 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> syn::Res

let mut nullable = false;
let mut default_value = None;
let mut comment = None;
let mut default_expr = None;
let mut select_as = None;
let mut save_as = None;
Expand Down Expand Up @@ -134,6 +143,8 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> syn::Res
meta.error(format!("Invalid auto_increment = {:?}", lit))
);
}
} else if meta.path.is_ident("comment") {
comment = Some(meta.value()?.parse::<Lit>()?);
} else if meta.path.is_ident("default_value") {
default_value = Some(meta.value()?.parse::<Lit>()?);
} else if meta.path.is_ident("default_expr") {
Expand Down Expand Up @@ -274,9 +285,13 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> syn::Res
if let Some(default_value) = default_value {
match_row = quote! { #match_row.default_value(#default_value) };
}
if let Some(comment) = comment {
match_row = quote! { #match_row.comment(#comment) };
}
if let Some(default_expr) = default_expr {
match_row = quote! { #match_row.default(#default_expr) };
}
// match_row = quote! { #match_row.comment() };
columns_trait.push(match_row);
}
}
Expand Down
1 change: 0 additions & 1 deletion sea-orm-macros/src/derives/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ impl DeriveModel {
/// Method to derive an ActiveModel
pub fn expand_derive_model(input: syn::DeriveInput) -> syn::Result<TokenStream> {
let ident_span = input.ident.span();

match DeriveModel::new(input) {
Ok(model) => model.expand(),
Err(Error::InputNotStruct) => Ok(quote_spanned! {
Expand Down
Loading