@b4moss/crudian 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -10
- package/dist/bun-sqlite/sql.d.ts +5 -1
- package/dist/bun-sqlite/sql.d.ts.map +1 -1
- package/dist/bun-sqlite/sql.js +7 -1
- package/dist/dialect/index.d.ts +7 -0
- package/dist/dialect/index.d.ts.map +1 -0
- package/dist/dialect/index.js +19 -0
- package/dist/dialect/mysql.d.ts +4 -0
- package/dist/dialect/mysql.d.ts.map +1 -0
- package/dist/dialect/mysql.js +24 -0
- package/dist/dialect/postgres.d.ts +4 -0
- package/dist/dialect/postgres.d.ts.map +1 -0
- package/dist/dialect/postgres.js +25 -0
- package/dist/dialect/sqlite.d.ts +4 -0
- package/dist/dialect/sqlite.d.ts.map +1 -0
- package/dist/dialect/sqlite.js +23 -0
- package/dist/dialect/types.d.ts +25 -0
- package/dist/dialect/types.d.ts.map +1 -0
- package/dist/dialect/types.js +5 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/pool.d.ts +18 -0
- package/dist/pool.d.ts.map +1 -0
- package/dist/pool.js +1 -0
- package/dist/prisma/crud.d.ts +2 -1
- package/dist/prisma/crud.d.ts.map +1 -1
- package/dist/prisma/crud.js +7 -4
- package/dist/prisma/server-dialect-harness.d.ts +16 -0
- package/dist/prisma/server-dialect-harness.d.ts.map +1 -0
- package/dist/prisma/server-dialect-harness.js +120 -0
- package/dist/sqlite/async-crud.d.ts +4 -0
- package/dist/sqlite/async-crud.d.ts.map +1 -1
- package/dist/sqlite/async-crud.js +57 -36
- package/dist/sqlite/pk.d.ts +6 -13
- package/dist/sqlite/pk.d.ts.map +1 -1
- package/dist/sqlite/pk.js +13 -6
- package/dist/sqlite/sql.d.ts +10 -1
- package/dist/sqlite/sql.d.ts.map +1 -1
- package/dist/sqlite/sql.js +60 -23
- package/dist/sqlite/sync-crud.d.ts +4 -0
- package/dist/sqlite/sync-crud.d.ts.map +1 -1
- package/dist/sqlite/sync-crud.js +48 -35
- package/dist/typeorm/crud.d.ts +24 -0
- package/dist/typeorm/crud.d.ts.map +1 -0
- package/dist/typeorm/crud.js +142 -0
- package/dist/typeorm/index.d.ts +8 -0
- package/dist/typeorm/index.d.ts.map +1 -0
- package/dist/typeorm/index.js +6 -0
- package/dist/typeorm/server-dialect-harness.d.ts +13 -0
- package/dist/typeorm/server-dialect-harness.d.ts.map +1 -0
- package/dist/typeorm/server-dialect-harness.js +120 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +31 -6
package/dist/sqlite/sync-crud.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { CrudianError, assertString, } from "../index.js";
|
|
2
|
+
import { sqliteDialect } from "../dialect/sqlite.js";
|
|
2
3
|
import { createPkGuard, resolvePk } from "./pk.js";
|
|
3
|
-
import { compileWhere,
|
|
4
|
+
import { compileWhere, resolveWhere } from "./sql.js";
|
|
4
5
|
function requireWhere(query, label) {
|
|
5
6
|
if (query.where === undefined || query.where === null) {
|
|
6
7
|
throw new CrudianError(`${label} requires where`);
|
|
7
8
|
}
|
|
8
9
|
}
|
|
9
|
-
function selectColumns(columns) {
|
|
10
|
+
function selectColumns(d, columns) {
|
|
10
11
|
if (!columns || columns.length === 0)
|
|
11
12
|
return "*";
|
|
12
|
-
return columns.map((c) => quoteIdent(c)).join(", ");
|
|
13
|
+
return columns.map((c) => d.quoteIdent(c)).join(", ");
|
|
13
14
|
}
|
|
14
15
|
function rowFromObject(value) {
|
|
15
16
|
if (value === null || typeof value !== "object") {
|
|
@@ -17,9 +18,11 @@ function rowFromObject(value) {
|
|
|
17
18
|
}
|
|
18
19
|
return { ...value };
|
|
19
20
|
}
|
|
20
|
-
|
|
21
|
+
/** Dialect-aware sync CRUD factory. */
|
|
22
|
+
export function createSyncCrud(db, ex, dialect, options) {
|
|
21
23
|
const pk = resolvePk(options);
|
|
22
|
-
const ensurePkColumn = createPkGuard(pk,
|
|
24
|
+
const ensurePkColumn = createPkGuard(pk, dialect, ex.all);
|
|
25
|
+
const d = dialect;
|
|
23
26
|
const crud = {
|
|
24
27
|
db,
|
|
25
28
|
create(table, cols) {
|
|
@@ -32,23 +35,24 @@ export function createSyncSqliteCrud(db, ex, options) {
|
|
|
32
35
|
if (keys.length === 0) {
|
|
33
36
|
throw new CrudianError("cols must not be empty");
|
|
34
37
|
}
|
|
35
|
-
const tbl = quoteIdent(table);
|
|
36
|
-
const colSql = keys.map((k) => quoteIdent(k)).join(", ");
|
|
37
|
-
|
|
38
|
+
const tbl = d.quoteIdent(table);
|
|
39
|
+
const colSql = keys.map((k) => d.quoteIdent(k)).join(", ");
|
|
40
|
+
let idx = 1;
|
|
41
|
+
const placeholders = keys.map(() => d.placeholder(idx++)).join(", ");
|
|
38
42
|
const args = keys.map((k) => cols[k]);
|
|
39
43
|
ex.run(`INSERT INTO ${tbl} (${colSql}) VALUES (${placeholders})`, args);
|
|
40
44
|
const pkValue = Object.prototype.hasOwnProperty.call(cols, pk)
|
|
41
45
|
? cols[pk]
|
|
42
|
-
: Number(ex.get(
|
|
43
|
-
const row = ex.get(`SELECT * FROM ${tbl} WHERE ${quoteIdent(pk)} =
|
|
46
|
+
: Number(ex.get(d.lastInsertIdSql())?.id);
|
|
47
|
+
const row = ex.get(`SELECT * FROM ${tbl} WHERE ${d.quoteIdent(pk)} = ${d.placeholder(1)}`, [pkValue]);
|
|
44
48
|
return rowFromObject(row);
|
|
45
49
|
},
|
|
46
50
|
read(table, query = {}) {
|
|
47
51
|
assertString(table, "table");
|
|
48
52
|
ensurePkColumn(table);
|
|
49
|
-
const tbl = quoteIdent(table);
|
|
50
|
-
const where = compileWhere(resolveWhere(query.where));
|
|
51
|
-
const sql = `SELECT ${selectColumns(query.columns)} FROM ${tbl}` +
|
|
53
|
+
const tbl = d.quoteIdent(table);
|
|
54
|
+
const where = compileWhere(d, resolveWhere(query.where));
|
|
55
|
+
const sql = `SELECT ${selectColumns(d, query.columns)} FROM ${tbl}` +
|
|
52
56
|
(where.sql ? ` WHERE ${where.sql}` : "") +
|
|
53
57
|
` LIMIT 1`;
|
|
54
58
|
const row = ex.get(sql, where.args);
|
|
@@ -65,25 +69,27 @@ export function createSyncSqliteCrud(db, ex, options) {
|
|
|
65
69
|
if (keys.length === 0) {
|
|
66
70
|
throw new CrudianError("cols must not be empty");
|
|
67
71
|
}
|
|
68
|
-
const tbl = quoteIdent(table);
|
|
69
|
-
|
|
72
|
+
const tbl = d.quoteIdent(table);
|
|
73
|
+
let idx = 1;
|
|
74
|
+
const sets = keys.map((k) => `${d.quoteIdent(k)} = ${d.placeholder(idx++)}`).join(", ");
|
|
75
|
+
const where = compileWhere(d, resolveWhere(query.where), idx);
|
|
70
76
|
if (!where.sql) {
|
|
71
77
|
throw new CrudianError("update requires where");
|
|
72
78
|
}
|
|
73
|
-
const sets = keys.map((k) => `${quoteIdent(k)} = ?`).join(", ");
|
|
74
79
|
const args = [...keys.map((k) => cols[k]), ...where.args];
|
|
75
80
|
const result = ex.run(`UPDATE ${tbl} SET ${sets} WHERE ${where.sql}`, args);
|
|
76
81
|
if (result.changes === 0)
|
|
77
82
|
return null;
|
|
78
|
-
const
|
|
83
|
+
const fetchWhere = compileWhere(d, resolveWhere(query.where));
|
|
84
|
+
const row = ex.get(`SELECT * FROM ${tbl} WHERE ${fetchWhere.sql} LIMIT 1`, fetchWhere.args);
|
|
79
85
|
return row == null ? null : rowFromObject(row);
|
|
80
86
|
},
|
|
81
87
|
delete(table, query) {
|
|
82
88
|
assertString(table, "table");
|
|
83
89
|
ensurePkColumn(table);
|
|
84
90
|
requireWhere(query, "delete");
|
|
85
|
-
const tbl = quoteIdent(table);
|
|
86
|
-
const where = compileWhere(resolveWhere(query.where));
|
|
91
|
+
const tbl = d.quoteIdent(table);
|
|
92
|
+
const where = compileWhere(d, resolveWhere(query.where));
|
|
87
93
|
if (!where.sql) {
|
|
88
94
|
throw new CrudianError("delete requires where");
|
|
89
95
|
}
|
|
@@ -112,8 +118,8 @@ export function createSyncSqliteCrud(db, ex, options) {
|
|
|
112
118
|
typeof query.cursor !== "string") {
|
|
113
119
|
throw new CrudianError("cursor must be a number, string, or null");
|
|
114
120
|
}
|
|
115
|
-
const tbl = quoteIdent(table);
|
|
116
|
-
const where = compileWhere(resolveWhere(query.where));
|
|
121
|
+
const tbl = d.quoteIdent(table);
|
|
122
|
+
const where = compileWhere(d, resolveWhere(query.where));
|
|
117
123
|
const total = crud.count(table, { where: query.where });
|
|
118
124
|
if (paging === "offset") {
|
|
119
125
|
const offset = query.offset ?? 0;
|
|
@@ -121,10 +127,11 @@ export function createSyncSqliteCrud(db, ex, options) {
|
|
|
121
127
|
throw new CrudianError("offset must be a non-negative number");
|
|
122
128
|
}
|
|
123
129
|
const args = [...where.args];
|
|
130
|
+
let idx = where.nextIndex;
|
|
124
131
|
const whereSql = where.sql ? ` WHERE ${where.sql}` : "";
|
|
125
|
-
const sql = `SELECT ${selectColumns(query.columns)} FROM ${tbl}` +
|
|
132
|
+
const sql = `SELECT ${selectColumns(d, query.columns)} FROM ${tbl}` +
|
|
126
133
|
whereSql +
|
|
127
|
-
` ORDER BY ${quoteIdent(pk)} ASC LIMIT
|
|
134
|
+
` ORDER BY ${d.quoteIdent(pk)} ASC LIMIT ${d.placeholder(idx++)} OFFSET ${d.placeholder(idx++)}`;
|
|
128
135
|
args.push(limit, offset);
|
|
129
136
|
const items = ex.all(sql, args).map((r) => rowFromObject(r));
|
|
130
137
|
return {
|
|
@@ -136,17 +143,18 @@ export function createSyncSqliteCrud(db, ex, options) {
|
|
|
136
143
|
};
|
|
137
144
|
}
|
|
138
145
|
const args = [...where.args];
|
|
146
|
+
let idx = where.nextIndex;
|
|
139
147
|
const parts = [];
|
|
140
148
|
if (where.sql)
|
|
141
149
|
parts.push(`(${where.sql})`);
|
|
142
150
|
if (query.cursor != null) {
|
|
143
|
-
parts.push(`${quoteIdent(pk)} >
|
|
151
|
+
parts.push(`${d.quoteIdent(pk)} > ${d.placeholder(idx++)}`);
|
|
144
152
|
args.push(query.cursor);
|
|
145
153
|
}
|
|
146
154
|
const whereSql = parts.length > 0 ? ` WHERE ${parts.join(" AND ")}` : "";
|
|
147
|
-
const sql = `SELECT ${selectColumns(query.columns)} FROM ${tbl}` +
|
|
155
|
+
const sql = `SELECT ${selectColumns(d, query.columns)} FROM ${tbl}` +
|
|
148
156
|
whereSql +
|
|
149
|
-
` ORDER BY ${quoteIdent(pk)} ASC LIMIT
|
|
157
|
+
` ORDER BY ${d.quoteIdent(pk)} ASC LIMIT ${d.placeholder(idx++)}`;
|
|
150
158
|
args.push(limit + 1);
|
|
151
159
|
const rows = ex.all(sql, args).map((r) => rowFromObject(r));
|
|
152
160
|
const hasMore = rows.length > limit;
|
|
@@ -164,9 +172,9 @@ export function createSyncSqliteCrud(db, ex, options) {
|
|
|
164
172
|
count(table, query = {}) {
|
|
165
173
|
assertString(table, "table");
|
|
166
174
|
ensurePkColumn(table);
|
|
167
|
-
const tbl = quoteIdent(table);
|
|
168
|
-
const where = compileWhere(resolveWhere(query.where));
|
|
169
|
-
const sql = `SELECT COUNT(*) AS ${quoteIdent("row_count")} FROM ${tbl}` +
|
|
175
|
+
const tbl = d.quoteIdent(table);
|
|
176
|
+
const where = compileWhere(d, resolveWhere(query.where));
|
|
177
|
+
const sql = `SELECT COUNT(*) AS ${d.quoteIdent("row_count")} FROM ${tbl}` +
|
|
170
178
|
(where.sql ? ` WHERE ${where.sql}` : "");
|
|
171
179
|
const row = ex.get(sql, where.args);
|
|
172
180
|
return Number(row?.row_count ?? 0);
|
|
@@ -174,9 +182,9 @@ export function createSyncSqliteCrud(db, ex, options) {
|
|
|
174
182
|
exists(table, query = {}) {
|
|
175
183
|
assertString(table, "table");
|
|
176
184
|
ensurePkColumn(table);
|
|
177
|
-
const tbl = quoteIdent(table);
|
|
178
|
-
const where = compileWhere(resolveWhere(query.where));
|
|
179
|
-
const sql = `SELECT 1 AS ${quoteIdent("ok")} FROM ${tbl}` +
|
|
185
|
+
const tbl = d.quoteIdent(table);
|
|
186
|
+
const where = compileWhere(d, resolveWhere(query.where));
|
|
187
|
+
const sql = `SELECT 1 AS ${d.quoteIdent("ok")} FROM ${tbl}` +
|
|
180
188
|
(where.sql ? ` WHERE ${where.sql}` : "") +
|
|
181
189
|
` LIMIT 1`;
|
|
182
190
|
return ex.get(sql, where.args) != null;
|
|
@@ -260,12 +268,13 @@ export function createSyncSqliteCrud(db, ex, options) {
|
|
|
260
268
|
if (keys.length === 0) {
|
|
261
269
|
throw new CrudianError("cols must not be empty");
|
|
262
270
|
}
|
|
263
|
-
const tbl = quoteIdent(table);
|
|
264
|
-
|
|
271
|
+
const tbl = d.quoteIdent(table);
|
|
272
|
+
let idx = 1;
|
|
273
|
+
const sets = keys.map((k) => `${d.quoteIdent(k)} = ${d.placeholder(idx++)}`).join(", ");
|
|
274
|
+
const where = compileWhere(d, resolveWhere(query.where), idx);
|
|
265
275
|
if (!where.sql) {
|
|
266
276
|
throw new CrudianError("bulkUpdate requires where");
|
|
267
277
|
}
|
|
268
|
-
const sets = keys.map((k) => `${quoteIdent(k)} = ?`).join(", ");
|
|
269
278
|
const args = [...keys.map((k) => cols[k]), ...where.args];
|
|
270
279
|
const result = ex.run(`UPDATE ${tbl} SET ${sets} WHERE ${where.sql}`, args);
|
|
271
280
|
return Number(result.changes ?? 0);
|
|
@@ -303,3 +312,7 @@ export function createSyncSqliteCrud(db, ex, options) {
|
|
|
303
312
|
};
|
|
304
313
|
return crud;
|
|
305
314
|
}
|
|
315
|
+
/** SQLite sync CRUD (compat). */
|
|
316
|
+
export function createSyncSqliteCrud(db, ex, options) {
|
|
317
|
+
return createSyncCrud(db, ex, sqliteDialect, options);
|
|
318
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type CreateCrudOptions } from "../index.js";
|
|
2
|
+
import { type AsyncSqliteCrud } from "../sqlite/async-crud.js";
|
|
3
|
+
/** Minimal EntityManager / QueryRunner query surface used by the adapter. */
|
|
4
|
+
export type TypeormLikeQuerier = {
|
|
5
|
+
query(query: string, parameters?: unknown[]): Promise<unknown>;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Minimal DataSource surface used by the adapter.
|
|
9
|
+
* Callers own `initialize` / entities / pool configuration.
|
|
10
|
+
*/
|
|
11
|
+
export type TypeormLikeDataSource = TypeormLikeQuerier & {
|
|
12
|
+
options: {
|
|
13
|
+
type?: string;
|
|
14
|
+
};
|
|
15
|
+
transaction<T>(runInTransaction: (entityManager: TypeormLikeQuerier) => Promise<T>): Promise<T>;
|
|
16
|
+
};
|
|
17
|
+
export type TypeormCrud = AsyncSqliteCrud<TypeormLikeDataSource>;
|
|
18
|
+
/**
|
|
19
|
+
* Create a Crud bound to a TypeORM DataSource.
|
|
20
|
+
* Methods are async. The injected DataSource is exposed as `crud.db`.
|
|
21
|
+
* Dialect defaults from `dataSource.options.type`; override with `options.dialect`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function createCrud(dataSource: TypeormLikeDataSource, options?: CreateCrudOptions): TypeormCrud;
|
|
24
|
+
//# sourceMappingURL=crud.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crud.d.ts","sourceRoot":"","sources":["../../src/typeorm/crud.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,aAAa,CAAA;AAEpB,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,yBAAyB,CAAA;AAGhC,6EAA6E;AAC7E,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CAC/D,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG,kBAAkB,GAAG;IACvD,OAAO,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC1B,WAAW,CAAC,CAAC,EACX,gBAAgB,EAAE,CAAC,aAAa,EAAE,kBAAkB,KAAK,OAAO,CAAC,CAAC,CAAC,GAClE,OAAO,CAAC,CAAC,CAAC,CAAA;CACd,CAAA;AAED,MAAM,MAAM,WAAW,GAAG,eAAe,CAAC,qBAAqB,CAAC,CAAA;AA8ChE;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,UAAU,EAAE,qBAAqB,EACjC,OAAO,CAAC,EAAE,iBAAiB,GAC1B,WAAW,CA0Db"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { CrudianError, } from "../index.js";
|
|
2
|
+
import { resolveDialect } from "../dialect/index.js";
|
|
3
|
+
import { createAsyncCrud, } from "../sqlite/async-crud.js";
|
|
4
|
+
function normalizeRow(row) {
|
|
5
|
+
const out = { ...row };
|
|
6
|
+
for (const [k, v] of Object.entries(out)) {
|
|
7
|
+
if (typeof v === "bigint")
|
|
8
|
+
out[k] = Number(v);
|
|
9
|
+
}
|
|
10
|
+
return out;
|
|
11
|
+
}
|
|
12
|
+
function normalizeQueryResult(result) {
|
|
13
|
+
if (result == null)
|
|
14
|
+
return [];
|
|
15
|
+
if (Array.isArray(result)) {
|
|
16
|
+
return result.filter(isPlainRow);
|
|
17
|
+
}
|
|
18
|
+
if (isPlainRow(result))
|
|
19
|
+
return [result];
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
function isPlainRow(value) {
|
|
23
|
+
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
24
|
+
}
|
|
25
|
+
function mapDataSourceType(type) {
|
|
26
|
+
switch (type) {
|
|
27
|
+
case "postgres":
|
|
28
|
+
case "aurora-postgres":
|
|
29
|
+
return "postgres";
|
|
30
|
+
case "mysql":
|
|
31
|
+
case "mariadb":
|
|
32
|
+
case "aurora-mysql":
|
|
33
|
+
return "mysql";
|
|
34
|
+
case "sqlite":
|
|
35
|
+
case "better-sqlite3":
|
|
36
|
+
case "capacitor":
|
|
37
|
+
case "cordova":
|
|
38
|
+
case "react-native":
|
|
39
|
+
case "expo":
|
|
40
|
+
case "sqljs":
|
|
41
|
+
case undefined:
|
|
42
|
+
return "sqlite";
|
|
43
|
+
default:
|
|
44
|
+
throw new CrudianError(`unsupported DataSource type: ${String(type)}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Create a Crud bound to a TypeORM DataSource.
|
|
49
|
+
* Methods are async. The injected DataSource is exposed as `crud.db`.
|
|
50
|
+
* Dialect defaults from `dataSource.options.type`; override with `options.dialect`.
|
|
51
|
+
*/
|
|
52
|
+
export function createCrud(dataSource, options) {
|
|
53
|
+
if (dataSource == null) {
|
|
54
|
+
throw new CrudianError("db is required");
|
|
55
|
+
}
|
|
56
|
+
if (typeof dataSource !== "object" ||
|
|
57
|
+
typeof dataSource.query !== "function" ||
|
|
58
|
+
typeof dataSource.transaction !== "function" ||
|
|
59
|
+
dataSource.options == null ||
|
|
60
|
+
typeof dataSource.options !== "object") {
|
|
61
|
+
throw new CrudianError("db must be a TypeORM DataSource");
|
|
62
|
+
}
|
|
63
|
+
let active = dataSource;
|
|
64
|
+
const dialectName = options?.dialect ?? mapDataSourceType(dataSource.options.type);
|
|
65
|
+
const dialect = resolveDialect(dialectName);
|
|
66
|
+
return createAsyncCrud(dataSource, {
|
|
67
|
+
async run(sql, args = []) {
|
|
68
|
+
if (dialect.name === "postgres") {
|
|
69
|
+
const trimmed = sql.trim();
|
|
70
|
+
if (/^(UPDATE|DELETE)\b/i.test(trimmed)) {
|
|
71
|
+
const wrapped = `WITH _crudian_write AS (${trimmed} RETURNING 1) ` +
|
|
72
|
+
`SELECT COUNT(*)::int AS changes FROM _crudian_write`;
|
|
73
|
+
const rows = normalizeQueryResult(await active.query(wrapped, args));
|
|
74
|
+
return { changes: Number(rows[0]?.changes ?? 0) };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const result = await active.query(sql, args);
|
|
78
|
+
return { changes: await resolveChanges(active, dialect.name, result) };
|
|
79
|
+
},
|
|
80
|
+
async get(sql, args = []) {
|
|
81
|
+
const rows = normalizeQueryResult(await active.query(sql, args));
|
|
82
|
+
const row = rows[0];
|
|
83
|
+
return row == null ? undefined : normalizeRow(row);
|
|
84
|
+
},
|
|
85
|
+
async all(sql, args = []) {
|
|
86
|
+
return normalizeQueryResult(await active.query(sql, args)).map(normalizeRow);
|
|
87
|
+
},
|
|
88
|
+
async transaction(fn) {
|
|
89
|
+
return dataSource.transaction(async (manager) => {
|
|
90
|
+
const prev = active;
|
|
91
|
+
active = manager;
|
|
92
|
+
try {
|
|
93
|
+
return await fn();
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
active = prev;
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
},
|
|
100
|
+
}, dialect, options);
|
|
101
|
+
}
|
|
102
|
+
async function resolveChanges(querier, dialectName, result) {
|
|
103
|
+
if (dialectName === "sqlite") {
|
|
104
|
+
// better-sqlite3 via TypeORM returns lastInsertRowid for writes, not changes.
|
|
105
|
+
const rows = normalizeQueryResult(await querier.query("SELECT changes() AS changes"));
|
|
106
|
+
return Number(rows[0]?.changes ?? 0);
|
|
107
|
+
}
|
|
108
|
+
if (dialectName === "mysql") {
|
|
109
|
+
const header = mysqlResultHeader(result);
|
|
110
|
+
if (header != null)
|
|
111
|
+
return Number(header.affectedRows ?? 0);
|
|
112
|
+
}
|
|
113
|
+
if (result != null && typeof result === "object" && !Array.isArray(result)) {
|
|
114
|
+
const obj = result;
|
|
115
|
+
if ("affected" in obj)
|
|
116
|
+
return Number(obj.affected ?? 0);
|
|
117
|
+
if ("affectedRows" in obj)
|
|
118
|
+
return Number(obj.affectedRows ?? 0);
|
|
119
|
+
if ("rowCount" in obj)
|
|
120
|
+
return Number(obj.rowCount ?? 0);
|
|
121
|
+
}
|
|
122
|
+
// Postgres (and similar): TypeORM often returns [] and drops rowCount.
|
|
123
|
+
if (dialectName === "postgres" && typeof result === "number") {
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
return 0;
|
|
127
|
+
}
|
|
128
|
+
function mysqlResultHeader(result) {
|
|
129
|
+
if (result == null)
|
|
130
|
+
return null;
|
|
131
|
+
if (Array.isArray(result)) {
|
|
132
|
+
const first = result[0];
|
|
133
|
+
if (first != null && typeof first === "object" && "affectedRows" in first) {
|
|
134
|
+
return first;
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
if (typeof result === "object" && "affectedRows" in result) {
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeORM adapter for @b4moss/crudian.
|
|
3
|
+
* Import via: `import { createCrud } from "@b4moss/crudian/typeorm"`
|
|
4
|
+
*/
|
|
5
|
+
export { createCrud, type TypeormCrud, type TypeormLikeDataSource, type TypeormLikeQuerier, } from "./crud.js";
|
|
6
|
+
export type { Row, SearchResult, WhereInput, ReadQuery, SearchQuery, CountQuery, DeleteQuery, UpdateQuery, DuplicateQuery, } from "../types.js";
|
|
7
|
+
export { CrudianError, where, WhereBuilder, type Op, type CondNode, type GroupNode, type WhereNode, } from "../index.js";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/typeorm/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,UAAU,EACV,KAAK,WAAW,EAChB,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,GACxB,MAAM,WAAW,CAAA;AAClB,YAAY,EACV,GAAG,EACH,YAAY,EACZ,UAAU,EACV,SAAS,EACT,WAAW,EACX,UAAU,EACV,WAAW,EACX,WAAW,EACX,cAAc,GACf,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,YAAY,EACZ,KAAK,EACL,YAAY,EACZ,KAAK,EAAE,EACP,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,SAAS,GACf,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DataSource } from "typeorm";
|
|
2
|
+
export type DialectName = "postgres" | "mysql";
|
|
3
|
+
export type TypeormServerDbHarness = {
|
|
4
|
+
dialect: DialectName;
|
|
5
|
+
envKey: "DATABASE_URL_POSTGRES" | "DATABASE_URL_MYSQL";
|
|
6
|
+
createDataSource: (url: string) => DataSource;
|
|
7
|
+
createItemsDDL: string;
|
|
8
|
+
dropItemsDDL: string;
|
|
9
|
+
createAltPkDDL: string;
|
|
10
|
+
dropAltPkDDL: string;
|
|
11
|
+
};
|
|
12
|
+
export declare function registerTypeormServerDialectTests(h: TypeormServerDbHarness): void;
|
|
13
|
+
//# sourceMappingURL=server-dialect-harness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-dialect-harness.d.ts","sourceRoot":"","sources":["../../src/typeorm/server-dialect-harness.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAIzC,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,OAAO,CAAA;AAE9C,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,EAAE,WAAW,CAAA;IACpB,MAAM,EAAE,uBAAuB,GAAG,oBAAoB,CAAA;IACtD,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,UAAU,CAAA;IAC7C,cAAc,EAAE,MAAM,CAAA;IACtB,YAAY,EAAE,MAAM,CAAA;IACpB,cAAc,EAAE,MAAM,CAAA;IACtB,YAAY,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,wBAAgB,iCAAiC,CAAC,CAAC,EAAE,sBAAsB,QA0I1E"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared contract suite for TypeORM against Postgres / MySQL.
|
|
3
|
+
* Skipped automatically when the DATABASE_URL_* env var is unset.
|
|
4
|
+
*/
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
import { after, before, describe, test } from "node:test";
|
|
7
|
+
import { CrudianError, where } from "../index.js";
|
|
8
|
+
import { createCrud } from "./index.js";
|
|
9
|
+
export function registerTypeormServerDialectTests(h) {
|
|
10
|
+
const url = process.env[h.envKey];
|
|
11
|
+
const suite = describe;
|
|
12
|
+
suite(`typeorm.${h.dialect}`, { skip: !url }, () => {
|
|
13
|
+
let dataSource;
|
|
14
|
+
let crud;
|
|
15
|
+
before(async () => {
|
|
16
|
+
if (!url)
|
|
17
|
+
return;
|
|
18
|
+
dataSource = h.createDataSource(url);
|
|
19
|
+
await dataSource.initialize();
|
|
20
|
+
await dataSource.query(h.dropItemsDDL);
|
|
21
|
+
await dataSource.query(h.createItemsDDL);
|
|
22
|
+
crud = createCrud(dataSource, { dialect: h.dialect });
|
|
23
|
+
});
|
|
24
|
+
after(async () => {
|
|
25
|
+
if (!url || !dataSource?.isInitialized)
|
|
26
|
+
return;
|
|
27
|
+
try {
|
|
28
|
+
await dataSource.query(h.dropItemsDDL);
|
|
29
|
+
await dataSource.query(h.dropAltPkDDL);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
/* ignore */
|
|
33
|
+
}
|
|
34
|
+
await dataSource.destroy();
|
|
35
|
+
});
|
|
36
|
+
async function reset() {
|
|
37
|
+
await dataSource.query(h.dropItemsDDL);
|
|
38
|
+
await dataSource.query(h.createItemsDDL);
|
|
39
|
+
}
|
|
40
|
+
test("正常系: create / read / update / delete", async () => {
|
|
41
|
+
await reset();
|
|
42
|
+
const created = await crud.create("items", { name: "alice", score: 10 });
|
|
43
|
+
assert.equal(created.name, "alice");
|
|
44
|
+
assert.ok(created.id != null);
|
|
45
|
+
const got = await crud.read("items", {
|
|
46
|
+
where: where().eq("id", created.id),
|
|
47
|
+
});
|
|
48
|
+
assert.equal(got?.name, "alice");
|
|
49
|
+
const updated = await crud.update("items", { score: 20 }, { where: where().eq("id", created.id) });
|
|
50
|
+
assert.equal(updated?.score, 20);
|
|
51
|
+
const n = await crud.delete("items", {
|
|
52
|
+
where: where().eq("id", created.id),
|
|
53
|
+
});
|
|
54
|
+
assert.equal(n, 1);
|
|
55
|
+
assert.equal(await crud.read("items", { where: where().eq("id", created.id) }), null);
|
|
56
|
+
});
|
|
57
|
+
test("正常系: count / exists / search offset / cursor", async () => {
|
|
58
|
+
await reset();
|
|
59
|
+
await crud.bulkCreate("items", [
|
|
60
|
+
{ name: "a", score: 1 },
|
|
61
|
+
{ name: "b", score: 2 },
|
|
62
|
+
{ name: "c", score: 3 },
|
|
63
|
+
]);
|
|
64
|
+
assert.equal(await crud.count("items"), 3);
|
|
65
|
+
assert.equal(await crud.exists("items", { where: where().eq("name", "b") }), true);
|
|
66
|
+
assert.equal(await crud.exists("items", { where: where().eq("name", "z") }), false);
|
|
67
|
+
const page = await crud.search("items", { limit: 2, offset: 0 });
|
|
68
|
+
assert.equal(page.items.length, 2);
|
|
69
|
+
assert.equal("total" in page && page.total, 3);
|
|
70
|
+
assert.equal("hasMore" in page && page.hasMore, true);
|
|
71
|
+
const cursorPage = await crud.search("items", {
|
|
72
|
+
paging: "cursor",
|
|
73
|
+
limit: 2,
|
|
74
|
+
});
|
|
75
|
+
assert.equal(cursorPage.items.length, 2);
|
|
76
|
+
assert.ok("nextCursor" in cursorPage);
|
|
77
|
+
});
|
|
78
|
+
test("正常系: upsert / duplicate / transaction", async () => {
|
|
79
|
+
await reset();
|
|
80
|
+
const a = await crud.create("items", { name: "x", score: 1 });
|
|
81
|
+
const up = await crud.upsert("items", {
|
|
82
|
+
id: a.id,
|
|
83
|
+
name: "x",
|
|
84
|
+
score: 9,
|
|
85
|
+
});
|
|
86
|
+
assert.equal(up.score, 9);
|
|
87
|
+
const dup = await crud.duplicate("items", {
|
|
88
|
+
where: where().eq("id", a.id),
|
|
89
|
+
overrides: { name: "y" },
|
|
90
|
+
});
|
|
91
|
+
assert.ok(dup);
|
|
92
|
+
assert.notEqual(dup.id, a.id);
|
|
93
|
+
assert.equal(dup.name, "y");
|
|
94
|
+
await crud.transaction(async () => {
|
|
95
|
+
await crud.create("items", { name: "tx", score: 1 });
|
|
96
|
+
});
|
|
97
|
+
assert.equal(await crud.exists("items", { where: where().eq("name", "tx") }), true);
|
|
98
|
+
});
|
|
99
|
+
test("正常系: 可変 PK", async () => {
|
|
100
|
+
await reset();
|
|
101
|
+
await dataSource.query(h.dropAltPkDDL);
|
|
102
|
+
await dataSource.query(h.createAltPkDDL);
|
|
103
|
+
const alt = createCrud(dataSource, { dialect: h.dialect, pk: "item_id" });
|
|
104
|
+
const row = await alt.create("alt_items", { name: "pk" });
|
|
105
|
+
assert.ok(row.item_id != null);
|
|
106
|
+
const got = await alt.read("alt_items", {
|
|
107
|
+
where: where().eq("item_id", row.item_id),
|
|
108
|
+
});
|
|
109
|
+
assert.equal(got?.name, "pk");
|
|
110
|
+
await dataSource.query(h.dropAltPkDDL);
|
|
111
|
+
});
|
|
112
|
+
test("異常系: 空 in / 不正 dialect は拒否", async () => {
|
|
113
|
+
await reset();
|
|
114
|
+
await assert.rejects(() => crud.search("items", {
|
|
115
|
+
where: where().in("id", []),
|
|
116
|
+
}), CrudianError);
|
|
117
|
+
assert.throws(() => createCrud(dataSource, { dialect: "nope" }), CrudianError);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -44,9 +44,16 @@ export type DuplicateQuery = {
|
|
|
44
44
|
where: WhereInput;
|
|
45
45
|
overrides?: Record<string, unknown>;
|
|
46
46
|
};
|
|
47
|
+
/** SQL dialect for adapters that support more than SQLite (e.g. Prisma). */
|
|
48
|
+
export type CreateCrudDialect = "sqlite" | "postgres" | "mysql";
|
|
47
49
|
/** Options for `createCrud(db, options?)`. */
|
|
48
50
|
export type CreateCrudOptions = {
|
|
49
51
|
/** Primary key column name. Default: `"id"`. */
|
|
50
52
|
pk?: string;
|
|
53
|
+
/**
|
|
54
|
+
* SQL dialect. Default: `"sqlite"`.
|
|
55
|
+
* Used by Prisma / TypeORM (and other multi-DB adapters). SQLite-only adapters ignore this.
|
|
56
|
+
*/
|
|
57
|
+
dialect?: CreateCrudDialect;
|
|
51
58
|
};
|
|
52
59
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAEzD,MAAM,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEzC,MAAM,MAAM,kBAAkB,CAAC,CAAC,GAAG,GAAG,IAAI;IACxC,KAAK,EAAE,CAAC,EAAE,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,OAAO,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,kBAAkB,CAAC,CAAC,GAAG,GAAG,IAAI;IACxC,KAAK,EAAE,CAAC,EAAE,CAAA;IACV,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAClC,OAAO,EAAE,OAAO,CAAA;IAChB,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,YAAY,CAAC,CAAC,GAAG,GAAG,IAAI,kBAAkB,CAAC,CAAC,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAA;AAEjF,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,SAAS,CAAA;AAEjD,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,KAAK,CAAC,EAAE,UAAU,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,KAAK,CAAC,EAAE,UAAU,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4CAA4C;IAC5C,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAC5B,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,CAAC,EAAE,UAAU,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,UAAU,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,UAAU,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,UAAU,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACpC,CAAA;AAED,8CAA8C;AAC9C,MAAM,MAAM,iBAAiB,GAAG;IAC9B,gDAAgD;IAChD,EAAE,CAAC,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAEzD,MAAM,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEzC,MAAM,MAAM,kBAAkB,CAAC,CAAC,GAAG,GAAG,IAAI;IACxC,KAAK,EAAE,CAAC,EAAE,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,OAAO,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,kBAAkB,CAAC,CAAC,GAAG,GAAG,IAAI;IACxC,KAAK,EAAE,CAAC,EAAE,CAAA;IACV,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAClC,OAAO,EAAE,OAAO,CAAA;IAChB,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,YAAY,CAAC,CAAC,GAAG,GAAG,IAAI,kBAAkB,CAAC,CAAC,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAA;AAEjF,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,SAAS,CAAA;AAEjD,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,KAAK,CAAC,EAAE,UAAU,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,KAAK,CAAC,EAAE,UAAU,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4CAA4C;IAC5C,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAC5B,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,CAAC,EAAE,UAAU,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,UAAU,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,UAAU,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,UAAU,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACpC,CAAA;AAED,4EAA4E;AAC5E,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAA;AAE/D,8CAA8C;AAC9C,MAAM,MAAM,iBAAiB,GAAG;IAC9B,gDAAgD;IAChD,EAAE,CAAC,EAAE,MAAM,CAAA;IACX;;;OAGG;IACH,OAAO,CAAC,EAAE,iBAAiB,CAAA;CAC5B,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@b4moss/crudian",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "CRUD abstraction for DDD repositories",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,6 +30,11 @@
|
|
|
30
30
|
"types": "./dist/libsql/index.d.ts",
|
|
31
31
|
"import": "./dist/libsql/index.js",
|
|
32
32
|
"default": "./dist/libsql/index.js"
|
|
33
|
+
},
|
|
34
|
+
"./typeorm": {
|
|
35
|
+
"types": "./dist/typeorm/index.d.ts",
|
|
36
|
+
"import": "./dist/typeorm/index.js",
|
|
37
|
+
"default": "./dist/typeorm/index.js"
|
|
33
38
|
}
|
|
34
39
|
},
|
|
35
40
|
"files": [
|
|
@@ -41,13 +46,23 @@
|
|
|
41
46
|
"build": "tsc -p tsconfig.json",
|
|
42
47
|
"prepublishOnly": "npm run build",
|
|
43
48
|
"prisma:generate": "prisma generate --schema prisma/schema.prisma",
|
|
44
|
-
"
|
|
49
|
+
"prisma:generate:postgres": "prisma generate --schema prisma/schema.postgres.prisma",
|
|
50
|
+
"prisma:generate:mysql": "prisma generate --schema prisma/schema.mysql.prisma",
|
|
51
|
+
"test": "bun run test:bun-sqlite && bun run test:drizzle && bun run test:prisma && bun run test:libsql && bun run test:typeorm && bun run test:dialect",
|
|
45
52
|
"test:bun-sqlite": "bun test src/bun-sqlite",
|
|
46
53
|
"test:drizzle": "tsx --test src/drizzle/crud.test.ts src/drizzle/pk.test.ts",
|
|
47
54
|
"test:prisma": "bun run prisma:generate && tsx --test src/prisma/crud.test.ts src/prisma/pk.test.ts",
|
|
48
|
-
"test:
|
|
49
|
-
|
|
50
|
-
|
|
55
|
+
"test:prisma:postgres": "bun run prisma:generate:postgres && DATABASE_URL_POSTGRES=\"${DATABASE_URL_POSTGRES:-postgresql://crudian:crudian@127.0.0.1:5432/crudian?sslmode=disable}\" tsx --test src/prisma/postgres.test.ts",
|
|
56
|
+
"test:prisma:mysql": "bun run prisma:generate:mysql && DATABASE_URL_MYSQL=\"${DATABASE_URL_MYSQL:-mysql://crudian:crudian@127.0.0.1:3306/crudian}\" tsx --test src/prisma/mysql.test.ts",
|
|
57
|
+
"test:libsql": "tsx --test src/libsql/crud.test.ts src/libsql/pk.test.ts",
|
|
58
|
+
"test:dialect": "tsx --test src/dialect/dialect.test.ts",
|
|
59
|
+
"test:node-adapters:coverage": "bun run prisma:generate && c8 --reporter=lcov --reporter=text-summary --report-dir=coverage/node-adapters --exclude='**/*.test.ts' --exclude='prisma/**' --exclude='dist/**' tsx --test src/drizzle/crud.test.ts src/drizzle/pk.test.ts src/prisma/crud.test.ts src/prisma/pk.test.ts src/libsql/crud.test.ts src/libsql/pk.test.ts src/dialect/dialect.test.ts",
|
|
60
|
+
"test:typeorm": "tsx --test src/typeorm/crud.test.ts src/typeorm/pk.test.ts",
|
|
61
|
+
"test:typeorm:bun": "bun test src/typeorm/crud.test.ts src/typeorm/pk.test.ts",
|
|
62
|
+
"test:typeorm:coverage": "c8 --reporter=lcov --reporter=text-summary --report-dir=coverage/typeorm --exclude='**/*.test.ts' --exclude='dist/**' tsx --test src/typeorm/crud.test.ts src/typeorm/pk.test.ts",
|
|
63
|
+
"test:typeorm:postgres": "DATABASE_URL_POSTGRES=\"${DATABASE_URL_POSTGRES:-postgresql://crudian:crudian@127.0.0.1:5432/crudian?sslmode=disable}\" tsx --test src/typeorm/postgres.test.ts",
|
|
64
|
+
"test:typeorm:mysql": "DATABASE_URL_MYSQL=\"${DATABASE_URL_MYSQL:-mysql://crudian:crudian@127.0.0.1:3306/crudian}\" tsx --test src/typeorm/mysql.test.ts"
|
|
65
|
+
}, "engines": {
|
|
51
66
|
"node": ">=24",
|
|
52
67
|
"bun": ">=1.0.0"
|
|
53
68
|
},
|
|
@@ -55,7 +70,8 @@
|
|
|
55
70
|
"@libsql/client": "^0.14.0 || ^0.15.0 || ^0.17.0",
|
|
56
71
|
"@prisma/client": "^6.0.0",
|
|
57
72
|
"better-sqlite3": "^11.0.0",
|
|
58
|
-
"drizzle-orm": "^0.39.0 || ^0.40.0 || ^0.41.0 || ^0.44.0"
|
|
73
|
+
"drizzle-orm": "^0.39.0 || ^0.40.0 || ^0.41.0 || ^0.44.0",
|
|
74
|
+
"typeorm": "^0.3.0"
|
|
59
75
|
},
|
|
60
76
|
"peerDependenciesMeta": {
|
|
61
77
|
"@libsql/client": {
|
|
@@ -69,6 +85,9 @@
|
|
|
69
85
|
},
|
|
70
86
|
"drizzle-orm": {
|
|
71
87
|
"optional": true
|
|
88
|
+
},
|
|
89
|
+
"typeorm": {
|
|
90
|
+
"optional": true
|
|
72
91
|
}
|
|
73
92
|
},
|
|
74
93
|
"devDependencies": {
|
|
@@ -77,9 +96,14 @@
|
|
|
77
96
|
"@types/better-sqlite3": "^7.6.13",
|
|
78
97
|
"better-sqlite3": "^13",
|
|
79
98
|
"bun-types": "^1.2.0",
|
|
99
|
+
"c8": "10",
|
|
80
100
|
"drizzle-orm": "^0.45.2",
|
|
101
|
+
"mysql2": "^3.14.0",
|
|
102
|
+
"pg": "^8.14.0",
|
|
81
103
|
"prisma": "^6.14.0",
|
|
104
|
+
"reflect-metadata": "^0.2.2",
|
|
82
105
|
"tsx": "^4.23.12",
|
|
106
|
+
"typeorm": "^0.3.22",
|
|
83
107
|
"typescript": "^5.8.0"
|
|
84
108
|
},
|
|
85
109
|
"keywords": [
|
|
@@ -90,6 +114,7 @@
|
|
|
90
114
|
"drizzle",
|
|
91
115
|
"prisma",
|
|
92
116
|
"libsql",
|
|
117
|
+
"typeorm",
|
|
93
118
|
"ddd"
|
|
94
119
|
],
|
|
95
120
|
"repository": {
|