@atscript/db-mysql 0.1.141 → 0.1.143

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
@@ -1353,13 +1353,21 @@ var MysqlAdapter = class MysqlAdapter extends _atscript_db.BaseDbAdapter {
1353
1353
  for (const index of this._table.indexes.values()) if (index.type === "fulltext") indexes.push({
1354
1354
  name: index.key,
1355
1355
  description: `FULLTEXT index on ${index.fields.map((f) => f.name).join(", ")}`,
1356
- type: "text"
1357
- });
1358
- for (const [field, vec] of this._vectorFields) indexes.push({
1359
- name: vec.indexName,
1360
- description: `VECTOR(${vec.dimensions}) on ${field}, ${vec.similarity}`,
1361
- type: "vector"
1356
+ type: "text",
1357
+ fields: this._indexLogicalPaths(index),
1358
+ isDefault: indexes.length === 0
1362
1359
  });
1360
+ let firstVector = true;
1361
+ for (const [field, vec] of this._vectorFields) {
1362
+ indexes.push({
1363
+ name: vec.indexName,
1364
+ description: `VECTOR(${vec.dimensions}) on ${field}, ${vec.similarity}`,
1365
+ type: "vector",
1366
+ fields: [field],
1367
+ isDefault: firstVector
1368
+ });
1369
+ firstVector = false;
1370
+ }
1363
1371
  return indexes;
1364
1372
  }
1365
1373
  async search(text, query, indexName) {
@@ -1456,7 +1464,7 @@ var MysqlAdapter = class MysqlAdapter extends _atscript_db.BaseDbAdapter {
1456
1464
  found = true;
1457
1465
  break;
1458
1466
  }
1459
- if (!found) throw new Error(`Vector index "${indexName}" not found`);
1467
+ if (!found) throw new Error((0, _atscript_db.vectorIndexNotFoundMessage)(indexName));
1460
1468
  } else {
1461
1469
  const first = this._vectorFields.entries().next();
1462
1470
  if (first.done) throw new Error("No vector fields defined");
@@ -1478,36 +1486,36 @@ var MysqlAdapter = class MysqlAdapter extends _atscript_db.BaseDbAdapter {
1478
1486
  vectorStr: vectorToString(vector)
1479
1487
  };
1480
1488
  }
