@classytic/mongokit 3.41.0 → 3.43.0
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 +28 -0
- package/dist/{Repository-DlhPbXlG.mjs → Repository-Dj6xqPxJ.mjs} +148 -1
- package/dist/{Repository-pnLw1rG5.d.mts → Repository-DnL4xk5w.d.mts} +10 -2
- package/dist/ai/index.d.mts +1 -1
- package/dist/better-auth/index.mjs +1 -1
- package/dist/{create-repository-BUx9vfG9.d.mts → create-repository-CJtVdwig.d.mts} +4 -4
- package/dist/{create-repository-Bg0H5rte.mjs → create-repository-UjwPWR1z.mjs} +2 -2
- package/dist/derive-DRBiegRH.mjs +375 -0
- package/dist/index-C0AjVqX3.d.mts +169 -0
- package/dist/index.d.mts +37 -8
- package/dist/index.mjs +53 -5
- package/dist/{multi-tenant.plugin-a3UhQARj.d.mts → multi-tenant.plugin-B_q9NUHc.d.mts} +1 -1
- package/dist/outbox/index.d.mts +1 -1
- package/dist/outbox/index.mjs +1 -1
- package/dist/{plugin-options-CRhIvSzx.d.mts → plugin-options-Cirmb4Kp.d.mts} +1 -1
- package/dist/plugins/index.d.mts +4 -4
- package/dist/plugins/index.mjs +50 -18
- package/dist/read-model/index.d.mts +1 -1
- package/dist/{repository-DNHfjAZX.d.mts → repository-MqAP409e.d.mts} +14 -3
- package/dist/search/index.d.mts +2 -0
- package/dist/search/index.mjs +2 -0
- package/dist/sync/index.d.mts +22 -1
- package/dist/sync/index.mjs +236 -61
- package/dist/testkit/index.d.mts +2 -2
- package/dist/testkit/index.mjs +1 -1
- package/dist/{timestamp.plugin-DvZlnKEc.mjs → timestamp.plugin-DpOWavVI.mjs} +1 -1
- package/dist/{to-plain-CjgEInWV.d.mts → to-plain-o5tUY2nV.d.mts} +2 -2
- package/dist/utils/index.d.mts +1 -1
- package/dist/{validation-chain.plugin-CTcNJCmV.d.mts → validation-chain.plugin-BAeC5eVT.d.mts} +12 -3
- package/dist/{validation-chain.plugin-D1WsGCYr.mjs → validation-chain.plugin-DRApTmkN.mjs} +3 -2
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -292,6 +292,33 @@ always escapes rather than rejects, so `?search=c++` never 400s. Trusted
|
|
|
292
292
|
migration/compat tooling can opt into the legacy warn-and-drop behavior with
|
|
293
293
|
`invalidInput: 'drop'`.
|
|
294
294
|
|
|
295
|
+
### Prefix search (search-as-you-type, indexed)
|
|
296
|
+
|
|
297
|
+
`searchMode: 'prefix'` finds documents where every query word starts a word of
|
|
298
|
+
`searchFields` (`moh ali` finds "Mohammed Al-Ali"), served by a multikey index
|
|
299
|
+
instead of an unanchored regex scan. The repository writes the normalised word
|
|
300
|
+
tokens into `searchKeysField` (default `_searchKeys`) on every write path.
|
|
301
|
+
Normalisation: lower-case, NFKD with diacritics stripped, Arabic folding
|
|
302
|
+
(tashkeel/tatweel removed, `أ إ آ → ا`, `ى → ي`, `ة → ه`), split on
|
|
303
|
+
whitespace/punctuation.
|
|
304
|
+
|
|
305
|
+
```ts
|
|
306
|
+
import { rebuildSearchKeys, searchKeysIndex, searchKeysPath } from '@classytic/mongokit';
|
|
307
|
+
|
|
308
|
+
schema.add({ _searchKeys: searchKeysPath() }); // string[], select: false
|
|
309
|
+
// Serves getAll({ search }) prefix search.
|
|
310
|
+
schema.index(searchKeysIndex().fields, searchKeysIndex().options);
|
|
311
|
+
|
|
312
|
+
const repo = new Repository(Person, [], {}, { searchMode: 'prefix', searchFields: ['name', 'email'] });
|
|
313
|
+
await rebuildSearchKeys(repo, { onlyMissing: true }); // backfill rows written before
|
|
314
|
+
await repo.getAll({ search: 'moh', page: 1 }); // composes with filters, tenant scope, keyset/offset, counts
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Clients highlight with the same rules from the mongoose-free subpath:
|
|
318
|
+
`import { findSearchMatches } from '@classytic/mongokit/search'`. Writes that
|
|
319
|
+
bypass the repository (raw `Model.updateOne`, Better Auth's adapter) write the
|
|
320
|
+
keys with `buildSearchKeys(doc, fields)`.
|
|
321
|
+
|
|
295
322
|
## Built-In Plugins
|
|
296
323
|
|
|
297
324
|
| Plugin | Purpose |
|
|
@@ -300,6 +327,7 @@ migration/compat tooling can opt into the legacy warn-and-drop behavior with
|
|
|
300
327
|
| `multiTenantPlugin` | Tenant scoping and tenant stamping |
|
|
301
328
|
| `softDeletePlugin` | Soft delete, restore, deleted-list queries, TTL |
|
|
302
329
|
| `timestampPlugin` | `createdAt` / `updatedAt` management |
|
|
330
|
+
| `searchKeysPlugin` | Prefix-search keys on every write (auto-installed by `searchMode: 'prefix'`) |
|
|
303
331
|
| `batchOperationsPlugin` | `bulkWrite` and batch helpers |
|
|
304
332
|
| `cachePlugin` | Pluggable read-through cache |
|
|
305
333
|
| `auditLogPlugin` / `auditTrailPlugin` | Audit trails — `auditTrailPlugin({ mode: 'transactional' })` gives session-joined entries that are atomic inside `withTransaction` (compliance-grade); the default `'best-effort'` mode is fire-and-forget observability. Call `ensureAuditTrailReady()` at boot so collection/index creation doesn't happen inside the first transaction |
|
|
@@ -7,6 +7,7 @@ import { i as applyToQuery, n as applyCursorTimeoutMode, r as applyToAggregate,
|
|
|
7
7
|
import { o as withTransaction, p as resolveMongoCapabilities, s as createTxBoundRepo } from "./transaction-DmiB4k2P.mjs";
|
|
8
8
|
import { _ as resolveCursorSecrets, d as withGroupTiebreak, f as withIdTiebreak, g as attachSignature, i as validateKeysetSort, l as assertOffsetWithinCap, n as getPrimaryField, o as encodeCursor, s as resolveCursorFilter, t as PaginationEngine, u as cursorScope, v as verifySignature } from "./PaginationEngine-DZnkbSrr.mjs";
|
|
9
9
|
import { calculateTotalPages } from "./pagination/utils/limits.mjs";
|
|
10
|
+
import { a as insertValues, c as writeKeys, d as buildSearchKeys, f as prefixSearchFilter, i as fieldValuesOf, n as SearchKeysWriteError, o as keysFromValues, r as analyzeUpdate, s as unresolvedForUpdate, t as SEARCH_KEYS_ERROR_CODES } from "./derive-DRBiegRH.mjs";
|
|
10
11
|
import { hasNearOperator, rewriteNearForCount } from "./query/primitives/geo.mjs";
|
|
11
12
|
import { a as scopeJoins, r as markGoverned } from "./join-scope-DSAznE8E.mjs";
|
|
12
13
|
import { BULK_UPSERT_ERROR_CODES, BULK_UPSERT_FAILURE_CODES, RepositoryBase, bulkUpsertOptionsError, createDistributionGuard, runChunkedArchive, runChunkedPurge, summarizeBulkUpsert, throwIfAborted, validatePluginOrder, withRetry } from "@classytic/repo-core/repository";
|
|
@@ -1569,6 +1570,117 @@ async function executeUpserts(model, ops, options) {
|
|
|
1569
1570
|
return results;
|
|
1570
1571
|
}
|
|
1571
1572
|
//#endregion
|
|
1573
|
+
//#region src/plugins/search-keys.plugin.ts
|
|
1574
|
+
/**
|
|
1575
|
+
* Search-keys plugin: keeps the `searchMode: 'prefix'` keys field in step with
|
|
1576
|
+
* its source fields on EVERY write path, inside the same write.
|
|
1577
|
+
*
|
|
1578
|
+
* create / createMany / bulkWrite insertOne / replaceOne → keys of the document
|
|
1579
|
+
* getOrCreate → keys of filter equalities + insert data
|
|
1580
|
+
* update / findOneAndUpdate / claim / claimVersion /
|
|
1581
|
+
* bulkWrite updateOne / bulkUpsert → keys of the new values; a write that
|
|
1582
|
+
* sets only SOME search fields reads the
|
|
1583
|
+
* others from the matched document first
|
|
1584
|
+
* updateMany / bulkWrite updateMany → keys of the new values; setting only
|
|
1585
|
+
* some search fields is refused (400),
|
|
1586
|
+
* the rest differ per document
|
|
1587
|
+
*
|
|
1588
|
+
* Caller-supplied values for the keys field are always dropped: the keys are
|
|
1589
|
+
* derived, never client-settable. Runs after every default-priority hook, so it
|
|
1590
|
+
* sees the payload other plugins (validation, defaults, tenant) produced.
|
|
1591
|
+
*
|
|
1592
|
+
* `Repository` installs this automatically for `searchMode: 'prefix'`; install
|
|
1593
|
+
* it by hand only to keep keys on a repository that searches some other way.
|
|
1594
|
+
*
|
|
1595
|
+
* Writes that bypass the repository (raw `Model.updateOne`, another driver such
|
|
1596
|
+
* as Better Auth's adapter) must write the keys themselves with
|
|
1597
|
+
* `buildSearchKeys`, or be repaired with `rebuildSearchKeys`.
|
|
1598
|
+
*/
|
|
1599
|
+
const isDoc = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1600
|
+
/** After every default-priority (user) hook: derive from the final payload. */
|
|
1601
|
+
const PRIORITY = HOOK_PRIORITY.DEFAULT + 100;
|
|
1602
|
+
function searchKeysPlugin(options) {
|
|
1603
|
+
const fields = [...options.fields];
|
|
1604
|
+
const keysField = options.keysField ?? "_searchKeys";
|
|
1605
|
+
if (fields.length === 0) throw new TypeError("[mongokit] searchKeysPlugin: `fields` must name at least one source field");
|
|
1606
|
+
const projection = Object.fromEntries(fields.map((f) => [f, 1]));
|
|
1607
|
+
const stampDoc = (doc) => {
|
|
1608
|
+
if (isDoc(doc)) doc[keysField] = buildSearchKeys(doc, fields);
|
|
1609
|
+
};
|
|
1610
|
+
/** Derive the keys for ONE update in place. `load` reads the matched document's current values. */
|
|
1611
|
+
const deriveOne = async (update, filter, upsert, load) => {
|
|
1612
|
+
if (!isDoc(update) && !Array.isArray(update)) return;
|
|
1613
|
+
const effect = analyzeUpdate(update, filter, fields, keysField);
|
|
1614
|
+
if (!isDoc(update)) return;
|
|
1615
|
+
if (!(Object.keys(effect.updated).length > 0)) {
|
|
1616
|
+
if (upsert && Object.keys(effect.onInsert).length > 0) writeKeys(update, keysField, keysFromValues(insertValues(effect), fields), "$setOnInsert");
|
|
1617
|
+
return;
|
|
1618
|
+
}
|
|
1619
|
+
const missing = unresolvedForUpdate(effect, fields);
|
|
1620
|
+
if (missing.length === 0) {
|
|
1621
|
+
writeKeys(update, keysField, keysFromValues({
|
|
1622
|
+
...effect.pinned,
|
|
1623
|
+
...effect.updated
|
|
1624
|
+
}, fields));
|
|
1625
|
+
return;
|
|
1626
|
+
}
|
|
1627
|
+
if (!load) throw new SearchKeysWriteError(`[mongokit] search keys: a multi-document update sets ${Object.keys(effect.updated).join(", ")} but not ${missing.join(", ")}; the keys would differ per document. Set every search field (${fields.join(", ")}) in this update, or update per document, or call rebuildSearchKeys afterwards`, SEARCH_KEYS_ERROR_CODES.PARTIAL_MULTI_UPDATE);
|
|
1628
|
+
const current = await load();
|
|
1629
|
+
let values;
|
|
1630
|
+
if (current) values = {
|
|
1631
|
+
...fieldValuesOf(current, fields),
|
|
1632
|
+
...effect.pinned,
|
|
1633
|
+
...effect.updated
|
|
1634
|
+
};
|
|
1635
|
+
else if (upsert) values = insertValues(effect);
|
|
1636
|
+
else return;
|
|
1637
|
+
writeKeys(update, keysField, keysFromValues(values, fields));
|
|
1638
|
+
};
|
|
1639
|
+
return {
|
|
1640
|
+
name: "search-keys",
|
|
1641
|
+
apply(repo) {
|
|
1642
|
+
const Model = repo.Model;
|
|
1643
|
+
const findOne = (filter, ctx, sort) => async () => {
|
|
1644
|
+
let q = Model.findOne(filter, projection, { session: ctx.session });
|
|
1645
|
+
if (sort) q = q.sort(sort);
|
|
1646
|
+
return await q.lean();
|
|
1647
|
+
};
|
|
1648
|
+
const byTarget = (ctx) => typeof ctx.loadTarget === "function" ? () => ctx.loadTarget.call(ctx) : void 0;
|
|
1649
|
+
repo.on("before:create", (ctx) => stampDoc(ctx.data), { priority: PRIORITY });
|
|
1650
|
+
repo.on("before:createMany", (ctx) => {
|
|
1651
|
+
for (const doc of ctx.dataArray ?? []) stampDoc(doc);
|
|
1652
|
+
}, { priority: PRIORITY });
|
|
1653
|
+
repo.on("before:getOrCreate", async (ctx) => {
|
|
1654
|
+
if (!isDoc(ctx.data)) return;
|
|
1655
|
+
const effect = analyzeUpdate({ $setOnInsert: ctx.data }, ctx.query, fields, keysField);
|
|
1656
|
+
ctx.data[keysField] = keysFromValues(insertValues(effect), fields);
|
|
1657
|
+
}, { priority: PRIORITY });
|
|
1658
|
+
for (const op of [
|
|
1659
|
+
"update",
|
|
1660
|
+
"claim",
|
|
1661
|
+
"claimVersion"
|
|
1662
|
+
]) repo.on(`before:${op}`, (ctx) => deriveOne(ctx.data, ctx.query, ctx.upsert === true, byTarget(ctx)), { priority: PRIORITY });
|
|
1663
|
+
repo.on("before:findOneAndUpdate", (ctx) => deriveOne(ctx.data, ctx.query, ctx.upsert === true, findOne(ctx.query, ctx, ctx.sort)), { priority: PRIORITY });
|
|
1664
|
+
repo.on("before:updateMany", (ctx) => deriveOne(ctx.data, ctx.query, ctx.upsert === true, void 0), { priority: PRIORITY });
|
|
1665
|
+
const deriveBulk = async (ctx) => {
|
|
1666
|
+
for (const subOp of ctx.operations ?? []) {
|
|
1667
|
+
if (!isDoc(subOp)) continue;
|
|
1668
|
+
const insert = subOp.insertOne;
|
|
1669
|
+
if (insert) stampDoc(insert.document);
|
|
1670
|
+
const replace = subOp.replaceOne;
|
|
1671
|
+
if (replace) stampDoc(replace.replacement);
|
|
1672
|
+
const one = subOp.updateOne;
|
|
1673
|
+
if (one) await deriveOne(one.update, one.filter, one.upsert === true, findOne(one.filter, ctx));
|
|
1674
|
+
const many = subOp.updateMany;
|
|
1675
|
+
if (many) await deriveOne(many.update, many.filter, many.upsert === true, void 0);
|
|
1676
|
+
}
|
|
1677
|
+
};
|
|
1678
|
+
repo.on("before:bulkWrite", deriveBulk, { priority: PRIORITY });
|
|
1679
|
+
repo.on("before:bulkUpsert", deriveBulk, { priority: PRIORITY });
|
|
1680
|
+
}
|
|
1681
|
+
};
|
|
1682
|
+
}
|
|
1683
|
+
//#endregion
|
|
1572
1684
|
//#region src/query/AggregationBuilder.ts
|
|
1573
1685
|
/**
|
|
1574
1686
|
* Normalize SortSpec to MongoDB's strict format (1 | -1)
|
|
@@ -2334,6 +2446,8 @@ var Repository = class extends RepositoryBase {
|
|
|
2334
2446
|
versionField;
|
|
2335
2447
|
searchMode;
|
|
2336
2448
|
searchFields;
|
|
2449
|
+
/** Field holding the prefix-search keys (`searchMode: 'prefix'`). Default `'_searchKeys'`. */
|
|
2450
|
+
searchKeysField;
|
|
2337
2451
|
_hasTextIndex = null;
|
|
2338
2452
|
/**
|
|
2339
2453
|
* Wrap-style middleware chain. Composed around every `_runOp`
|
|
@@ -2381,12 +2495,14 @@ var Repository = class extends RepositoryBase {
|
|
|
2381
2495
|
this.versionField = options.versionField ?? "__v";
|
|
2382
2496
|
this.searchMode = options.searchMode ?? "text";
|
|
2383
2497
|
this.searchFields = options.searchFields;
|
|
2498
|
+
this.searchKeysField = options.searchKeysField ?? "_searchKeys";
|
|
2384
2499
|
this._wireStrictQueryStripDiagnostic(options.warnOnStrictQueryStrip === true);
|
|
2385
2500
|
this._checkDistribution = options.distribution ? createDistributionGuard(options.distribution, options.distribution.onMiss ?? ((info) => {
|
|
2386
2501
|
warn(`[mongokit] Repository "${this.model}": ${info.operation} filter omits the distribution key "${info.key}" — this fans out across every shard. Include the key, list the op in distribution.exemptOperations, or set onMissingKey: 'off'.`);
|
|
2387
2502
|
})) : void 0;
|
|
2388
2503
|
this._guardIdAddressed = options.distribution !== void 0 && options.distribution.key !== this.idField;
|
|
2389
2504
|
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.`);
|
|
2505
|
+
if (this.searchMode === "prefix") plugins = [...plugins, ...this._prefixSearchPlugins(plugins)];
|
|
2390
2506
|
for (const plugin of plugins) this.use(plugin);
|
|
2391
2507
|
if (options.requirePlugins && options.requirePlugins.length > 0) {
|
|
2392
2508
|
const installedNames = new Set(plugins.map((p) => p?.name).filter(Boolean));
|
|
@@ -5074,6 +5190,22 @@ var Repository = class extends RepositoryBase {
|
|
|
5074
5190
|
return sort !== "-createdAt" && !!(context.sort ?? params.sort);
|
|
5075
5191
|
}
|
|
5076
5192
|
/**
|
|
5193
|
+
* `searchMode: 'prefix'` preconditions + its write plugin. Throws when the keys could never
|
|
5194
|
+
* be written (no `searchFields`, or a strict schema that would strip the keys field); warns
|
|
5195
|
+
* when no index includes the keys field (every search would then scan).
|
|
5196
|
+
*/
|
|
5197
|
+
_prefixSearchPlugins(plugins) {
|
|
5198
|
+
const field = this.searchKeysField;
|
|
5199
|
+
if (!this.searchFields || this.searchFields.length === 0) throw new TypeError(`[mongokit] Repository "${this.model}" configured with searchMode: 'prefix' but no searchFields: name the source fields whose words the search keys are built from.`);
|
|
5200
|
+
const schema = this.Model.schema;
|
|
5201
|
+
if (schema.get("strict") !== false && !schema.path(field)) throw new TypeError(`[mongokit] Repository "${this.model}" (searchMode: 'prefix'): the schema has no '${field}' path, so a strict schema would silently strip the search keys. Add it: schema.add({ '${field}': searchKeysPath() }).`);
|
|
5202
|
+
if (!schema.indexes().some((idx) => field in (idx[0] ?? {}))) warn(`[mongokit] Repository "${this.model}" (searchMode: 'prefix'): no index includes '${field}', so every search scans the collection. Declare one: schema.index(searchKeysIndex('${field}').fields).`);
|
|
5203
|
+
return plugins.some((p) => p?.name === "search-keys") ? [] : [searchKeysPlugin({
|
|
5204
|
+
fields: this.searchFields,
|
|
5205
|
+
keysField: field
|
|
5206
|
+
})];
|
|
5207
|
+
}
|
|
5208
|
+
/**
|
|
5077
5209
|
* Build the MongoDB query filter with search merged in. Handles text
|
|
5078
5210
|
* search ($text), regex search ($or of $regex), and the search-resolver
|
|
5079
5211
|
* plugin contract (search already cleared by a before:getAll hook).
|
|
@@ -5081,6 +5213,21 @@ var Repository = class extends RepositoryBase {
|
|
|
5081
5213
|
_buildSearchQuery(filters, search) {
|
|
5082
5214
|
const query = { ...filters };
|
|
5083
5215
|
if (!search) return query;
|
|
5216
|
+
if (this.searchMode === "prefix") {
|
|
5217
|
+
const cond = prefixSearchFilter(String(search), { keysField: this.searchKeysField });
|
|
5218
|
+
if (!cond) return query;
|
|
5219
|
+
const arms = Array.isArray(cond.$and) ? cond.$and : [cond];
|
|
5220
|
+
if (arms.length === 1 && !(this.searchKeysField in query)) return {
|
|
5221
|
+
...query,
|
|
5222
|
+
...cond
|
|
5223
|
+
};
|
|
5224
|
+
const existingAnd = Array.isArray(query.$and) ? query.$and : [];
|
|
5225
|
+
const { $and: _existing, ...rest } = query;
|
|
5226
|
+
return {
|
|
5227
|
+
...rest,
|
|
5228
|
+
$and: [...existingAnd, ...arms]
|
|
5229
|
+
};
|
|
5230
|
+
}
|
|
5084
5231
|
if (this._hasTextIndex === null) this._hasTextIndex = this.Model.schema.indexes().some((idx) => idx[0] && Object.values(idx[0]).includes("text"));
|
|
5085
5232
|
let effectiveMode = this.searchMode === "regex" ? "regex" : "text";
|
|
5086
5233
|
if (this.searchMode === "auto") effectiveMode = this._hasTextIndex ? "text" : "regex";
|
|
@@ -5246,4 +5393,4 @@ var Repository = class extends RepositoryBase {
|
|
|
5246
5393
|
}
|
|
5247
5394
|
};
|
|
5248
5395
|
//#endregion
|
|
5249
|
-
export {
|
|
5396
|
+
export { ALL_OPERATIONS as a, READ_OPERATIONS as c, searchKeysPlugin as i, operationsByPolicyKey as l, Repository as n, MUTATING_OPERATIONS as o, AggregationBuilder as r, OP_REGISTRY as s, HOOK_PRIORITY$1 as t, createMongoPurgePort as u };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { S as LookupOptions, _ as SessionOptions, b as WithTransactionOptions, c as DeleteResult, f as LookupPopulateOptions, g as ReadOptions, h as OperationOptions, i as CacheableOptions, l as FindOneAndUpdateOptions, n as AggregateOptions, o as CreateOptions, p as LookupPopulateResult, s as DeleteManyResult, t as AggregateCallOptions, u as GetByIdsOptions, v as UpdateManyResult, x as LookupBuilder, y as UpdateOptions } from "./operations-XiFgG5US.mjs";
|
|
2
2
|
import { A as ObjectId, F as SortSpec$1, M as ReadPreferenceType, N as SelectSpec, c as MongokitPageExtras, i as CountStrategy, j as PopulateSpec, r as CollationOptions, t as AggregatePaginationOptions, u as PaginationConfig } from "./pagination-D6psses0.mjs";
|
|
3
|
-
import { _ as RepositoryOptions, d as PluginType, f as PrioritizedHook, o as Middleware, p as RepositoryContext } from "./repository-
|
|
3
|
+
import { _ as RepositoryOptions, d as PluginType, f as PrioritizedHook, o as Middleware, p as RepositoryContext } from "./repository-MqAP409e.mjs";
|
|
4
4
|
import { n as PaginationEngine } from "./PaginationEngine-CRHyuUtw.mjs";
|
|
5
5
|
import { AggPaginationRequest, AggRequest, AggResult, ArchiveOptions, ArchiveResult, ArchiveSink, BulkUpsertOptions, BulkUpsertResult, ChangeEvent, FilterInput, KeysetAggPaginationResult, QueryOptions, RepoCapabilities, RepositoryBase, TenantPurgeOptions, TenantPurgeResult, TenantPurgeStrategy, WatchOptions } from "@classytic/repo-core/repository";
|
|
6
6
|
import { ClientSession, Expression, Model, PipelineStage, PopulateOptions } from "mongoose";
|
|
@@ -599,8 +599,10 @@ declare class Repository<TDoc = unknown> extends RepositoryBase {
|
|
|
599
599
|
readonly idField: string;
|
|
600
600
|
/** Version field for `ifVersion` CAS writes. Default '__v'. */
|
|
601
601
|
readonly versionField: string;
|
|
602
|
-
readonly searchMode: 'text' | 'regex' | 'auto';
|
|
602
|
+
readonly searchMode: 'text' | 'regex' | 'auto' | 'prefix';
|
|
603
603
|
readonly searchFields: string[] | undefined;
|
|
604
|
+
/** Field holding the prefix-search keys (`searchMode: 'prefix'`). Default `'_searchKeys'`. */
|
|
605
|
+
readonly searchKeysField: string;
|
|
604
606
|
[key: string]: unknown;
|
|
605
607
|
private _hasTextIndex;
|
|
606
608
|
/**
|
|
@@ -1896,6 +1898,12 @@ declare class Repository<TDoc = unknown> extends RepositoryBase {
|
|
|
1896
1898
|
* sort with no page means the caller wants a cursor).
|
|
1897
1899
|
*/
|
|
1898
1900
|
private _detectPaginationMode;
|
|
1901
|
+
/**
|
|
1902
|
+
* `searchMode: 'prefix'` preconditions + its write plugin. Throws when the keys could never
|
|
1903
|
+
* be written (no `searchFields`, or a strict schema that would strip the keys field); warns
|
|
1904
|
+
* when no index includes the keys field (every search would then scan).
|
|
1905
|
+
*/
|
|
1906
|
+
private _prefixSearchPlugins;
|
|
1899
1907
|
/**
|
|
1900
1908
|
* Build the MongoDB query filter with search merged in. Handles text
|
|
1901
1909
|
* search ($text), regex search ($or of $regex), and the search-resolver
|
package/dist/ai/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as Repository } from "../Repository-
|
|
1
|
+
import { n as Repository } from "../Repository-Dj6xqPxJ.mjs";
|
|
2
2
|
import { n as createMongooseAdapter } from "../adapter-CkMoMF83.mjs";
|
|
3
3
|
import { asReadOnlyRepo } from "@classytic/repo-core/repository";
|
|
4
4
|
import { pluralizeBetterAuthCollection, resolveBetterAuthCollections } from "@classytic/repo-core/better-auth";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { u as PaginationConfig } from "./pagination-D6psses0.mjs";
|
|
2
|
-
import { _ as RepositoryOptions, d as PluginType } from "./repository-
|
|
3
|
-
import { D as AuditTrailOptions, i as CustomIdOptions, t as MultiTenantOptions, y as RepositoryCachePluginOptions } from "./multi-tenant.plugin-
|
|
4
|
-
import { r as Repository } from "./Repository-
|
|
5
|
-
import { i as Logger, o as SoftDeleteOptions } from "./plugin-options-
|
|
2
|
+
import { _ as RepositoryOptions, d as PluginType } from "./repository-MqAP409e.mjs";
|
|
3
|
+
import { D as AuditTrailOptions, i as CustomIdOptions, t as MultiTenantOptions, y as RepositoryCachePluginOptions } from "./multi-tenant.plugin-B_q9NUHc.mjs";
|
|
4
|
+
import { r as Repository } from "./Repository-DnL4xk5w.mjs";
|
|
5
|
+
import { i as Logger, o as SoftDeleteOptions } from "./plugin-options-Cirmb4Kp.mjs";
|
|
6
6
|
import { Model } from "mongoose";
|
|
7
7
|
//#region src/create-repository.d.ts
|
|
8
8
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as Repository } from "./Repository-
|
|
2
|
-
import { b as auditLogPlugin, g as cachePlugin, i as multiTenantPlugin, l as customIdPlugin, n as softDeletePlugin, t as timestampPlugin, v as auditTrailPlugin } from "./timestamp.plugin-
|
|
1
|
+
import { n as Repository } from "./Repository-Dj6xqPxJ.mjs";
|
|
2
|
+
import { b as auditLogPlugin, g as cachePlugin, i as multiTenantPlugin, l as customIdPlugin, n as softDeletePlugin, t as timestampPlugin, v as auditTrailPlugin } from "./timestamp.plugin-DpOWavVI.mjs";
|
|
3
3
|
import { n as batchOperationsPlugin, t as methodRegistryPlugin } from "./method-registry.plugin-C63pGn1d.mjs";
|
|
4
4
|
//#region src/create-repository.ts
|
|
5
5
|
function isLoggerAudit(value) {
|