@atscript/db-mysql 0.1.164 → 0.1.166
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 +36 -29
- package/dist/index.d.cts +6 -1
- package/dist/index.d.mts +6 -1
- package/dist/index.mjs +38 -31
- package/package.json +8 -8
package/dist/index.cjs
CHANGED
|
@@ -391,8 +391,8 @@ function buildInsertMany(table, rows, columns) {
|
|
|
391
391
|
/**
|
|
392
392
|
* Builds a SELECT statement with optional sort, limit, offset, projection.
|
|
393
393
|
*/
|
|
394
|
-
function buildSelect(table, where, controls, lock) {
|
|
395
|
-
return (0, _atscript_db_sql_tools.buildSelect)(mysqlDialect, table, where, controls, lock);
|
|
394
|
+
function buildSelect(table, where, controls, lock, defaultOrder) {
|
|
395
|
+
return (0, _atscript_db_sql_tools.buildSelect)(mysqlDialect, table, where, controls, lock, defaultOrder);
|
|
396
396
|
}
|
|
397
397
|
/**
|
|
398
398
|
* Builds an UPDATE ... SET ... WHERE statement with optional [ORDER BY …] LIMIT.
|
|
@@ -959,11 +959,16 @@ var MysqlAdapter = class MysqlAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
959
959
|
_mapConstraintError(error) {
|
|
960
960
|
if (error && typeof error === "object" && "errno" in error) {
|
|
961
961
|
const err = error;
|
|
962
|
-
if (err.errno === 1062 || err.errno === 1586)
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
}
|
|
966
|
-
if (err.errno === 1451 || err.errno === 1452)
|
|
962
|
+
if (err.errno === 1062 || err.errno === 1586) {
|
|
963
|
+
const name = (err.message?.match(/^[\s\S]*for key '(?:[^']*\.)?([^'.]+)'/))?.[1];
|
|
964
|
+
throw (0, _atscript_db.constraintViolation)("CONFLICT", name === "PRIMARY" ? { primaryKey: true } : { name }, err.sqlMessage ?? err.message);
|
|
965
|
+
}
|
|
966
|
+
if (err.errno === 1451 || err.errno === 1452) {
|
|
967
|
+
const message = err.sqlMessage ?? err.message;
|
|
968
|
+
const referencing = message.match(/fails \((?:`[^`]*`\.)?`([^`]+)`/)?.[1];
|
|
969
|
+
const columns = (message.match(/FOREIGN KEY \(([^)]+)\)/)?.[1])?.split(",").map((c) => c.trim().replace(/^`|`$/g, ""));
|
|
970
|
+
throw (0, _atscript_db.constraintViolation)("FK_VIOLATION", err.errno === 1451 ? { referencedBy: referencing } : { columns }, message);
|
|
971
|
+
}
|
|
967
972
|
if (err.errno === 1213 || err.errno === 1205 || err.errno === 3572) throw new _atscript_db.DbError(err.errno === 1213 ? "DEADLOCK" : "LOCK_TIMEOUT", [{
|
|
968
973
|
path: "",
|
|
969
974
|
message: err.sqlMessage ?? err.message
|
|
@@ -971,20 +976,6 @@ var MysqlAdapter = class MysqlAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
971
976
|
}
|
|
972
977
|
throw error;
|
|
973
978
|
}
|
|
974
|
-
_mapFkError(message) {
|
|
975
|
-
const fkMatch = message.match(/FOREIGN KEY \(`(\w+)`\)/);
|
|
976
|
-
if (fkMatch) {
|
|
977
|
-
const physicalCol = fkMatch[1];
|
|
978
|
-
return [{
|
|
979
|
-
path: this._table.fieldDescriptors.find((f) => f.physicalName === physicalCol)?.path ?? physicalCol,
|
|
980
|
-
message
|
|
981
|
-
}];
|
|
982
|
-
}
|
|
983
|
-
return [{
|
|
984
|
-
path: "",
|
|
985
|
-
message
|
|
986
|
-
}];
|
|
987
|
-
}
|
|
988
979
|
async insertOne(data) {
|
|
989
980
|
const { sql, params } = buildInsert(this.resolveTableName(), data);
|
|
990
981
|
this._log(sql, params);
|
|
@@ -1389,7 +1380,7 @@ var MysqlAdapter = class MysqlAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
1389
1380
|
return (await this._groupInsertedIds(group, result.insertId, step)).map((insertedId) => ({ insertedId }));
|
|
1390
1381
|
} catch (error) {
|
|
1391
1382
|
if (!(0, _atscript_db.isConflict)(error)) throw error;
|
|
1392
|
-
if (group.generated && error.
|
|
1383
|
+
if (group.generated && error.hint?.primaryKey === true) throw error;
|
|
1393
1384
|
return;
|
|
1394
1385
|
}
|
|
1395
1386
|
}
|
|
@@ -2075,7 +2066,8 @@ var MysqlAdapter = class MysqlAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
2075
2066
|
const indexes = [];
|
|
2076
2067
|
const { all: ftAll, def: ftDefault } = this._fulltextIndexes();
|
|
2077
2068
|
for (const index of ftAll) indexes.push({
|
|
2078
|
-
name: index.
|
|
2069
|
+
name: index.name,
|
|
2070
|
+
aliases: [index.key],
|
|
2079
2071
|
description: (0, _atscript_db.describeFulltext)(index, (names) => `FULLTEXT index on ${names}`),
|
|
2080
2072
|
type: "text",
|
|
2081
2073
|
fields: this._indexLogicalPaths(index),
|
|
@@ -2096,7 +2088,7 @@ var MysqlAdapter = class MysqlAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
2096
2088
|
}
|
|
2097
2089
|
async search(text, query, indexName) {
|
|
2098
2090
|
const combinedWhere = this._buildSearchWhere(text, query, indexName);
|
|
2099
|
-
const { sql, params } = buildSelect(this.resolveTableName(), combinedWhere, query.controls);
|
|
2091
|
+
const { sql, params } = buildSelect(this.resolveTableName(), combinedWhere, query.controls, void 0, combinedWhere.rank);
|
|
2100
2092
|
this._log(sql, params);
|
|
2101
2093
|
return this._exec().all(sql, params);
|
|
2102
2094
|
}
|
|
@@ -2104,7 +2096,7 @@ var MysqlAdapter = class MysqlAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
2104
2096
|
const combinedWhere = this._buildSearchWhere(text, query, indexName);
|
|
2105
2097
|
const tableName = this.resolveTableName();
|
|
2106
2098
|
const selectPromise = (async () => {
|
|
2107
|
-
const { sql, params } = buildSelect(tableName, combinedWhere, query.controls);
|
|
2099
|
+
const { sql, params } = buildSelect(tableName, combinedWhere, query.controls, void 0, combinedWhere.rank);
|
|
2108
2100
|
this._log(sql, params);
|
|
2109
2101
|
return this._exec().all(sql, params);
|
|
2110
2102
|
})();
|
|
@@ -2119,16 +2111,32 @@ var MysqlAdapter = class MysqlAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
2119
2111
|
count
|
|
2120
2112
|
};
|
|
2121
2113
|
}
|
|
2114
|
+
/**
|
|
2115
|
+
* The search predicate (AND the request filter) and its relevance order
|
|
2116
|
+
* (`rank`, since 0.1.165) — used as the ORDER BY when the read has no
|
|
2117
|
+
* `$sort`: exact-number hits first, then `MATCH … AGAINST` relevance, then
|
|
2118
|
+
* the primary key. Grouped searches use only the predicate.
|
|
2119
|
+
*/
|
|
2122
2120
|
_buildSearchWhere(text, query, indexName) {
|
|
2123
2121
|
const fulltextIndex = this._getFulltextIndex(indexName);
|
|
2124
|
-
if (!fulltextIndex) throw new Error(
|
|
2122
|
+
if (!fulltextIndex) throw new Error((0, _atscript_db.searchIndexNotFoundMessage)(indexName));
|
|
2125
2123
|
const { text: textFields, integer: integerFields } = (0, _atscript_db.splitFulltextFields)(fulltextIndex);
|
|
2126
2124
|
const where = buildWhere(query.filter);
|
|
2127
2125
|
const n = integerFields.length > 0 ? (0, _atscript_db.searchTermInteger)(text) : void 0;
|
|
2128
2126
|
const matchClause = `MATCH(${textFields.map((f) => qi(f.name)).join(", ")}) AGAINST(? IN NATURAL LANGUAGE MODE)`;
|
|
2127
|
+
const rank = (0, _atscript_db_sql_tools.searchRankOrder)(mysqlDialect, {
|
|
2128
|
+
exactEqualities: n === void 0 ? [] : integerFields.map((f) => `${qi(f.name)} = ?`),
|
|
2129
|
+
n,
|
|
2130
|
+
textRank: textFields.length > 0 ? {
|
|
2131
|
+
sql: `${matchClause} DESC`,
|
|
2132
|
+
params: [text]
|
|
2133
|
+
} : void 0,
|
|
2134
|
+
pkColumns: this._table.primaryKeys.map((key) => this._table.physicalPath(key))
|
|
2135
|
+
});
|
|
2129
2136
|
const withWhere = (clause, params) => ({
|
|
2130
2137
|
sql: where.sql === "1=1" ? clause : `${where.sql} AND ${clause}`,
|
|
2131
|
-
params: [...where.params, ...params]
|
|
2138
|
+
params: [...where.params, ...params],
|
|
2139
|
+
rank
|
|
2132
2140
|
});
|
|
2133
2141
|
if (n === void 0) return textFields.length === 0 ? withWhere(_atscript_db_sql_tools.EMPTY_OR.sql, []) : withWhere(matchClause, [text]);
|
|
2134
2142
|
const keys = this._table.primaryKeys.map((key) => qi(this._table.physicalPath(key)));
|
|
@@ -2152,8 +2160,7 @@ var MysqlAdapter = class MysqlAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
2152
2160
|
}
|
|
2153
2161
|
_getFulltextIndex(indexName) {
|
|
2154
2162
|
const { all, def } = this._fulltextIndexes();
|
|
2155
|
-
|
|
2156
|
-
return all.find((index) => index.key === indexName);
|
|
2163
|
+
return indexName ? (0, _atscript_db.resolveFulltextIndex)(all, indexName) : def;
|
|
2157
2164
|
}
|
|
2158
2165
|
/** The table's fulltext indexes and the default one, built once per table. */
|
|
2159
2166
|
_fulltextIndexes() {
|
package/dist/index.d.cts
CHANGED
|
@@ -239,7 +239,6 @@ declare class MysqlAdapter extends BaseDbAdapter {
|
|
|
239
239
|
private _wrapConstraintError;
|
|
240
240
|
/** Rethrows `error` as a structured `DbError` when it is a unique / FK violation or a deadlock / lock wait timeout, else as is. */
|
|
241
241
|
private _mapConstraintError;
|
|
242
|
-
private _mapFkError;
|
|
243
242
|
insertOne(data: Record<string, unknown>): Promise<TDbInsertResult>;
|
|
244
243
|
insertMany(data: Array<Record<string, unknown>>): Promise<TDbInsertManyResult>;
|
|
245
244
|
/** ONE multi-row INSERT of a homogeneous id group on `exec`; the rows' ids in group order. */
|
|
@@ -474,6 +473,12 @@ declare class MysqlAdapter extends BaseDbAdapter {
|
|
|
474
473
|
data: Array<Record<string, unknown>>;
|
|
475
474
|
count: number;
|
|
476
475
|
}>;
|
|
476
|
+
/**
|
|
477
|
+
* The search predicate (AND the request filter) and its relevance order
|
|
478
|
+
* (`rank`, since 0.1.165) — used as the ORDER BY when the read has no
|
|
479
|
+
* `$sort`: exact-number hits first, then `MATCH … AGAINST` relevance, then
|
|
480
|
+
* the primary key. Grouped searches use only the predicate.
|
|
481
|
+
*/
|
|
477
482
|
private _buildSearchWhere;
|
|
478
483
|
private _getFulltextIndex;
|
|
479
484
|
/** The table's fulltext indexes and the default one, built once per table. */
|
package/dist/index.d.mts
CHANGED
|
@@ -239,7 +239,6 @@ declare class MysqlAdapter extends BaseDbAdapter {
|
|
|
239
239
|
private _wrapConstraintError;
|
|
240
240
|
/** Rethrows `error` as a structured `DbError` when it is a unique / FK violation or a deadlock / lock wait timeout, else as is. */
|
|
241
241
|
private _mapConstraintError;
|
|
242
|
-
private _mapFkError;
|
|
243
242
|
insertOne(data: Record<string, unknown>): Promise<TDbInsertResult>;
|
|
244
243
|
insertMany(data: Array<Record<string, unknown>>): Promise<TDbInsertManyResult>;
|
|
245
244
|
/** ONE multi-row INSERT of a homogeneous id group on `exec`; the rows' ids in group order. */
|
|
@@ -474,6 +473,12 @@ declare class MysqlAdapter extends BaseDbAdapter {
|
|
|
474
473
|
data: Array<Record<string, unknown>>;
|
|
475
474
|
count: number;
|
|
476
475
|
}>;
|
|
476
|
+
/**
|
|
477
|
+
* The search predicate (AND the request filter) and its relevance order
|
|
478
|
+
* (`rank`, since 0.1.165) — used as the ORDER BY when the read has no
|
|
479
|
+
* `$sort`: exact-number hits first, then `MATCH … AGAINST` relevance, then
|
|
480
|
+
* the primary key. Grouped searches use only the predicate.
|
|
481
|
+
*/
|
|
477
482
|
private _buildSearchWhere;
|
|
478
483
|
private _getFulltextIndex;
|
|
479
484
|
/** The table's fulltext indexes and the default one, built once per table. */
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ALL_AGGREGATE_FNS, ALL_BUCKET_UNITS, ALL_ISOLATION_LEVELS, ALL_VIEW_CAPABILITIES, BaseDbAdapter, DbError, DbSpace, NoopLogger, bucketTimeZoneUnavailable, containsRelationFilter, defaultFulltextIndex, describeFulltext, fkKey, forEachResolvedRelation, isConflict, searchTermInteger, splitFulltextFields, uniqueKeyTuple, vectorIndexNotFoundMessage } from "@atscript/db";
|
|
1
|
+
import { ALL_AGGREGATE_FNS, ALL_BUCKET_UNITS, ALL_ISOLATION_LEVELS, ALL_VIEW_CAPABILITIES, BaseDbAdapter, DbError, DbSpace, NoopLogger, bucketTimeZoneUnavailable, constraintViolation, containsRelationFilter, defaultFulltextIndex, describeFulltext, fkKey, forEachResolvedRelation, isConflict, resolveFulltextIndex, searchIndexNotFoundMessage, searchTermInteger, splitFulltextFields, uniqueKeyTuple, vectorIndexNotFoundMessage } from "@atscript/db";
|
|
2
2
|
import { resolveAggregateSearch } from "@atscript/db/agg";
|
|
3
|
-
import { EMPTY_OR, SEARCH_SOURCE_ALIAS, arithOverflowError, buildAggregateCount, buildAggregateSelect, buildCreateView, buildDelete, buildGeoSearchCount, buildGeoSearchSelect, buildInsert, buildInsertMany, buildJsonColumnCopy, buildJsonifyText, buildKeyViolationCount, buildPartitionedSelect, buildSelect, buildUpdate, buildVectorSearchCount, buildVectorSearchSelect, buildWhere as buildWhere$1, chunkInsertRows, defaultValueForType, defaultValueToSqlLiteral, derivedColumnExpr, fillReplacePayload, foreignKeySql, fromSourceHint, fromSourceSql, geoWindowFromControls, jsonDollarPath, mapQueryErrors, normalizeGeoPointValue, numericOutOfRangeError, orFragment, orderByList, parseRegexString, renameGeoDistance, replaceColumnsFor, sqlTimeZoneLiteral, stripPartitionRowNumber, toSqlValue, unquoteSqlStringLiteral, vectorDistanceSource, viewReadSource, writeLimitCount } from "@atscript/db-sql-tools";
|
|
3
|
+
import { EMPTY_OR, SEARCH_SOURCE_ALIAS, arithOverflowError, buildAggregateCount, buildAggregateSelect, buildCreateView, buildDelete, buildGeoSearchCount, buildGeoSearchSelect, buildInsert, buildInsertMany, buildJsonColumnCopy, buildJsonifyText, buildKeyViolationCount, buildPartitionedSelect, buildSelect, buildUpdate, buildVectorSearchCount, buildVectorSearchSelect, buildWhere as buildWhere$1, chunkInsertRows, defaultValueForType, defaultValueToSqlLiteral, derivedColumnExpr, fillReplacePayload, foreignKeySql, fromSourceHint, fromSourceSql, geoWindowFromControls, jsonDollarPath, mapQueryErrors, normalizeGeoPointValue, numericOutOfRangeError, orFragment, orderByList, parseRegexString, renameGeoDistance, replaceColumnsFor, searchRankOrder, sqlTimeZoneLiteral, stripPartitionRowNumber, toSqlValue, unquoteSqlStringLiteral, vectorDistanceSource, viewReadSource, writeLimitCount } 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
|
/**
|
|
@@ -390,8 +390,8 @@ function buildInsertMany$1(table, rows, columns) {
|
|
|
390
390
|
/**
|
|
391
391
|
* Builds a SELECT statement with optional sort, limit, offset, projection.
|
|
392
392
|
*/
|
|
393
|
-
function buildSelect$1(table, where, controls, lock) {
|
|
394
|
-
return buildSelect(mysqlDialect, table, where, controls, lock);
|
|
393
|
+
function buildSelect$1(table, where, controls, lock, defaultOrder) {
|
|
394
|
+
return buildSelect(mysqlDialect, table, where, controls, lock, defaultOrder);
|
|
395
395
|
}
|
|
396
396
|
/**
|
|
397
397
|
* Builds an UPDATE ... SET ... WHERE statement with optional [ORDER BY …] LIMIT.
|
|
@@ -958,11 +958,16 @@ var MysqlAdapter = class MysqlAdapter extends BaseDbAdapter {
|
|
|
958
958
|
_mapConstraintError(error) {
|
|
959
959
|
if (error && typeof error === "object" && "errno" in error) {
|
|
960
960
|
const err = error;
|
|
961
|
-
if (err.errno === 1062 || err.errno === 1586)
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
}
|
|
965
|
-
if (err.errno === 1451 || err.errno === 1452)
|
|
961
|
+
if (err.errno === 1062 || err.errno === 1586) {
|
|
962
|
+
const name = (err.message?.match(/^[\s\S]*for key '(?:[^']*\.)?([^'.]+)'/))?.[1];
|
|
963
|
+
throw constraintViolation("CONFLICT", name === "PRIMARY" ? { primaryKey: true } : { name }, err.sqlMessage ?? err.message);
|
|
964
|
+
}
|
|
965
|
+
if (err.errno === 1451 || err.errno === 1452) {
|
|
966
|
+
const message = err.sqlMessage ?? err.message;
|
|
967
|
+
const referencing = message.match(/fails \((?:`[^`]*`\.)?`([^`]+)`/)?.[1];
|
|
968
|
+
const columns = (message.match(/FOREIGN KEY \(([^)]+)\)/)?.[1])?.split(",").map((c) => c.trim().replace(/^`|`$/g, ""));
|
|
969
|
+
throw constraintViolation("FK_VIOLATION", err.errno === 1451 ? { referencedBy: referencing } : { columns }, message);
|
|
970
|
+
}
|
|
966
971
|
if (err.errno === 1213 || err.errno === 1205 || err.errno === 3572) throw new DbError(err.errno === 1213 ? "DEADLOCK" : "LOCK_TIMEOUT", [{
|
|
967
972
|
path: "",
|
|
968
973
|
message: err.sqlMessage ?? err.message
|
|
@@ -970,20 +975,6 @@ var MysqlAdapter = class MysqlAdapter extends BaseDbAdapter {
|
|
|
970
975
|
}
|
|
971
976
|
throw error;
|
|
972
977
|
}
|
|
973
|
-
_mapFkError(message) {
|
|
974
|
-
const fkMatch = message.match(/FOREIGN KEY \(`(\w+)`\)/);
|
|
975
|
-
if (fkMatch) {
|
|
976
|
-
const physicalCol = fkMatch[1];
|
|
977
|
-
return [{
|
|
978
|
-
path: this._table.fieldDescriptors.find((f) => f.physicalName === physicalCol)?.path ?? physicalCol,
|
|
979
|
-
message
|
|
980
|
-
}];
|
|
981
|
-
}
|
|
982
|
-
return [{
|
|
983
|
-
path: "",
|
|
984
|
-
message
|
|
985
|
-
}];
|
|
986
|
-
}
|
|
987
978
|
async insertOne(data) {
|
|
988
979
|
const { sql, params } = buildInsert$1(this.resolveTableName(), data);
|
|
989
980
|
this._log(sql, params);
|
|
@@ -1388,7 +1379,7 @@ var MysqlAdapter = class MysqlAdapter extends BaseDbAdapter {
|
|
|
1388
1379
|
return (await this._groupInsertedIds(group, result.insertId, step)).map((insertedId) => ({ insertedId }));
|
|
1389
1380
|
} catch (error) {
|
|
1390
1381
|
if (!isConflict(error)) throw error;
|
|
1391
|
-
if (group.generated && error.
|
|
1382
|
+
if (group.generated && error.hint?.primaryKey === true) throw error;
|
|
1392
1383
|
return;
|
|
1393
1384
|
}
|
|
1394
1385
|
}
|
|
@@ -2074,7 +2065,8 @@ var MysqlAdapter = class MysqlAdapter extends BaseDbAdapter {
|
|
|
2074
2065
|
const indexes = [];
|
|
2075
2066
|
const { all: ftAll, def: ftDefault } = this._fulltextIndexes();
|
|
2076
2067
|
for (const index of ftAll) indexes.push({
|
|
2077
|
-
name: index.
|
|
2068
|
+
name: index.name,
|
|
2069
|
+
aliases: [index.key],
|
|
2078
2070
|
description: describeFulltext(index, (names) => `FULLTEXT index on ${names}`),
|
|
2079
2071
|
type: "text",
|
|
2080
2072
|
fields: this._indexLogicalPaths(index),
|
|
@@ -2095,7 +2087,7 @@ var MysqlAdapter = class MysqlAdapter extends BaseDbAdapter {
|
|
|
2095
2087
|
}
|
|
2096
2088
|
async search(text, query, indexName) {
|
|
2097
2089
|
const combinedWhere = this._buildSearchWhere(text, query, indexName);
|
|
2098
|
-
const { sql, params } = buildSelect$1(this.resolveTableName(), combinedWhere, query.controls);
|
|
2090
|
+
const { sql, params } = buildSelect$1(this.resolveTableName(), combinedWhere, query.controls, void 0, combinedWhere.rank);
|
|
2099
2091
|
this._log(sql, params);
|
|
2100
2092
|
return this._exec().all(sql, params);
|
|
2101
2093
|
}
|
|
@@ -2103,7 +2095,7 @@ var MysqlAdapter = class MysqlAdapter extends BaseDbAdapter {
|
|
|
2103
2095
|
const combinedWhere = this._buildSearchWhere(text, query, indexName);
|
|
2104
2096
|
const tableName = this.resolveTableName();
|
|
2105
2097
|
const selectPromise = (async () => {
|
|
2106
|
-
const { sql, params } = buildSelect$1(tableName, combinedWhere, query.controls);
|
|
2098
|
+
const { sql, params } = buildSelect$1(tableName, combinedWhere, query.controls, void 0, combinedWhere.rank);
|
|
2107
2099
|
this._log(sql, params);
|
|
2108
2100
|
return this._exec().all(sql, params);
|
|
2109
2101
|
})();
|
|
@@ -2118,16 +2110,32 @@ var MysqlAdapter = class MysqlAdapter extends BaseDbAdapter {
|
|
|
2118
2110
|
count
|
|
2119
2111
|
};
|
|
2120
2112
|
}
|
|
2113
|
+
/**
|
|
2114
|
+
* The search predicate (AND the request filter) and its relevance order
|
|
2115
|
+
* (`rank`, since 0.1.165) — used as the ORDER BY when the read has no
|
|
2116
|
+
* `$sort`: exact-number hits first, then `MATCH … AGAINST` relevance, then
|
|
2117
|
+
* the primary key. Grouped searches use only the predicate.
|
|
2118
|
+
*/
|
|
2121
2119
|
_buildSearchWhere(text, query, indexName) {
|
|
2122
2120
|
const fulltextIndex = this._getFulltextIndex(indexName);
|
|
2123
|
-
if (!fulltextIndex) throw new Error(
|
|
2121
|
+
if (!fulltextIndex) throw new Error(searchIndexNotFoundMessage(indexName));
|
|
2124
2122
|
const { text: textFields, integer: integerFields } = splitFulltextFields(fulltextIndex);
|
|
2125
2123
|
const where = buildWhere(query.filter);
|
|
2126
2124
|
const n = integerFields.length > 0 ? searchTermInteger(text) : void 0;
|
|
2127
2125
|
const matchClause = `MATCH(${textFields.map((f) => qi(f.name)).join(", ")}) AGAINST(? IN NATURAL LANGUAGE MODE)`;
|
|
2126
|
+
const rank = searchRankOrder(mysqlDialect, {
|
|
2127
|
+
exactEqualities: n === void 0 ? [] : integerFields.map((f) => `${qi(f.name)} = ?`),
|
|
2128
|
+
n,
|
|
2129
|
+
textRank: textFields.length > 0 ? {
|
|
2130
|
+
sql: `${matchClause} DESC`,
|
|
2131
|
+
params: [text]
|
|
2132
|
+
} : void 0,
|
|
2133
|
+
pkColumns: this._table.primaryKeys.map((key) => this._table.physicalPath(key))
|
|
2134
|
+
});
|
|
2128
2135
|
const withWhere = (clause, params) => ({
|
|
2129
2136
|
sql: where.sql === "1=1" ? clause : `${where.sql} AND ${clause}`,
|
|
2130
|
-
params: [...where.params, ...params]
|
|
2137
|
+
params: [...where.params, ...params],
|
|
2138
|
+
rank
|
|
2131
2139
|
});
|
|
2132
2140
|
if (n === void 0) return textFields.length === 0 ? withWhere(EMPTY_OR.sql, []) : withWhere(matchClause, [text]);
|
|
2133
2141
|
const keys = this._table.primaryKeys.map((key) => qi(this._table.physicalPath(key)));
|
|
@@ -2151,8 +2159,7 @@ var MysqlAdapter = class MysqlAdapter extends BaseDbAdapter {
|
|
|
2151
2159
|
}
|
|
2152
2160
|
_getFulltextIndex(indexName) {
|
|
2153
2161
|
const { all, def } = this._fulltextIndexes();
|
|
2154
|
-
|
|
2155
|
-
return all.find((index) => index.key === indexName);
|
|
2162
|
+
return indexName ? resolveFulltextIndex(all, indexName) : def;
|
|
2156
2163
|
}
|
|
2157
2164
|
/** The table's fulltext indexes and the default one, built once per table. */
|
|
2158
2165
|
_fulltextIndexes() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atscript/db-mysql",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.166",
|
|
4
4
|
"description": "MySQL adapter for @atscript/db with mysql2 driver support.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"atscript",
|
|
@@ -41,19 +41,19 @@
|
|
|
41
41
|
"access": "public"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@atscript/core": "^0.1
|
|
45
|
-
"@atscript/typescript": "^0.1
|
|
44
|
+
"@atscript/core": "^0.2.1",
|
|
45
|
+
"@atscript/typescript": "^0.2.1",
|
|
46
46
|
"@uniqu/core": "^0.1.15",
|
|
47
47
|
"mysql2": "^3.11.0",
|
|
48
|
-
"unplugin-atscript": "^0.1
|
|
48
|
+
"unplugin-atscript": "^0.2.1"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
|
-
"@atscript/core": "^0.1
|
|
52
|
-
"@atscript/typescript": "^0.1
|
|
51
|
+
"@atscript/core": "^0.2.1",
|
|
52
|
+
"@atscript/typescript": "^0.2.1",
|
|
53
53
|
"@uniqu/core": "^0.1.15",
|
|
54
54
|
"mysql2": ">=3.0.0",
|
|
55
|
-
"@atscript/db": "^0.1.
|
|
56
|
-
"@atscript/db-sql-tools": "^0.1.
|
|
55
|
+
"@atscript/db": "^0.1.166",
|
|
56
|
+
"@atscript/db-sql-tools": "^0.1.166"
|
|
57
57
|
},
|
|
58
58
|
"peerDependenciesMeta": {
|
|
59
59
|
"mysql2": {
|