Skip to content

Commit d2baefb

Browse files
committed
Implement insert
1 parent f100d97 commit d2baefb

File tree

11 files changed

+203
-56
lines changed

11 files changed

+203
-56
lines changed

Cargo.lock

Lines changed: 9 additions & 0 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: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import 'reflect-metadata'
22

3+
import { existsSync, unlinkSync, writeFileSync } from 'node:fs'
4+
35
import {
46
Column,
57
DevupModel,
@@ -8,9 +10,13 @@ import {
810
Model,
911
} from '@devup-api/model'
1012
import { createSqliteConnection } from '@devup-sql/sqlite'
11-
describe('sqlite', async () => {
13+
describe.sequential('sqlite', async () => {
14+
if (existsSync('./test.db')) {
15+
unlinkSync('./test.db')
16+
}
17+
writeFileSync('./test.db', '')
1218
const pool = await createSqliteConnection({
13-
url: 'sqlite::memory:',
19+
url: 'sqlite:./test.db',
1420
})
1521
it.each([
1622
['SELECT 1 as value', { value: 1 }],
@@ -74,6 +80,7 @@ describe('sqlite', async () => {
7480

7581
const hasRevision = await pool.hasRevision()
7682
expect(hasRevision).toBe(false)
83+
console.log('hasRevision', hasRevision)
7784
if (!hasRevision) {
7885
await pool.setupRevision()
7986
}
@@ -101,10 +108,36 @@ describe('sqlite', async () => {
101108
tag: '',
102109
})
103110

104-
user.username = 'devup'
105-
await user.save()
111+
await pool.save(user)
112+
expect(await pool.fetchAll('SELECT COUNT(*) as count FROM user')).toEqual(
113+
[
114+
{
115+
count: 1,
116+
},
117+
],
118+
)
119+
const ac = await pool.begin()
120+
await pool.save(user, ac)
121+
122+
expect(await pool.fetchAll('SELECT COUNT(*) as count FROM user')).toEqual(
123+
[
124+
{
125+
count: 1,
126+
},
127+
],
128+
)
129+
await pool.commit(ac)
130+
131+
expect(await pool.fetchAll('SELECT COUNT(*) as count FROM user')).toEqual(
132+
[
133+
{
134+
count: 2,
135+
},
136+
],
137+
)
138+
// await user.save()
106139

107-
const user2 = new User()
140+
// const user2 = new User()
108141

109142
// const user = await User.findById(1)
110143
// expect(user?.username).toEqual('devup')

libs/node/model/main.js

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,35 @@
22
/* eslint-disable */
33
/* prettier-ignore */
44
module.exports=require('./index')
5-
class DevupModel{}
5+
class DevupModel{
6+
constructor(data){
7+
if(data){
8+
createModelInstance(this, data)
9+
}
10+
}
11+
12+
static create(data){
13+
return createModelInstance(new this(), data)
14+
}
15+
}
16+
617
module.exports.DevupModel=DevupModel
18+
19+
20+
function createModelInstance(obj, data){
21+
obj.__devup_name = obj.constructor.name
22+
if(data){
23+
for(const key of Object.keys(data)){
24+
let value = data[key]
25+
if (value instanceof Date){
26+
value = value.toISOString()
27+
}
28+
obj[key] = value
29+
}
30+
}
31+
return obj
32+
}
33+
34+
module.exports.createModelInstance=createModelInstance
35+
36+

sql/core/devup_database/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ version = "0.1.0"
44
edition = "2024"
55

66
[dependencies]
7-
sqlx = { version = "0.8" }
7+
sqlx = { version = "0.8", features = ["any"] }
88
devup_database_diff = { path = "../devup_database_diff" }
99
devup_migrate = { path = "../devup_migrate" }
1010
model = { path = "../../../core/model" }
1111
database_strategy = { path = "../database_strategy" }
12+
serde_json = "1.0.140"
13+
inflections = "1.1.1"

sql/core/devup_database/src/lib.rs

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
use database_strategy::{DatabaseStrategy, QueryParams};
2+
23
use devup_migrate::generate_revision_sql::GenerateRevisionActionSqlResult;
34
use devup_migrate::get_all_revisions;
45
use devup_migrate::revision::DevupSqlRevision;
56
use devup_migrate::{
67
generate::generate_models_from_revisions, generate_revision_sql::generate_revision_action_sql,
78
};
9+
use inflections::case::to_snake_case;
810
use model::{DevupModel, get_all_models};
9-
use sqlx::query;
11+
use serde_json::Value;
12+
use sqlx::any::AnyTransactionManager;
13+
use sqlx::{AnyConnection, TransactionManager, query};
1014
use std::time::Duration;
1115

1216
use devup_database_diff::diff_models;
@@ -160,7 +164,7 @@ impl DevupSqlPool {
160164
.execute(&mut *tx)
161165
.await?;
162166

163-
self.commit(tx).await?;
167+
self.commit(&mut *tx).await?;
164168
return Ok(());
165169
}
166170

@@ -224,7 +228,7 @@ impl DevupSqlPool {
224228
.bind(target_revision)
225229
.execute(&mut *tx)
226230
.await?;
227-
self.commit(tx).await?;
231+
self.commit(&mut *tx).await?;
228232
Ok(())
229233
}
230234

@@ -244,7 +248,7 @@ impl DevupSqlPool {
244248
.database_strategy
245249
.setup_revision(&mut tx)
246250
.await?;
247-
self.commit(tx).await?;
251+
self.commit(&mut *tx).await?;
248252
Ok(())
249253
}
250254

@@ -269,11 +273,66 @@ impl DevupSqlPool {
269273
}
270274
}
271275

272-
pub async fn commit(&self, tx: Transaction<'_, Any>) -> Result<(), Error> {
273-
tx.commit().await
276+
pub async fn commit(&self, tx: &mut AnyConnection) -> Result<(), Error> {
277+
AnyTransactionManager::commit(tx).await?;
278+
Ok(())
279+
}
280+
281+
pub async fn rollback(&self, tx: &mut AnyConnection) -> Result<(), Error> {
282+
AnyTransactionManager::rollback(tx).await?;
283+
Ok(())
274284
}
275285

276-
pub async fn rollback(&self, tx: Transaction<'_, Any>) -> Result<(), Error> {
277-
tx.rollback().await
286+
pub async fn save(&self, obj: &Value, tx: Option<&mut AnyConnection>) -> Result<(), Error> {
287+
let table_name = obj
288+
.get::<String>("__devup_name".to_string())
289+
.ok_or(Error::ColumnNotFound("__devup_name".to_string()))?
290+
.as_str()
291+
.ok_or(Error::ColumnNotFound("__devup_name".to_string()))?;
292+
293+
let mut keys = Vec::new();
294+
let mut values = Vec::new();
295+
296+
for (key, value) in obj
297+
.as_object()
298+
.ok_or(Error::ColumnNotFound("__devup_name".to_string()))?
299+
.iter()
300+
{
301+
if key.starts_with("__devup_") {
302+
continue;
303+
}
304+
if let Some(value) = value.as_str() {
305+
keys.push(to_snake_case(key));
306+
values.push(value);
307+
}
308+
}
309+
310+
let sql = format!(
311+
"INSERT INTO {} ({}) VALUES ({})",
312+
to_snake_case(table_name),
313+
keys.join(", "),
314+
values
315+
.iter()
316+
.enumerate()
317+
.map(
318+
|(idx, _)| match self.options.database_strategy.get_query_params() {
319+
QueryParams::Number => format!("${}", idx + 1),
320+
QueryParams::QuestionMark => "?".to_string(),
321+
}
322+
)
323+
.collect::<Vec<String>>()
324+
.join(", ")
325+
);
326+
327+
let mut query = query(&sql);
328+
for value in values {
329+
query = query.bind(value);
330+
}
331+
if let Some(tx) = tx {
332+
query.execute(&mut *tx).await?;
333+
} else {
334+
query.execute(self.pool.as_ref().unwrap()).await?;
335+
}
336+
Ok(())
278337
}
279338
}

sql/core/devup_migrate/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ serde = { version = "1.0.219", features = ["derive"] }
1111
tokio = { version = "1.44.2", features = ["fs"] }
1212
serde_json = "1.0.140"
1313
database_strategy = { path = "../database_strategy" }
14+
inflections = "1.1.1"
1415

1516
[dev-dependencies]
1617
database_strategy_mysql = { path = "../database_strategy_mysql" }

sql/core/devup_migrate/src/generate_revision_sql.rs

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use database_strategy::{DatabaseStrategy, QueryParams};
1+
use database_strategy::DatabaseStrategy;
2+
use inflections::case::to_snake_case;
23
use model::column::DevupModelColumnDefault;
34

45
use crate::revision::DevupSqlRevisionAction;
@@ -225,20 +226,6 @@ pub fn generate_revision_action_sql(
225226
GenerateRevisionActionSqlResult { result }
226227
}
227228

228-
fn to_snake_case(s: &str) -> String {
229-
let mut result = String::new();
230-
for (i, c) in s.chars().enumerate() {
231-
if c.is_uppercase() {
232-
if i > 0 {
233-
result.push('_');
234-
}
235-
result.push(c.to_ascii_lowercase());
236-
} else {
237-
result.push(c);
238-
}
239-
}
240-
result
241-
}
242229
#[cfg(test)]
243230
mod tests {
244231
use database_strategy_mysql::MysqlDatabaseStrategy;

sql/libs/node/mysql/index.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,5 +78,8 @@ export declare class DevupNodeSqlPool {
7878
hasRevision(): Promise<boolean>
7979
getRevisionSql(revision: number, isUp: boolean): Promise<Array<GenerateRevisionActionSqlWithParams>>
8080
setupRevision(): Promise<void>
81+
commit(tx: DevupNodeSqlTransaction): Promise<void>
82+
rollback(tx: DevupNodeSqlTransaction): Promise<void>
83+
save(obj: any, tx?: DevupNodeSqlTransaction | undefined | null): Promise<void>
8184
}
8285
export declare class DevupNodeSqlTransaction { }

0 commit comments

Comments
 (0)