@atscript/db-mongo 0.1.146 → 0.1.148

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.d.cts CHANGED
@@ -1,5 +1,6 @@
1
- import { BaseDbAdapter, DbQuery, DbSpace, FilterExpr, TColumnDiff, TDbDeleteResult, TDbFieldMeta, TDbForeignKey, TDbInsertManyResult, TDbInsertResult, TDbObjectKind, TDbRelation, TDbUpdateResult, TExistingTableOption, TFieldOps, TMetadataOverrides, TPrimaryKeyChange, TSearchIndexInfo, TSyncColumnResult, TTableResolver, TableMetadata, WithRelation, getKeyProps } from "@atscript/db";
2
- import { AggregationCursor, ClientSession, Collection, Db, Document, Filter, MongoClient, ObjectId, UpdateFilter, UpdateOptions } from "mongodb";
1
+ import { a as buildMongoFilter, c as mongoFilterStages, i as TMongoFilterPlan, l as planStages, n as TMongoFieldCollation, o as buildMongoQuery, r as TMongoFilterOptions, s as collationOfAdapter, t as REL_FILTER_TEMP_PREFIX } from "./mongo-filter-CGd9ryOD.cjs";
2
+ import { BaseDbAdapter, DbQuery, DbSpace, FilterExpr, TColumnDiff, TDbCollation, TDbDeleteResult, TDbFieldMeta, TDbForeignKey, TDbInsertIgnoreSlot, TDbInsertManyResult, TDbInsertResult, TDbObjectKind, TDbRelation, TDbUpdateResult, TExistingTableOption, TFieldOps, TMetadataOverrides, TPrimaryKeyChange, TSearchIndexInfo, TSyncColumnResult, TTableResolver, TViewCapability, TableMetadata, WithRelation, getKeyProps } from "@atscript/db";
3
+ import { AggregateOptions, AggregationCursor, ClientSession, Collection, Db, Document, Filter, MongoClient, ObjectId, UpdateFilter, UpdateOptions } from "mongodb";
3
4
  import { TAtscriptAnnotatedType, TMetadataMap, TValidatorOptions, TValidatorPlugin, Validator } from "@atscript/typescript/utils";
4
5
  import { AggregateFn, BucketUnit } from "@uniqu/core";
5
6
 
