@atscript/db-sqlite 0.1.145 → 0.1.147
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 +43 -12
- package/dist/index.d.cts +22 -3
- package/dist/index.d.mts +22 -3
- package/dist/index.mjs +45 -14
- package/package.json +10 -10
package/dist/index.cjs
CHANGED
|
@@ -86,7 +86,8 @@ var BetterSqlite3Driver = class {
|
|
|
86
86
|
//#region src/calendar-bucket.ts
|
|
87
87
|
/**
|
|
88
88
|
* Name of the scalar SQL function the adapter registers on its driver:
|
|
89
|
-
* `atscript_bucket(value, unit, tz, weekStart)` → TEXT `'YYYY-MM-DD'`
|
|
89
|
+
* `atscript_bucket(value, unit, tz, weekStart)` → TEXT `'YYYY-MM-DD'`
|
|
90
|
+
* (`'YYYY-MM-DDTHH:00'` for unit `hour`) or NULL.
|
|
90
91
|
*/
|
|
91
92
|
const SQLITE_BUCKET_FN = "atscript_bucket";
|
|
92
93
|
/**
|
|
@@ -287,6 +288,7 @@ const sqliteDialect = {
|
|
|
287
288
|
},
|
|
288
289
|
calendarBucket: sqliteCalendarBucket,
|
|
289
290
|
jsonExtract: sqliteJsonExtract,
|
|
291
|
+
castDouble: (expr) => `CAST(${expr} AS REAL)`,
|
|
290
292
|
createViewPrefix: "CREATE VIEW IF NOT EXISTS"
|
|
291
293
|
};
|
|
292
294
|
/**
|
|
@@ -438,8 +440,9 @@ function buildCreateTable(table, fields, foreignKeys, options) {
|
|
|
438
440
|
colDefs.push(`PRIMARY KEY (${pkCols})`);
|
|
439
441
|
}
|
|
440
442
|
if (foreignKeys) for (const fk of foreignKeys.values()) {
|
|
441
|
-
const
|
|
442
|
-
const
|
|
443
|
+
const { fields, targetFields } = (0, _atscript_db.fkColumns)(fk);
|
|
444
|
+
const localCols = fields.map((f) => `"${esc(f)}"`).join(", ");
|
|
445
|
+
const targetCols = targetFields.map((f) => `"${esc(f)}"`).join(", ");
|
|
443
446
|
let constraint = `FOREIGN KEY (${localCols}) REFERENCES "${esc(fk.targetTable)}" (${targetCols})`;
|
|
444
447
|
if (fk.onDelete) constraint += ` ON DELETE ${(0, _atscript_db_sql_tools.refActionToSql)(fk.onDelete)}`;
|
|
445
448
|
if (fk.onUpdate) constraint += ` ON UPDATE ${(0, _atscript_db_sql_tools.refActionToSql)(fk.onUpdate)}`;
|
|
@@ -452,23 +455,28 @@ function buildCreateTable(table, fields, foreignKeys, options) {
|
|
|
452
455
|
/**
|
|
453
456
|
* Translates a uniqu filter expression into a parameterized SQL WHERE clause.
|
|
454
457
|
*
|
|
458
|
+
* Relational predicates (`$some` / `$none`) render as correlated `EXISTS`
|
|
459
|
+
* subqueries referencing the outer table by `opts.qualifier` (default: the
|
|
460
|
+
* source table name) — a statement with an aliased FROM must pass its alias.
|
|
461
|
+
*
|
|
462
|
+
* @param opts - since 0.1.147
|
|
455
463
|
* @returns `{ sql, params }` — the WHERE clause (without "WHERE") and bound params.
|
|
456
464
|
* Returns `{ sql: '1=1', params: [] }` for empty/null filters.
|
|
457
465
|
*/
|
|
458
|
-
function buildWhere(filter) {
|
|
459
|
-
return (0, _atscript_db_sql_tools.buildWhere)(sqliteDialect, filter);
|
|
466
|
+
function buildWhere(filter, opts) {
|
|
467
|
+
return (0, _atscript_db_sql_tools.buildWhere)(sqliteDialect, filter, opts);
|
|
460
468
|
}
|
|
461
469
|
/**
|
|
462
470
|
* Like {@link buildWhere} but prefixes all column references with a table alias.
|
|
463
471
|
* Produces `alias."col"` instead of `"col"` — needed for JOINed queries (e.g. FTS5 search).
|
|
472
|
+
* Relational predicates correlate to the same alias (since 0.1.147); their
|
|
473
|
+
* own subquery aliases stay unprefixed.
|
|
464
474
|
*/
|
|
465
475
|
function buildPrefixedWhere(alias, filter) {
|
|
466
|
-
return (0, _atscript_db_sql_tools.buildWhere)({
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
}
|
|
471
|
-
}, filter);
|
|
476
|
+
return (0, _atscript_db_sql_tools.buildWhere)(sqliteDialect, filter, {
|
|
477
|
+
columnRef: (name) => `${alias}."${esc(name)}"`,
|
|
478
|
+
qualifier: alias
|
|
479
|
+
});
|
|
472
480
|
}
|
|
473
481
|
//#endregion
|
|
474
482
|
//#region src/tx-gate.ts
|
|
@@ -710,6 +718,10 @@ var SqliteAdapter = class SqliteAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
710
718
|
aggregateFns() {
|
|
711
719
|
return _atscript_db.ALL_AGGREGATE_FNS;
|
|
712
720
|
}
|
|
721
|
+
/** Computed view columns and first-row joins. */
|
|
722
|
+
viewCapabilities() {
|
|
723
|
+
return _atscript_db.ALL_VIEW_CAPABILITIES;
|
|
724
|
+
}
|
|
713
725
|
/** Whether the SQLite connection has the sqlite-vec extension loaded. */
|
|
714
726
|
_supportsVector;
|
|
715
727
|
/** Whether SQLite math functions (radians/asin/...) are available — geo search. */
|
|
@@ -865,6 +877,15 @@ var SqliteAdapter = class SqliteAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
865
877
|
resolveTableName() {
|
|
866
878
|
return super.resolveTableName(false);
|
|
867
879
|
}
|
|
880
|
+
/**
|
|
881
|
+
* Relational predicates (`$some` / `$none`) render as correlated
|
|
882
|
+
* `[NOT] EXISTS` subqueries — in reads and in mutation filters alike.
|
|
883
|
+
*
|
|
884
|
+
* @since 0.1.147
|
|
885
|
+
*/
|
|
886
|
+
supportsRelationFilters(_mode) {
|
|
887
|
+
return true;
|
|
888
|
+
}
|
|
868
889
|
/** SQLite enforces FK constraints natively via PRAGMA foreign_keys. */
|
|
869
890
|
supportsNativeForeignKeys() {
|
|
870
891
|
return true;
|
|
@@ -935,6 +956,16 @@ var SqliteAdapter = class SqliteAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
935
956
|
this._log(sql, params);
|
|
936
957
|
return this._stmt(() => this.driver.all(sql, params));
|
|
937
958
|
}
|
|
959
|
+
/**
|
|
960
|
+
* `$skip` / `$limit` per partition in one statement: a `ROW_NUMBER()`
|
|
961
|
+
* window over `partitionBy` (the generic `$with` loader's per-parent page).
|
|
962
|
+
*/
|
|
963
|
+
async findManyPerPartition(query, partitionBy) {
|
|
964
|
+
const where = buildWhere(query.filter);
|
|
965
|
+
const { sql, params } = (0, _atscript_db_sql_tools.buildPartitionedSelect)(sqliteDialect, this.resolveTableName(), where, query.controls, partitionBy);
|
|
966
|
+
this._log(sql, params);
|
|
967
|
+
return (0, _atscript_db_sql_tools.stripPartitionRowNumber)(await this._stmt(() => this.driver.all(sql, params)));
|
|
968
|
+
}
|
|
938
969
|
async count(query) {
|
|
939
970
|
const where = buildWhere(query.filter);
|
|
940
971
|
const sql = `SELECT COUNT(*) as cnt FROM "${esc(this.resolveTableName())}" WHERE ${where.sql}`;
|
|
@@ -1658,7 +1689,7 @@ var SqliteAdapter = class SqliteAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
1658
1689
|
const controls = query.controls ?? {};
|
|
1659
1690
|
return {
|
|
1660
1691
|
tableName: this.resolveTableName(),
|
|
1661
|
-
where: buildWhere(query.filter),
|
|
1692
|
+
where: buildWhere(query.filter, { qualifier: sqliteDialect.quoteTable(_atscript_db_sql_tools.SEARCH_SOURCE_ALIAS) }),
|
|
1662
1693
|
dist: haversineDistanceExpr(`"${esc(column)}"`, point),
|
|
1663
1694
|
window: (0, _atscript_db_sql_tools.geoWindowFromControls)(controls),
|
|
1664
1695
|
controls
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { AggregateFn, BaseDbAdapter, BucketUnit, DbQuery, DbSpace, FilterExpr, TColumnDiff, TDbDeleteResult, TDbFieldMeta, TDbInsertManyResult, TDbInsertResult, TDbObjectKind, TDbUpdateResult, TEnsureTableOptions, TExistingColumn, TFieldOps, TGenericLogger, TReferencingForeignKey, TSearchIndexInfo, TSyncColumnResult, TValueFormatterPair } from "@atscript/db";
|
|
1
|
+
import { AggregateFn, BaseDbAdapter, BucketUnit, DbQuery, DbSpace, FilterExpr, TColumnDiff, TDbDeleteResult, TDbFieldMeta, TDbInsertManyResult, TDbInsertResult, TDbObjectKind, TDbUpdateResult, TEnsureTableOptions, TExistingColumn, TFieldOps, TGenericLogger, TReferencingForeignKey, TSearchIndexInfo, TSyncColumnResult, TValueFormatterPair, TViewCapability } from "@atscript/db";
|
|
2
2
|
import { TMetadataMap } from "@atscript/typescript/utils";
|
|
3
3
|
import { FilterExpr as FilterExpr$1 } from "@uniqu/core";
|
|
4
|
-
import { TSqlFragment, TSqlFragment as TSqlFragment$1 } from "@atscript/db-sql-tools";
|
|
4
|
+
import { TFilterVisitorOptions, TSqlFragment, TSqlFragment as TSqlFragment$1 } from "@atscript/db-sql-tools";
|
|
5
5
|
|
|
6
6
|
//#region src/types.d.ts
|
|
7
7
|
/**
|
|
@@ -269,6 +269,8 @@ declare class SqliteAdapter extends BaseDbAdapter {
|
|
|
269
269
|
calendarBucketUnits(): ReadonlySet<BucketUnit>;
|
|
270
270
|
/** Every aggregate function, `countDistinct` included. */
|
|
271
271
|
aggregateFns(): ReadonlySet<AggregateFn>;
|
|
272
|
+
/** Computed view columns and first-row joins. */
|
|
273
|
+
viewCapabilities(): ReadonlySet<TViewCapability>;
|
|
272
274
|
/** Whether the SQLite connection has the sqlite-vec extension loaded. */
|
|
273
275
|
private _supportsVector;
|
|
274
276
|
/** Whether SQLite math functions (radians/asin/...) are available — geo search. */
|
|
@@ -319,6 +321,13 @@ declare class SqliteAdapter extends BaseDbAdapter {
|
|
|
319
321
|
protected _rollbackTransaction(state: unknown): Promise<void>;
|
|
320
322
|
/** SQLite does not use schemas — override to always exclude schema. */
|
|
321
323
|
resolveTableName(): string;
|
|
324
|
+
/**
|
|
325
|
+
* Relational predicates (`$some` / `$none`) render as correlated
|
|
326
|
+
* `[NOT] EXISTS` subqueries — in reads and in mutation filters alike.
|
|
327
|
+
*
|
|
328
|
+
* @since 0.1.147
|
|
329
|
+
*/
|
|
330
|
+
supportsRelationFilters(_mode: "read" | "write"): boolean;
|
|
322
331
|
/** SQLite enforces FK constraints natively via PRAGMA foreign_keys. */
|
|
323
332
|
supportsNativeForeignKeys(): boolean;
|
|
324
333
|
prepareId(id: unknown, _fieldType: unknown): unknown;
|
|
@@ -331,6 +340,11 @@ declare class SqliteAdapter extends BaseDbAdapter {
|
|
|
331
340
|
insertMany(data: Array<Record<string, unknown>>): Promise<TDbInsertManyResult>;
|
|
332
341
|
findOne(query: DbQuery): Promise<Record<string, unknown> | null>;
|
|
333
342
|
findMany(query: DbQuery): Promise<Array<Record<string, unknown>>>;
|
|
343
|
+
/**
|
|
344
|
+
* `$skip` / `$limit` per partition in one statement: a `ROW_NUMBER()`
|
|
345
|
+
* window over `partitionBy` (the generic `$with` loader's per-parent page).
|
|
346
|
+
*/
|
|
347
|
+
findManyPerPartition(query: DbQuery, partitionBy: readonly string[]): Promise<Array<Record<string, unknown>>>;
|
|
334
348
|
count(query: DbQuery): Promise<number>;
|
|
335
349
|
aggregate(query: DbQuery): Promise<Array<Record<string, unknown>>>;
|
|
336
350
|
updateOne(filter: FilterExpr, data: Record<string, unknown>, ops?: TFieldOps, expectedVersion?: number): Promise<TDbUpdateResult>;
|
|
@@ -488,10 +502,15 @@ declare class SqliteAdapter extends BaseDbAdapter {
|
|
|
488
502
|
/**
|
|
489
503
|
* Translates a uniqu filter expression into a parameterized SQL WHERE clause.
|
|
490
504
|
*
|
|
505
|
+
* Relational predicates (`$some` / `$none`) render as correlated `EXISTS`
|
|
506
|
+
* subqueries referencing the outer table by `opts.qualifier` (default: the
|
|
507
|
+
* source table name) — a statement with an aliased FROM must pass its alias.
|
|
508
|
+
*
|
|
509
|
+
* @param opts - since 0.1.147
|
|
491
510
|
* @returns `{ sql, params }` — the WHERE clause (without "WHERE") and bound params.
|
|
492
511
|
* Returns `{ sql: '1=1', params: [] }` for empty/null filters.
|
|
493
512
|
*/
|
|
494
|
-
declare function buildWhere(filter: FilterExpr$1): TSqlFragment$1;
|
|
513
|
+
declare function buildWhere(filter: FilterExpr$1, opts?: TFilterVisitorOptions): TSqlFragment$1;
|
|
495
514
|
//#endregion
|
|
496
515
|
//#region src/index.d.ts
|
|
497
516
|
/** `createAdapter` options: driver options plus the transaction-gate options (since 0.1.128). */
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AggregateFn, BaseDbAdapter, BucketUnit, DbQuery, DbSpace, FilterExpr, TColumnDiff, TDbDeleteResult, TDbFieldMeta, TDbInsertManyResult, TDbInsertResult, TDbObjectKind, TDbUpdateResult, TEnsureTableOptions, TExistingColumn, TFieldOps, TGenericLogger, TReferencingForeignKey, TSearchIndexInfo, TSyncColumnResult, TValueFormatterPair } from "@atscript/db";
|
|
2
|
-
import { TSqlFragment, TSqlFragment as TSqlFragment$1 } from "@atscript/db-sql-tools";
|
|
1
|
+
import { AggregateFn, BaseDbAdapter, BucketUnit, DbQuery, DbSpace, FilterExpr, TColumnDiff, TDbDeleteResult, TDbFieldMeta, TDbInsertManyResult, TDbInsertResult, TDbObjectKind, TDbUpdateResult, TEnsureTableOptions, TExistingColumn, TFieldOps, TGenericLogger, TReferencingForeignKey, TSearchIndexInfo, TSyncColumnResult, TValueFormatterPair, TViewCapability } from "@atscript/db";
|
|
2
|
+
import { TFilterVisitorOptions, TSqlFragment, TSqlFragment as TSqlFragment$1 } from "@atscript/db-sql-tools";
|
|
3
3
|
import { FilterExpr as FilterExpr$1 } from "@uniqu/core";
|
|
4
4
|
import { TMetadataMap } from "@atscript/typescript/utils";
|
|
5
5
|
|
|
@@ -269,6 +269,8 @@ declare class SqliteAdapter extends BaseDbAdapter {
|
|
|
269
269
|
calendarBucketUnits(): ReadonlySet<BucketUnit>;
|
|
270
270
|
/** Every aggregate function, `countDistinct` included. */
|
|
271
271
|
aggregateFns(): ReadonlySet<AggregateFn>;
|
|
272
|
+
/** Computed view columns and first-row joins. */
|
|
273
|
+
viewCapabilities(): ReadonlySet<TViewCapability>;
|
|
272
274
|
/** Whether the SQLite connection has the sqlite-vec extension loaded. */
|
|
273
275
|
private _supportsVector;
|
|
274
276
|
/** Whether SQLite math functions (radians/asin/...) are available — geo search. */
|
|
@@ -319,6 +321,13 @@ declare class SqliteAdapter extends BaseDbAdapter {
|
|
|
319
321
|
protected _rollbackTransaction(state: unknown): Promise<void>;
|
|
320
322
|
/** SQLite does not use schemas — override to always exclude schema. */
|
|
321
323
|
resolveTableName(): string;
|
|
324
|
+
/**
|
|
325
|
+
* Relational predicates (`$some` / `$none`) render as correlated
|
|
326
|
+
* `[NOT] EXISTS` subqueries — in reads and in mutation filters alike.
|
|
327
|
+
*
|
|
328
|
+
* @since 0.1.147
|
|
329
|
+
*/
|
|
330
|
+
supportsRelationFilters(_mode: "read" | "write"): boolean;
|
|
322
331
|
/** SQLite enforces FK constraints natively via PRAGMA foreign_keys. */
|
|
323
332
|
supportsNativeForeignKeys(): boolean;
|
|
324
333
|
prepareId(id: unknown, _fieldType: unknown): unknown;
|
|
@@ -331,6 +340,11 @@ declare class SqliteAdapter extends BaseDbAdapter {
|
|
|
331
340
|
insertMany(data: Array<Record<string, unknown>>): Promise<TDbInsertManyResult>;
|
|
332
341
|
findOne(query: DbQuery): Promise<Record<string, unknown> | null>;
|
|
333
342
|
findMany(query: DbQuery): Promise<Array<Record<string, unknown>>>;
|
|
343
|
+
/**
|
|
344
|
+
* `$skip` / `$limit` per partition in one statement: a `ROW_NUMBER()`
|
|
345
|
+
* window over `partitionBy` (the generic `$with` loader's per-parent page).
|
|
346
|
+
*/
|
|
347
|
+
findManyPerPartition(query: DbQuery, partitionBy: readonly string[]): Promise<Array<Record<string, unknown>>>;
|
|
334
348
|
count(query: DbQuery): Promise<number>;
|
|
335
349
|
aggregate(query: DbQuery): Promise<Array<Record<string, unknown>>>;
|
|
336
350
|
updateOne(filter: FilterExpr, data: Record<string, unknown>, ops?: TFieldOps, expectedVersion?: number): Promise<TDbUpdateResult>;
|
|
@@ -488,10 +502,15 @@ declare class SqliteAdapter extends BaseDbAdapter {
|
|
|
488
502
|
/**
|
|
489
503
|
* Translates a uniqu filter expression into a parameterized SQL WHERE clause.
|
|
490
504
|
*
|
|
505
|
+
* Relational predicates (`$some` / `$none`) render as correlated `EXISTS`
|
|
506
|
+
* subqueries referencing the outer table by `opts.qualifier` (default: the
|
|
507
|
+
* source table name) — a statement with an aliased FROM must pass its alias.
|
|
508
|
+
*
|
|
509
|
+
* @param opts - since 0.1.147
|
|
491
510
|
* @returns `{ sql, params }` — the WHERE clause (without "WHERE") and bound params.
|
|
492
511
|
* Returns `{ sql: '1=1', params: [] }` for empty/null filters.
|
|
493
512
|
*/
|
|
494
|
-
declare function buildWhere(filter: FilterExpr$1): TSqlFragment$1;
|
|
513
|
+
declare function buildWhere(filter: FilterExpr$1, opts?: TFilterVisitorOptions): TSqlFragment$1;
|
|
495
514
|
//#endregion
|
|
496
515
|
//#region src/index.d.ts
|
|
497
516
|
/** `createAdapter` options: driver options plus the transaction-gate options (since 0.1.128). */
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
-
import { ALL_AGGREGATE_FNS, ALL_BUCKET_UNITS, BaseDbAdapter, DbError, DbSpace, searchIndexNotFoundMessage, vectorIndexNotFoundMessage } from "@atscript/db";
|
|
2
|
+
import { ALL_AGGREGATE_FNS, ALL_BUCKET_UNITS, ALL_VIEW_CAPABILITIES, BaseDbAdapter, DbError, DbSpace, fkColumns, searchIndexNotFoundMessage, vectorIndexNotFoundMessage } from "@atscript/db";
|
|
3
3
|
import { resolveAggregateSearch } from "@atscript/db/agg";
|
|
4
|
-
import { EMPTY_AND, buildAggregateCount, buildAggregateSelect, buildCreateView, buildDelete, buildGeoSearchCount, buildGeoSearchSelect, buildInsert, buildSelect, buildUpdate, buildVectorSearchCount, buildVectorSearchSelect, buildWhere as buildWhere$1, defaultValueForType, defaultValueToSqlLiteral, derivedColumnExpr, fillReplacePayload, geoWindowFromControls, jsonDollarPath, parseRegexString, refActionToSql, renameGeoDistance, replaceColumnsFor, sqlTimeZoneLiteral, toSqlValue } from "@atscript/db-sql-tools";
|
|
4
|
+
import { EMPTY_AND, SEARCH_SOURCE_ALIAS, buildAggregateCount, buildAggregateSelect, buildCreateView, buildDelete, buildGeoSearchCount, buildGeoSearchSelect, buildInsert, buildPartitionedSelect, buildSelect, buildUpdate, buildVectorSearchCount, buildVectorSearchSelect, buildWhere as buildWhere$1, defaultValueForType, defaultValueToSqlLiteral, derivedColumnExpr, fillReplacePayload, geoWindowFromControls, jsonDollarPath, parseRegexString, refActionToSql, renameGeoDistance, replaceColumnsFor, sqlTimeZoneLiteral, stripPartitionRowNumber, toSqlValue } from "@atscript/db-sql-tools";
|
|
5
5
|
import { bucketer } from "@uniqu/core";
|
|
6
6
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
7
7
|
//#region src/better-sqlite3-driver.ts
|
|
@@ -85,7 +85,8 @@ var BetterSqlite3Driver = class {
|
|
|
85
85
|
//#region src/calendar-bucket.ts
|
|
86
86
|
/**
|
|
87
87
|
* Name of the scalar SQL function the adapter registers on its driver:
|
|
88
|
-
* `atscript_bucket(value, unit, tz, weekStart)` → TEXT `'YYYY-MM-DD'`
|
|
88
|
+
* `atscript_bucket(value, unit, tz, weekStart)` → TEXT `'YYYY-MM-DD'`
|
|
89
|
+
* (`'YYYY-MM-DDTHH:00'` for unit `hour`) or NULL.
|
|
89
90
|
*/
|
|
90
91
|
const SQLITE_BUCKET_FN = "atscript_bucket";
|
|
91
92
|
/**
|
|
@@ -286,6 +287,7 @@ const sqliteDialect = {
|
|
|
286
287
|
},
|
|
287
288
|
calendarBucket: sqliteCalendarBucket,
|
|
288
289
|
jsonExtract: sqliteJsonExtract,
|
|
290
|
+
castDouble: (expr) => `CAST(${expr} AS REAL)`,
|
|
289
291
|
createViewPrefix: "CREATE VIEW IF NOT EXISTS"
|
|
290
292
|
};
|
|
291
293
|
/**
|
|
@@ -437,8 +439,9 @@ function buildCreateTable(table, fields, foreignKeys, options) {
|
|
|
437
439
|
colDefs.push(`PRIMARY KEY (${pkCols})`);
|
|
438
440
|
}
|
|
439
441
|
if (foreignKeys) for (const fk of foreignKeys.values()) {
|
|
440
|
-
const
|
|
441
|
-
const
|
|
442
|
+
const { fields, targetFields } = fkColumns(fk);
|
|
443
|
+
const localCols = fields.map((f) => `"${esc(f)}"`).join(", ");
|
|
444
|
+
const targetCols = targetFields.map((f) => `"${esc(f)}"`).join(", ");
|
|
442
445
|
let constraint = `FOREIGN KEY (${localCols}) REFERENCES "${esc(fk.targetTable)}" (${targetCols})`;
|
|
443
446
|
if (fk.onDelete) constraint += ` ON DELETE ${refActionToSql(fk.onDelete)}`;
|
|
444
447
|
if (fk.onUpdate) constraint += ` ON UPDATE ${refActionToSql(fk.onUpdate)}`;
|
|
@@ -451,23 +454,28 @@ function buildCreateTable(table, fields, foreignKeys, options) {
|
|
|
451
454
|
/**
|
|
452
455
|
* Translates a uniqu filter expression into a parameterized SQL WHERE clause.
|
|
453
456
|
*
|
|
457
|
+
* Relational predicates (`$some` / `$none`) render as correlated `EXISTS`
|
|
458
|
+
* subqueries referencing the outer table by `opts.qualifier` (default: the
|
|
459
|
+
* source table name) — a statement with an aliased FROM must pass its alias.
|
|
460
|
+
*
|
|
461
|
+
* @param opts - since 0.1.147
|
|
454
462
|
* @returns `{ sql, params }` — the WHERE clause (without "WHERE") and bound params.
|
|
455
463
|
* Returns `{ sql: '1=1', params: [] }` for empty/null filters.
|
|
456
464
|
*/
|
|
457
|
-
function buildWhere(filter) {
|
|
458
|
-
return buildWhere$1(sqliteDialect, filter);
|
|
465
|
+
function buildWhere(filter, opts) {
|
|
466
|
+
return buildWhere$1(sqliteDialect, filter, opts);
|
|
459
467
|
}
|
|
460
468
|
/**
|
|
461
469
|
* Like {@link buildWhere} but prefixes all column references with a table alias.
|
|
462
470
|
* Produces `alias."col"` instead of `"col"` — needed for JOINed queries (e.g. FTS5 search).
|
|
471
|
+
* Relational predicates correlate to the same alias (since 0.1.147); their
|
|
472
|
+
* own subquery aliases stay unprefixed.
|
|
463
473
|
*/
|
|
464
474
|
function buildPrefixedWhere(alias, filter) {
|
|
465
|
-
return buildWhere$1({
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
}
|
|
470
|
-
}, filter);
|
|
475
|
+
return buildWhere$1(sqliteDialect, filter, {
|
|
476
|
+
columnRef: (name) => `${alias}."${esc(name)}"`,
|
|
477
|
+
qualifier: alias
|
|
478
|
+
});
|
|
471
479
|
}
|
|
472
480
|
//#endregion
|
|
473
481
|
//#region src/tx-gate.ts
|
|
@@ -709,6 +717,10 @@ var SqliteAdapter = class SqliteAdapter extends BaseDbAdapter {
|
|
|
709
717
|
aggregateFns() {
|
|
710
718
|
return ALL_AGGREGATE_FNS;
|
|
711
719
|
}
|
|
720
|
+
/** Computed view columns and first-row joins. */
|
|
721
|
+
viewCapabilities() {
|
|
722
|
+
return ALL_VIEW_CAPABILITIES;
|
|
723
|
+
}
|
|
712
724
|
/** Whether the SQLite connection has the sqlite-vec extension loaded. */
|
|
713
725
|
_supportsVector;
|
|
714
726
|
/** Whether SQLite math functions (radians/asin/...) are available — geo search. */
|
|
@@ -864,6 +876,15 @@ var SqliteAdapter = class SqliteAdapter extends BaseDbAdapter {
|
|
|
864
876
|
resolveTableName() {
|
|
865
877
|
return super.resolveTableName(false);
|
|
866
878
|
}
|
|
879
|
+
/**
|
|
880
|
+
* Relational predicates (`$some` / `$none`) render as correlated
|
|
881
|
+
* `[NOT] EXISTS` subqueries — in reads and in mutation filters alike.
|
|
882
|
+
*
|
|
883
|
+
* @since 0.1.147
|
|
884
|
+
*/
|
|
885
|
+
supportsRelationFilters(_mode) {
|
|
886
|
+
return true;
|
|
887
|
+
}
|
|
867
888
|
/** SQLite enforces FK constraints natively via PRAGMA foreign_keys. */
|
|
868
889
|
supportsNativeForeignKeys() {
|
|
869
890
|
return true;
|
|
@@ -934,6 +955,16 @@ var SqliteAdapter = class SqliteAdapter extends BaseDbAdapter {
|
|
|
934
955
|
this._log(sql, params);
|
|
935
956
|
return this._stmt(() => this.driver.all(sql, params));
|
|
936
957
|
}
|
|
958
|
+
/**
|
|
959
|
+
* `$skip` / `$limit` per partition in one statement: a `ROW_NUMBER()`
|
|
960
|
+
* window over `partitionBy` (the generic `$with` loader's per-parent page).
|
|
961
|
+
*/
|
|
962
|
+
async findManyPerPartition(query, partitionBy) {
|
|
963
|
+
const where = buildWhere(query.filter);
|
|
964
|
+
const { sql, params } = buildPartitionedSelect(sqliteDialect, this.resolveTableName(), where, query.controls, partitionBy);
|
|
965
|
+
this._log(sql, params);
|
|
966
|
+
return stripPartitionRowNumber(await this._stmt(() => this.driver.all(sql, params)));
|
|
967
|
+
}
|
|
937
968
|
async count(query) {
|
|
938
969
|
const where = buildWhere(query.filter);
|
|
939
970
|
const sql = `SELECT COUNT(*) as cnt FROM "${esc(this.resolveTableName())}" WHERE ${where.sql}`;
|
|
@@ -1657,7 +1688,7 @@ var SqliteAdapter = class SqliteAdapter extends BaseDbAdapter {
|
|
|
1657
1688
|
const controls = query.controls ?? {};
|
|
1658
1689
|
return {
|
|
1659
1690
|
tableName: this.resolveTableName(),
|
|
1660
|
-
where: buildWhere(query.filter),
|
|
1691
|
+
where: buildWhere(query.filter, { qualifier: sqliteDialect.quoteTable(SEARCH_SOURCE_ALIAS) }),
|
|
1661
1692
|
dist: haversineDistanceExpr(`"${esc(column)}"`, point),
|
|
1662
1693
|
window: geoWindowFromControls(controls),
|
|
1663
1694
|
controls
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atscript/db-sqlite",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.147",
|
|
4
4
|
"description": "SQLite adapter for @atscript/db with swappable driver support.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"atscript",
|
|
@@ -36,21 +36,21 @@
|
|
|
36
36
|
"access": "public"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@atscript/core": "^0.1.
|
|
40
|
-
"@atscript/typescript": "^0.1.
|
|
39
|
+
"@atscript/core": "^0.1.99",
|
|
40
|
+
"@atscript/typescript": "^0.1.99",
|
|
41
41
|
"@types/better-sqlite3": "^7.6.13",
|
|
42
|
-
"@uniqu/core": "^0.1.
|
|
42
|
+
"@uniqu/core": "^0.1.12",
|
|
43
43
|
"better-sqlite3": "^12.6.2",
|
|
44
44
|
"sqlite-vec": "^0.1.9",
|
|
45
|
-
"unplugin-atscript": "^0.1.
|
|
45
|
+
"unplugin-atscript": "^0.1.99"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
|
-
"@atscript/core": "^0.1.
|
|
49
|
-
"@atscript/typescript": "^0.1.
|
|
50
|
-
"@uniqu/core": "^0.1.
|
|
48
|
+
"@atscript/core": "^0.1.99",
|
|
49
|
+
"@atscript/typescript": "^0.1.99",
|
|
50
|
+
"@uniqu/core": "^0.1.12",
|
|
51
51
|
"better-sqlite3": ">=11.0.0",
|
|
52
|
-
"@atscript/db": "^0.1.
|
|
53
|
-
"@atscript/db-sql-tools": "^0.1.
|
|
52
|
+
"@atscript/db": "^0.1.147",
|
|
53
|
+
"@atscript/db-sql-tools": "^0.1.147"
|
|
54
54
|
},
|
|
55
55
|
"peerDependenciesMeta": {
|
|
56
56
|
"better-sqlite3": {
|