@atscript/db-sqlite 0.1.128 → 0.1.130

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 CHANGED
@@ -1,6 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let _atscript_db = require("@atscript/db");
3
3
  let node_module = require("node:module");
4
+ let _atscript_db_agg = require("@atscript/db/agg");
4
5
  let _atscript_db_sql_tools = require("@atscript/db-sql-tools");
5
6
  let node_async_hooks = require("node:async_hooks");
6
7
  //#region src/better-sqlite3-driver.ts
@@ -807,8 +808,9 @@ var SqliteAdapter = class SqliteAdapter extends _atscript_db.BaseDbAdapter {
807
808
  return (await this._stmt(() => this.driver.get(sql, where.params)))?.cnt ?? 0;
808
809
  }
809
810
  async aggregate(query) {
810
- const where = buildWhere(query.filter);
811
811
  const tableName = this.resolveTableName();
812
+ const search = (0, _atscript_db_agg.resolveAggregateSearch)(query.controls);
813
+ const where = search ? andWhere(this._buildFtsMatchWhere(search.text, search.indexName), buildWhere(query.filter)) : buildWhere(query.filter);
812
814
  if (query.controls.$count) {
813
815
  const { sql, params } = buildAggregateCount(tableName, where, query.controls);
814
816
  this._log(sql, params);
@@ -1240,6 +1242,26 @@ var SqliteAdapter = class SqliteAdapter extends _atscript_db.BaseDbAdapter {
1240
1242
  return ftIndexes[0];
1241
1243
  }
1242
1244
  /**
1245
+ * The FTS5 match restated as a standalone WHERE fragment:
1246
+ * `rowid IN (SELECT rowid FROM "<table>__fts__<idx>" WHERE "<table>__fts__<idx>" MATCH ?)`.
1247
+ *
1248
+ * The external-content FTS5 tables this adapter creates carry
1249
+ * `content_rowid='rowid'`, so the virtual table's `rowid` IS the content
1250
+ * table's rowid, and the unqualified `rowid` outside the subquery resolves
1251
+ * against the aggregate's single FROM table. {@link _buildFtsBase} is the
1252
+ * leaf path's JOIN form, which the unaliased aggregate builders cannot take.
1253
+ *
1254
+ * Index resolution goes through {@link _resolveFtsIndex}, as the leaf path
1255
+ * does, so a named `$index` and its "not found" error behave identically.
1256
+ */
1257
+ _buildFtsMatchWhere(text, indexName) {
1258
+ const quoted = `"${esc(this._ftsTableName(this._resolveFtsIndex(indexName).name))}"`;
1259
+ return {
1260
+ sql: `rowid IN (SELECT rowid FROM ${quoted} WHERE ${quoted} MATCH ?)`,
1261
+ params: [text]
1262
+ };
1263
+ }
1264
+ /**
1243
1265
  * Builds the shared FROM+JOIN+WHERE fragment for FTS5 queries.
1244
1266
  * Both data and count queries reuse this to avoid duplicating index resolution and filter translation.
1245
1267
  */
@@ -1598,6 +1620,18 @@ var SqliteAdapter = class SqliteAdapter extends _atscript_db.BaseDbAdapter {
1598
1620
  for (const name of this._listShadowTables(tableName, "vec")) this._dropVecTable(name);
1599
1621
  }
1600
1622
  };
1623
+ /**
1624
+ * ANDs two WHERE fragments, keeping `left`'s params first so placeholder order
1625
+ * follows the rendered SQL. An empty `right` — what {@link buildWhere} returns
1626
+ * for no filter — is dropped rather than appended.
1627
+ */
1628
+ function andWhere(left, right) {
1629
+ if (right.sql === _atscript_db_sql_tools.EMPTY_AND.sql) return left;
1630
+ return {
1631
+ sql: `${left.sql} AND (${right.sql})`,
1632
+ params: [...left.params, ...right.params]
1633
+ };
1634
+ }
1601
1635
  /** Normalizes SQLite PRAGMA dflt_value to match serialized format.
1602
1636
  * PRAGMA returns `'active'` (SQL-quoted), we store `active` (raw). */
1603
1637
  function normalizeSqliteDefault(value) {
package/dist/index.d.cts CHANGED
@@ -366,6 +366,20 @@ declare class SqliteAdapter extends BaseDbAdapter {
366
366
  private _getFulltextIndexes;
367
367
  /** Resolves a fulltext index by name, or returns the first available. */
368
368
  private _resolveFtsIndex;
369
+ /**
370
+ * The FTS5 match restated as a standalone WHERE fragment:
371
+ * `rowid IN (SELECT rowid FROM "<table>__fts__<idx>" WHERE "<table>__fts__<idx>" MATCH ?)`.
372
+ *
373
+ * The external-content FTS5 tables this adapter creates carry
374
+ * `content_rowid='rowid'`, so the virtual table's `rowid` IS the content
375
+ * table's rowid, and the unqualified `rowid` outside the subquery resolves
376
+ * against the aggregate's single FROM table. {@link _buildFtsBase} is the
377
+ * leaf path's JOIN form, which the unaliased aggregate builders cannot take.
378
+ *
379
+ * Index resolution goes through {@link _resolveFtsIndex}, as the leaf path
380
+ * does, so a named `$index` and its "not found" error behave identically.
381
+ */
382
+ private _buildFtsMatchWhere;
369
383
  /**
370
384
  * Builds the shared FROM+JOIN+WHERE fragment for FTS5 queries.
371
385
  * Both data and count queries reuse this to avoid duplicating index resolution and filter translation.
package/dist/index.d.mts CHANGED
@@ -366,6 +366,20 @@ declare class SqliteAdapter extends BaseDbAdapter {
366
366
  private _getFulltextIndexes;
367
367
  /** Resolves a fulltext index by name, or returns the first available. */
368
368
  private _resolveFtsIndex;
369
+ /**
370
+ * The FTS5 match restated as a standalone WHERE fragment:
371
+ * `rowid IN (SELECT rowid FROM "<table>__fts__<idx>" WHERE "<table>__fts__<idx>" MATCH ?)`.
372
+ *
373
+ * The external-content FTS5 tables this adapter creates carry
374
+ * `content_rowid='rowid'`, so the virtual table's `rowid` IS the content
375
+ * table's rowid, and the unqualified `rowid` outside the subquery resolves
376
+ * against the aggregate's single FROM table. {@link _buildFtsBase} is the
377
+ * leaf path's JOIN form, which the unaliased aggregate builders cannot take.
378
+ *
379
+ * Index resolution goes through {@link _resolveFtsIndex}, as the leaf path
380
+ * does, so a named `$index` and its "not found" error behave identically.
381
+ */
382
+ private _buildFtsMatchWhere;
369
383
  /**
370
384
  * Builds the shared FROM+JOIN+WHERE fragment for FTS5 queries.
371
385
  * Both data and count queries reuse this to avoid duplicating index resolution and filter translation.
package/dist/index.mjs CHANGED
@@ -1,6 +1,7 @@
1
1
  import { createRequire } from "node:module";
2
2
  import { BaseDbAdapter, DbError, DbSpace } from "@atscript/db";
3
- import { buildAggregateCount, buildAggregateSelect, buildCreateView, buildDelete, buildGeoSearchCount, buildGeoSearchSelect, buildInsert, buildSelect, buildUpdate, buildWhere as buildWhere$1, defaultValueForType, defaultValueToSqlLiteral, fillReplacePayload, geoWindowFromControls, parseRegexString, refActionToSql, renameGeoDistance, replaceColumnsFor, toSqlValue } from "@atscript/db-sql-tools";
3
+ import { resolveAggregateSearch } from "@atscript/db/agg";
4
+ import { EMPTY_AND, buildAggregateCount, buildAggregateSelect, buildCreateView, buildDelete, buildGeoSearchCount, buildGeoSearchSelect, buildInsert, buildSelect, buildUpdate, buildWhere as buildWhere$1, defaultValueForType, defaultValueToSqlLiteral, fillReplacePayload, geoWindowFromControls, parseRegexString, refActionToSql, renameGeoDistance, replaceColumnsFor, toSqlValue } from "@atscript/db-sql-tools";
4
5
  import { AsyncLocalStorage } from "node:async_hooks";
5
6
  //#region src/better-sqlite3-driver.ts
6
7
  /**
@@ -806,8 +807,9 @@ var SqliteAdapter = class SqliteAdapter extends BaseDbAdapter {
806
807
  return (await this._stmt(() => this.driver.get(sql, where.params)))?.cnt ?? 0;
807
808
  }
808
809
  async aggregate(query) {
809
- const where = buildWhere(query.filter);
810
810
  const tableName = this.resolveTableName();
811
+ const search = resolveAggregateSearch(query.controls);
812
+ const where = search ? andWhere(this._buildFtsMatchWhere(search.text, search.indexName), buildWhere(query.filter)) : buildWhere(query.filter);
811
813
  if (query.controls.$count) {
812
814
  const { sql, params } = buildAggregateCount$1(tableName, where, query.controls);
813
815
  this._log(sql, params);
@@ -1239,6 +1241,26 @@ var SqliteAdapter = class SqliteAdapter extends BaseDbAdapter {
1239
1241
  return ftIndexes[0];
1240
1242
  }
1241
1243
  /**
1244
+ * The FTS5 match restated as a standalone WHERE fragment:
1245
+ * `rowid IN (SELECT rowid FROM "<table>__fts__<idx>" WHERE "<table>__fts__<idx>" MATCH ?)`.
1246
+ *
1247
+ * The external-content FTS5 tables this adapter creates carry
1248
+ * `content_rowid='rowid'`, so the virtual table's `rowid` IS the content
1249
+ * table's rowid, and the unqualified `rowid` outside the subquery resolves
1250
+ * against the aggregate's single FROM table. {@link _buildFtsBase} is the
1251
+ * leaf path's JOIN form, which the unaliased aggregate builders cannot take.
1252
+ *
1253
+ * Index resolution goes through {@link _resolveFtsIndex}, as the leaf path
1254
+ * does, so a named `$index` and its "not found" error behave identically.
1255
+ */
1256
+ _buildFtsMatchWhere(text, indexName) {
1257
+ const quoted = `"${esc(this._ftsTableName(this._resolveFtsIndex(indexName).name))}"`;
1258
+ return {
1259
+ sql: `rowid IN (SELECT rowid FROM ${quoted} WHERE ${quoted} MATCH ?)`,
1260
+ params: [text]
1261
+ };
1262
+ }
1263
+ /**
1242
1264
  * Builds the shared FROM+JOIN+WHERE fragment for FTS5 queries.
1243
1265
  * Both data and count queries reuse this to avoid duplicating index resolution and filter translation.
1244
1266
  */
@@ -1597,6 +1619,18 @@ var SqliteAdapter = class SqliteAdapter extends BaseDbAdapter {
1597
1619
  for (const name of this._listShadowTables(tableName, "vec")) this._dropVecTable(name);
1598
1620
  }
1599
1621
  };
1622
+ /**
1623
+ * ANDs two WHERE fragments, keeping `left`'s params first so placeholder order
1624
+ * follows the rendered SQL. An empty `right` — what {@link buildWhere} returns
1625
+ * for no filter — is dropped rather than appended.
1626
+ */
1627
+ function andWhere(left, right) {
1628
+ if (right.sql === EMPTY_AND.sql) return left;
1629
+ return {
1630
+ sql: `${left.sql} AND (${right.sql})`,
1631
+ params: [...left.params, ...right.params]
1632
+ };
1633
+ }
1600
1634
  /** Normalizes SQLite PRAGMA dflt_value to match serialized format.
1601
1635
  * PRAGMA returns `'active'` (SQL-quoted), we store `active` (raw). */
1602
1636
  function normalizeSqliteDefault(value) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atscript/db-sqlite",
3
- "version": "0.1.128",
3
+ "version": "0.1.130",
4
4
  "description": "SQLite adapter for @atscript/db with swappable driver support.",
5
5
  "keywords": [
6
6
  "atscript",
@@ -49,8 +49,8 @@
49
49
  "@atscript/typescript": "^0.1.92",
50
50
  "@uniqu/core": "^0.1.8",
51
51
  "better-sqlite3": ">=11.0.0",
52
- "@atscript/db": "^0.1.128",
53
- "@atscript/db-sql-tools": "^0.1.128"
52
+ "@atscript/db": "^0.1.130",
53
+ "@atscript/db-sql-tools": "^0.1.130"
54
54
  },
55
55
  "peerDependenciesMeta": {
56
56
  "better-sqlite3": {