uql-orm 0.55.0 → 0.57.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.
Files changed (109) hide show
  1. package/README.md +1 -1
  2. package/dist/browser/uql-browser.min.js +2 -2
  3. package/dist/browser/uql-browser.min.js.map +4 -4
  4. package/dist/bunSql/bunSql.util.js +1 -1
  5. package/dist/cockroachdb/cockroachDialect.d.ts +5 -2
  6. package/dist/cockroachdb/cockroachDialect.js +2 -10
  7. package/dist/d1/d1SqliteDialect.d.ts +1 -0
  8. package/dist/d1/d1SqliteDialect.js +2 -0
  9. package/dist/dialect/abstractSqlDialect.d.ts +195 -32
  10. package/dist/dialect/abstractSqlDialect.js +406 -199
  11. package/dist/dialect/aliases.d.ts +10 -7
  12. package/dist/dialect/aliases.js +12 -7
  13. package/dist/dialect/hydrateColumn.d.ts +8 -2
  14. package/dist/dialect/hydrateColumn.js +33 -1
  15. package/dist/dialect/jsonSql.d.ts +13 -5
  16. package/dist/dialect/jsonSql.js +24 -7
  17. package/dist/dialect/mysqlLikeSqlDialect.d.ts +30 -2
  18. package/dist/dialect/mysqlLikeSqlDialect.js +58 -7
  19. package/dist/dialect/pgLikeSqlDialect.d.ts +20 -20
  20. package/dist/dialect/pgLikeSqlDialect.js +25 -50
  21. package/dist/dialect/pgVectorMetrics.d.ts +13 -0
  22. package/dist/dialect/pgVectorMetrics.js +17 -0
  23. package/dist/dialect/queryContext.d.ts +3 -7
  24. package/dist/dialect/queryContext.js +13 -8
  25. package/dist/dialect/queryJoins.d.ts +8 -4
  26. package/dist/dialect/queryJoins.js +27 -15
  27. package/dist/dialect/vectorSqlDialect.d.ts +2 -2
  28. package/dist/dialect/vectorSqlDialect.js +2 -3
  29. package/dist/entity/index.d.ts +1 -1
  30. package/dist/entity/index.js +1 -1
  31. package/dist/entity/metadata/definition.d.ts +4 -2
  32. package/dist/entity/metadata/definition.js +27 -29
  33. package/dist/maria/mariaDialect.d.ts +13 -6
  34. package/dist/maria/mariaDialect.js +29 -9
  35. package/dist/migrate/builder/splitSqlStatements.js +2 -2
  36. package/dist/migrate/cli.d.ts +2 -3
  37. package/dist/migrate/cli.js +4 -11
  38. package/dist/migrate/codegen/fieldOptionsSource.js +1 -1
  39. package/dist/migrate/ddl/index.d.ts +1 -5
  40. package/dist/migrate/ddl/index.js +14 -25
  41. package/dist/migrate/ddl/indexDdl.d.ts +11 -2
  42. package/dist/migrate/ddl/indexDdl.js +17 -1
  43. package/dist/migrate/ddl/mssqlIndexDdl.d.ts +10 -0
  44. package/dist/migrate/ddl/mssqlIndexDdl.js +10 -0
  45. package/dist/migrate/ddl/mysqlIndexDdl.d.ts +10 -17
  46. package/dist/migrate/ddl/mysqlIndexDdl.js +16 -27
  47. package/dist/migrate/ddl/pgIndexDdl.d.ts +18 -3
  48. package/dist/migrate/ddl/pgIndexDdl.js +29 -3
  49. package/dist/migrate/drift/driftDetector.js +21 -8
  50. package/dist/migrate/generator/mongoSchemaGenerator.js +1 -1
  51. package/dist/migrate/introspection/baseSqlIntrospector.d.ts +1 -1
  52. package/dist/migrate/introspection/baseSqlIntrospector.js +65 -76
  53. package/dist/migrate/introspection/mssqlIntrospector.js +2 -1
  54. package/dist/migrate/introspection/mysqlIntrospector.js +5 -8
  55. package/dist/migrate/introspection/sqliteIntrospector.js +2 -5
  56. package/dist/migrate/migrator.d.ts +7 -4
  57. package/dist/migrate/migrator.js +9 -14
  58. package/dist/migrate/schemaGenerator.d.ts +3 -3
  59. package/dist/migrate/schemaGenerator.js +7 -13
  60. package/dist/migrate/schemaGeneratorAsync.d.ts +2 -3
  61. package/dist/mongo/mongoDialect.d.ts +31 -18
  62. package/dist/mongo/mongoDialect.js +147 -108
  63. package/dist/mongo/mongodbQuerier.d.ts +10 -17
  64. package/dist/mongo/mongodbQuerier.js +34 -108
  65. package/dist/mssql/mssqlDialect.d.ts +16 -0
  66. package/dist/mssql/mssqlDialect.js +26 -4
  67. package/dist/mysql/mysqlDialect.d.ts +2 -0
  68. package/dist/mysql/mysqlDialect.js +4 -0
  69. package/dist/querier/abstractQuerier.d.ts +20 -36
  70. package/dist/querier/abstractQuerier.js +44 -143
  71. package/dist/querier/abstractQuerierPool.d.ts +2 -2
  72. package/dist/querier/abstractSqlQuerier.d.ts +11 -22
  73. package/dist/querier/abstractSqlQuerier.js +49 -53
  74. package/dist/schema/canonicalType.js +4 -6
  75. package/dist/schema/dependencyGraph.js +2 -4
  76. package/dist/schema/indexDifferences.js +5 -5
  77. package/dist/schema/schemaASTBuilder.js +34 -12
  78. package/dist/schema/schemaASTDiffer.d.ts +10 -2
  79. package/dist/schema/schemaASTDiffer.js +17 -16
  80. package/dist/schema/types.d.ts +1 -1
  81. package/dist/sqlite/sqliteDialect.d.ts +20 -1
  82. package/dist/sqlite/sqliteDialect.js +40 -8
  83. package/dist/turso/tursoDialect.d.ts +2 -0
  84. package/dist/turso/tursoDialect.js +2 -0
  85. package/dist/type/config.d.ts +2 -2
  86. package/dist/type/dialect.d.ts +4 -5
  87. package/dist/type/entity.d.ts +2 -1
  88. package/dist/type/migratorDialect.d.ts +4 -0
  89. package/dist/type/querier.d.ts +6 -6
  90. package/dist/type/query.d.ts +25 -48
  91. package/dist/type/query.js +10 -5
  92. package/dist/type/queryAggregate.d.ts +10 -10
  93. package/dist/type/queryAggregate.js +1 -1
  94. package/dist/type/universalQuerier.d.ts +4 -4
  95. package/dist/util/dialect.util.d.ts +8 -2
  96. package/dist/util/dialect.util.js +19 -0
  97. package/dist/util/field.util.d.ts +5 -0
  98. package/dist/util/field.util.js +19 -0
  99. package/dist/util/logger.d.ts +10 -1
  100. package/dist/util/logger.js +18 -0
  101. package/dist/util/object.util.d.ts +4 -0
  102. package/dist/util/object.util.js +8 -0
  103. package/dist/util/relationQuery.util.d.ts +15 -68
  104. package/dist/util/relationQuery.util.js +35 -83
  105. package/dist/util/rowKey.util.d.ts +1 -11
  106. package/dist/util/rowKey.util.js +1 -13
  107. package/package.json +1 -1
  108. package/dist/querier/relationCount.d.ts +0 -16
  109. package/dist/querier/relationCount.js +0 -121