@@ -277,6 +278,12 @@ declare class MongoAdapter extends BaseDbAdapter {
277
278
  private get _client();
278
279
  /** Every adapter over this client (or database handle) shares one session (since 0.1.128). */
279
280
  protected _transactionOwner(): unknown;
281
+ /**
282
+ * Same store = same client (or database handle) AND the same database: a
283
+ * `$lookup` only reads collections of the pipeline's own database, and one
284
+ * client may serve several (since 0.1.147).
285
+ */
286
+ sharesStoreWith(other: BaseDbAdapter): boolean;
280
287
  /**
281
288
  * Per-client cache: whether transactions are unavailable (standalone MongoDB).
282
289
  * Shared across all adapter instances for the same client so topology is probed once.
@@ -296,7 +303,7 @@ declare class MongoAdapter extends BaseDbAdapter {
296
303
  session: ClientSession;
297
304
  } | Record<string, never>;
298
305
  get collection(): Collection<any>;
299
- aggregatePipeline(pipeline: Document[]): AggregationCursor;
306
+ aggregatePipeline(pipeline: Document[], options?: AggregateOptions): AggregationCursor;
300
307
  aggregate(query: DbQuery): Promise<Array<Record<string, unknown>>>;
301
308
  get idType(): "string" | "number" | "objectId";
302
309
  prepareId(id: unknown, _fieldType: unknown): unknown;
@@ -307,10 +314,14 @@ declare class MongoAdapter extends BaseDbAdapter {
307
314
  prepareIdFromIdType<D = string | number | ObjectId>(id: string | number | ObjectId): D;
308
315
  supportsNestedObjects(): boolean;
309
316
  supportsNativePatch(): boolean;
310
- /** All five units, over MongoDB's bundled time zone database (see `agg.ts` `bucketExpression`). */
317
+ /** Every unit, over MongoDB's bundled time zone database (see `agg.ts` `bucketExpression`). */
311
318
  calendarBucketUnits(): ReadonlySet<BucketUnit>;
312
- /** Every aggregate function, `countDistinct` included. */
319
+ /** Every aggregate function: `countDistinct`, `first` and `last` included. */
313
320
  aggregateFns(): ReadonlySet<AggregateFn>;
321
+ /** Arithmetic in an aggregate `$select` (`{ $expr }`, `{ $fn, $expr }`). */
322
+ supportsAggregateExpressions(): boolean;
323
+ /** Computed view columns and first-row joins. */
324
+ viewCapabilities(): ReadonlySet<TViewCapability>;
314
325
  /**
315
326
  * See BaseDbAdapter.viewRenderRevision. 2 = 0.1.137 (null-guarded field filters, nested document paths).
316
327
  * BUMP whenever `buildViewPipeline` output changes for an unchanged view definition.
@@ -348,6 +359,46 @@ declare class MongoAdapter extends BaseDbAdapter {
348
359
  } | undefined;
349
360
  getAdapterTableName(_type: unknown): string | undefined;
350
361
  supportsNativeRelations(): boolean;
362
+ /**
363
+ * Relational predicates (`{ nav: { $some | $none: … } }`) render as
364
+ * correlated `$lookup` stages, so a read whose filter holds one runs as an
365
+ * aggregation pipeline (find / count / findManyWithCount / grouped
366
+ * aggregate / search / geo); predicate-free reads keep their plain
367
+ * `find` / `countDocuments` path.
368
+ *
369
+ * Writes (`updateMany` / `replaceMany` / `deleteMany` and the single-row
370
+ * variants, whose scope may carry a predicate) first resolve the matching
371
+ * `_id`s through that pipeline, then write by `_id` in batches of
372
+ * {@link REL_WRITE_BATCH} — re-checking the predicate-free part of the
373
+ * filter. Inside an active transaction both steps share its session and
374
+ * are atomic; without one there is a window between resolving and writing
375
+ * in which a related document can change, so a written document may no
376
+ * longer satisfy the predicate (or a newly matching one is missed).
377
+ *
378
+ * Collation: such a pipeline runs without an operation-wide `collation`
379
+ * (it would govern the join keys and every related field too); each
380
+ * table's `'nocase'` fields are compared case-insensitively explicitly
381
+ * ({@link TMongoFilterOptions.collation}) — on reads and on these writes.
382
+ *
383
+ * @since 0.1.147
384
+ */
385
+ supportsRelationFilters(_mode: "read" | "write"): boolean;
386
+ /**
387
+ * The `@db.column.collate` of a field (physical or logical path), or
388
+ * `undefined` for a byte-wise one — how predicate pipelines render this
389
+ * table's `'nocase'` comparisons ({@link TMongoFilterOptions.collation}).
390
+ *
391
+ * @since 0.1.147
392
+ */
393
+ fieldCollation(field: string): TDbCollation | undefined;
394
+ /** Filter-rendering options of a pipeline with relational predicates on this table. */
395
+ private get _predicateFilterOpts();
396
+ /**
397
+ * Operation options of a read: the request collation for a predicate-free
398
+ * filter ({@link _getCollationOpts}); none with relational predicates —
399
+ * those pipelines render collation per field ({@link _predicateFilterOpts}).
400
+ */
401
+ private _readOpts;
351
402
  loadRelations(rows: Array<Record<string, unknown>>, withRelations: WithRelation[], relations: ReadonlyMap<string, TDbRelation>, foreignKeys: ReadonlyMap<string, TDbForeignKey>, tableResolver?: TTableResolver): Promise<void>;
352
403
  /** Returns the context object used by CollectionPatcher. */
353
404
  getPatcherContext(): TCollectionPatcherContext;
@@ -394,6 +445,37 @@ declare class MongoAdapter extends BaseDbAdapter {
394
445
  * rather than silently dropping the CAS predicate.
395
446
  */
396
447
  private _buildCasFilter;
448
+ /**
449
+ * The id-resolving pipeline of a write filter holding relational
450
+ * predicates: the matching `_id`s (in the active transaction's session,
451
+ * if any), each table's `'nocase'` fields compared like on reads
452
+ * ({@link _predicateFilterOpts}). `pre` is the predicate-free part, which
453
+ * every `_id`-based write re-checks — so a document that stopped matching
454
+ * it in between is not written.
455
+ */
456
+ private _predicateWritePlan;
457
+ /** A write filter's `_id` filter (re-checking `pre`). */
458
+ private static _byIds;
459
+ /** Single-document write over a predicate filter: the first match's `_id` filter (`undefined`: none). */
460
+ private _predicateWriteFilterOne;
461
+ /**
462
+ * Multi-document write over `filter`: a predicate-free filter is written
463
+ * as is; one with predicates calls `write` with one `_id`-based filter per
464
+ * batch of {@link REL_WRITE_BATCH} matching ids, streamed from the cursor
465
+ * (never all ids in memory at once).
466
+ *
467
+ * The ids come sorted by `_id`, so writes made while the cursor is open
468
+ * can never feed back into it (otherwise a document an update moves within
469
+ * the index the cursor scans could be returned — and written — twice):
470
+ * after the `$lookup`s that `$sort` consumes every match before the first
471
+ * batch returns, and an `_id` order read from the `_id` index is stable
472
+ * (`_id` never changes).
473
+ */
474
+ private _forEachMatching;
475
+ /** Runs an update-shaped write over `filter` ({@link _forEachMatching}), counts summed. */
476
+ private _updateMatching;
477
+ /** The filter of a single-document write — its predicates resolved to one `_id`. */
478
+ private _writeFilterOne;
397
479
  /**
398
480
  * Wraps an async operation to catch MongoDB duplicate key errors
399
481
  * (code 11000) and rethrow as structured `DbError` — every write path
@@ -401,10 +483,35 @@ declare class MongoAdapter extends BaseDbAdapter {
401
483
  * so a unique-index violation is a `CONFLICT` whichever statement hit it.
402
484
  */
403
485
  private _wrapDuplicateKeyError;
486
+ /** Rethrows a duplicate-key (11000) server error as `CONFLICT`, anything else as is. */
487
+ private _mapConstraintError;
404
488
  /** An update-shaped write under {@link _wrapDuplicateKeyError}, reduced to `TDbUpdateResult`. */
405
489
  private _wrapUpdate;
406
490
  insertOne(data: Record<string, unknown>): Promise<TDbInsertResult>;
407
491
  insertMany(data: Array<Record<string, unknown>>): Promise<TDbInsertManyResult>;
492
+ supportsInsertIgnore(): boolean;
493
+ /**
494
+ * Conflict-ignoring batch insert (the core already removed in-batch duplicates).
495
+ *
496
+ * Outside a transaction: `insertMany(…, { ordered: false })`; duplicate-key
497
+ * write errors (11000) mark the skipped rows, every other write error
498
+ * rethrows after the batch (rows already written stay — as for a plain
499
+ * non-transactional `insertMany`).
500
+ *
501
+ * Inside a transaction a duplicate key would abort the transaction even with
502
+ * `ordered: false`, so the stored keys are looked up first (inside the
503
+ * session), the matches are skipped and the rest is inserted ordered. A
504
+ * residual 11000 (e.g. a collation-equal value) throws `CONFLICT`.
505
+ */
506
+ insertManyIgnore(data: Array<Record<string, unknown>>): Promise<TDbInsertIgnoreSlot[]>;
507
+ /**
508
+ * Indices of `data` rows whose primary (`_id`) or unique-index key tuple is
509
+ * already stored (rows with a null / missing key component never collide).
510
+ * One `$or` query per chunk covers every key set.
511
+ */
512
+ private _findStoredKeyConflicts;
513
+ /** Version default + `@db.default.increment` allocation shared by every batch insert. */
514
+ private _prepareInsertBatch;
408
515
  findOne(query: DbQuery): Promise<Record<string, unknown> | null>;
409
516
  findMany(query: DbQuery): Promise<Array<Record<string, unknown>>>;
410
517
  count(query: DbQuery): Promise<number>;
@@ -452,11 +559,16 @@ declare class MongoAdapter extends BaseDbAdapter {
452
559
  private _getCurrentFieldMax;
453
560
  /** Allocates increment values for a batch of items, assigning in order. */
454
561
  private _assignBatchIncrements;
562
+ /** A find whose filter holds relational predicates, as an aggregation pipeline. */
563
+ private _aggregateFind;
455
564
  private _buildFindOptions;
456
565
  /**
457
566
  * Returns MongoDB collation options if any filter field has a non-binary collation.
458
567
  * Uses pre-computed insights when available, falls back to computing them on demand.
459
568
  * Maps: nocase → strength 2 (case-insensitive), unicode → strength 1 (case+accent-insensitive).
569
+ * Predicate-free filters only — a filter with relational predicates never gets an
570
+ * operation-wide collation ({@link _readOpts}), so insights are never computed over
571
+ * resolved predicate operands.
460
572
  */
461
573
  private _getCollationOpts;
462
574
  protected _addMongoIndexField(type: TPlainIndex["type"], name: string, field: string, weight?: number): void;
@@ -484,27 +596,10 @@ declare class MongoAdapter extends BaseDbAdapter {
484
596
  private _descendSearchNode;
485
597
  }
486
598
  //#endregion
487
- //#region src/lib/mongo-filter.d.ts
488
- /**
489
- * Translates a generic {@link FilterExpr} into a MongoDB-compatible
490
- * {@link Filter} document.
491
- *
492
- * MongoDB's query language is nearly identical to the `FilterExpr` structure,
493
- * so this is largely a structural pass-through via the `walkFilter` visitor.
494
- * `fieldOperands` (view predicates only — `translateQueryTree` output) turns
495
- * `{ $field: path }` operands into field-to-field `$expr` comparisons; a
496
- * request filter never gets that reading.
497
- */
498
- declare function buildMongoFilter(filter: FilterExpr, {
499
- fieldOperands
500
- }?: {
501
- fieldOperands?: boolean;
502
- }): Filter<any>;
503
- //#endregion
504
599
  //#region src/lib/validate-plugins.d.ts
505
600
  declare const validateMongoIdPlugin: TValidatorPlugin;
506
601
  //#endregion
507
602
  //#region src/lib/index.d.ts
508
603
  declare function createAdapter(connection: string, _options?: Record<string, unknown>): DbSpace;
509
604
  //#endregion
510
- export { CollectionPatcher, INDEX_PREFIX, MongoAdapter, TCollectionPatcherContext, type TMongoIndex, type TMongoSearchIndexDefinition, type TPlainIndex, type TSearchIndex, buildMongoFilter, createAdapter, mongoIndexKey, validateMongoIdPlugin };
605
+ export { CollectionPatcher, INDEX_PREFIX, MongoAdapter, REL_FILTER_TEMP_PREFIX, TCollectionPatcherContext, TMongoFieldCollation, TMongoFilterOptions, TMongoFilterPlan, type TMongoIndex, type TMongoSearchIndexDefinition, type TPlainIndex, type TSearchIndex, buildMongoFilter, buildMongoQuery, collationOfAdapter, createAdapter, mongoFilterStages, mongoIndexKey, planStages, validateMongoIdPlugin };
package/dist/index.d.mts CHANGED
@@ -1,5 +1,6 @@
1
- import { BaseDbAdapter, DbQuery, DbSpace, FilterExpr, TColumnDiff, TDbDeleteResult, TDbFieldMeta, TDbForeignKey, TDbInsertManyResult, TDbInsertResult, TDbObjectKind, TDbRelation, TDbUpdateResult, TExistingTableOption, TFieldOps, TMetadataOverrides, TPrimaryKeyChange, TSearchIndexInfo, TSyncColumnResult, TTableResolver, TableMetadata, WithRelation, getKeyProps } from "@atscript/db";
2
- import { AggregationCursor, ClientSession, Collection, Db, Document, Filter, MongoClient, ObjectId, UpdateFilter, UpdateOptions } from "mongodb";
1
+ import { a as buildMongoFilter, c as mongoFilterStages, i as TMongoFilterPlan, l as planStages, n as TMongoFieldCollation, o as buildMongoQuery, r as TMongoFilterOptions, s as collationOfAdapter, t as REL_FILTER_TEMP_PREFIX } from "./mongo-filter-CGd9ryOD.mjs";
2
+ import { BaseDbAdapter, DbQuery, DbSpace, FilterExpr, TColumnDiff, TDbCollation, TDbDeleteResult, TDbFieldMeta, TDbForeignKey, TDbInsertIgnoreSlot, TDbInsertManyResult, TDbInsertResult, TDbObjectKind, TDbRelation, TDbUpdateResult, TExistingTableOption, TFieldOps, TMetadataOverrides, TPrimaryKeyChange, TSearchIndexInfo, TSyncColumnResult, TTableResolver, TViewCapability, TableMetadata, WithRelation, getKeyProps } from "@atscript/db";
3
+ import { AggregateOptions, AggregationCursor, ClientSession, Collection, Db, Document, Filter, MongoClient, ObjectId, UpdateFilter, UpdateOptions } from "mongodb";
3
4
  import { AggregateFn, BucketUnit } from "@uniqu/core";
4
5
  import { TAtscriptAnnotatedType, TMetadataMap, TValidatorOptions, TValidatorPlugin, Validator } from "@atscript/typescript/utils";
5
6
 
@@ -277,6 +278,12 @@ declare class MongoAdapter extends BaseDbAdapter {
277
278
  private get _client();
278
279
  /** Every adapter over this client (or database handle) shares one session (since 0.1.128). */
279
280
  protected _transactionOwner(): unknown;
281
+ /**
282
+ * Same store = same client (or database handle) AND the same database: a
283
+ * `$lookup` only reads collections of the pipeline's own database, and one
284
+ * client may serve several (since 0.1.147).
285
+ */
286
+ sharesStoreWith(other: BaseDbAdapter): boolean;
280
287
  /**
281
288
  * Per-client cache: whether transactions are unavailable (standalone MongoDB).
282
289
  * Shared across all adapter instances for the same client so topology is probed once.
@@ -296,7 +303,7 @@ declare class MongoAdapter extends BaseDbAdapter {
296
303
  session: ClientSession;
297
304
  } | Record<string, never>;
298
305
  get collection(): Collection<any>;
299
- aggregatePipeline(pipeline: Document[]): AggregationCursor;
306
+ aggregatePipeline(pipeline: Document[], options?: AggregateOptions): AggregationCursor;
300
307
  aggregate(query: DbQuery): Promise<Array<Record<string, unknown>>>;
301
308
  get idType(): "string" | "number" | "objectId";
302
309
  prepareId(id: unknown, _fieldType: unknown): unknown;
@@ -307,10 +314,14 @@ declare class MongoAdapter extends BaseDbAdapter {
307
314
  prepareIdFromIdType<D = string | number | ObjectId>(id: string | number | ObjectId): D;
308
315
  supportsNestedObjects(): boolean;
309
316
  supportsNativePatch(): boolean;
310
- /** All five units, over MongoDB's bundled time zone database (see `agg.ts` `bucketExpression`). */
317
+ /** Every unit, over MongoDB's bundled time zone database (see `agg.ts` `bucketExpression`). */
311
318
  calendarBucketUnits(): ReadonlySet<BucketUnit>;
312
- /** Every aggregate function, `countDistinct` included. */
319
+ /** Every aggregate function: `countDistinct`, `first` and `last` included. */
313
320
  aggregateFns(): ReadonlySet<AggregateFn>;
321
+ /** Arithmetic in an aggregate `$select` (`{ $expr }`, `{ $fn, $expr }`). */
322
+ supportsAggregateExpressions(): boolean;
323
+ /** Computed view columns and first-row joins. */
324
+ viewCapabilities(): ReadonlySet<TViewCapability>;
314
325
  /**
315
326
  * See BaseDbAdapter.viewRenderRevision. 2 = 0.1.137 (null-guarded field filters, nested document paths).
316
327
  * BUMP whenever `buildViewPipeline` output changes for an unchanged view definition.
@@ -348,6 +359,46 @@ declare class MongoAdapter extends BaseDbAdapter {
348
359
  } | undefined;
349
360
  getAdapterTableName(_type: unknown): string | undefined;
350
361
  supportsNativeRelations(): boolean;
362
+ /**
363
+ * Relational predicates (`{ nav: { $some | $none: … } }`) render as
364
+ * correlated `$lookup` stages, so a read whose filter holds one runs as an
365
+ * aggregation pipeline (find / count / findManyWithCount / grouped
366
+ * aggregate / search / geo); predicate-free reads keep their plain
367
+ * `find` / `countDocuments` path.
368
+ *
369
+ * Writes (`updateMany` / `replaceMany` / `deleteMany` and the single-row
370
+ * variants, whose scope may carry a predicate) first resolve the matching
371
+ * `_id`s through that pipeline, then write by `_id` in batches of
372
+ * {@link REL_WRITE_BATCH} — re-checking the predicate-free part of the
373
+ * filter. Inside an active transaction both steps share its session and
374
+ * are atomic; without one there is a window between resolving and writing
375
+ * in which a related document can change, so a written document may no
376
+ * longer satisfy the predicate (or a newly matching one is missed).
377
+ *
378
+ * Collation: such a pipeline runs without an operation-wide `collation`
379
+ * (it would govern the join keys and every related field too); each
380
+ * table's `'nocase'` fields are compared case-insensitively explicitly
381
+ * ({@link TMongoFilterOptions.collation}) — on reads and on these writes.
382
+ *
383
+ * @since 0.1.147
384
+ */
385
+ supportsRelationFilters(_mode: "read" | "write"): boolean;
386
+ /**
387
+ * The `@db.column.collate` of a field (physical or logical path), or
388
+ * `undefined` for a byte-wise one — how predicate pipelines render this
389
+ * table's `'nocase'` comparisons ({@link TMongoFilterOptions.collation}).
390
+ *
391
+ * @since 0.1.147
392
+ */
393
+ fieldCollation(field: string): TDbCollation | undefined;
394
+ /** Filter-rendering options of a pipeline with relational predicates on this table. */
395
+ private get _predicateFilterOpts();
396
+ /**
397
+ * Operation options of a read: the request collation for a predicate-free
398
+ * filter ({@link _getCollationOpts}); none with relational predicates —
399
+ * those pipelines render collation per field ({@link _predicateFilterOpts}).
400
+ */
401
+ private _readOpts;
351
402
  loadRelations(rows: Array<Record<string, unknown>>, withRelations: WithRelation[], relations: ReadonlyMap<string, TDbRelation>, foreignKeys: ReadonlyMap<string, TDbForeignKey>, tableResolver?: TTableResolver): Promise<void>;
352
403
  /** Returns the context object used by CollectionPatcher. */
353
404
  getPatcherContext(): TCollectionPatcherContext;
@@ -394,6 +445,37 @@ declare class MongoAdapter extends BaseDbAdapter {
394
445
  * rather than silently dropping the CAS predicate.
395
446
  */
396
447
  private _buildCasFilter;
448
+ /**
449
+ * The id-resolving pipeline of a write filter holding relational
450
+ * predicates: the matching `_id`s (in the active transaction's session,
451
+ * if any), each table's `'nocase'` fields compared like on reads
452
+ * ({@link _predicateFilterOpts}). `pre` is the predicate-free part, which
453
+ * every `_id`-based write re-checks — so a document that stopped matching
454
+ * it in between is not written.
455
+ */
456
+ private _predicateWritePlan;
457
+ /** A write filter's `_id` filter (re-checking `pre`). */
458
+ private static _byIds;
459
+ /** Single-document write over a predicate filter: the first match's `_id` filter (`undefined`: none). */
460
+ private _predicateWriteFilterOne;
461
+ /**
462
+ * Multi-document write over `filter`: a predicate-free filter is written
463
+ * as is; one with predicates calls `write` with one `_id`-based filter per
464
+ * batch of {@link REL_WRITE_BATCH} matching ids, streamed from the cursor
465
+ * (never all ids in memory at once).
466
+ *
467
+ * The ids come sorted by `_id`, so writes made while the cursor is open
468
+ * can never feed back into it (otherwise a document an update moves within
469
+ * the index the cursor scans could be returned — and written — twice):
470
+ * after the `$lookup`s that `$sort` consumes every match before the first
471
+ * batch returns, and an `_id` order read from the `_id` index is stable
472
+ * (`_id` never changes).
473
+ */
474
+ private _forEachMatching;
475
+ /** Runs an update-shaped write over `filter` ({@link _forEachMatching}), counts summed. */
476
+ private _updateMatching;
477
+ /** The filter of a single-document write — its predicates resolved to one `_id`. */
478
+ private _writeFilterOne;
397
479
  /**
398
480
  * Wraps an async operation to catch MongoDB duplicate key errors
399
481
  * (code 11000) and rethrow as structured `DbError` — every write path
@@ -401,10 +483,35 @@ declare class MongoAdapter extends BaseDbAdapter {
401
483
  * so a unique-index violation is a `CONFLICT` whichever statement hit it.
402
484
  */
403
485
  private _wrapDuplicateKeyError;
486
+ /** Rethrows a duplicate-key (11000) server error as `CONFLICT`, anything else as is. */
487
+ private _mapConstraintError;
404
488
  /** An update-shaped write under {@link _wrapDuplicateKeyError}, reduced to `TDbUpdateResult`. */
405
489
  private _wrapUpdate;
406
490
  insertOne(data: Record<string, unknown>): Promise<TDbInsertResult>;
407
491
  insertMany(data: Array<Record<string, unknown>>): Promise<TDbInsertManyResult>;
492
+ supportsInsertIgnore(): boolean;
493
+ /**
494
+ * Conflict-ignoring batch insert (the core already removed in-batch duplicates).
495
+ *
496
+ * Outside a transaction: `insertMany(…, { ordered: false })`; duplicate-key
497
+ * write errors (11000) mark the skipped rows, every other write error
498
+ * rethrows after the batch (rows already written stay — as for a plain
499
+ * non-transactional `insertMany`).
500
+ *
501
+ * Inside a transaction a duplicate key would abort the transaction even with
502
+ * `ordered: false`, so the stored keys are looked up first (inside the
503
+ * session), the matches are skipped and the rest is inserted ordered. A
504
+ * residual 11000 (e.g. a collation-equal value) throws `CONFLICT`.
505
+ */
506
+ insertManyIgnore(data: Array<Record<string, unknown>>): Promise<TDbInsertIgnoreSlot[]>;
507
+ /**
508
+ * Indices of `data` rows whose primary (`_id`) or unique-index key tuple is
509
+ * already stored (rows with a null / missing key component never collide).
510
+ * One `$or` query per chunk covers every key set.
511
+ */
512
+ private _findStoredKeyConflicts;
513
+ /** Version default + `@db.default.increment` allocation shared by every batch insert. */
514
+ private _prepareInsertBatch;
408
515
  findOne(query: DbQuery): Promise<Record<string, unknown> | null>;
409
516
  findMany(query: DbQuery): Promise<Array<Record<string, unknown>>>;
410
517
  count(query: DbQuery): Promise<number>;
@@ -452,11 +559,16 @@ declare class MongoAdapter extends BaseDbAdapter {
452
559
  private _getCurrentFieldMax;
453
560
  /** Allocates increment values for a batch of items, assigning in order. */
454
561
  private _assignBatchIncrements;
562
+ /** A find whose filter holds relational predicates, as an aggregation pipeline. */
563
+ private _aggregateFind;
455
564
  private _buildFindOptions;
456
565
  /**
457
566
  * Returns MongoDB collation options if any filter field has a non-binary collation.
458
567
  * Uses pre-computed insights when available, falls back to computing them on demand.
459
568
  * Maps: nocase → strength 2 (case-insensitive), unicode → strength 1 (case+accent-insensitive).
569
+ * Predicate-free filters only — a filter with relational predicates never gets an
570
+ * operation-wide collation ({@link _readOpts}), so insights are never computed over
571
+ * resolved predicate operands.
460
572
  */
461
573
  private _getCollationOpts;
462
574
  protected _addMongoIndexField(type: TPlainIndex["type"], name: string, field: string, weight?: number): void;
@@ -484,27 +596,10 @@ declare class MongoAdapter extends BaseDbAdapter {
484
596
  private _descendSearchNode;
485
597
  }
486
598
  //#endregion
487
- //#region src/lib/mongo-filter.d.ts
488
- /**
489
- * Translates a generic {@link FilterExpr} into a MongoDB-compatible
490
- * {@link Filter} document.
491
- *
492
- * MongoDB's query language is nearly identical to the `FilterExpr` structure,
493
- * so this is largely a structural pass-through via the `walkFilter` visitor.
494
- * `fieldOperands` (view predicates only — `translateQueryTree` output) turns
495
- * `{ $field: path }` operands into field-to-field `$expr` comparisons; a
496
- * request filter never gets that reading.
497
- */
498
- declare function buildMongoFilter(filter: FilterExpr, {
499
- fieldOperands
500
- }?: {
501
- fieldOperands?: boolean;
502
- }): Filter<any>;
503
- //#endregion
504
599
  //#region src/lib/validate-plugins.d.ts
505
600
  declare const validateMongoIdPlugin: TValidatorPlugin;
506
601
  //#endregion
507
602
  //#region src/lib/index.d.ts
508
603
  declare function createAdapter(connection: string, _options?: Record<string, unknown>): DbSpace;
509
604
  //#endregion
510
- export { CollectionPatcher, INDEX_PREFIX, MongoAdapter, TCollectionPatcherContext, type TMongoIndex, type TMongoSearchIndexDefinition, type TPlainIndex, type TSearchIndex, buildMongoFilter, createAdapter, mongoIndexKey, validateMongoIdPlugin };
605
+ export { CollectionPatcher, INDEX_PREFIX, MongoAdapter, REL_FILTER_TEMP_PREFIX, TCollectionPatcherContext, TMongoFieldCollation, TMongoFilterOptions, TMongoFilterPlan, type TMongoIndex, type TMongoSearchIndexDefinition, type TPlainIndex, type TSearchIndex, buildMongoFilter, buildMongoQuery, collationOfAdapter, createAdapter, mongoFilterStages, mongoIndexKey, planStages, validateMongoIdPlugin };