@mikro-orm/knex 6.0.0-dev.176 → 6.0.0-dev.178

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/knex",
3
- "version": "6.0.0-dev.176",
3
+ "version": "6.0.0-dev.178",
4
4
  "description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
5
5
  "main": "index.js",
6
6
  "module": "index.mjs",
@@ -66,6 +66,6 @@
66
66
  "@mikro-orm/core": "^5.9.2"
67
67
  },
68
68
  "peerDependencies": {
69
- "@mikro-orm/core": "6.0.0-dev.176"
69
+ "@mikro-orm/core": "6.0.0-dev.178"
70
70
  }
71
71
  }
@@ -1,4 +1,4 @@
1
- import { type Dictionary, type EntityMetadata, type EntityProperty, type NamingStrategy, type Configuration } from '@mikro-orm/core';
1
+ import { type Configuration, type Dictionary, type EntityMetadata, type EntityProperty, type MikroORMOptions, type NamingStrategy } from '@mikro-orm/core';
2
2
  import type { SchemaHelper } from './SchemaHelper';
3
3
  import type { CheckDef, Column, ForeignKey, IndexDef } from '../typings';
4
4
  import type { AbstractSqlPlatform } from '../AbstractSqlPlatform';
@@ -25,7 +25,11 @@ export declare class DatabaseTable {
25
25
  addColumn(column: Column): void;
26
26
  addColumnFromProperty(prop: EntityProperty, meta: EntityMetadata, config: Configuration): void;
27
27
  private getIndexName;
28
- getEntityDeclaration(namingStrategy: NamingStrategy, schemaHelper: SchemaHelper): EntityMetadata;
28
+ getEntityDeclaration(namingStrategy: NamingStrategy, schemaHelper: SchemaHelper, scalarPropertiesForRelations: NonNullable<MikroORMOptions['entityGenerator']['scalarPropertiesForRelations']>): EntityMetadata;
29
+ private foreignKeysToProps;
30
+ private findFkIndex;
31
+ private getIndexProperties;
32
+ private getSafeBaseNameForFkProp;
29
33
  /**
30
34
  * The shortest name is stripped of the default namespace. All other namespaced elements are returned as full-qualified names.
31
35
  */
@@ -38,10 +42,12 @@ export declare class DatabaseTable {
38
42
  hasCheck(checkName: string): boolean;
39
43
  getPrimaryKey(): IndexDef | undefined;
40
44
  hasPrimaryKey(): boolean;
45
+ private getForeignKeyDeclaration;
41
46
  private getPropertyDeclaration;
42
47
  private getReferenceKind;
43
48
  private getPropertyName;
44
- private getPropertyType;
49
+ private getPropertyTypeForForeignKey;
50
+ private getPropertyTypeForColumn;
45
51
  private getPropertyDefaultValue;
46
52
  addIndex(meta: EntityMetadata, index: {
47
53
  properties: string | string[];
@@ -105,7 +105,7 @@ class DatabaseTable {
105
105
  });
106
106
  if ([core_1.ReferenceKind.MANY_TO_ONE, core_1.ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
107
107
  const constraintName = this.getIndexName(true, prop.fieldNames, 'foreign');
108
- let schema = prop.targetMeta.schema === '*' ? this.schema : (prop.targetMeta.schema ?? config.get('schema', this.platform.getDefaultSchemaName()));
108
+ let schema = prop.targetMeta.root.schema === '*' ? this.schema : (prop.targetMeta.root.schema ?? config.get('schema', this.platform.getDefaultSchemaName()));
109
109
  if (prop.referencedTableName.includes('.')) {
110
110
  schema = undefined;
111
111
  }
@@ -151,40 +151,281 @@ class DatabaseTable {
151
151
  }
152
152
  return this.platform.getIndexName(this.name, columnNames, type);
153
153
  }
154
- getEntityDeclaration(namingStrategy, schemaHelper) {
154
+ getEntityDeclaration(namingStrategy, schemaHelper, scalarPropertiesForRelations) {
155
+ const { fksOnColumnProps, fksOnStandaloneProps, columnFks, fkIndexes, nullableForeignKeys, skippedColumnNames, } = this.foreignKeysToProps(namingStrategy, scalarPropertiesForRelations);
155
156
  let name = namingStrategy.getClassName(this.name, '_');
156
157
  name = name.match(/^\d/) ? 'E' + name : name;
157
158
  const schema = new core_1.EntitySchema({ name, collection: this.name, schema: this.schema });
158
159
  const compositeFkIndexes = {};
159
160
  const compositeFkUniques = {};
160
- for (const index of this.indexes.filter(index => index.columnNames.length > 1)) {
161
- const properties = index.columnNames.map(col => this.getPropertyName(namingStrategy, this.getColumn(col)));
162
- const ret = { name: index.keyName, properties: core_1.Utils.unique(properties) };
163
- if (ret.properties.length === 1) {
161
+ const potentiallyUnmappedIndexes = this.indexes.filter(index => !index.primary // Skip primary index. Whether it's in use by scalar column or FK, it's already mapped.
162
+ && (index.columnNames.length > 1 // All composite indexes are to be mapped to entity decorators or FK props.
163
+ || !(index.columnNames[0] in columnFks) // Non-composite indexes for scalar props are to be mapped to the column.
164
+ || skippedColumnNames.includes(index.columnNames[0]) // Non-composite indexes for skipped columns are to be mapped as entity decorators.
165
+ ));
166
+ for (const index of potentiallyUnmappedIndexes) {
167
+ const ret = { name: index.keyName };
168
+ // Index is for FK. Map to the FK prop and move on.
169
+ const fkForIndex = fkIndexes.get(index);
170
+ if (fkForIndex) {
171
+ ret.properties = [this.getPropertyName(namingStrategy, fkForIndex.baseName, fkForIndex.fk)];
164
172
  const map = index.unique ? compositeFkUniques : compositeFkIndexes;
165
173
  map[ret.properties[0]] = { keyName: index.keyName };
166
174
  continue;
167
175
  }
168
- if (index.primary) {
169
- //
176
+ const properties = this.getIndexProperties(index, columnFks, fksOnColumnProps, fksOnStandaloneProps, namingStrategy);
177
+ // If there is a column that cannot be unambiguously mapped to a prop, render an expression.
178
+ if (typeof properties === 'undefined') {
179
+ ret.expression = schemaHelper.getCreateIndexSQL(this.name, index);
170
180
  }
171
- else if (index.unique) {
181
+ else {
182
+ ret.properties = properties;
183
+ // If the index is for one property that is not a FK prop, map to the column prop and move on.
184
+ if (properties.length === 1 && !fksOnStandaloneProps.has(properties[0])) {
185
+ const map = index.unique ? compositeFkUniques : compositeFkIndexes;
186
+ map[properties[0]] = { keyName: index.keyName };
187
+ continue;
188
+ }
189
+ }
190
+ // Composite indexes that aren't exclusively mapped to FK props get an entity decorator.
191
+ if (index.unique) {
172
192
  schema.addUnique(ret);
193
+ continue;
173
194
  }
174
- else {
175
- schema.addIndex(ret);
195
+ schema.addIndex(ret);
196
+ }
197
+ const addedStandaloneFkPropsBasedOnColumn = new Set;
198
+ const nonSkippedColumns = this.getColumns().filter(column => !skippedColumnNames.includes(column.name));
199
+ for (const column of nonSkippedColumns) {
200
+ const columnName = column.name;
201
+ const standaloneFkPropBasedOnColumn = fksOnStandaloneProps.get(columnName);
202
+ if (standaloneFkPropBasedOnColumn && !fksOnColumnProps.get(columnName)) {
203
+ addedStandaloneFkPropsBasedOnColumn.add(columnName);
204
+ const [fkIndex, currentFk] = standaloneFkPropBasedOnColumn;
205
+ const prop = this.getForeignKeyDeclaration(currentFk, namingStrategy, schemaHelper, fkIndex, nullableForeignKeys.has(currentFk), columnName);
206
+ schema.addProperty(prop.name, prop.type, prop);
176
207
  }
208
+ const prop = this.getPropertyDeclaration(column, namingStrategy, schemaHelper, compositeFkIndexes, compositeFkUniques, columnFks, fksOnColumnProps.get(columnName));
209
+ schema.addProperty(prop.name, prop.type, prop);
177
210
  }
178
- for (const column of this.getColumns()) {
179
- const prop = this.getPropertyDeclaration(column, namingStrategy, schemaHelper, compositeFkIndexes, compositeFkUniques);
211
+ for (const [propBaseName, [fkIndex, currentFk]] of fksOnStandaloneProps.entries()) {
212
+ if (addedStandaloneFkPropsBasedOnColumn.has(propBaseName)) {
213
+ continue;
214
+ }
215
+ const prop = this.getForeignKeyDeclaration(currentFk, namingStrategy, schemaHelper, fkIndex, nullableForeignKeys.has(currentFk), propBaseName);
180
216
  schema.addProperty(prop.name, prop.type, prop);
181
217
  }
182
218
  const meta = schema.init().meta;
183
- meta.relations
184
- .filter(prop => prop.primary && prop.kind === core_1.ReferenceKind.MANY_TO_ONE && !meta.compositePK)
185
- .forEach(prop => prop.kind = core_1.ReferenceKind.ONE_TO_ONE);
219
+ const oneToOneCandidateProperties = meta.relations
220
+ .filter(prop => prop.primary && prop.kind === core_1.ReferenceKind.MANY_TO_ONE);
221
+ if (oneToOneCandidateProperties.length === 1
222
+ && oneToOneCandidateProperties[0].fieldNames.length === (new Set(meta.getPrimaryProps().flatMap(prop => prop.fieldNames))).size) {
223
+ oneToOneCandidateProperties[0].kind = core_1.ReferenceKind.ONE_TO_ONE;
224
+ }
186
225
  return meta;
187
226
  }
227
+ foreignKeysToProps(namingStrategy, scalarPropertiesForRelations) {
228
+ const fks = Object.values(this.getForeignKeys());
229
+ const fksOnColumnProps = new Map();
230
+ const fksOnStandaloneProps = new Map();
231
+ const columnFks = {};
232
+ const fkIndexes = new Map();
233
+ const nullableForeignKeys = new Set();
234
+ for (const currentFk of fks) {
235
+ const fkIndex = this.findFkIndex(currentFk);
236
+ if (currentFk.columnNames.length === 1 && !fks.some(fk => fk !== currentFk && fk.columnNames.length === 1 && currentFk.columnNames[0] === fk.columnNames[0])) {
237
+ // Non-composite FK is the only possible one for a column. Render the column with it.
238
+ const columnName = currentFk.columnNames[0];
239
+ columnFks[columnName] ??= [];
240
+ columnFks[columnName].push(currentFk);
241
+ if (this.getColumn(columnName)?.nullable) {
242
+ nullableForeignKeys.add(currentFk);
243
+ }
244
+ if (scalarPropertiesForRelations === 'always') {
245
+ const baseName = this.getSafeBaseNameForFkProp(namingStrategy, currentFk, fks, columnName);
246
+ fksOnStandaloneProps.set(baseName, [fkIndex, currentFk]);
247
+ fkIndexes.set(fkIndex, { fk: currentFk, baseName });
248
+ }
249
+ else {
250
+ fksOnColumnProps.set(columnName, currentFk);
251
+ fkIndexes.set(fkIndex, { fk: currentFk, baseName: columnName });
252
+ }
253
+ continue;
254
+ }
255
+ const specificColumnNames = [];
256
+ const nullableColumnsInFk = [];
257
+ for (const columnName of currentFk.columnNames) {
258
+ columnFks[columnName] ??= [];
259
+ columnFks[columnName].push(currentFk);
260
+ if (!fks.some(fk => fk !== currentFk && fk.columnNames.includes(columnName))) {
261
+ specificColumnNames.push(columnName);
262
+ }
263
+ if (this.getColumn(columnName)?.nullable) {
264
+ nullableColumnsInFk.push(columnName);
265
+ }
266
+ }
267
+ if (nullableColumnsInFk.length > 0) {
268
+ nullableForeignKeys.add(currentFk);
269
+ }
270
+ if (specificColumnNames.length === 1 && ((nullableColumnsInFk.length === currentFk.columnNames.length || nullableColumnsInFk.length === 0) || (nullableColumnsInFk.length === 1 && nullableColumnsInFk[0] === specificColumnNames[0]))) {
271
+ // Composite FK has exactly one column which is not used in any other FK.
272
+ // The FK also doesn't have a mix of nullable and non-nullable columns,
273
+ // or its only nullable column is this very one.
274
+ // It is safe to just render this FK attached to the specific column.
275
+ const columnName = specificColumnNames[0];
276
+ if (scalarPropertiesForRelations === 'always') {
277
+ const baseName = this.getSafeBaseNameForFkProp(namingStrategy, currentFk, fks, columnName);
278
+ fksOnStandaloneProps.set(baseName, [fkIndex, currentFk]);
279
+ fkIndexes.set(fkIndex, { fk: currentFk, baseName });
280
+ }
281
+ else {
282
+ fksOnColumnProps.set(columnName, currentFk);
283
+ fkIndexes.set(fkIndex, { fk: currentFk, baseName: columnName });
284
+ }
285
+ continue;
286
+ }
287
+ if (specificColumnNames.length === currentFk.columnNames.length) {
288
+ // All columns involved with this FK are only covered by this one FK.
289
+ if (nullableColumnsInFk.length <= 1) {
290
+ // Also, this FK is either not nullable, or has only one nullable column.
291
+ // It is safe to name the FK after the nullable column, or any non-nullable one (the first one is picked).
292
+ const columnName = nullableColumnsInFk.at(0) ?? currentFk.columnNames[0];
293
+ if (scalarPropertiesForRelations === 'always') {
294
+ const baseName = this.getSafeBaseNameForFkProp(namingStrategy, currentFk, fks, columnName);
295
+ fksOnStandaloneProps.set(baseName, [fkIndex, currentFk]);
296
+ fkIndexes.set(fkIndex, { fk: currentFk, baseName });
297
+ }
298
+ else {
299
+ fksOnColumnProps.set(columnName, currentFk);
300
+ fkIndexes.set(fkIndex, { fk: currentFk, baseName: columnName });
301
+ }
302
+ continue;
303
+ }
304
+ // If the first nullable column's name with FK is different from the name without FK,
305
+ // name a standalone prop after the column, but treat the column prop itself as not having FK.
306
+ const columnName = nullableColumnsInFk[0];
307
+ const baseName = this.getSafeBaseNameForFkProp(namingStrategy, currentFk, fks, columnName);
308
+ fksOnStandaloneProps.set(baseName, [fkIndex, currentFk]);
309
+ fkIndexes.set(fkIndex, { fk: currentFk, baseName });
310
+ continue;
311
+ }
312
+ // FK is not unambiguously mappable to a column. Pick another name for a standalone FK prop.
313
+ const baseName = this.getSafeBaseNameForFkProp(namingStrategy, currentFk, fks);
314
+ fksOnStandaloneProps.set(baseName, [fkIndex, currentFk]);
315
+ fkIndexes.set(fkIndex, { fk: currentFk, baseName });
316
+ }
317
+ const columnsInFks = Object.keys(columnFks);
318
+ const skippingHandlers = {
319
+ // Never generate scalar props for composite keys,
320
+ // i.e. always skip columns if they are covered by foreign keys.
321
+ never: (column) => columnsInFks.includes(column.name) && !fksOnColumnProps.has(column.name),
322
+ // Always generate scalar props for composite keys,
323
+ // i.e. do not skip columns, even if they are covered by foreign keys.
324
+ always: (column) => false,
325
+ // Smart scalar props generation.
326
+ // Skips columns if they are covered by foreign keys.
327
+ // But also does not skip if the column is not nullable, and yet all involved FKs are nullable,
328
+ // or if one or more FKs involved has multiple nullable columns.
329
+ smart: (column) => {
330
+ return columnsInFks.includes(column.name)
331
+ && !fksOnColumnProps.has(column.name)
332
+ && (column.nullable
333
+ ? columnFks[column.name].some(fk => !fk.columnNames.some(fkColumnName => fkColumnName !== column.name && this.getColumn(fkColumnName)?.nullable))
334
+ : columnFks[column.name].some(fk => !nullableForeignKeys.has(fk)));
335
+ },
336
+ };
337
+ const skippedColumnNames = this.getColumns().filter(skippingHandlers[scalarPropertiesForRelations]).map(column => column.name);
338
+ return { fksOnColumnProps, fksOnStandaloneProps, columnFks, fkIndexes, nullableForeignKeys, skippedColumnNames };
339
+ }
340
+ findFkIndex(currentFk) {
341
+ const fkColumnsLength = currentFk.columnNames.length;
342
+ const possibleIndexes = this.indexes.filter(index => {
343
+ return index.columnNames.length >= fkColumnsLength && !currentFk.columnNames.some((columnName, i) => index.columnNames[i] !== columnName);
344
+ });
345
+ possibleIndexes.sort((a, b) => {
346
+ if (a.primary !== b.primary) {
347
+ return a.primary ? -1 : 1;
348
+ }
349
+ if (a.unique !== b.unique) {
350
+ return a.unique ? -1 : 1;
351
+ }
352
+ if (a.columnNames.length !== b.columnNames.length) {
353
+ return a.columnNames.length < b.columnNames.length ? -1 : 1;
354
+ }
355
+ return a.keyName.localeCompare(b.keyName);
356
+ });
357
+ return possibleIndexes[0];
358
+ }
359
+ getIndexProperties(index, columnFks, fksOnColumnProps, fksOnStandaloneProps, namingStrategy) {
360
+ const propBaseNames = new Set();
361
+ const columnNames = index.columnNames;
362
+ const l = columnNames.length;
363
+ for (let i = 0; i < l; ++i) {
364
+ const columnName = columnNames[i];
365
+ // The column is not involved with FKs.
366
+ // It has a prop named after it.
367
+ // Add it and move on.
368
+ if (!(columnName in columnFks)) {
369
+ propBaseNames.add(columnName);
370
+ continue;
371
+ }
372
+ // If the prop named after the column has a FK and the FK's columns are a subset of this index,
373
+ // include this prop and move on.
374
+ const columnPropFk = fksOnColumnProps.get(columnName);
375
+ if (columnPropFk && !columnPropFk.columnNames.some(fkColumnName => {
376
+ return !columnNames.includes(fkColumnName);
377
+ })) {
378
+ propBaseNames.add(columnName);
379
+ continue;
380
+ }
381
+ // If there is at least one standalone FK featuring this column,
382
+ // and all of its columns are a subset of this index,
383
+ // include that FK, and consider mapping of this column to a prop a success.
384
+ let propAdded = false;
385
+ for (const [propName, [, fk]] of fksOnStandaloneProps) {
386
+ if (!columnFks[columnName].includes(fk)) {
387
+ continue;
388
+ }
389
+ if (!fk.columnNames.some(fkColumnName => {
390
+ return !columnNames.includes(fkColumnName);
391
+ })) {
392
+ propBaseNames.add(propName);
393
+ propAdded = true;
394
+ }
395
+ }
396
+ if (propAdded) {
397
+ continue;
398
+ }
399
+ // If we have reached this point, it means the column is not mappable to a prop name.
400
+ // Break the whole prop creation.
401
+ return;
402
+ }
403
+ return Array.from(propBaseNames).map(baseName => this.getPropertyName(namingStrategy, baseName, fksOnColumnProps.get(baseName)));
404
+ }
405
+ getSafeBaseNameForFkProp(namingStrategy, currentFk, fks, columnName) {
406
+ if (columnName && this.getPropertyName(namingStrategy, columnName, currentFk) !== this.getPropertyName(namingStrategy, columnName)) {
407
+ // The eligible scalar column name is different from the name of the FK prop of the same column.
408
+ // Both can be safely rendered.
409
+ // Use the column name as a base for the FK prop.
410
+ return columnName;
411
+ }
412
+ if (!fks.some(fk => fk !== currentFk && fk.referencedTableName === currentFk.referencedTableName) && !this.getColumn(currentFk.referencedTableName)) {
413
+ // FK is the only one in this table that references this other table.
414
+ // The name of the referenced table is not shared with a column in this table,
415
+ // so it is safe to output prop name based on the referenced entity.
416
+ return currentFk.referencedTableName;
417
+ }
418
+ // Any ambiguous FK is rendered with a name based on the FK constraint name
419
+ let finalPropBaseName = currentFk.constraintName;
420
+ while (this.getColumn(finalPropBaseName)) {
421
+ // In the unlikely event that the FK constraint name is shared by a column name, generate a name by
422
+ // continuously prefixing with "fk_", until a non-existent column is hit.
423
+ // The worst case scenario is a very long name with several repeated "fk_"
424
+ // that is not really a valid DB identifier but a valid JS variable name.
425
+ finalPropBaseName = `fk_${finalPropBaseName}`;
426
+ }
427
+ return finalPropBaseName;
428
+ }
188
429
  /**
189
430
  * The shortest name is stripped of the default namespace. All other namespaced elements are returned as full-qualified names.
190
431
  */
@@ -218,13 +459,48 @@ class DatabaseTable {
218
459
  hasPrimaryKey() {
219
460
  return !!this.getPrimaryKey();
220
461
  }
221
- getPropertyDeclaration(column, namingStrategy, schemaHelper, compositeFkIndexes, compositeFkUniques) {
222
- const fk = Object.values(this.foreignKeys).find(fk => fk.columnNames.includes(column.name));
223
- const prop = this.getPropertyName(namingStrategy, column);
462
+ getForeignKeyDeclaration(fk, namingStrategy, schemaHelper, fkIndex, nullable, propNameBase) {
463
+ const prop = this.getPropertyName(namingStrategy, propNameBase, fk);
464
+ const kind = (fkIndex.unique && !fkIndex.primary) ? this.getReferenceKind(fk, fkIndex) : this.getReferenceKind(fk);
465
+ const type = this.getPropertyTypeForForeignKey(namingStrategy, fk);
466
+ const fkOptions = {};
467
+ fkOptions.fieldNames = fk.columnNames;
468
+ fkOptions.referencedTableName = fk.referencedTableName;
469
+ fkOptions.referencedColumnNames = fk.referencedColumnNames;
470
+ fkOptions.updateRule = fk.updateRule?.toLowerCase();
471
+ fkOptions.deleteRule = fk.deleteRule?.toLowerCase();
472
+ const columnOptions = {};
473
+ if (fk.columnNames.length === 1) {
474
+ const column = this.getColumn(fk.columnNames[0]);
475
+ columnOptions.default = this.getPropertyDefaultValue(schemaHelper, column, type);
476
+ columnOptions.defaultRaw = this.getPropertyDefaultValue(schemaHelper, column, type, true);
477
+ columnOptions.nullable = column.nullable;
478
+ columnOptions.primary = column.primary;
479
+ columnOptions.length = column.length;
480
+ columnOptions.precision = column.precision;
481
+ columnOptions.scale = column.scale;
482
+ columnOptions.enum = !!column.enumItems?.length;
483
+ columnOptions.items = column.enumItems;
484
+ }
485
+ return {
486
+ name: prop,
487
+ type,
488
+ kind,
489
+ ...columnOptions,
490
+ nullable,
491
+ primary: fkIndex.primary || !fk.columnNames.some(columnName => !this.getPrimaryKey()?.columnNames.includes(columnName)),
492
+ index: !fkIndex.unique ? fkIndex.keyName : undefined,
493
+ unique: (fkIndex.unique && !fkIndex.primary) ? fkIndex.keyName : undefined,
494
+ ...fkOptions,
495
+ };
496
+ }
497
+ getPropertyDeclaration(column, namingStrategy, schemaHelper, compositeFkIndexes, compositeFkUniques, columnFks, fk) {
498
+ const prop = this.getPropertyName(namingStrategy, column.name, fk);
499
+ const persist = !(column.name in columnFks && typeof fk === 'undefined');
224
500
  const index = compositeFkIndexes[prop] || this.indexes.find(idx => idx.columnNames[0] === column.name && !idx.composite && !idx.unique && !idx.primary);
225
501
  const unique = compositeFkUniques[prop] || this.indexes.find(idx => idx.columnNames[0] === column.name && !idx.composite && idx.unique && !idx.primary);
226
502
  const kind = this.getReferenceKind(fk, unique);
227
- const type = this.getPropertyType(namingStrategy, column, fk);
503
+ const type = this.getPropertyTypeForColumn(namingStrategy, column, fk);
228
504
  const fkOptions = {};
229
505
  if (fk) {
230
506
  fkOptions.fieldNames = fk.columnNames;
@@ -241,7 +517,7 @@ class DatabaseTable {
241
517
  default: this.getPropertyDefaultValue(schemaHelper, column, type),
242
518
  defaultRaw: this.getPropertyDefaultValue(schemaHelper, column, type, true),
243
519
  nullable: column.nullable,
244
- primary: column.primary,
520
+ primary: column.primary && persist,
245
521
  fieldName: column.name,
246
522
  length: column.length,
247
523
  precision: column.precision,
@@ -250,6 +526,7 @@ class DatabaseTable {
250
526
  unique: unique ? unique.keyName : undefined,
251
527
  enum: !!column.enumItems?.length,
252
528
  items: column.enumItems,
529
+ persist,
253
530
  ...fkOptions,
254
531
  };
255
532
  }
@@ -262,19 +539,25 @@ class DatabaseTable {
262
539
  }
263
540
  return core_1.ReferenceKind.SCALAR;
264
541
  }
265
- getPropertyName(namingStrategy, column) {
266
- const fk = Object.values(this.foreignKeys).find(fk => fk.columnNames.includes(column.name));
267
- let field = column.name;
542
+ getPropertyName(namingStrategy, baseName, fk) {
543
+ let field = baseName;
268
544
  if (fk) {
269
- const idx = fk.columnNames.indexOf(column.name);
270
- field = field.replace(new RegExp(`_${fk.referencedColumnNames[idx]}$`), '');
545
+ const idx = fk.columnNames.indexOf(baseName);
546
+ let replacedFieldName = field.replace(new RegExp(`_${fk.referencedColumnNames[idx]}$`), '');
547
+ if (replacedFieldName === field) {
548
+ replacedFieldName = field.replace(new RegExp(`_${namingStrategy.referenceColumnName()}$`), '');
549
+ }
550
+ field = replacedFieldName;
271
551
  }
272
552
  return namingStrategy.columnNameToProperty(field);
273
553
  }
274
- getPropertyType(namingStrategy, column, fk) {
554
+ getPropertyTypeForForeignKey(namingStrategy, fk) {
555
+ const parts = fk.referencedTableName.split('.', 2);
556
+ return namingStrategy.getClassName(parts.length > 1 ? parts[1] : parts[0], '_');
557
+ }
558
+ getPropertyTypeForColumn(namingStrategy, column, fk) {
275
559
  if (fk) {
276
- const parts = fk.referencedTableName.split('.', 2);
277
- return namingStrategy.getClassName(parts.length > 1 ? parts[1] : parts[0], '_');
560
+ return this.getPropertyTypeForForeignKey(namingStrategy, fk);
278
561
  }
279
562
  // If this column is using an enum.
280
563
  if (column.enumItems?.length) {
@@ -84,7 +84,7 @@ class SchemaHelper {
84
84
  }
85
85
  tableName = this.platform.quoteIdentifier(tableName);
86
86
  const keyName = this.platform.quoteIdentifier(index.keyName);
87
- return `create index ${keyName} on ${tableName} (${index.columnNames.map(c => this.platform.quoteIdentifier(c)).join(', ')})`;
87
+ return `create ${index.unique ? 'unique ' : ''}index ${keyName} on ${tableName} (${index.columnNames.map(c => this.platform.quoteIdentifier(c)).join(', ')})`;
88
88
  }
89
89
  getDropIndexSQL(tableName, index) {
90
90
  return `drop index ${this.platform.quoteIdentifier(index.keyName)}`;