@@ -24,11 +24,8 @@ export class MysqlSchemaIntrospector extends AbstractSqlSchemaIntrospector {
24
24
  `;
25
25
  }
26
26
  parseTableExistsResult(results) {
27
- const row = results[0];
28
- if (row?.count !== undefined) {
29
- return (this.toNumber(row.count) ?? 0) > 0;
30
- }
31
- return false;
27
+ // No row, or no count in it, reads as `NaN`, which is not above zero.
28
+ return Number(results[0]?.count) > 0;
32
29
  }
33
30
  getColumnsQuery(_tableName) {
34
31
  return /*sql*/ `
@@ -97,7 +94,7 @@ export class MysqlSchemaIntrospector extends AbstractSqlSchemaIntrospector {
97
94
  async mapColumnsResult(_read, _tableName, results) {
98
95
  return results.map((row) => ({
99
96
  name: row.column_name,
100
- type: (row.column_type || '').toUpperCase(),
97
+ type: row.column_type.toUpperCase(),
101
98
  nullable: row.is_nullable === 'YES',
102
99
  defaultValue: this.parseDefaultValue(row.column_default),
103
100
  isPrimaryKey: row.column_key === 'PRI',
@@ -122,8 +119,8 @@ export class MysqlSchemaIntrospector extends AbstractSqlSchemaIntrospector {
122
119
  async mapForeignKeysResult(_read, _tableName, results) {
123
120
  return results.map((row) => ({
124
121
  name: row.constraint_name,
125
- columns: (row.columns || '').split(','),
126
- references: { table: row.referenced_table, columns: (row.referenced_columns || '').split(',') },
122
+ columns: row.columns.split(','),
123
+ references: { table: row.referenced_table, columns: row.referenced_columns.split(',') },
127
124
  onDelete: this.normalizeReferentialAction(row.delete_rule),
128
125
  onUpdate: this.normalizeReferentialAction(row.update_rule),
129
126
  }));
@@ -22,11 +22,8 @@ export class SqliteSchemaIntrospector extends AbstractSqlSchemaIntrospector {
22
22
  `;
23
23
  }
24
24
  parseTableExistsResult(results) {
25
- const row = results[0];
26
- if (row?.count !== undefined) {
27
- return (this.toNumber(row.count) ?? 0) > 0;
28
- }
29
- return false;
25
+ // No row, or no count in it, reads as `NaN`, which is not above zero.
26
+ return Number(results[0]?.count) > 0;
30
27
  }
31
28
  /**
32
29
  * `table_xinfo`, not `table_info`: the latter omits generated columns entirely, so a table carrying
@@ -1,4 +1,4 @@
1
- import type { DialectName, LoggingOptions, Migration, MigrationDefinition, MigrationResult, MigrationStorage, MigratorOptions, MongoQuerier, Querier, QuerierPool, SchemaDiff, SchemaGenerator, SchemaIntrospector, SyncOptions, Type } from '../type/index.js';
1
+ import type { DialectName, LoggingOptions, Migration, MigrationDefinition, MigrationResult, MigrationStorage, MigratorDialect, MigratorOptions, MongoQuerier, Querier, QuerierPool, SchemaDiff, SchemaGenerator, SchemaIntrospector, SyncOptions, Type } from '../type/index.js';
2
2
  import { LoggerWrapper } from '../util/index.js';
3
3
  import type { IMigrationBuilder } from './builder/types.js';
4
4
  /**
@@ -18,9 +18,12 @@ export declare class Migrator {
18
18
  schemaIntrospector?: SchemaIntrospector;
19
19
  private readonly _defaultForeignKeyAction?;
20
20
  private _mongoSchemaLoadPromise?;
21
- constructor(pool: QuerierPool, options?: MigratorOptions);
22
- /** Loads MongoDB schema generator on first use; SQL generators are set in the constructor (or via {@link setSchemaGenerator}). */
23
- private ensureSchemaGenerator;
21
+ constructor(pool: QuerierPool<Querier, MigratorDialect>, options?: MigratorOptions);
22
+ /**
23
+ * Loads MongoDB's schema generator on first use, so the optional `mongodb` peer loads only then. SQL
24
+ * generators are set in the constructor (or via {@link setSchemaGenerator}).
25
+ */
26
+ ensureSchemaGenerator(): Promise<void>;
24
27
  /**
25
28
  * Set the schema generator for DDL operations
26
29
  */
@@ -10,7 +10,6 @@ import { buildSqlQuerierMigrationModule, EMPTY_MANUAL_MIGRATION_DOWN_INNER, EMPT
10
10
  import { runMongoCommand } from './generator/mongoCommand.js';
11
11
  import { introspectorFor } from './introspection/registry.js';
12
12
  import { createSchemaGenerator } from './schemaGenerator.js';
13
- import { createSchemaGeneratorAsync } from './schemaGeneratorAsync.js';
14
13
  import { DatabaseMigrationStorage } from './storage/databaseStorage.js';
15
14
  /**
16
15
  * Main class for managing database migrations
@@ -37,7 +36,7 @@ export class Migrator {
37
36
  _mongoSchemaLoadPromise;
38
37
  constructor(pool, options = {}) {
39
38
  this.pool = pool;
40
- this.dialectName = pool.dialect.dialectName ?? 'postgres';
39
+ this.dialectName = pool.dialect.dialectName;
41
40
  this._defaultForeignKeyAction = options.defaultForeignKeyAction;
42
41
  this.storage =
43
42
  options.storage ??
@@ -51,18 +50,17 @@ export class Migrator {
51
50
  this.schemaGenerator =
52
51
  options.schemaGenerator ?? (this.dialectName === 'mongodb' ? undefined : this.createGenerator());
53
52
  }
54
- /** Loads MongoDB schema generator on first use; SQL generators are set in the constructor (or via {@link setSchemaGenerator}). */
53
+ /**
54
+ * Loads MongoDB's schema generator on first use, so the optional `mongodb` peer loads only then. SQL
55
+ * generators are set in the constructor (or via {@link setSchemaGenerator}).
56
+ */
55
57
  async ensureSchemaGenerator() {
56
58
  if (this.schemaGenerator || this.dialectName !== 'mongodb') {
57
59
  return;
58
60
  }
59
- if (!this._mongoSchemaLoadPromise) {
60
- this._mongoSchemaLoadPromise = createSchemaGeneratorAsync(this.pool.dialect, this._defaultForeignKeyAction).then((gen) => {
61
- if (gen) {
62
- this.schemaGenerator = gen;
63
- }
64
- });
65
- }
61
+ this._mongoSchemaLoadPromise ??= import('./generator/mongoSchemaGenerator.js').then(({ MongoSchemaGenerator }) => {
62
+ this.schemaGenerator = new MongoSchemaGenerator(this.pool.dialect.namingStrategy, this._defaultForeignKeyAction);
63
+ });
66
64
  await this._mongoSchemaLoadPromise;
67
65
  }
68
66
  /**
@@ -302,12 +300,9 @@ export class Migrator {
302
300
  }
303
301
  async findEntityForTable(tableName) {
304
302
  await this.ensureSchemaGenerator();
305
- if (!this.schemaGenerator) {
306
- return undefined;
307
- }
308
303
  for (const entity of this.entities) {
309
304
  const meta = getMeta(entity);
310
- const name = this.schemaGenerator.resolveTableName(meta);
305
+ const name = this.generator.resolveTableName(meta);
311
306
  if (name === tableName) {
312
307
  return entity;
313
308
  }
@@ -1,8 +1,8 @@
1
- import { type AbstractDialect, AbstractSqlDialect } from '../dialect/index.js';
1
+ import type { AbstractSqlDialect } from '../dialect/index.js';
2
2
  import type { SchemaAST } from '../schema/schemaAST.js';
3
3
  import { type DiffOptions } from '../schema/schemaASTDiffer.js';
4
4
  import type { CanonicalType, ColumnNode, ForeignKeyAction, IndexNode, TableNode } from '../schema/types.js';
5
- import type { ColumnSchema, CreateSchemaOptions, DialectFeatures, DropSchemaOptions, EntityMeta, FieldMeta, FieldOptions, ForeignKeySchema, IndexSchema, NamingStrategy, SchemaDiff, SchemaGenerator, SqlDdlGenerator, Type } from '../type/index.js';
5
+ import type { ColumnSchema, CreateSchemaOptions, DialectFeatures, DropSchemaOptions, EntityMeta, FieldMeta, FieldOptions, ForeignKeySchema, IndexSchema, MigratorDialect, NamingStrategy, SchemaDiff, SchemaGenerator, SqlDdlGenerator, Type } from '../type/index.js';
6
6
  import type { FullColumnDefinition, TableDefinition } from './builder/types.js';
7
7
  import { type IndexDdl, type TableDdl } from './ddl/index.js';
8
8
  /**
@@ -222,4 +222,4 @@ export declare function buildEntityAST(generator: Pick<SchemaGenerator, 'resolve
222
222
  * Synchronous factory for SQL schema generators only.
223
223
  * For MongoDB, use `createSchemaGeneratorAsync` from `./schemaGeneratorAsync.js` so the optional `mongodb` peer is not loaded at import time.
224
224
  */
225
- export declare function createSchemaGenerator(dialect: AbstractDialect, defaultForeignKeyAction?: ForeignKeyAction): SqlSchemaGenerator | undefined;
225
+ export declare function createSchemaGenerator(dialect: MigratorDialect, defaultForeignKeyAction?: ForeignKeyAction): SqlSchemaGenerator | undefined;
@@ -1,6 +1,5 @@
1
- import { AbstractSqlDialect } from '../dialect/index.js';
2
1
  import { getMeta, soleIdOf } from '../entity/index.js';
3
- import { areTypesEqual, canonicalToSql, engineType, fieldOptionsToCanonical, isVectorCategory, } from '../schema/canonicalType.js';
2
+ import { canonicalToSql, engineType, fieldOptionsToCanonical, isVectorCategory } from '../schema/canonicalType.js';
4
3
  import { indexSignature } from '../schema/indexDifferences.js';
5
4
  import { buildSchemaAST } from '../schema/schemaASTBuilder.js';
6
5
  import { diffRelationshipNodes, diffTable } from '../schema/schemaASTDiffer.js';
@@ -474,8 +473,6 @@ export class SqlSchemaGenerator {
474
473
  if (current == null || desired == null)
475
474
  return current == null && desired == null;
476
475
  const normalize = (value) => {
477
- if (value === null)
478
- return 'null';
479
476
  // Render first: the desired side may be a symbolic expression, the current side is always the
480
477
  // engine's own text, and `{"kind":"now"}` matches no spelling of `CURRENT_TIMESTAMP`.
481
478
  const val = SqlExpression.isExpression(value) ? formatDefaultValue(value, this.dialect) : value;
@@ -518,10 +515,8 @@ export class SqlSchemaGenerator {
518
515
  constraints.push(`CONSTRAINT ${this.escapeId(name)} CHECK (${check.expression})`);
519
516
  });
520
517
  for (const rel of table.outgoingRelations) {
521
- if (rel.from.columns.length > 0) {
522
- const refTable = this.dialect.escapeQualifiedId(rel.to.table.name, rel.to.table.schema);
523
- constraints.push(this.foreignKeyConstraint(table.name, foreignKeyOf(rel), refTable));
524
- }
518
+ const refTable = this.dialect.escapeQualifiedId(rel.to.table.name, rel.to.table.schema);
519
+ constraints.push(this.foreignKeyConstraint(table.name, foreignKeyOf(rel), refTable));
525
520
  }
526
521
  const ifNotExists = options.ifNotExists && this.features.ifNotExists ? 'IF NOT EXISTS ' : '';
527
522
  let createSql = `CREATE TABLE ${ifNotExists}${this.dialect.escapeQualifiedId(table.name, table.schema)} (\n`;
@@ -547,8 +542,10 @@ export class SqlSchemaGenerator {
547
542
  }
548
543
  statements.push(createSql);
549
544
  statements.push(...this.generateCommentStatements(table));
545
+ // A table created only if missing creates its indexes the same way, or re-creating a schema fails on the first.
546
+ const indexOptions = { ifNotExists: !!options.ifNotExists && this.features.indexIfNotExists };
550
547
  for (const idx of table.indexes) {
551
- statements.push(this.generateCreateIndexFromNode(idx));
548
+ statements.push(this.generateCreateIndexFromNode(idx, indexOptions));
552
549
  }
553
550
  return statements;
554
551
  }
@@ -730,8 +727,5 @@ export function buildEntityAST(generator, entities, defaultForeignKeyAction) {
730
727
  * For MongoDB, use `createSchemaGeneratorAsync` from `./schemaGeneratorAsync.js` so the optional `mongodb` peer is not loaded at import time.
731
728
  */
732
729
  export function createSchemaGenerator(dialect, defaultForeignKeyAction) {
733
- if (!(dialect instanceof AbstractSqlDialect)) {
734
- return undefined;
735
- }
736
- return new SqlSchemaGenerator(dialect, defaultForeignKeyAction);
730
+ return dialect.dialectName === 'mongodb' ? undefined : new SqlSchemaGenerator(dialect, defaultForeignKeyAction);
737
731
  }
@@ -1,8 +1,7 @@
1
- import type { AbstractDialect } from '../dialect/abstractDialect.js';
2
1
  import type { ForeignKeyAction } from '../schema/types.js';
3
- import type { SchemaGenerator } from '../type/index.js';
2
+ import type { MigratorDialect, SchemaGenerator } from '../type/index.js';
4
3
  /**
5
4
  * Async factory for schema generators. Use this for MongoDB so the optional peer
6
5
  * `mongodb` is only loaded when this path runs. SQL dialects delegate to {@link createSchemaGenerator}.
7
6
  */
8
- export declare function createSchemaGeneratorAsync(dialect: AbstractDialect, defaultForeignKeyAction?: ForeignKeyAction): Promise<SchemaGenerator | undefined>;
7
+ export declare function createSchemaGeneratorAsync(dialect: MigratorDialect, defaultForeignKeyAction?: ForeignKeyAction): Promise<SchemaGenerator | undefined>;
@@ -65,16 +65,18 @@ export declare class MongoDialect extends AbstractDialect {
65
65
  */
66
66
  private appendRelationLookup;
67
67
  /**
68
- * The correlated `$lookup` for one relation, as `temp`: through its junction for a ManyToMany, or
69
- * straight at the target otherwise. `tail` decides what the lookup leaves behind - a row to test
70
- * for existence, or a `$count` - so a filter and an ordering build the same stage.
68
+ * The correlated `$lookup` for the target rows of one relation `where` narrows, as `temp`: straight at
69
+ * the target, or for a many-to-many from inside its junction's rows. The caller's filter bypass is not
70
+ * passed down, as on the SQL dialects. `tail` decides what the lookup leaves behind - a row to test for
71
+ * existence, or a `$count` - so a filter and an ordering build the same stage.
71
72
  */
72
73
  private relationLookup;
73
74
  /**
74
- * ManyToMany counts/tests junction rows, so the target is reached from inside the junction's own
75
- * lookup - the junction's filters apply too, since a soft-deleted link is not a link.
75
+ * The junction a many-to-many reaches its targets through: the lookup keys matching a parent's rows of
76
+ * it, its own filters, since a soft-deleted link is not a link, and the field holding each target's id.
77
+ * Each end is one field matched against one `_id`, so both sides must be sole-keyed.
76
78
  */
77
- private junctionLookup;
79
+ private junctionOf;
78
80
  /**
79
81
  * Compares the looked-up row count, which is `[{ n: <count> }]` or `[]` when nothing matched - hence
80
82
  * the `$ifNull` fallback to 0, so `{ $size: 0 }` matches parents with no related row at all.
@@ -99,7 +101,7 @@ export declare class MongoDialect extends AbstractDialect {
99
101
  protected mapTableNameRow(row: {
100
102
  table_name: string;
101
103
  }): string;
102
- /** String operators → { pattern: (v) => regex, caseInsensitive } */
104
+ /** String operators -> { pattern: (v) => regex, caseInsensitive } */
103
105
  private static readonly REGEX_OP_MAP;
104
106
  /** MongoDB native operators - pass through as-is. */
105
107
  private static readonly NATIVE_OPS;
@@ -127,10 +129,26 @@ export declare class MongoDialect extends AbstractDialect {
127
129
  * per parent, and the `$set` that lifts the tally onto the document as the field the `$sort` then
128
130
  * orders by. A parent with no related row gets no lookup result at all, which is a zero.
129
131
  */
130
- sortCountStages<E extends Document>(entity: Type<E>, sort: QuerySortMap<E> | undefined, opts?: QueryOptions): {
132
+ sortCountStages<E extends Document>(entity: Type<E>, sort: QuerySortMap<E> | undefined): {
131
133
  readonly stages: MongoAggregationPipelineEntry<Document>[];
132
134
  readonly fields: string[];
133
135
  };
136
+ /** The correlated lookup counting a relation's rows, which `where` narrows, into `temp`. */
137
+ private tallyLookup;
138
+ /** The tally a lookup left in `temp`, which holds no row at all where nothing matched: a zero. */
139
+ private tally;
140
+ /**
141
+ * The lookups reading each to-many a query populates, and the tally of each `$count`, onto the fields
142
+ * its rows answer under, and the fields they parked a junction's pairings or a tally on taken back out.
143
+ * [The design](../../../../architecture/relations-in-one-statement.md).
144
+ */
145
+ private relationReadStages;
146
+ /**
147
+ * A to-many's rows as a lookup running their own read, whose filters, ordering and page apply per
148
+ * parent inside it. A many-to-many reads its targets, each once, by the ids its junction pairs the
149
+ * parent with, parked in a temporary field of the parent's.
150
+ */
151
+ private toManyLookup;
134
152
  /** Whether a `$sort` reads a relation, which is what forces the lookups to run before it. */
135
153
  sortsRelations<E extends Document>(entity: Type<E>, sort: QuerySortMap<E> | undefined): boolean;
136
154
  /**
@@ -152,7 +170,7 @@ export declare class MongoDialect extends AbstractDialect {
152
170
  * Shared by the plain pipeline and the `$vectorSearch` one, which each used to spell the order out
153
171
  * for themselves and each got a different part of it wrong.
154
172
  */
155
- readStages<E extends Document>(entity: Type<E>, q: Query<E>, opts?: QueryOptions, extra?: MongoReadStages): MongoAggregationPipelineEntry<Document>[];
173
+ readStages<E extends Document>(entity: Type<E>, q: Query<E>, extra?: MongoReadStages): MongoAggregationPipelineEntry<Document>[];
156
174
  /**
157
175
  * `$distinct` as a `$group` on the columns the query projects - the same set a SQL dialect puts
158
176
  * after `SELECT DISTINCT` - and the `$replaceRoot` that lifts the grouped key back to the top
@@ -162,16 +180,11 @@ export declare class MongoDialect extends AbstractDialect {
162
180
  private distinctStages;
163
181
  /**
164
182
  * The scalar projection a narrowing query asks for, widened by what the pipeline itself produced:
165
- * the joined documents, and the `_id` a to-many fill groups children by. It goes last, after the
166
- * lookups have read the join keys - projecting any earlier is what used to leave `$populate`
167
- * empty, and is why the pipeline emitted no projection at all and returned every column.
183
+ * each populated relation and the tallies. It goes last, after the lookups have read the join keys -
184
+ * projecting any earlier is what used to leave `$populate` empty, and is why the pipeline emitted no
185
+ * projection at all and returned every column.
168
186
  */
169
187
  pipelineProjection<E extends Document>(entity: Type<E>, q: Query<E>): Record<string, 0 | 1> | undefined;
170
- /**
171
- * `$lookup`/`$unwind` stages for the joinable relations a query populates. Shared by the plain
172
- * aggregation pipeline and the `$vectorSearch` one, so relations load the same way in both.
173
- */
174
- relationStages<E extends Document>(entity: Type<E>, q: Query<E>, opts?: QueryOptions): MongoAggregationPipelineEntry<E>[];
175
188
  /**
176
189
  * The `$lookup`/`$unwind` pair for each relation joined below `parent`, its own relations nested
177
190
  * inside its pipeline and resolved before the projection that reads them.
@@ -187,7 +200,7 @@ export declare class MongoDialect extends AbstractDialect {
187
200
  /** `[column, key]` for the fields whose stored name differs from their property name, memoized per entity. */
188
201
  private renamedColumns;
189
202
  private referenceKeys;
190
- normalizeIds<E extends Document>(meta: EntityMeta<E>, docs: Document[] | undefined): E[] | undefined;
203
+ normalizeIds<E extends Document>(meta: EntityMeta<E>, docs: Document[]): E[];
191
204
  /** `doc` is the wire shape - `_id`, stored names, `ObjectId`s - and what comes back is the code's. */
192
205
  normalizeId<E extends Document>(meta: EntityMeta<E>, doc: Document | undefined): E | undefined;
193
206
  /**