@atscript/db-sqlite 0.1.30 → 0.1.32
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/dist/index.cjs +28 -26
- package/dist/index.d.ts +6 -6
- package/dist/index.mjs +27 -25
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -40,45 +40,46 @@ const EMPTY_OR = {
|
|
|
40
40
|
*/ const sqlVisitor = {
|
|
41
41
|
comparison(field, op, value) {
|
|
42
42
|
const col = `"${escapeIdent(field)}"`;
|
|
43
|
+
const v = toSqliteParam(value);
|
|
43
44
|
switch (op) {
|
|
44
45
|
case "$eq": {
|
|
45
|
-
if (
|
|
46
|
+
if (v === null) return {
|
|
46
47
|
sql: `${col} IS NULL`,
|
|
47
48
|
params: []
|
|
48
49
|
};
|
|
49
50
|
return {
|
|
50
51
|
sql: `${col} = ?`,
|
|
51
|
-
params: [
|
|
52
|
+
params: [v]
|
|
52
53
|
};
|
|
53
54
|
}
|
|
54
55
|
case "$ne": {
|
|
55
|
-
if (
|
|
56
|
+
if (v === null) return {
|
|
56
57
|
sql: `${col} IS NOT NULL`,
|
|
57
58
|
params: []
|
|
58
59
|
};
|
|
59
60
|
return {
|
|
60
61
|
sql: `${col} != ?`,
|
|
61
|
-
params: [
|
|
62
|
+
params: [v]
|
|
62
63
|
};
|
|
63
64
|
}
|
|
64
65
|
case "$gt": return {
|
|
65
66
|
sql: `${col} > ?`,
|
|
66
|
-
params: [
|
|
67
|
+
params: [v]
|
|
67
68
|
};
|
|
68
69
|
case "$gte": return {
|
|
69
70
|
sql: `${col} >= ?`,
|
|
70
|
-
params: [
|
|
71
|
+
params: [v]
|
|
71
72
|
};
|
|
72
73
|
case "$lt": return {
|
|
73
74
|
sql: `${col} < ?`,
|
|
74
|
-
params: [
|
|
75
|
+
params: [v]
|
|
75
76
|
};
|
|
76
77
|
case "$lte": return {
|
|
77
78
|
sql: `${col} <= ?`,
|
|
78
|
-
params: [
|
|
79
|
+
params: [v]
|
|
79
80
|
};
|
|
80
81
|
case "$in": {
|
|
81
|
-
const arr = value;
|
|
82
|
+
const arr = value.map(toSqliteParam);
|
|
82
83
|
if (arr.length === 0) return EMPTY_OR;
|
|
83
84
|
const placeholders = arr.map(() => "?").join(", ");
|
|
84
85
|
return {
|
|
@@ -87,7 +88,7 @@ const EMPTY_OR = {
|
|
|
87
88
|
};
|
|
88
89
|
}
|
|
89
90
|
case "$nin": {
|
|
90
|
-
const arr = value;
|
|
91
|
+
const arr = value.map(toSqliteParam);
|
|
91
92
|
if (arr.length === 0) return EMPTY_AND;
|
|
92
93
|
const placeholders = arr.map(() => "?").join(", ");
|
|
93
94
|
return {
|
|
@@ -162,6 +163,13 @@ function buildWhere(filter) {
|
|
|
162
163
|
*/ function escapeIdent(name) {
|
|
163
164
|
return name.replace(/"/g, "\"\"");
|
|
164
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* Converts a JS value to a SQLite-bindable parameter.
|
|
168
|
+
* SQLite cannot bind booleans — they must be 0/1.
|
|
169
|
+
*/ function toSqliteParam(value) {
|
|
170
|
+
if (typeof value === "boolean") return value ? 1 : 0;
|
|
171
|
+
return value;
|
|
172
|
+
}
|
|
165
173
|
|
|
166
174
|
//#endregion
|
|
167
175
|
//#region packages/db-sqlite/src/sql-builder.ts
|
|
@@ -220,7 +228,7 @@ function buildCreateTable(table, fields) {
|
|
|
220
228
|
const primaryKeys = fields.filter((f) => f.isPrimaryKey);
|
|
221
229
|
for (const field of fields) {
|
|
222
230
|
if (field.ignored) continue;
|
|
223
|
-
const sqlType = sqliteTypeFromDesignType(field.designType);
|
|
231
|
+
const sqlType = field.isPrimaryKey && (field.designType === "number" || field.designType === "integer") ? "INTEGER" : sqliteTypeFromDesignType(field.designType);
|
|
224
232
|
let def = `"${esc$1(field.physicalName)}" ${sqlType}`;
|
|
225
233
|
if (field.isPrimaryKey && primaryKeys.length === 1) def += " PRIMARY KEY";
|
|
226
234
|
if (!field.optional && !field.isPrimaryKey) def += " NOT NULL";
|
|
@@ -242,16 +250,14 @@ function sqliteTypeFromDesignType(designType) {
|
|
|
242
250
|
}
|
|
243
251
|
}
|
|
244
252
|
function buildProjection(select) {
|
|
245
|
-
|
|
246
|
-
if (
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
if (firstVal === 1) return entries.filter(([_, v]) => v === 1).map(([k]) => `"${esc$1(k)}"`).join(", ");
|
|
254
|
-
return "*";
|
|
253
|
+
const fields = select?.asArray;
|
|
254
|
+
if (!fields) return "*";
|
|
255
|
+
let sql = "";
|
|
256
|
+
for (let i = 0; i < fields.length; i++) {
|
|
257
|
+
if (i > 0) sql += ", ";
|
|
258
|
+
sql += `"${esc$1(fields[i])}"`;
|
|
259
|
+
}
|
|
260
|
+
return sql || "*";
|
|
255
261
|
}
|
|
256
262
|
function esc$1(name) {
|
|
257
263
|
return name.replace(/"/g, "\"\"");
|
|
@@ -405,15 +411,11 @@ var SqliteAdapter = class extends __atscript_utils_db.BaseDbAdapter {
|
|
|
405
411
|
}
|
|
406
412
|
async syncIndexes() {
|
|
407
413
|
const tableName = this.resolveTableName();
|
|
408
|
-
const columnMap = this._table.columnMap;
|
|
409
414
|
await this.syncIndexesWithDiff({
|
|
410
415
|
listExisting: async () => this.driver.all(`PRAGMA index_list("${esc(tableName)}")`).filter((i) => !i.name.startsWith("sqlite_")),
|
|
411
416
|
createIndex: async (index) => {
|
|
412
417
|
const unique = index.type === "unique" ? "UNIQUE " : "";
|
|
413
|
-
const cols = index.fields.map((f) => {
|
|
414
|
-
const physical = columnMap.get(f.name) ?? f.name;
|
|
415
|
-
return `"${esc(physical)}" ${f.sort === "desc" ? "DESC" : "ASC"}`;
|
|
416
|
-
}).join(", ");
|
|
418
|
+
const cols = index.fields.map((f) => `"${esc(f.name)}" ${f.sort === "desc" ? "DESC" : "ASC"}`).join(", ");
|
|
417
419
|
this.driver.exec(`CREATE ${unique}INDEX IF NOT EXISTS "${esc(index.key)}" ON "${esc(tableName)}" (${cols})`);
|
|
418
420
|
},
|
|
419
421
|
dropIndex: async (name) => {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { TAtscriptAnnotatedType } from '@atscript/typescript/utils';
|
|
2
|
-
import { BaseDbAdapter, TDbInsertResult, TDbInsertManyResult, TDbUpdateResult, TDbDeleteResult } from '@atscript/utils-db';
|
|
3
|
-
import { Uniquery, FilterExpr } from '@uniqu/core';
|
|
2
|
+
import { BaseDbAdapter, TDbInsertResult, TDbInsertManyResult, DbQuery, FilterExpr, TDbUpdateResult, TDbDeleteResult } from '@atscript/utils-db';
|
|
4
3
|
import * as better_sqlite3 from 'better-sqlite3';
|
|
4
|
+
import { FilterExpr as FilterExpr$1 } from '@uniqu/core';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Result of a SQL statement that modifies data (INSERT, UPDATE, DELETE).
|
|
@@ -71,9 +71,9 @@ declare class SqliteAdapter extends BaseDbAdapter {
|
|
|
71
71
|
prepareId(id: unknown, _fieldType: TAtscriptAnnotatedType): unknown;
|
|
72
72
|
insertOne(data: Record<string, unknown>): Promise<TDbInsertResult>;
|
|
73
73
|
insertMany(data: Array<Record<string, unknown>>): Promise<TDbInsertManyResult>;
|
|
74
|
-
findOne(query:
|
|
75
|
-
findMany(query:
|
|
76
|
-
count(query:
|
|
74
|
+
findOne(query: DbQuery): Promise<Record<string, unknown> | null>;
|
|
75
|
+
findMany(query: DbQuery): Promise<Array<Record<string, unknown>>>;
|
|
76
|
+
count(query: DbQuery): Promise<number>;
|
|
77
77
|
updateOne(filter: FilterExpr, data: Record<string, unknown>): Promise<TDbUpdateResult>;
|
|
78
78
|
updateMany(filter: FilterExpr, data: Record<string, unknown>): Promise<TDbUpdateResult>;
|
|
79
79
|
replaceOne(filter: FilterExpr, data: Record<string, unknown>): Promise<TDbUpdateResult>;
|
|
@@ -130,7 +130,7 @@ interface TSqlFragment {
|
|
|
130
130
|
* @returns `{ sql, params }` — the WHERE clause (without "WHERE") and bound params.
|
|
131
131
|
* Returns `{ sql: '1=1', params: [] }` for empty/null filters.
|
|
132
132
|
*/
|
|
133
|
-
declare function buildWhere(filter: FilterExpr): TSqlFragment;
|
|
133
|
+
declare function buildWhere(filter: FilterExpr$1): TSqlFragment;
|
|
134
134
|
|
|
135
135
|
export { BetterSqlite3Driver, SqliteAdapter, buildWhere };
|
|
136
136
|
export type { TSqlFragment, TSqliteDriver, TSqliteRunResult };
|
package/dist/index.mjs
CHANGED
|
@@ -23,45 +23,46 @@ const EMPTY_OR = {
|
|
|
23
23
|
*/ const sqlVisitor = {
|
|
24
24
|
comparison(field, op, value) {
|
|
25
25
|
const col = `"${escapeIdent(field)}"`;
|
|
26
|
+
const v = toSqliteParam(value);
|
|
26
27
|
switch (op) {
|
|
27
28
|
case "$eq": {
|
|
28
|
-
if (
|
|
29
|
+
if (v === null) return {
|
|
29
30
|
sql: `${col} IS NULL`,
|
|
30
31
|
params: []
|
|
31
32
|
};
|
|
32
33
|
return {
|
|
33
34
|
sql: `${col} = ?`,
|
|
34
|
-
params: [
|
|
35
|
+
params: [v]
|
|
35
36
|
};
|
|
36
37
|
}
|
|
37
38
|
case "$ne": {
|
|
38
|
-
if (
|
|
39
|
+
if (v === null) return {
|
|
39
40
|
sql: `${col} IS NOT NULL`,
|
|
40
41
|
params: []
|
|
41
42
|
};
|
|
42
43
|
return {
|
|
43
44
|
sql: `${col} != ?`,
|
|
44
|
-
params: [
|
|
45
|
+
params: [v]
|
|
45
46
|
};
|
|
46
47
|
}
|
|
47
48
|
case "$gt": return {
|
|
48
49
|
sql: `${col} > ?`,
|
|
49
|
-
params: [
|
|
50
|
+
params: [v]
|
|
50
51
|
};
|
|
51
52
|
case "$gte": return {
|
|
52
53
|
sql: `${col} >= ?`,
|
|
53
|
-
params: [
|
|
54
|
+
params: [v]
|
|
54
55
|
};
|
|
55
56
|
case "$lt": return {
|
|
56
57
|
sql: `${col} < ?`,
|
|
57
|
-
params: [
|
|
58
|
+
params: [v]
|
|
58
59
|
};
|
|
59
60
|
case "$lte": return {
|
|
60
61
|
sql: `${col} <= ?`,
|
|
61
|
-
params: [
|
|
62
|
+
params: [v]
|
|
62
63
|
};
|
|
63
64
|
case "$in": {
|
|
64
|
-
const arr = value;
|
|
65
|
+
const arr = value.map(toSqliteParam);
|
|
65
66
|
if (arr.length === 0) return EMPTY_OR;
|
|
66
67
|
const placeholders = arr.map(() => "?").join(", ");
|
|
67
68
|
return {
|
|
@@ -70,7 +71,7 @@ const EMPTY_OR = {
|
|
|
70
71
|
};
|
|
71
72
|
}
|
|
72
73
|
case "$nin": {
|
|
73
|
-
const arr = value;
|
|
74
|
+
const arr = value.map(toSqliteParam);
|
|
74
75
|
if (arr.length === 0) return EMPTY_AND;
|
|
75
76
|
const placeholders = arr.map(() => "?").join(", ");
|
|
76
77
|
return {
|
|
@@ -145,6 +146,13 @@ function buildWhere(filter) {
|
|
|
145
146
|
*/ function escapeIdent(name) {
|
|
146
147
|
return name.replace(/"/g, "\"\"");
|
|
147
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* Converts a JS value to a SQLite-bindable parameter.
|
|
151
|
+
* SQLite cannot bind booleans — they must be 0/1.
|
|
152
|
+
*/ function toSqliteParam(value) {
|
|
153
|
+
if (typeof value === "boolean") return value ? 1 : 0;
|
|
154
|
+
return value;
|
|
155
|
+
}
|
|
148
156
|
|
|
149
157
|
//#endregion
|
|
150
158
|
//#region packages/db-sqlite/src/sql-builder.ts
|
|
@@ -203,7 +211,7 @@ function buildCreateTable(table, fields) {
|
|
|
203
211
|
const primaryKeys = fields.filter((f) => f.isPrimaryKey);
|
|
204
212
|
for (const field of fields) {
|
|
205
213
|
if (field.ignored) continue;
|
|
206
|
-
const sqlType = sqliteTypeFromDesignType(field.designType);
|
|
214
|
+
const sqlType = field.isPrimaryKey && (field.designType === "number" || field.designType === "integer") ? "INTEGER" : sqliteTypeFromDesignType(field.designType);
|
|
207
215
|
let def = `"${esc$1(field.physicalName)}" ${sqlType}`;
|
|
208
216
|
if (field.isPrimaryKey && primaryKeys.length === 1) def += " PRIMARY KEY";
|
|
209
217
|
if (!field.optional && !field.isPrimaryKey) def += " NOT NULL";
|
|
@@ -225,16 +233,14 @@ function sqliteTypeFromDesignType(designType) {
|
|
|
225
233
|
}
|
|
226
234
|
}
|
|
227
235
|
function buildProjection(select) {
|
|
228
|
-
|
|
229
|
-
if (
|
|
230
|
-
|
|
231
|
-
|
|
236
|
+
const fields = select?.asArray;
|
|
237
|
+
if (!fields) return "*";
|
|
238
|
+
let sql = "";
|
|
239
|
+
for (let i = 0; i < fields.length; i++) {
|
|
240
|
+
if (i > 0) sql += ", ";
|
|
241
|
+
sql += `"${esc$1(fields[i])}"`;
|
|
232
242
|
}
|
|
233
|
-
|
|
234
|
-
if (entries.length === 0) return "*";
|
|
235
|
-
const firstVal = entries[0][1];
|
|
236
|
-
if (firstVal === 1) return entries.filter(([_, v]) => v === 1).map(([k]) => `"${esc$1(k)}"`).join(", ");
|
|
237
|
-
return "*";
|
|
243
|
+
return sql || "*";
|
|
238
244
|
}
|
|
239
245
|
function esc$1(name) {
|
|
240
246
|
return name.replace(/"/g, "\"\"");
|
|
@@ -388,15 +394,11 @@ var SqliteAdapter = class extends BaseDbAdapter {
|
|
|
388
394
|
}
|
|
389
395
|
async syncIndexes() {
|
|
390
396
|
const tableName = this.resolveTableName();
|
|
391
|
-
const columnMap = this._table.columnMap;
|
|
392
397
|
await this.syncIndexesWithDiff({
|
|
393
398
|
listExisting: async () => this.driver.all(`PRAGMA index_list("${esc(tableName)}")`).filter((i) => !i.name.startsWith("sqlite_")),
|
|
394
399
|
createIndex: async (index) => {
|
|
395
400
|
const unique = index.type === "unique" ? "UNIQUE " : "";
|
|
396
|
-
const cols = index.fields.map((f) => {
|
|
397
|
-
const physical = columnMap.get(f.name) ?? f.name;
|
|
398
|
-
return `"${esc(physical)}" ${f.sort === "desc" ? "DESC" : "ASC"}`;
|
|
399
|
-
}).join(", ");
|
|
401
|
+
const cols = index.fields.map((f) => `"${esc(f.name)}" ${f.sort === "desc" ? "DESC" : "ASC"}`).join(", ");
|
|
400
402
|
this.driver.exec(`CREATE ${unique}INDEX IF NOT EXISTS "${esc(index.key)}" ON "${esc(tableName)}" (${cols})`);
|
|
401
403
|
},
|
|
402
404
|
dropIndex: async (name) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atscript/db-sqlite",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.32",
|
|
4
4
|
"description": "SQLite adapter for @atscript/utils-db with swappable driver support.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"atscript",
|
|
@@ -38,11 +38,11 @@
|
|
|
38
38
|
"vitest": "3.2.4"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
|
-
"@uniqu/core": "^0.0.
|
|
41
|
+
"@uniqu/core": "^0.0.2",
|
|
42
42
|
"better-sqlite3": ">=11.0.0",
|
|
43
|
-
"@atscript/core": "^0.1.
|
|
44
|
-
"@atscript/typescript": "^0.1.
|
|
45
|
-
"@atscript/utils-db": "^0.1.
|
|
43
|
+
"@atscript/core": "^0.1.32",
|
|
44
|
+
"@atscript/typescript": "^0.1.32",
|
|
45
|
+
"@atscript/utils-db": "^0.1.32"
|
|
46
46
|
},
|
|
47
47
|
"peerDependenciesMeta": {
|
|
48
48
|
"better-sqlite3": {
|