@b4moss/crudian 0.9.0 → 0.10.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 +32 -8
- 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 +2 -1
- package/dist/index.d.ts.map +1 -1
- 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/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -1
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { CrudianError, assertString, } from "../index.js";
|
|
2
|
+
import { sqliteDialect } from "../dialect/sqlite.js";
|
|
2
3
|
import { createAsyncPkGuard, 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 async CRUD factory. */
|
|
22
|
+
export function createAsyncCrud(db, ex, dialect, options) {
|
|
21
23
|
const pk = resolvePk(options);
|
|
22
|
-
const ensurePkColumn = createAsyncPkGuard(pk, ex.all);
|
|
24
|
+
const ensurePkColumn = createAsyncPkGuard(pk, dialect, ex.all);
|
|
25
|
+
const d = dialect;
|
|
23
26
|
const crud = {
|
|
24
27
|
db,
|
|
25
28
|
async create(table, cols) {
|
|
@@ -32,21 +35,30 @@ export function createAsyncSqliteCrud(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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
if (d.supportsInsertReturning) {
|
|
44
|
+
// Single-statement insert+fetch avoids last_insert_rowid() across pooled
|
|
45
|
+
// connections (Prisma SQLite), which can return an empty row after COUNT.
|
|
46
|
+
const row = await ex.get(`INSERT INTO ${tbl} (${colSql}) VALUES (${placeholders}) RETURNING *`, args);
|
|
47
|
+
return rowFromObject(row);
|
|
48
|
+
}
|
|
49
|
+
await ex.run(`INSERT INTO ${tbl} (${colSql}) VALUES (${placeholders})`, args);
|
|
50
|
+
const pkValue = Object.prototype.hasOwnProperty.call(cols, pk)
|
|
51
|
+
? cols[pk]
|
|
52
|
+
: Number((await ex.get(d.lastInsertIdSql()))?.id);
|
|
53
|
+
const row = await ex.get(`SELECT * FROM ${tbl} WHERE ${d.quoteIdent(pk)} = ${d.placeholder(1)}`, [pkValue]);
|
|
42
54
|
return rowFromObject(row);
|
|
43
55
|
},
|
|
44
56
|
async read(table, query = {}) {
|
|
45
57
|
assertString(table, "table");
|
|
46
58
|
await ensurePkColumn(table);
|
|
47
|
-
const tbl = quoteIdent(table);
|
|
48
|
-
const where = compileWhere(resolveWhere(query.where));
|
|
49
|
-
const sql = `SELECT ${selectColumns(query.columns)} FROM ${tbl}` +
|
|
59
|
+
const tbl = d.quoteIdent(table);
|
|
60
|
+
const where = compileWhere(d, resolveWhere(query.where));
|
|
61
|
+
const sql = `SELECT ${selectColumns(d, query.columns)} FROM ${tbl}` +
|
|
50
62
|
(where.sql ? ` WHERE ${where.sql}` : "") +
|
|
51
63
|
` LIMIT 1`;
|
|
52
64
|
const row = await ex.get(sql, where.args);
|
|
@@ -63,25 +75,27 @@ export function createAsyncSqliteCrud(db, ex, options) {
|
|
|
63
75
|
if (keys.length === 0) {
|
|
64
76
|
throw new CrudianError("cols must not be empty");
|
|
65
77
|
}
|
|
66
|
-
const tbl = quoteIdent(table);
|
|
67
|
-
|
|
78
|
+
const tbl = d.quoteIdent(table);
|
|
79
|
+
let idx = 1;
|
|
80
|
+
const sets = keys.map((k) => `${d.quoteIdent(k)} = ${d.placeholder(idx++)}`).join(", ");
|
|
81
|
+
const where = compileWhere(d, resolveWhere(query.where), idx);
|
|
68
82
|
if (!where.sql) {
|
|
69
83
|
throw new CrudianError("update requires where");
|
|
70
84
|
}
|
|
71
|
-
const sets = keys.map((k) => `${quoteIdent(k)} = ?`).join(", ");
|
|
72
85
|
const args = [...keys.map((k) => cols[k]), ...where.args];
|
|
73
86
|
const result = await ex.run(`UPDATE ${tbl} SET ${sets} WHERE ${where.sql}`, args);
|
|
74
87
|
if (result.changes === 0)
|
|
75
88
|
return null;
|
|
76
|
-
const
|
|
89
|
+
const fetchWhere = compileWhere(d, resolveWhere(query.where));
|
|
90
|
+
const row = await ex.get(`SELECT * FROM ${tbl} WHERE ${fetchWhere.sql} LIMIT 1`, fetchWhere.args);
|
|
77
91
|
return row == null ? null : rowFromObject(row);
|
|
78
92
|
},
|
|
79
93
|
async delete(table, query) {
|
|
80
94
|
assertString(table, "table");
|
|
81
95
|
await ensurePkColumn(table);
|
|
82
96
|
requireWhere(query, "delete");
|
|
83
|
-
const tbl = quoteIdent(table);
|
|
84
|
-
const where = compileWhere(resolveWhere(query.where));
|
|
97
|
+
const tbl = d.quoteIdent(table);
|
|
98
|
+
const where = compileWhere(d, resolveWhere(query.where));
|
|
85
99
|
if (!where.sql) {
|
|
86
100
|
throw new CrudianError("delete requires where");
|
|
87
101
|
}
|
|
@@ -110,8 +124,8 @@ export function createAsyncSqliteCrud(db, ex, options) {
|
|
|
110
124
|
typeof query.cursor !== "string") {
|
|
111
125
|
throw new CrudianError("cursor must be a number, string, or null");
|
|
112
126
|
}
|
|
113
|
-
const tbl = quoteIdent(table);
|
|
114
|
-
const where = compileWhere(resolveWhere(query.where));
|
|
127
|
+
const tbl = d.quoteIdent(table);
|
|
128
|
+
const where = compileWhere(d, resolveWhere(query.where));
|
|
115
129
|
const total = await crud.count(table, { where: query.where });
|
|
116
130
|
if (paging === "offset") {
|
|
117
131
|
const offset = query.offset ?? 0;
|
|
@@ -119,10 +133,11 @@ export function createAsyncSqliteCrud(db, ex, options) {
|
|
|
119
133
|
throw new CrudianError("offset must be a non-negative number");
|
|
120
134
|
}
|
|
121
135
|
const args = [...where.args];
|
|
136
|
+
let idx = where.nextIndex;
|
|
122
137
|
const whereSql = where.sql ? ` WHERE ${where.sql}` : "";
|
|
123
|
-
const sql = `SELECT ${selectColumns(query.columns)} FROM ${tbl}` +
|
|
138
|
+
const sql = `SELECT ${selectColumns(d, query.columns)} FROM ${tbl}` +
|
|
124
139
|
whereSql +
|
|
125
|
-
` ORDER BY ${quoteIdent(pk)} ASC LIMIT
|
|
140
|
+
` ORDER BY ${d.quoteIdent(pk)} ASC LIMIT ${d.placeholder(idx++)} OFFSET ${d.placeholder(idx++)}`;
|
|
126
141
|
args.push(limit, offset);
|
|
127
142
|
const items = (await ex.all(sql, args)).map((r) => rowFromObject(r));
|
|
128
143
|
return {
|
|
@@ -134,17 +149,18 @@ export function createAsyncSqliteCrud(db, ex, options) {
|
|
|
134
149
|
};
|
|
135
150
|
}
|
|
136
151
|
const args = [...where.args];
|
|
152
|
+
let idx = where.nextIndex;
|
|
137
153
|
const parts = [];
|
|
138
154
|
if (where.sql)
|
|
139
155
|
parts.push(`(${where.sql})`);
|
|
140
156
|
if (query.cursor != null) {
|
|
141
|
-
parts.push(`${quoteIdent(pk)} >
|
|
157
|
+
parts.push(`${d.quoteIdent(pk)} > ${d.placeholder(idx++)}`);
|
|
142
158
|
args.push(query.cursor);
|
|
143
159
|
}
|
|
144
160
|
const whereSql = parts.length > 0 ? ` WHERE ${parts.join(" AND ")}` : "";
|
|
145
|
-
const sql = `SELECT ${selectColumns(query.columns)} FROM ${tbl}` +
|
|
161
|
+
const sql = `SELECT ${selectColumns(d, query.columns)} FROM ${tbl}` +
|
|
146
162
|
whereSql +
|
|
147
|
-
` ORDER BY ${quoteIdent(pk)} ASC LIMIT
|
|
163
|
+
` ORDER BY ${d.quoteIdent(pk)} ASC LIMIT ${d.placeholder(idx++)}`;
|
|
148
164
|
args.push(limit + 1);
|
|
149
165
|
const rows = (await ex.all(sql, args)).map((r) => rowFromObject(r));
|
|
150
166
|
const hasMore = rows.length > limit;
|
|
@@ -162,9 +178,9 @@ export function createAsyncSqliteCrud(db, ex, options) {
|
|
|
162
178
|
async count(table, query = {}) {
|
|
163
179
|
assertString(table, "table");
|
|
164
180
|
await ensurePkColumn(table);
|
|
165
|
-
const tbl = quoteIdent(table);
|
|
166
|
-
const where = compileWhere(resolveWhere(query.where));
|
|
167
|
-
const sql = `SELECT COUNT(*) AS ${quoteIdent("row_count")} FROM ${tbl}` +
|
|
181
|
+
const tbl = d.quoteIdent(table);
|
|
182
|
+
const where = compileWhere(d, resolveWhere(query.where));
|
|
183
|
+
const sql = `SELECT COUNT(*) AS ${d.quoteIdent("row_count")} FROM ${tbl}` +
|
|
168
184
|
(where.sql ? ` WHERE ${where.sql}` : "");
|
|
169
185
|
const row = await ex.get(sql, where.args);
|
|
170
186
|
return Number(row?.row_count ?? 0);
|
|
@@ -172,9 +188,9 @@ export function createAsyncSqliteCrud(db, ex, options) {
|
|
|
172
188
|
async exists(table, query = {}) {
|
|
173
189
|
assertString(table, "table");
|
|
174
190
|
await ensurePkColumn(table);
|
|
175
|
-
const tbl = quoteIdent(table);
|
|
176
|
-
const where = compileWhere(resolveWhere(query.where));
|
|
177
|
-
const sql = `SELECT 1 AS ${quoteIdent("ok")} FROM ${tbl}` +
|
|
191
|
+
const tbl = d.quoteIdent(table);
|
|
192
|
+
const where = compileWhere(d, resolveWhere(query.where));
|
|
193
|
+
const sql = `SELECT 1 AS ${d.quoteIdent("ok")} FROM ${tbl}` +
|
|
178
194
|
(where.sql ? ` WHERE ${where.sql}` : "") +
|
|
179
195
|
` LIMIT 1`;
|
|
180
196
|
const row = await ex.get(sql, where.args);
|
|
@@ -259,12 +275,13 @@ export function createAsyncSqliteCrud(db, ex, options) {
|
|
|
259
275
|
if (keys.length === 0) {
|
|
260
276
|
throw new CrudianError("cols must not be empty");
|
|
261
277
|
}
|
|
262
|
-
const tbl = quoteIdent(table);
|
|
263
|
-
|
|
278
|
+
const tbl = d.quoteIdent(table);
|
|
279
|
+
let idx = 1;
|
|
280
|
+
const sets = keys.map((k) => `${d.quoteIdent(k)} = ${d.placeholder(idx++)}`).join(", ");
|
|
281
|
+
const where = compileWhere(d, resolveWhere(query.where), idx);
|
|
264
282
|
if (!where.sql) {
|
|
265
283
|
throw new CrudianError("bulkUpdate requires where");
|
|
266
284
|
}
|
|
267
|
-
const sets = keys.map((k) => `${quoteIdent(k)} = ?`).join(", ");
|
|
268
285
|
const args = [...keys.map((k) => cols[k]), ...where.args];
|
|
269
286
|
const result = await ex.run(`UPDATE ${tbl} SET ${sets} WHERE ${where.sql}`, args);
|
|
270
287
|
return Number(result.changes ?? 0);
|
|
@@ -302,3 +319,7 @@ export function createAsyncSqliteCrud(db, ex, options) {
|
|
|
302
319
|
};
|
|
303
320
|
return crud;
|
|
304
321
|
}
|
|
322
|
+
/** SQLite async CRUD (compat). */
|
|
323
|
+
export function createAsyncSqliteCrud(db, ex, options) {
|
|
324
|
+
return createAsyncCrud(db, ex, sqliteDialect, options);
|
|
325
|
+
}
|
package/dist/sqlite/pk.d.ts
CHANGED
|
@@ -1,22 +1,15 @@
|
|
|
1
1
|
import { type CreateCrudOptions } from "../index.js";
|
|
2
|
+
import type { Dialect } from "../dialect/types.js";
|
|
2
3
|
/** Resolve PK column name from createCrud options. Default: `"id"`. */
|
|
3
4
|
export declare function resolvePk(options?: CreateCrudOptions): string;
|
|
4
|
-
export type PkColumnChecker = {
|
|
5
|
-
get(sql: string, args?: unknown[]): {
|
|
6
|
-
name?: unknown;
|
|
7
|
-
} | RowLike | undefined;
|
|
8
|
-
};
|
|
9
|
-
export type AsyncPkColumnChecker = {
|
|
10
|
-
get(sql: string, args?: unknown[]): Promise<{
|
|
11
|
-
name?: unknown;
|
|
12
|
-
} | RowLike | undefined>;
|
|
13
|
-
};
|
|
14
5
|
type RowLike = Record<string, unknown>;
|
|
15
6
|
/**
|
|
16
|
-
* Ensure `pk` exists on `table` via
|
|
7
|
+
* Ensure `pk` exists on `table` via dialect.describeColumns. Caches per table.
|
|
17
8
|
* Throws CrudianError when the column is missing.
|
|
18
9
|
*/
|
|
19
|
-
export declare function createPkGuard(pk: string,
|
|
20
|
-
export declare function createAsyncPkGuard(pk: string, all: (sql: string, args?: unknown[]) => Promise<RowLike[]>): (table: string) => Promise<void>;
|
|
10
|
+
export declare function createPkGuard(pk: string, dialect: Dialect, all: (sql: string, args?: unknown[]) => RowLike[]): (table: string) => void;
|
|
11
|
+
export declare function createAsyncPkGuard(pk: string, dialect: Dialect, all: (sql: string, args?: unknown[]) => Promise<RowLike[]>): (table: string) => Promise<void>;
|
|
12
|
+
/** @deprecated Prefer createPkGuard(pk, dialect, all). */
|
|
13
|
+
export declare function createPkGuardSqlite(pk: string, get: (sql: string, args?: unknown[]) => RowLike | undefined, all: (sql: string, args?: unknown[]) => RowLike[]): (table: string) => void;
|
|
21
14
|
export {};
|
|
22
15
|
//# sourceMappingURL=pk.d.ts.map
|
package/dist/sqlite/pk.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pk.d.ts","sourceRoot":"","sources":["../../src/sqlite/pk.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"pk.d.ts","sourceRoot":"","sources":["../../src/sqlite/pk.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAClE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGlD,uEAAuE;AACvE,wBAAgB,SAAS,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAW7D;AAED,KAAK,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEtC;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,OAAO,EAAE,IAGlB,OAAO,MAAM,KAAG,IAAI,CAcpD;AAED,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,IAGrB,OAAO,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC,CAcnE;AAED,0DAA0D;AAC1D,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,MAAM,EACV,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,OAAO,GAAG,SAAS,EAC3D,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,OAAO,EAAE,WA1CX,MAAM,KAAG,IAAI,CA8CpD"}
|
package/dist/sqlite/pk.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CrudianError } from "../index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { sqliteDialect } from "../dialect/sqlite.js";
|
|
3
3
|
/** Resolve PK column name from createCrud options. Default: `"id"`. */
|
|
4
4
|
export function resolvePk(options) {
|
|
5
5
|
if (options == null || options.pk === undefined) {
|
|
@@ -14,15 +14,16 @@ export function resolvePk(options) {
|
|
|
14
14
|
return options.pk;
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
|
-
* Ensure `pk` exists on `table` via
|
|
17
|
+
* Ensure `pk` exists on `table` via dialect.describeColumns. Caches per table.
|
|
18
18
|
* Throws CrudianError when the column is missing.
|
|
19
19
|
*/
|
|
20
|
-
export function createPkGuard(pk,
|
|
20
|
+
export function createPkGuard(pk, dialect, all) {
|
|
21
21
|
const ok = new Set();
|
|
22
22
|
return function ensurePkColumn(table) {
|
|
23
23
|
if (ok.has(table))
|
|
24
24
|
return;
|
|
25
|
-
const
|
|
25
|
+
const q = dialect.describeColumns(table);
|
|
26
|
+
const rows = all(q.sql, q.args);
|
|
26
27
|
const names = new Set(rows.map((r) => String(r.name ?? "")).filter((n) => n.length > 0));
|
|
27
28
|
if (!names.has(pk)) {
|
|
28
29
|
throw new CrudianError(`pk column "${pk}" does not exist on table "${table}"`);
|
|
@@ -30,12 +31,13 @@ export function createPkGuard(pk, get, all) {
|
|
|
30
31
|
ok.add(table);
|
|
31
32
|
};
|
|
32
33
|
}
|
|
33
|
-
export function createAsyncPkGuard(pk, all) {
|
|
34
|
+
export function createAsyncPkGuard(pk, dialect, all) {
|
|
34
35
|
const ok = new Set();
|
|
35
36
|
return async function ensurePkColumn(table) {
|
|
36
37
|
if (ok.has(table))
|
|
37
38
|
return;
|
|
38
|
-
const
|
|
39
|
+
const q = dialect.describeColumns(table);
|
|
40
|
+
const rows = await all(q.sql, q.args);
|
|
39
41
|
const names = new Set(rows.map((r) => String(r.name ?? "")).filter((n) => n.length > 0));
|
|
40
42
|
if (!names.has(pk)) {
|
|
41
43
|
throw new CrudianError(`pk column "${pk}" does not exist on table "${table}"`);
|
|
@@ -43,3 +45,8 @@ export function createAsyncPkGuard(pk, all) {
|
|
|
43
45
|
ok.add(table);
|
|
44
46
|
};
|
|
45
47
|
}
|
|
48
|
+
/** @deprecated Prefer createPkGuard(pk, dialect, all). */
|
|
49
|
+
export function createPkGuardSqlite(pk, get, all) {
|
|
50
|
+
void get;
|
|
51
|
+
return createPkGuard(pk, sqliteDialect, all);
|
|
52
|
+
}
|
package/dist/sqlite/sql.d.ts
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import { type WhereInput, type WhereNode } from "../index.js";
|
|
2
|
+
import type { Dialect } from "../dialect/types.js";
|
|
3
|
+
/** @deprecated Prefer dialect.quoteIdent; kept for local helper call sites. */
|
|
2
4
|
export declare function quoteIdent(name: string): string;
|
|
3
5
|
export declare function resolveWhere(input: WhereInput | undefined): WhereNode | undefined;
|
|
4
|
-
export
|
|
6
|
+
export type CompiledWhere = {
|
|
5
7
|
sql: string;
|
|
6
8
|
args: unknown[];
|
|
9
|
+
/** Next 1-based placeholder index after this fragment. */
|
|
10
|
+
nextIndex: number;
|
|
7
11
|
};
|
|
12
|
+
/**
|
|
13
|
+
* Compile a where AST using dialect placeholders.
|
|
14
|
+
* @param startIndex 1-based index for the first placeholder in this fragment.
|
|
15
|
+
*/
|
|
16
|
+
export declare function compileWhere(dialect: Dialect, node: WhereNode | undefined, startIndex?: number): CompiledWhere;
|
|
8
17
|
//# sourceMappingURL=sql.d.ts.map
|
package/dist/sqlite/sql.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../../src/sqlite/sql.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../../src/sqlite/sql.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,UAAU,EACf,KAAK,SAAS,EACf,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGlD,+EAA+E;AAC/E,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAIjF;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,OAAO,EAAE,CAAA;IACf,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,SAAS,GAAG,SAAS,EAC3B,UAAU,SAAI,GACb,aAAa,CA0Ff"}
|
package/dist/sqlite/sql.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { CrudianError,
|
|
1
|
+
import { CrudianError, isWhereBuilder, } from "../index.js";
|
|
2
|
+
import { sqliteDialect } from "../dialect/sqlite.js";
|
|
3
|
+
/** @deprecated Prefer dialect.quoteIdent; kept for local helper call sites. */
|
|
2
4
|
export function quoteIdent(name) {
|
|
3
|
-
|
|
4
|
-
return `"${name.replaceAll('"', '""')}"`;
|
|
5
|
+
return sqliteDialect.quoteIdent(name);
|
|
5
6
|
}
|
|
6
7
|
export function resolveWhere(input) {
|
|
7
8
|
if (input === undefined)
|
|
@@ -10,51 +11,87 @@ export function resolveWhere(input) {
|
|
|
10
11
|
return input.toNode();
|
|
11
12
|
return input;
|
|
12
13
|
}
|
|
13
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Compile a where AST using dialect placeholders.
|
|
16
|
+
* @param startIndex 1-based index for the first placeholder in this fragment.
|
|
17
|
+
*/
|
|
18
|
+
export function compileWhere(dialect, node, startIndex = 1) {
|
|
14
19
|
if (!node)
|
|
15
|
-
return { sql: "", args: [] };
|
|
20
|
+
return { sql: "", args: [], nextIndex: startIndex };
|
|
16
21
|
if (node.type === "and" || node.type === "or") {
|
|
17
22
|
if (node.children.length === 0)
|
|
18
|
-
return { sql: "", args: [] };
|
|
23
|
+
return { sql: "", args: [], nextIndex: startIndex };
|
|
19
24
|
const parts = [];
|
|
20
25
|
const args = [];
|
|
26
|
+
let idx = startIndex;
|
|
21
27
|
for (const child of node.children) {
|
|
22
|
-
const compiled = compileWhere(child);
|
|
28
|
+
const compiled = compileWhere(dialect, child, idx);
|
|
23
29
|
if (!compiled.sql)
|
|
24
30
|
continue;
|
|
25
31
|
parts.push(`(${compiled.sql})`);
|
|
26
32
|
args.push(...compiled.args);
|
|
33
|
+
idx = compiled.nextIndex;
|
|
27
34
|
}
|
|
28
35
|
if (parts.length === 0)
|
|
29
|
-
return { sql: "", args: [] };
|
|
30
|
-
if (parts.length === 1)
|
|
31
|
-
return { sql: parts[0].slice(1, -1), args };
|
|
36
|
+
return { sql: "", args: [], nextIndex: startIndex };
|
|
37
|
+
if (parts.length === 1) {
|
|
38
|
+
return { sql: parts[0].slice(1, -1), args, nextIndex: idx };
|
|
39
|
+
}
|
|
32
40
|
const joiner = node.type === "and" ? " AND " : " OR ";
|
|
33
|
-
return { sql: parts.join(joiner), args };
|
|
41
|
+
return { sql: parts.join(joiner), args, nextIndex: idx };
|
|
34
42
|
}
|
|
35
43
|
if (node.type !== "cond") {
|
|
36
44
|
throw new CrudianError("invalid where node");
|
|
37
45
|
}
|
|
38
|
-
const col = quoteIdent(node.column);
|
|
46
|
+
const col = dialect.quoteIdent(node.column);
|
|
47
|
+
let idx = startIndex;
|
|
39
48
|
switch (node.op) {
|
|
40
49
|
case "eq":
|
|
41
|
-
return {
|
|
50
|
+
return {
|
|
51
|
+
sql: `${col} = ${dialect.placeholder(idx)}`,
|
|
52
|
+
args: [node.value],
|
|
53
|
+
nextIndex: idx + 1,
|
|
54
|
+
};
|
|
42
55
|
case "ne":
|
|
43
|
-
return {
|
|
56
|
+
return {
|
|
57
|
+
sql: `${col} <> ${dialect.placeholder(idx)}`,
|
|
58
|
+
args: [node.value],
|
|
59
|
+
nextIndex: idx + 1,
|
|
60
|
+
};
|
|
44
61
|
case "lt":
|
|
45
|
-
return {
|
|
62
|
+
return {
|
|
63
|
+
sql: `${col} < ${dialect.placeholder(idx)}`,
|
|
64
|
+
args: [node.value],
|
|
65
|
+
nextIndex: idx + 1,
|
|
66
|
+
};
|
|
46
67
|
case "gt":
|
|
47
|
-
return {
|
|
68
|
+
return {
|
|
69
|
+
sql: `${col} > ${dialect.placeholder(idx)}`,
|
|
70
|
+
args: [node.value],
|
|
71
|
+
nextIndex: idx + 1,
|
|
72
|
+
};
|
|
48
73
|
case "lte":
|
|
49
|
-
return {
|
|
74
|
+
return {
|
|
75
|
+
sql: `${col} <= ${dialect.placeholder(idx)}`,
|
|
76
|
+
args: [node.value],
|
|
77
|
+
nextIndex: idx + 1,
|
|
78
|
+
};
|
|
50
79
|
case "gte":
|
|
51
|
-
return {
|
|
80
|
+
return {
|
|
81
|
+
sql: `${col} >= ${dialect.placeholder(idx)}`,
|
|
82
|
+
args: [node.value],
|
|
83
|
+
nextIndex: idx + 1,
|
|
84
|
+
};
|
|
52
85
|
case "like":
|
|
53
|
-
return {
|
|
86
|
+
return {
|
|
87
|
+
sql: `${col} LIKE ${dialect.placeholder(idx)}`,
|
|
88
|
+
args: [node.value],
|
|
89
|
+
nextIndex: idx + 1,
|
|
90
|
+
};
|
|
54
91
|
case "isNull":
|
|
55
|
-
return { sql: `${col} IS NULL`, args: [] };
|
|
92
|
+
return { sql: `${col} IS NULL`, args: [], nextIndex: idx };
|
|
56
93
|
case "isNotNull":
|
|
57
|
-
return { sql: `${col} IS NOT NULL`, args: [] };
|
|
94
|
+
return { sql: `${col} IS NOT NULL`, args: [], nextIndex: idx };
|
|
58
95
|
case "in": {
|
|
59
96
|
const values = node.value;
|
|
60
97
|
if (!Array.isArray(values)) {
|
|
@@ -63,8 +100,8 @@ export function compileWhere(node) {
|
|
|
63
100
|
if (values.length === 0) {
|
|
64
101
|
throw new CrudianError("in requires a non-empty array");
|
|
65
102
|
}
|
|
66
|
-
const placeholders = values.map(() =>
|
|
67
|
-
return { sql: `${col} IN (${placeholders})`, args: values };
|
|
103
|
+
const placeholders = values.map(() => dialect.placeholder(idx++)).join(", ");
|
|
104
|
+
return { sql: `${col} IN (${placeholders})`, args: values, nextIndex: idx };
|
|
68
105
|
}
|
|
69
106
|
default:
|
|
70
107
|
throw new CrudianError(`unknown op: ${node.op}`);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type CountQuery, type CreateCrudOptions, type DeleteQuery, type DuplicateQuery, type ReadQuery, type Row, type SearchQuery, type SearchResult, type UpdateQuery } from "../index.js";
|
|
2
|
+
import type { Dialect } from "../dialect/types.js";
|
|
2
3
|
export type SyncSqliteExecutor = {
|
|
3
4
|
run(sql: string, args?: unknown[]): {
|
|
4
5
|
changes: number;
|
|
@@ -25,5 +26,8 @@ export type SyncSqliteCrud<TDb> = {
|
|
|
25
26
|
exists(table: string, query?: CountQuery): boolean;
|
|
26
27
|
transaction<T>(fn: () => T): T;
|
|
27
28
|
};
|
|
29
|
+
/** Dialect-aware sync CRUD factory. */
|
|
30
|
+
export declare function createSyncCrud<TDb>(db: TDb, ex: SyncSqliteExecutor, dialect: Dialect, options?: CreateCrudOptions): SyncSqliteCrud<TDb>;
|
|
31
|
+
/** SQLite sync CRUD (compat). */
|
|
28
32
|
export declare function createSyncSqliteCrud<TDb>(db: TDb, ex: SyncSqliteExecutor, options?: CreateCrudOptions): SyncSqliteCrud<TDb>;
|
|
29
33
|
//# sourceMappingURL=sync-crud.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-crud.d.ts","sourceRoot":"","sources":["../../src/sqlite/sync-crud.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,GAAG,EACR,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,WAAW,EACjB,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"sync-crud.d.ts","sourceRoot":"","sources":["../../src/sqlite/sync-crud.ts"],"names":[],"mappings":"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"}
|