@classytic/mongokit 3.5.4 → 3.5.6
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/README.md +228 -9
- package/dist/{PaginationEngine-DCs-zKwZ.mjs → PaginationEngine-CpsQl471.mjs} +5 -3
- package/dist/actions/index.d.mts +1 -1
- package/dist/ai/index.d.mts +1 -1
- package/dist/coercion-B19MD38s.d.mts +106 -0
- package/dist/id-resolution-LZ-cCwR5.mjs +81 -0
- package/dist/{index-BNpVzw_-.d.mts → index-DmVbUzDL.d.mts} +1 -1
- package/dist/index.d.mts +84 -6
- package/dist/index.mjs +101 -36
- package/dist/indexes-qIBCZ3mY.d.mts +41 -0
- package/dist/{mongooseToJsonSchema-DpjhFfaO.mjs → mongooseToJsonSchema-8Cyu3NFJ.mjs} +50 -45
- package/dist/{mongooseToJsonSchema-Dsx3YAAx.d.mts → mongooseToJsonSchema-DQMU0Dlv.d.mts} +4 -3
- package/dist/pagination/PaginationEngine.d.mts +1 -1
- package/dist/pagination/PaginationEngine.mjs +1 -1
- package/dist/plugins/index.d.mts +1 -1
- package/dist/plugins/index.mjs +1 -1
- package/dist/query/primitives/coercion.d.mts +2 -0
- package/dist/query/primitives/coercion.mjs +148 -0
- package/dist/query/primitives/geo.d.mts +116 -0
- package/dist/query/primitives/geo.mjs +211 -0
- package/dist/query/primitives/indexes.d.mts +2 -0
- package/dist/query/primitives/indexes.mjs +46 -0
- package/dist/{types-CkE3mOaW.d.mts → types-BwO4u3JN.d.mts} +25 -0
- package/dist/utils/index.d.mts +60 -3
- package/dist/utils/index.mjs +4 -3
- package/dist/{validation-chain.plugin-BYMZB8dN.d.mts → validation-chain.plugin-BtmT-FFB.d.mts} +1 -1
- package/dist/{validation-chain.plugin-KjPV_6_N.mjs → validation-chain.plugin-DCYjnPau.mjs} +81 -20
- package/package.json +15 -3
- /package/dist/{field-selection-reyDRzXf.mjs → field-selection-C5o7jyyA.mjs} +0 -0
package/dist/{validation-chain.plugin-BYMZB8dN.d.mts → validation-chain.plugin-BtmT-FFB.d.mts}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { I as Logger, J as Plugin, St as ValidatorDefinition, T as FieldPreset, U as OffsetPaginationResult, V as ObjectId, Z as PopulateSpec, bt as ValidationChainOptions, et as RepositoryContext, f as CascadeOptions, l as CacheOptions, nt as RepositoryInstance, pt as SortSpec, st as SelectSpec, u as CacheStats, ut as SoftDeleteOptions } from "./types-
|
|
1
|
+
import { I as Logger, J as Plugin, St as ValidatorDefinition, T as FieldPreset, U as OffsetPaginationResult, V as ObjectId, Z as PopulateSpec, bt as ValidationChainOptions, et as RepositoryContext, f as CascadeOptions, l as CacheOptions, nt as RepositoryInstance, pt as SortSpec, st as SelectSpec, u as CacheStats, ut as SoftDeleteOptions } from "./types-BwO4u3JN.mjs";
|
|
2
2
|
import mongoose, { ClientSession } from "mongoose";
|
|
3
3
|
|
|
4
4
|
//#region src/plugins/aggregate-helpers.plugin.d.ts
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { a as warn, i as debug, n as parseDuplicateKeyError, t as createError } from "./error-Bpbi_NKo.mjs";
|
|
2
2
|
import { a as exists, c as getOrCreate, d as deleteByQuery, g as upsert, i as count, m as createMany, n as updateByQuery, o as getById, p as create, s as getByQuery, t as update, u as deleteById, v as distinct, y as LookupBuilder } from "./update-AVfKWNGt.mjs";
|
|
3
|
-
import { t as PaginationEngine } from "./PaginationEngine-
|
|
4
|
-
import {
|
|
3
|
+
import { t as PaginationEngine } from "./PaginationEngine-CpsQl471.mjs";
|
|
4
|
+
import { hasNearOperator, rewriteNearForCount } from "./query/primitives/geo.mjs";
|
|
5
|
+
import { r as isValidIdForType, t as getSchemaIdType } from "./id-resolution-LZ-cCwR5.mjs";
|
|
6
|
+
import { a as byIdKey, c as listQueryKey, l as modelPattern, o as byQueryKey, r as getFieldsForUser, u as versionKey } from "./field-selection-C5o7jyyA.mjs";
|
|
5
7
|
import mongoose from "mongoose";
|
|
6
8
|
//#region src/plugins/aggregate-helpers.plugin.ts
|
|
7
9
|
/**
|
|
@@ -1182,6 +1184,8 @@ var Repository = class {
|
|
|
1182
1184
|
_pagination;
|
|
1183
1185
|
_hookMode;
|
|
1184
1186
|
idField;
|
|
1187
|
+
searchMode;
|
|
1188
|
+
searchFields;
|
|
1185
1189
|
_hasTextIndex = null;
|
|
1186
1190
|
constructor(Model, plugins = [], paginationConfig = {}, options = {}) {
|
|
1187
1191
|
this.Model = Model;
|
|
@@ -1190,6 +1194,9 @@ var Repository = class {
|
|
|
1190
1194
|
this._pagination = new PaginationEngine(Model, paginationConfig);
|
|
1191
1195
|
this._hookMode = options.hooks ?? "async";
|
|
1192
1196
|
this.idField = options.idField ?? "_id";
|
|
1197
|
+
this.searchMode = options.searchMode ?? "text";
|
|
1198
|
+
this.searchFields = options.searchFields;
|
|
1199
|
+
if (this.searchMode === "regex" && (!this.searchFields || this.searchFields.length === 0)) warn(`[mongokit] Repository "${this.model}" configured with searchMode: 'regex' but no searchFields provided. getAll({ search }) will throw until searchFields is set.`);
|
|
1193
1200
|
plugins.forEach((plugin) => {
|
|
1194
1201
|
this.use(plugin);
|
|
1195
1202
|
});
|
|
@@ -1364,7 +1371,7 @@ var Repository = class {
|
|
|
1364
1371
|
});
|
|
1365
1372
|
return result;
|
|
1366
1373
|
}
|
|
1367
|
-
if (
|
|
1374
|
+
if (!isValidIdForType(id, getSchemaIdType(this.Model.schema))) {
|
|
1368
1375
|
if (context.throwOnNotFound === false || options.throwOnNotFound === false) return null;
|
|
1369
1376
|
throw createError(404, "Document not found");
|
|
1370
1377
|
}
|
|
@@ -1542,25 +1549,19 @@ var Repository = class {
|
|
|
1542
1549
|
sort: context.sort ?? params.sort
|
|
1543
1550
|
});
|
|
1544
1551
|
const filters = context.filters ?? params.filters ?? {};
|
|
1545
|
-
const search = context.search
|
|
1546
|
-
const
|
|
1552
|
+
const search = context.search;
|
|
1553
|
+
const isNearQuery = hasNearOperator(filters);
|
|
1554
|
+
const sort = this._resolveSort(context, params, isNearQuery);
|
|
1547
1555
|
const limit = context.limit ?? params.limit ?? params.pagination?.limit ?? this._pagination.config.defaultLimit;
|
|
1548
1556
|
const page = context.page ?? params.pagination?.page ?? params.page;
|
|
1549
1557
|
const after = context.after ?? params.cursor ?? params.after;
|
|
1550
1558
|
const mode = context.mode ?? params.mode;
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
else useKeyset = !page && !!(after || sort !== "-createdAt" && (context.sort ?? params.sort));
|
|
1554
|
-
const query = { ...filters };
|
|
1555
|
-
if (search) {
|
|
1556
|
-
if (this._hasTextIndex === null) this._hasTextIndex = this.Model.schema.indexes().some((idx) => idx[0] && Object.values(idx[0]).includes("text"));
|
|
1557
|
-
if (this._hasTextIndex) query.$text = { $search: search };
|
|
1558
|
-
else throw createError(400, `No text index found for ${this.model}. Cannot perform text search.`);
|
|
1559
|
-
}
|
|
1559
|
+
const useKeyset = this._detectPaginationMode(mode, page, after, sort, context, params);
|
|
1560
|
+
const query = this._buildSearchQuery(filters, search);
|
|
1560
1561
|
const populateSpec = options.populateOptions || params.populateOptions || context.populate || options.populate;
|
|
1561
1562
|
const paginationOptions = {
|
|
1562
1563
|
filters: query,
|
|
1563
|
-
sort: this._parseSort(sort),
|
|
1564
|
+
sort: isNearQuery ? void 0 : this._parseSort(sort),
|
|
1564
1565
|
limit,
|
|
1565
1566
|
populate: this._parsePopulate(populateSpec),
|
|
1566
1567
|
select: context.select || options.select,
|
|
@@ -1630,11 +1631,21 @@ var Repository = class {
|
|
|
1630
1631
|
sort: paginationOptions.sort,
|
|
1631
1632
|
after
|
|
1632
1633
|
});
|
|
1633
|
-
else
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1634
|
+
else {
|
|
1635
|
+
let countFilters;
|
|
1636
|
+
let forcedCountStrategy;
|
|
1637
|
+
if (isNearQuery) {
|
|
1638
|
+
const rewritten = rewriteNearForCount(query);
|
|
1639
|
+
if (rewritten) countFilters = rewritten;
|
|
1640
|
+
else forcedCountStrategy = "none";
|
|
1641
|
+
}
|
|
1642
|
+
result = await this._pagination.paginate({
|
|
1643
|
+
...paginationOptions,
|
|
1644
|
+
page: page || 1,
|
|
1645
|
+
countFilters,
|
|
1646
|
+
countStrategy: context.countStrategy ?? params.countStrategy ?? forcedCountStrategy
|
|
1647
|
+
});
|
|
1648
|
+
}
|
|
1638
1649
|
await this._emitHook("after:getAll", {
|
|
1639
1650
|
context,
|
|
1640
1651
|
result
|
|
@@ -2201,6 +2212,56 @@ var Repository = class {
|
|
|
2201
2212
|
return context;
|
|
2202
2213
|
}
|
|
2203
2214
|
/**
|
|
2215
|
+
* Resolve the effective sort for getAll. Handles $near conflict detection
|
|
2216
|
+
* (warns + drops explicit sort when $near is in filters).
|
|
2217
|
+
*/
|
|
2218
|
+
_resolveSort(context, params, isNearQuery) {
|
|
2219
|
+
const explicitSort = context.sort ?? params.sort;
|
|
2220
|
+
if (isNearQuery) {
|
|
2221
|
+
if (explicitSort !== void 0) warn(`[mongokit] Repository "${this.model}" dropping explicit sort (${JSON.stringify(explicitSort)}) because the filter contains $near / $nearSphere. MongoDB forbids explicit sort with $near. Use [withinRadius] instead of [near] if you need a custom sort.`);
|
|
2222
|
+
return;
|
|
2223
|
+
}
|
|
2224
|
+
return explicitSort ?? "-createdAt";
|
|
2225
|
+
}
|
|
2226
|
+
/**
|
|
2227
|
+
* Detect whether to use keyset (cursor) or offset (page) pagination.
|
|
2228
|
+
*/
|
|
2229
|
+
_detectPaginationMode(mode, page, after, sort, context, params) {
|
|
2230
|
+
if (mode) return mode === "keyset";
|
|
2231
|
+
return !page && !!(after || sort !== "-createdAt" && (context.sort ?? params.sort));
|
|
2232
|
+
}
|
|
2233
|
+
/**
|
|
2234
|
+
* Build the MongoDB query filter with search merged in. Handles text
|
|
2235
|
+
* search ($text), regex search ($or of $regex), and the search-resolver
|
|
2236
|
+
* plugin contract (search already cleared by a before:getAll hook).
|
|
2237
|
+
*/
|
|
2238
|
+
_buildSearchQuery(filters, search) {
|
|
2239
|
+
const query = { ...filters };
|
|
2240
|
+
if (!search) return query;
|
|
2241
|
+
if (this._hasTextIndex === null) this._hasTextIndex = this.Model.schema.indexes().some((idx) => idx[0] && Object.values(idx[0]).includes("text"));
|
|
2242
|
+
let effectiveMode = this.searchMode === "regex" ? "regex" : "text";
|
|
2243
|
+
if (this.searchMode === "auto") effectiveMode = this._hasTextIndex ? "text" : "regex";
|
|
2244
|
+
if (effectiveMode === "regex") {
|
|
2245
|
+
if (!this.searchFields || this.searchFields.length === 0) throw createError(400, `Repository "${this.model}" configured with searchMode: '${this.searchMode}' but no searchFields provided.`);
|
|
2246
|
+
const escaped = String(search).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2247
|
+
const orConds = this.searchFields.map((field) => ({ [field]: {
|
|
2248
|
+
$regex: escaped,
|
|
2249
|
+
$options: "i"
|
|
2250
|
+
} }));
|
|
2251
|
+
if (Array.isArray(query.$or)) {
|
|
2252
|
+
const existingOr = query.$or;
|
|
2253
|
+
delete query.$or;
|
|
2254
|
+
query.$and = [
|
|
2255
|
+
...Array.isArray(query.$and) ? query.$and : [],
|
|
2256
|
+
{ $or: existingOr },
|
|
2257
|
+
{ $or: orConds }
|
|
2258
|
+
];
|
|
2259
|
+
} else query.$or = orConds;
|
|
2260
|
+
} else if (this._hasTextIndex) query.$text = { $search: search };
|
|
2261
|
+
else throw createError(400, `No text index found for ${this.model}. Cannot perform text search. Configure Repository with searchMode: 'regex' (and searchFields) or 'auto' to enable index-free search.`);
|
|
2262
|
+
return query;
|
|
2263
|
+
}
|
|
2264
|
+
/**
|
|
2204
2265
|
* Parse sort string or object
|
|
2205
2266
|
*/
|
|
2206
2267
|
_parseSort(sort) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classytic/mongokit",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.6",
|
|
4
4
|
"description": "Production-grade MongoDB repositories with zero dependencies - smart pagination, events, and plugins",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -31,6 +31,18 @@
|
|
|
31
31
|
"./ai": {
|
|
32
32
|
"types": "./dist/ai/index.d.mts",
|
|
33
33
|
"default": "./dist/ai/index.mjs"
|
|
34
|
+
},
|
|
35
|
+
"./query/primitives/geo": {
|
|
36
|
+
"types": "./dist/query/primitives/geo.d.mts",
|
|
37
|
+
"default": "./dist/query/primitives/geo.mjs"
|
|
38
|
+
},
|
|
39
|
+
"./query/primitives/coercion": {
|
|
40
|
+
"types": "./dist/query/primitives/coercion.d.mts",
|
|
41
|
+
"default": "./dist/query/primitives/coercion.mjs"
|
|
42
|
+
},
|
|
43
|
+
"./query/primitives/indexes": {
|
|
44
|
+
"types": "./dist/query/primitives/indexes.d.mts",
|
|
45
|
+
"default": "./dist/query/primitives/indexes.mjs"
|
|
34
46
|
}
|
|
35
47
|
},
|
|
36
48
|
"files": [
|
|
@@ -81,7 +93,7 @@
|
|
|
81
93
|
},
|
|
82
94
|
"homepage": "https://github.com/classytic/mongokit#readme",
|
|
83
95
|
"peerDependencies": {
|
|
84
|
-
"mongoose": "
|
|
96
|
+
"mongoose": ">=9.4.1"
|
|
85
97
|
},
|
|
86
98
|
"engines": {
|
|
87
99
|
"node": ">=22"
|
|
@@ -111,7 +123,7 @@
|
|
|
111
123
|
"@vitest/coverage-v8": "^3.2.4",
|
|
112
124
|
"knip": "^6.3.0",
|
|
113
125
|
"mongodb-memory-server": "^10.4.3",
|
|
114
|
-
"mongoose": "^9.1
|
|
126
|
+
"mongoose": "^9.4.1",
|
|
115
127
|
"tsdown": "^0.21.7",
|
|
116
128
|
"typescript": "^5.7.0",
|
|
117
129
|
"vitest": "^3.2.4"
|
|
File without changes
|