Skip to content

Commit 22403f1

Browse files
committed
Impelement find
1 parent 574a513 commit 22403f1

File tree

24 files changed

+347
-351
lines changed

24 files changed

+347
-351
lines changed

Cargo.lock

Lines changed: 8 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

__tests__/sql/index.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,9 @@ describe.sequential('sqlite', async () => {
218218
],
219219
)
220220

221+
const allUsers = await pool.find(User)
222+
expect(allUsers).toEqual([user, user2])
223+
221224
await pool.transaction(async (ac) => {
222225
await pool.delete(user2, ac)
223226
await pool.delete(user, ac)

core/api-option/src/lib.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,14 @@ pub enum DtoType {
1111
Delete,
1212
}
1313

14-
#[derive(Debug, Serialize, Deserialize, Clone)]
14+
#[derive(Debug, Default)]
1515
pub struct DevupApiOption {
1616
pub pick: Vec<String>,
1717
pub omit: Vec<String>,
1818
pub scope: Vec<String>,
1919
}
20+
21+
#[derive(Debug, Default)]
22+
pub struct DevupApiQueryOption {
23+
pub query: Vec<String>,
24+
}

core/api/src/lib.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -106,40 +106,48 @@ pub fn get_all_proxy_routers() -> Vec<Arc<ProxyRouter>> {
106106

107107
// Schema
108108

109-
static SCHEMA_MAP: Lazy<Mutex<HashMap<String, DevupSchema>>> =
109+
static SCHEMA_MAP: Lazy<Mutex<HashMap<String, Arc<DevupSchema>>>> =
110110
Lazy::new(|| Mutex::new(HashMap::new()));
111111

112112
pub fn add_schema(schema: DevupSchema) {
113113
let mut schema_map = SCHEMA_MAP.lock().unwrap();
114-
schema_map.insert(schema.name.clone(), schema);
114+
schema_map.insert(schema.name.clone(), Arc::new(schema));
115115
}
116116

117-
pub fn get_schema(name: &str) -> Option<DevupSchema> {
117+
pub fn get_schema(name: &str) -> Option<Arc<DevupSchema>> {
118118
let schema_map = SCHEMA_MAP.lock().unwrap();
119-
schema_map.get(name).cloned()
119+
schema_map.get(name).map(Arc::clone)
120120
}
121121

122-
pub fn get_all_schemas() -> Vec<DevupSchema> {
122+
pub fn get_all_schemas() -> Vec<Arc<DevupSchema>> {
123123
let schema_map = SCHEMA_MAP.lock().unwrap();
124124
schema_map.values().cloned().collect()
125125
}
126126

127127
// Model
128128

129-
static MODEL_MAP: Lazy<Mutex<HashMap<String, model::DevupModel>>> =
129+
static MODEL_MAP: Lazy<Mutex<HashMap<String, Arc<model::DevupModel>>>> =
130130
Lazy::new(|| Mutex::new(HashMap::new()));
131131

132132
pub fn add_model(model: model::DevupModel) {
133133
let mut model_map = MODEL_MAP.lock().unwrap();
134-
model_map.insert(model.name.clone(), model);
134+
model_map.insert(model.name.clone(), Arc::new(model));
135135
}
136136

137-
pub fn get_model(name: &str) -> Option<model::DevupModel> {
137+
pub fn get_model(name: &str) -> Option<Arc<model::DevupModel>> {
138138
let model_map = MODEL_MAP.lock().unwrap();
139139
model_map.get(name).cloned()
140140
}
141141

142-
pub fn get_all_models() -> Vec<model::DevupModel> {
142+
pub fn get_all_models() -> Vec<Arc<model::DevupModel>> {
143143
let model_map = MODEL_MAP.lock().unwrap();
144144
model_map.values().cloned().collect()
145145
}
146+
147+
pub fn get_model_storage() -> HashMap<String, Arc<model::DevupModel>> {
148+
let model_map = MODEL_MAP.lock().unwrap();
149+
model_map
150+
.iter()
151+
.map(|(name, model)| (name.clone(), Arc::clone(model)))
152+
.collect()
153+
}

core/model/src/lib.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ use serde::{Deserialize, Serialize};
1010
use shared_memory::*;
1111
use std::process;
1212

13+
#[derive(Debug, Copy, Clone)]
14+
pub enum ObjectFieldNameType {
15+
SnakeCase,
16+
CamelCase,
17+
}
18+
1319
#[derive(Debug, Serialize, Deserialize, Clone, Encode, Decode)]
1420
pub struct DevupModel {
1521
pub name: String,
@@ -38,17 +44,18 @@ fn get_shmem_ptr() -> Result<Shmem, ShmemError> {
3844
shmem.set_owner(false);
3945
Ok(shmem)
4046
}
41-
pub fn add_model(model: DevupModel) -> Result<(), Box<dyn std::error::Error>> {
47+
pub fn add_model(model: DevupModel) -> Result<Arc<DevupModel>, Box<dyn std::error::Error>> {
4248
let mut shmem = get_shmem_ptr()?;
4349

4450
let mut data: (HashMap<String, Arc<DevupModel>>, usize) =
4551
bincode::decode_from_slice(unsafe { shmem.as_slice() }, config::standard())?;
46-
data.0.insert(model.name.clone(), Arc::new(model));
52+
let n = Arc::new(model);
53+
data.0.insert(n.name.clone(), n.clone());
4754
let serialized = bincode::encode_to_vec(&data, config::standard())?;
4855
unsafe {
4956
shmem.as_slice_mut()[0..serialized.len()].copy_from_slice(&serialized);
5057
};
51-
Ok(())
58+
Ok(n)
5259
}
5360

5461
pub fn get_model(name: &str) -> Result<Arc<DevupModel>, Box<dyn std::error::Error>> {

libs/node/model/main.js

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,8 @@
33
/* prettier-ignore */
44
module.exports=require('./index')
55
class DevupModel{
6-
constructor(data){
7-
if(data)createModelInstance(this, data)
8-
}
9-
static create(data){
10-
return createModelInstance(new this(), data)
11-
}
6+
constructor(data){if(data)createModelInstance(this, data)}
7+
static create(data){return createModelInstance(new this(), data)}
128
}
139

1410
module.exports.DevupModel=DevupModel
@@ -26,7 +22,3 @@ function createModelInstance(obj, data){
2622
}
2723
return obj
2824
}
29-
30-
module.exports.createModelInstance=createModelInstance
31-
32-

libs/node/model/src/model.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@ pub fn model(env: Env, name: Option<String>) -> Result<JsFunction> {
88
let global = ctx.env.get_global()?;
99
let reflect: JsObject = global.get_named_property("Reflect")?;
1010
let get_metadata: JsFunction = reflect.get_named_property("getMetadata")?;
11-
let cls: JsObject = ctx.get(0)?;
11+
let mut cls: JsObject = ctx.get(0)?;
1212
let model_name: JsString = cls.get_named_property("name")?;
1313
let model_name = match name.clone() {
1414
Some(name) => name,
1515
None => model_name.into_utf8()?.as_str()?.to_string(),
1616
};
17-
17+
cls.set_named_property(
18+
"__devup_name",
19+
&ctx.env.create_string(model_name.as_str())?.into_unknown(),
20+
)?;
1821
add_model(DevupModel {
1922
name: model_name.clone(),
2023
fields: ctx.env.from_js_value(get_metadata.call(

libs/node/model/src/utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use napi::{Env, JsFunction, JsObject, JsUnknown, bindgen_prelude::*};
22

3-
pub fn log(env: &Env, value: JsUnknown) -> Result<()> {
3+
pub fn log(env: &Env, value: &JsUnknown) -> Result<()> {
44
let global = env.get_global()?;
55
let console: JsObject = global.get_named_property("console")?;
66
let log_fn = console.get_named_property::<JsFunction>("log")?;

sql/core/database_strategy/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,7 @@ sqlx = { version = "0.8", features = ["postgres", "mysql", "sqlite"] }
88
async-trait = "0.1"
99
model = { path = "../../../core/model" }
1010
serde_json = "1.0.140"
11+
inflections = "1.1.1"
12+
devup_sql = { path = "../devup_sql" }
13+
sql_utils = { path = "../sql_utils" }
14+
api = { path = "../../../core/api" }

sql/core/database_strategy/src/lib.rs

Lines changed: 113 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
use std::sync::Arc;
1+
use std::{io, sync::Arc};
22

3+
use api::get_model_storage;
34
use async_trait::async_trait;
4-
use model::{DevupModel, column::DevupModelColumn};
5+
use devup_sql::generate_find_sql_result;
6+
use inflections::case::to_snake_case;
7+
use model::{DevupModel, DevupModelFieldType, ObjectFieldNameType, column::DevupModelColumn};
58
use serde_json::{Map, Value};
9+
use sql_utils::generate_where_sql;
610
use sqlx::{Error, MySql, Postgres, Sqlite, Transaction};
711

812
pub enum QueryParams {
@@ -86,12 +90,117 @@ pub trait DatabaseStrategy: Send + Sync {
8690
instance_id: &Map<String, Value>,
8791
obj: &Value,
8892
tx: &mut DatabaseTransaction,
89-
) -> Result<SqlResult, Error>;
93+
) -> Result<SqlResult, Error> {
94+
let (fields, values): (Vec<_>, Vec<_>) = obj
95+
.as_object()
96+
.ok_or(Error::Protocol("Wrong object".to_string()))?
97+
.into_iter()
98+
.filter_map(|(key, value)| {
99+
if key.starts_with("__devup_") {
100+
None
101+
} else {
102+
Some((to_snake_case(key), value.clone()))
103+
}
104+
})
105+
.unzip();
106+
let q = format!(
107+
"UPDATE {} SET {} WHERE {}",
108+
to_snake_case(&model.name),
109+
fields
110+
.into_iter()
111+
.map(|f| format!("{} = ?", f))
112+
.collect::<Vec<String>>()
113+
.join(","),
114+
generate_where_sql(&Value::Object(instance_id.clone()))?
115+
);
116+
self.execute(&q, &values, Some(tx))
117+
.await
118+
.map_err(|e| Error::Protocol(format!("Update Error {} {} {:?}", e, q, values)))?;
119+
Ok(SqlResult {
120+
instance_id: instance_id.clone(),
121+
instance: obj
122+
.as_object()
123+
.ok_or(Error::Protocol("Wrong object".to_string()))?
124+
.clone(),
125+
})
126+
}
90127

91128
async fn delete_sql(
92129
&self,
93130
model: Arc<DevupModel>,
94131
instance_id: &Map<String, Value>,
95132
tx: &mut DatabaseTransaction,
96-
) -> Result<(), Error>;
133+
) -> Result<(), Error> {
134+
let q = format!(
135+
"DELETE FROM {} WHERE {}",
136+
to_snake_case(&model.name),
137+
generate_where_sql(&Value::Object(instance_id.clone()))?
138+
);
139+
self.execute(&q, &[], Some(tx))
140+
.await
141+
.map_err(|e| Error::Protocol(format!("Delete Error {} {} {:?}", e, q, instance_id)))?;
142+
Ok(())
143+
}
144+
145+
async fn find(
146+
&self,
147+
model: &DevupModel,
148+
tx: Option<&mut DatabaseTransaction>,
149+
field_name_type: ObjectFieldNameType,
150+
// option: Option<DevupApiQueryOption>,
151+
) -> Result<Vec<Value>, Error> {
152+
let q = generate_find_sql_result(&model, None, &get_model_storage());
153+
let s = &q.to_sql(field_name_type);
154+
dbg!(s);
155+
let result = self.fetch_all(s, &[], tx).await?;
156+
Ok(result
157+
.into_iter()
158+
.map(|v| add_instance_id(model, v, field_name_type))
159+
.collect::<Result<Vec<_>, _>>()?)
160+
}
161+
}
162+
163+
pub fn add_instance_id(
164+
model: &DevupModel,
165+
mut obj: Value,
166+
field_name_type: ObjectFieldNameType,
167+
) -> Result<Value, io::Error> {
168+
let _obj = obj
169+
.as_object_mut()
170+
.ok_or(io::Error::new(io::ErrorKind::InvalidData, "Not an object"))?;
171+
// create instance id object
172+
let instance_id = {
173+
let mut instance_id = Map::new();
174+
175+
for field in model.fields.iter() {
176+
if let DevupModelFieldType::Column(column) = field {
177+
if column.primary_key {
178+
instance_id.insert(
179+
match field_name_type {
180+
ObjectFieldNameType::SnakeCase => to_snake_case(&column.name),
181+
// column name is already camel case
182+
ObjectFieldNameType::CamelCase => column.name.clone(),
183+
},
184+
_obj.get(&match field_name_type {
185+
ObjectFieldNameType::SnakeCase => to_snake_case(&column.name),
186+
// column name is already camel case
187+
ObjectFieldNameType::CamelCase => column.name.clone(),
188+
})
189+
.ok_or(io::Error::new(
190+
io::ErrorKind::InvalidData,
191+
"Primary key not found",
192+
))?
193+
.clone(),
194+
);
195+
}
196+
}
197+
}
198+
instance_id
199+
};
200+
201+
_obj.insert(
202+
"__devup_instance_id".to_string(),
203+
Value::Object(instance_id),
204+
);
205+
Ok(obj)
97206
}

0 commit comments

Comments
 (0)