1481
- _buildVectorSearchQuery(vector, query, indexName) {
1482
- const ctx = this._prepareVectorSearch(vector, query, indexName);
1483
- const inner = `SELECT *, ${ctx.distanceFn}(${qi(ctx.field)}, STRING_TO_VECTOR(?)) AS _distance FROM ${quoteTableName(ctx.tableName)} WHERE ${ctx.where.sql}`;
1484
- const params = [ctx.vectorStr, ...ctx.where.params];
1485
- let sql = `SELECT * FROM (${inner}) _v`;
1486
- if (ctx.threshold !== void 0) {
1487
- sql += ` WHERE _distance <= ?`;
1488
- params.push(2 * (1 - ctx.threshold));
1489
- }
1490
- sql += ` ORDER BY _distance ASC`;
1491
- if (ctx.controls.$skip) sql += ` LIMIT ${Number(ctx.controls.$limit) || 1e3} OFFSET ${Number(ctx.controls.$skip)}`;
1492
- else sql += ` LIMIT ${Number(ctx.controls.$limit) || 20}`;
1489
+ /**
1490
+ * The row source + distance cap of a vector search. The threshold is a
1491
+ * normalized score matching MongoDB Atlas semantics: cosine score =
1492
+ * (1 + cos_sim) / 2, VEC_DISTANCE_COSINE = 1 - cos_sim, so the distance cap
1493
+ * is 2 * (1 - score).
1494
+ */
1495
+ _vectorSearchSource(ctx, withRows) {
1496
+ const distExpr = {
1497
+ sql: `${ctx.distanceFn}(${qi(ctx.field)}, STRING_TO_VECTOR(?))`,
1498
+ params: [ctx.vectorStr]
1499
+ };
1493
1500
  return {
1494
- sql,
1495
- params
1501
+ source: (0, _atscript_db_sql_tools.vectorDistanceSource)(mysqlDialect, ctx.tableName, ctx.where, distExpr, withRows),
1502
+ maxDistance: ctx.threshold === void 0 ? void 0 : 2 * (1 - ctx.threshold)
1496
1503
  };
1497
1504
  }
1498
- _buildVectorSearchCountQuery(vector, query, indexName) {
1505
+ _buildVectorSearchQuery(vector, query, indexName) {
1499
1506
  const ctx = this._prepareVectorSearch(vector, query, indexName);
1500
- const inner = `SELECT ${ctx.distanceFn}(${qi(ctx.field)}, STRING_TO_VECTOR(?)) AS _distance FROM ${quoteTableName(ctx.tableName)} WHERE ${ctx.where.sql}`;
1501
- const params = [ctx.vectorStr, ...ctx.where.params];
1502
- let sql = `SELECT COUNT(*) AS cnt FROM (${inner}) _v`;
1503
- if (ctx.threshold !== void 0) {
1504
- sql += ` WHERE _distance <= ?`;
1505
- params.push(2 * (1 - ctx.threshold));
1506
- }
1507
- return {
1508
- sql,
1509
- params
1510
- };
1507
+ const { source, maxDistance } = this._vectorSearchSource(ctx, true);
1508
+ const skip = Number(ctx.controls.$skip) || 0;
1509
+ return (0, _atscript_db_sql_tools.buildVectorSearchSelect)(mysqlDialect, source, {
1510
+ select: ctx.controls.$select,
1511
+ limit: Number(ctx.controls.$limit) || (skip ? 1e3 : 20),
1512
+ skip,
1513
+ maxDistance
1514
+ });
1515
+ }
1516
+ _buildVectorSearchCountQuery(vector, query, indexName) {
1517
+ const { source, maxDistance } = this._vectorSearchSource(this._prepareVectorSearch(vector, query, indexName), false);
1518
+ return (0, _atscript_db_sql_tools.buildVectorSearchCount)(mysqlDialect, source, { maxDistance });
1511
1519
  }
1512
1520
  /** Resolves threshold: query-time $threshold > schema-level @db.search.vector.threshold. */
1513
1521
  _resolveVectorThreshold(controls, indexName) {
@@ -1549,10 +1557,7 @@ var MysqlAdapter = class MysqlAdapter extends _atscript_db.BaseDbAdapter {
1549
1557
  };
1550
1558
  }
1551
1559
  _buildGeoSearchSelect(ctx) {
1552
- return (0, _atscript_db_sql_tools.buildGeoSearchSelect)(mysqlDialect, ctx.tableName, ctx.where, ctx.dist, ctx.window, {
1553
- $limit: ctx.controls.$limit,
1554
- $skip: ctx.controls.$skip
1555
- });
1560
+ return (0, _atscript_db_sql_tools.buildGeoSearchSelect)(mysqlDialect, ctx.tableName, ctx.where, ctx.dist, ctx.window, ctx.controls);
1556
1561
  }
1557
1562
  /**
1558
1563
  * Migrates a v1 JSON `[lng, lat]` column to native `POINT SRID 4326` via a
package/dist/index.d.cts CHANGED
@@ -255,6 +255,13 @@ declare class MysqlAdapter extends BaseDbAdapter {
255
255
  }>;
256
256
  /** Resolves vector field and computes shared context for vector search SQL builders. */
257
257
  private _prepareVectorSearch;
258
+ /**
259
+ * The row source + distance cap of a vector search. The threshold is a
260
+ * normalized score matching MongoDB Atlas semantics: cosine score =
261
+ * (1 + cos_sim) / 2, VEC_DISTANCE_COSINE = 1 - cos_sim, so the distance cap
262
+ * is 2 * (1 - score).
263
+ */
264
+ private _vectorSearchSource;
258
265
  private _buildVectorSearchQuery;
259
266
  private _buildVectorSearchCountQuery;
260
267
  /** Resolves threshold: query-time $threshold > schema-level @db.search.vector.threshold. */
package/dist/index.d.mts CHANGED
@@ -255,6 +255,13 @@ declare class MysqlAdapter extends BaseDbAdapter {
255
255
  }>;
256
256
  /** Resolves vector field and computes shared context for vector search SQL builders. */
257
257
  private _prepareVectorSearch;
258
+ /**
259
+ * The row source + distance cap of a vector search. The threshold is a
260
+ * normalized score matching MongoDB Atlas semantics: cosine score =
261
+ * (1 + cos_sim) / 2, VEC_DISTANCE_COSINE = 1 - cos_sim, so the distance cap
262
+ * is 2 * (1 - score).
263
+ */
264
+ private _vectorSearchSource;
258
265
  private _buildVectorSearchQuery;
259
266
  private _buildVectorSearchCountQuery;
260
267
  /** Resolves threshold: query-time $threshold > schema-level @db.search.vector.threshold. */
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { ALL_AGGREGATE_FNS, ALL_BUCKET_UNITS, BaseDbAdapter, DbError, DbSpace, bucketTimeZoneUnavailable } from "@atscript/db";
1
+ import { ALL_AGGREGATE_FNS, ALL_BUCKET_UNITS, BaseDbAdapter, DbError, DbSpace, bucketTimeZoneUnavailable, vectorIndexNotFoundMessage } from "@atscript/db";
2
2
  import { resolveAggregateSearch } from "@atscript/db/agg";
3
- import { buildAggregateCount, buildAggregateSelect, buildCreateView, buildDelete, buildGeoSearchCount, buildGeoSearchSelect, buildInsert, buildInsertMany, buildSelect, buildUpdate, buildWhere as buildWhere$1, defaultValueForType, defaultValueToSqlLiteral, derivedColumnExpr, fillReplacePayload, geoWindowFromControls, insertManyColumns, jsonDollarPath, normalizeGeoPointValue, parseRegexString, refActionToSql, renameGeoDistance, replaceColumnsFor, sqlTimeZoneLiteral, toSqlValue } from "@atscript/db-sql-tools";
3
+ import { buildAggregateCount, buildAggregateSelect, buildCreateView, buildDelete, buildGeoSearchCount, buildGeoSearchSelect, buildInsert, buildInsertMany, buildSelect, buildUpdate, buildVectorSearchCount, buildVectorSearchSelect, buildWhere as buildWhere$1, defaultValueForType, defaultValueToSqlLiteral, derivedColumnExpr, fillReplacePayload, geoWindowFromControls, insertManyColumns, jsonDollarPath, normalizeGeoPointValue, parseRegexString, refActionToSql, renameGeoDistance, replaceColumnsFor, sqlTimeZoneLiteral, toSqlValue, vectorDistanceSource } from "@atscript/db-sql-tools";
4
4
  import { BUCKET_MAX_INSTANT, BUCKET_MIN_INSTANT } from "@uniqu/core";
5
5
  //#region src/sql-builder.ts
6
6
  /** TEXT / BLOB families (`TINYTEXT` … `LONGBLOB`). */
@@ -1352,13 +1352,21 @@ var MysqlAdapter = class MysqlAdapter extends BaseDbAdapter {
1352
1352
  for (const index of this._table.indexes.values()) if (index.type === "fulltext") indexes.push({
1353
1353
  name: index.key,
1354
1354
  description: `FULLTEXT index on ${index.fields.map((f) => f.name).join(", ")}`,
1355
- type: "text"
1356
- });
1357
- for (const [field, vec] of this._vectorFields) indexes.push({
1358
- name: vec.indexName,
1359
- description: `VECTOR(${vec.dimensions}) on ${field}, ${vec.similarity}`,
1360
- type: "vector"
1355
+ type: "text",
1356
+ fields: this._indexLogicalPaths(index),
1357
+ isDefault: indexes.length === 0
1361
1358
  });
1359
+ let firstVector = true;
1360
+ for (const [field, vec] of this._vectorFields) {
1361
+ indexes.push({
1362
+ name: vec.indexName,
1363
+ description: `VECTOR(${vec.dimensions}) on ${field}, ${vec.similarity}`,
1364
+ type: "vector",
1365
+ fields: [field],
1366
+ isDefault: firstVector
1367
+ });
1368
+ firstVector = false;
1369
+ }
1362
1370
  return indexes;
1363
1371
  }
1364
1372
  async search(text, query, indexName) {
@@ -1455,7 +1463,7 @@ var MysqlAdapter = class MysqlAdapter extends BaseDbAdapter {
1455
1463
  found = true;
1456
1464
  break;
1457
1465
  }
1458
- if (!found) throw new Error(`Vector index "${indexName}" not found`);
1466
+ if (!found) throw new Error(vectorIndexNotFoundMessage(indexName));
1459
1467
  } else {
1460
1468
  const first = this._vectorFields.entries().next();
1461
1469
  if (first.done) throw new Error("No vector fields defined");
@@ -1477,36 +1485,36 @@ var MysqlAdapter = class MysqlAdapter extends BaseDbAdapter {
1477
1485
  vectorStr: vectorToString(vector)
1478
1486
  };
1479
1487
  }
1480
- _buildVectorSearchQuery(vector, query, indexName) {
1481
- const ctx = this._prepareVectorSearch(vector, query, indexName);
1482
- const inner = `SELECT *, ${ctx.distanceFn}(${qi(ctx.field)}, STRING_TO_VECTOR(?)) AS _distance FROM ${quoteTableName(ctx.tableName)} WHERE ${ctx.where.sql}`;
1483
- const params = [ctx.vectorStr, ...ctx.where.params];
1484
- let sql = `SELECT * FROM (${inner}) _v`;
1485
- if (ctx.threshold !== void 0) {
1486
- sql += ` WHERE _distance <= ?`;
1487
- params.push(2 * (1 - ctx.threshold));
1488
- }
1489
- sql += ` ORDER BY _distance ASC`;
1490
- if (ctx.controls.$skip) sql += ` LIMIT ${Number(ctx.controls.$limit) || 1e3} OFFSET ${Number(ctx.controls.$skip)}`;
1491
- else sql += ` LIMIT ${Number(ctx.controls.$limit) || 20}`;
1488
+ /**
1489
+ * The row source + distance cap of a vector search. The threshold is a
1490
+ * normalized score matching MongoDB Atlas semantics: cosine score =
1491
+ * (1 + cos_sim) / 2, VEC_DISTANCE_COSINE = 1 - cos_sim, so the distance cap
1492
+ * is 2 * (1 - score).
1493
+ */
1494
+ _vectorSearchSource(ctx, withRows) {
1495
+ const distExpr = {
1496
+ sql: `${ctx.distanceFn}(${qi(ctx.field)}, STRING_TO_VECTOR(?))`,
1497
+ params: [ctx.vectorStr]
1498
+ };
1492
1499
  return {
1493
- sql,
1494
- params
1500
+ source: vectorDistanceSource(mysqlDialect, ctx.tableName, ctx.where, distExpr, withRows),
1501
+ maxDistance: ctx.threshold === void 0 ? void 0 : 2 * (1 - ctx.threshold)
1495
1502
  };
1496
1503
  }
1497
- _buildVectorSearchCountQuery(vector, query, indexName) {
1504
+ _buildVectorSearchQuery(vector, query, indexName) {
1498
1505
  const ctx = this._prepareVectorSearch(vector, query, indexName);
1499
- const inner = `SELECT ${ctx.distanceFn}(${qi(ctx.field)}, STRING_TO_VECTOR(?)) AS _distance FROM ${quoteTableName(ctx.tableName)} WHERE ${ctx.where.sql}`;
1500
- const params = [ctx.vectorStr, ...ctx.where.params];
1501
- let sql = `SELECT COUNT(*) AS cnt FROM (${inner}) _v`;
1502
- if (ctx.threshold !== void 0) {
1503
- sql += ` WHERE _distance <= ?`;
1504
- params.push(2 * (1 - ctx.threshold));
1505
- }
1506
- return {
1507
- sql,
1508
- params
1509
- };
1506
+ const { source, maxDistance } = this._vectorSearchSource(ctx, true);
1507
+ const skip = Number(ctx.controls.$skip) || 0;
1508
+ return buildVectorSearchSelect(mysqlDialect, source, {
1509
+ select: ctx.controls.$select,
1510
+ limit: Number(ctx.controls.$limit) || (skip ? 1e3 : 20),
1511
+ skip,
1512
+ maxDistance
1513
+ });
1514
+ }
1515
+ _buildVectorSearchCountQuery(vector, query, indexName) {
1516
+ const { source, maxDistance } = this._vectorSearchSource(this._prepareVectorSearch(vector, query, indexName), false);
1517
+ return buildVectorSearchCount(mysqlDialect, source, { maxDistance });
1510
1518
  }
1511
1519
  /** Resolves threshold: query-time $threshold > schema-level @db.search.vector.threshold. */
1512
1520
  _resolveVectorThreshold(controls, indexName) {
@@ -1548,10 +1556,7 @@ var MysqlAdapter = class MysqlAdapter extends BaseDbAdapter {
1548
1556
  };
1549
1557
  }
1550
1558
  _buildGeoSearchSelect(ctx) {
1551
- return buildGeoSearchSelect(mysqlDialect, ctx.tableName, ctx.where, ctx.dist, ctx.window, {
1552
- $limit: ctx.controls.$limit,
1553
- $skip: ctx.controls.$skip
1554
- });
1559
+ return buildGeoSearchSelect(mysqlDialect, ctx.tableName, ctx.where, ctx.dist, ctx.window, ctx.controls);
1555
1560
  }
1556
1561
  /**
1557
1562
  * Migrates a v1 JSON `[lng, lat]` column to native `POINT SRID 4326` via a
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atscript/db-mysql",
3
- "version": "0.1.141",
3
+ "version": "0.1.143",
4
4
  "description": "MySQL adapter for @atscript/db with mysql2 driver support.",
5
5
  "keywords": [
6
6
  "atscript",
@@ -52,8 +52,8 @@
52
52
  "@atscript/typescript": "^0.1.95",
53
53
  "@uniqu/core": "^0.1.11",
54
54
  "mysql2": ">=3.0.0",
55
- "@atscript/db": "^0.1.141",
56
- "@atscript/db-sql-tools": "^0.1.141"
55
+ "@atscript/db-sql-tools": "^0.1.143",
56
+ "@atscript/db": "^0.1.143"
57
57
  },
58
58
  "peerDependenciesMeta": {
59
59
  "mysql2": {