@mikro-orm/core 6.4.17-dev.9 → 6.4.17-dev.90

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 (54) hide show
  1. package/EntityManager.d.ts +11 -2
  2. package/EntityManager.js +37 -22
  3. package/README.md +1 -2
  4. package/connections/Connection.d.ts +4 -2
  5. package/connections/Connection.js +2 -2
  6. package/decorators/Entity.d.ts +14 -0
  7. package/decorators/Indexed.d.ts +2 -2
  8. package/decorators/Transactional.d.ts +1 -0
  9. package/decorators/Transactional.js +3 -3
  10. package/drivers/IDatabaseDriver.d.ts +4 -0
  11. package/entity/ArrayCollection.d.ts +3 -1
  12. package/entity/ArrayCollection.js +7 -2
  13. package/entity/EntityFactory.d.ts +6 -0
  14. package/entity/EntityFactory.js +17 -6
  15. package/entity/EntityHelper.js +4 -1
  16. package/entity/EntityLoader.js +26 -18
  17. package/entity/Reference.d.ts +5 -0
  18. package/entity/Reference.js +16 -0
  19. package/entity/WrappedEntity.js +1 -1
  20. package/entity/defineEntity.d.ts +528 -0
  21. package/entity/defineEntity.js +684 -0
  22. package/entity/index.d.ts +2 -0
  23. package/entity/index.js +2 -0
  24. package/entity/utils.d.ts +7 -0
  25. package/entity/utils.js +16 -3
  26. package/enums.d.ts +3 -1
  27. package/enums.js +2 -0
  28. package/hydration/ObjectHydrator.js +1 -1
  29. package/index.d.ts +1 -1
  30. package/index.mjs +4 -0
  31. package/metadata/MetadataDiscovery.d.ts +0 -1
  32. package/metadata/MetadataDiscovery.js +16 -13
  33. package/package.json +4 -4
  34. package/platforms/Platform.d.ts +3 -1
  35. package/types/BooleanType.d.ts +1 -1
  36. package/typings.d.ts +18 -9
  37. package/typings.js +21 -4
  38. package/unit-of-work/ChangeSetPersister.d.ts +4 -2
  39. package/unit-of-work/ChangeSetPersister.js +14 -10
  40. package/unit-of-work/UnitOfWork.d.ts +1 -1
  41. package/unit-of-work/UnitOfWork.js +22 -6
  42. package/utils/Configuration.d.ts +7 -1
  43. package/utils/Configuration.js +1 -0
  44. package/utils/ConfigurationLoader.js +2 -2
  45. package/utils/Cursor.js +3 -0
  46. package/utils/EntityComparator.d.ts +6 -2
  47. package/utils/EntityComparator.js +29 -8
  48. package/utils/QueryHelper.d.ts +6 -0
  49. package/utils/QueryHelper.js +47 -4
  50. package/utils/RawQueryFragment.d.ts +34 -0
  51. package/utils/RawQueryFragment.js +35 -0
  52. package/utils/Utils.d.ts +2 -2
  53. package/utils/Utils.js +32 -8
  54. package/utils/upsert-utils.js +9 -1
package/entity/index.js CHANGED
@@ -27,3 +27,5 @@ __exportStar(require("./Reference"), exports);
27
27
  __exportStar(require("./BaseEntity"), exports);
28
28
  __exportStar(require("./WrappedEntity"), exports);
29
29
  __exportStar(require("./wrap"), exports);
30
+ __exportStar(require("./defineEntity"), exports);
31
+ __exportStar(require("./utils"), exports);
package/entity/utils.d.ts CHANGED
@@ -1,5 +1,12 @@
1
1
  import type { EntityMetadata, PopulateOptions } from '../typings';
2
+ import { LoadStrategy, ReferenceKind } from '../enums';
2
3
  /**
3
4
  * @internal
4
5
  */
5
6
  export declare function expandDotPaths<Entity>(meta: EntityMetadata<Entity>, populate?: readonly (string | PopulateOptions<Entity>)[], normalized?: boolean): PopulateOptions<Entity>[];
7
+ /**
8
+ * Returns the loading strategy based on the provided hint.
9
+ * If `BALANCED` strategy is used, it will return JOINED if the property is a to-one relation.
10
+ * @internal
11
+ */
12
+ export declare function getLoadingStrategy(strategy: LoadStrategy | `${LoadStrategy}`, kind: ReferenceKind): LoadStrategy.SELECT_IN | LoadStrategy.JOINED;
package/entity/utils.js CHANGED
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.expandDotPaths = expandDotPaths;
4
+ exports.getLoadingStrategy = getLoadingStrategy;
4
5
  const enums_1 = require("../enums");
5
- const core_1 = require("@mikro-orm/core");
6
+ const Utils_1 = require("../utils/Utils");
6
7
  /**
7
8
  * Expands `books.perex` like populate to use `children` array instead of the dot syntax
8
9
  */
@@ -20,7 +21,7 @@ function expandNestedPopulate(parentProp, parts, strategy, all) {
20
21
  * @internal
21
22
  */
22
23
  function expandDotPaths(meta, populate, normalized = false) {
23
- const ret = normalized ? populate : core_1.Utils.asArray(populate).map(field => {
24
+ const ret = normalized ? populate : Utils_1.Utils.asArray(populate).map(field => {
24
25
  if (typeof field === 'string') {
25
26
  return { field };
26
27
  }
@@ -37,7 +38,6 @@ function expandDotPaths(meta, populate, normalized = false) {
37
38
  p.field = f;
38
39
  p.children ??= [];
39
40
  const prop = meta.properties[p.field];
40
- p.strategy ??= prop.strategy;
41
41
  if (parts[0] === enums_1.PopulatePath.ALL) {
42
42
  prop.targetMeta.props
43
43
  .filter(prop => prop.lazy || prop.kind !== enums_1.ReferenceKind.SCALAR)
@@ -58,3 +58,16 @@ function expandDotPaths(meta, populate, normalized = false) {
58
58
  }
59
59
  return ret;
60
60
  }
61
+ /**
62
+ * Returns the loading strategy based on the provided hint.
63
+ * If `BALANCED` strategy is used, it will return JOINED if the property is a to-one relation.
64
+ * @internal
65
+ */
66
+ function getLoadingStrategy(strategy, kind) {
67
+ if (strategy === enums_1.LoadStrategy.BALANCED) {
68
+ return [enums_1.ReferenceKind.MANY_TO_ONE, enums_1.ReferenceKind.ONE_TO_ONE].includes(kind)
69
+ ? enums_1.LoadStrategy.JOINED
70
+ : enums_1.LoadStrategy.SELECT_IN;
71
+ }
72
+ return strategy;
73
+ }
package/enums.d.ts CHANGED
@@ -85,6 +85,7 @@ export declare enum QueryFlag {
85
85
  INCLUDE_LAZY_FORMULAS = "INCLUDE_LAZY_FORMULAS",
86
86
  AUTO_JOIN_ONE_TO_ONE_OWNER = "AUTO_JOIN_ONE_TO_ONE_OWNER",
87
87
  INFER_POPULATE = "INFER_POPULATE",
88
+ DISABLE_NESTED_INNER_JOIN = "DISABLE_NESTED_INNER_JOIN",
88
89
  IDENTITY_INSERT = "IDENTITY_INSERT"
89
90
  }
90
91
  export declare const SCALAR_TYPES: string[];
@@ -108,7 +109,8 @@ export declare enum Cascade {
108
109
  }
109
110
  export declare enum LoadStrategy {
110
111
  SELECT_IN = "select-in",
111
- JOINED = "joined"
112
+ JOINED = "joined",
113
+ BALANCED = "balanced"
112
114
  }
113
115
  export declare enum DataloaderType {
114
116
  NONE = 0,
package/enums.js CHANGED
@@ -98,6 +98,7 @@ var QueryFlag;
98
98
  QueryFlag["INCLUDE_LAZY_FORMULAS"] = "INCLUDE_LAZY_FORMULAS";
99
99
  QueryFlag["AUTO_JOIN_ONE_TO_ONE_OWNER"] = "AUTO_JOIN_ONE_TO_ONE_OWNER";
100
100
  QueryFlag["INFER_POPULATE"] = "INFER_POPULATE";
101
+ QueryFlag["DISABLE_NESTED_INNER_JOIN"] = "DISABLE_NESTED_INNER_JOIN";
101
102
  QueryFlag["IDENTITY_INSERT"] = "IDENTITY_INSERT";
102
103
  })(QueryFlag || (exports.QueryFlag = QueryFlag = {}));
103
104
  exports.SCALAR_TYPES = ['string', 'number', 'boolean', 'bigint', 'Date', 'Buffer', 'RegExp'];
@@ -125,6 +126,7 @@ var LoadStrategy;
125
126
  (function (LoadStrategy) {
126
127
  LoadStrategy["SELECT_IN"] = "select-in";
127
128
  LoadStrategy["JOINED"] = "joined";
129
+ LoadStrategy["BALANCED"] = "balanced";
128
130
  })(LoadStrategy || (exports.LoadStrategy = LoadStrategy = {}));
129
131
  var DataloaderType;
130
132
  (function (DataloaderType) {
@@ -65,7 +65,7 @@ class ObjectHydrator extends Hydrator_1.Hydrator {
65
65
  const ret = [];
66
66
  const idx = this.tmpIndex++;
67
67
  const nullVal = this.config.get('forceUndefined') ? 'undefined' : 'null';
68
- if (prop.getter && !prop.setter) {
68
+ if (prop.getter && !prop.setter && prop.persist === false) {
69
69
  return [];
70
70
  }
71
71
  if (prop.ref) {
package/index.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * @packageDocumentation
3
3
  * @module core
4
4
  */
5
- export { Constructor, ConnectionType, Dictionary, PrimaryKeyProp, Primary, IPrimaryKey, ObjectQuery, FilterQuery, IWrappedEntity, EntityName, EntityData, Highlighter, MaybePromise, AnyEntity, EntityClass, EntityProperty, EntityMetadata, QBFilterQuery, PopulateOptions, Populate, Loaded, New, LoadedReference, LoadedCollection, IMigrator, IMigrationGenerator, MigratorEvent, GetRepository, EntityRepositoryType, MigrationObject, DeepPartial, PrimaryProperty, Cast, IsUnknown, EntityDictionary, EntityDTO, MigrationDiff, GenerateOptions, FilterObject, IEntityGenerator, ISeedManager, EntityClassGroup, OptionalProps, EagerProps, HiddenProps, RequiredEntityData, CheckCallback, SimpleColumnMeta, Rel, Ref, ScalarRef, EntityRef, ISchemaGenerator, UmzugMigration, MigrateOptions, MigrationResult, MigrationRow, EntityKey, EntityValue, EntityDataValue, FilterKey, Opt, EntityType, FromEntityType, Selected, IsSubset, NoInfer, EntityProps, ExpandProperty, ExpandScalar, FilterItemValue, ExpandQuery, Scalar, ExpandHint, Hidden, FilterValue, MergeLoaded, MergeSelected, Config, DefineConfig, TypeConfig, ClearDatabaseOptions, CreateSchemaOptions, EnsureDatabaseOptions, UpdateSchemaOptions, DropSchemaOptions, RefreshDatabaseOptions, AutoPath, UnboxArray, MetadataProcessor, ImportsResolver, } from './typings';
5
+ export { Constructor, ConnectionType, Dictionary, PrimaryKeyProp, Primary, IPrimaryKey, ObjectQuery, FilterQuery, IWrappedEntity, EntityName, EntityData, Highlighter, MaybePromise, AnyEntity, EntityClass, EntityProperty, EntityMetadata, QBFilterQuery, PopulateOptions, Populate, Loaded, New, LoadedReference, LoadedCollection, IMigrator, IMigrationGenerator, MigratorEvent, GetRepository, EntityRepositoryType, MigrationObject, DeepPartial, PrimaryProperty, Cast, IsUnknown, EntityDictionary, EntityDTO, MigrationDiff, GenerateOptions, FilterObject, IEntityGenerator, ISeedManager, EntityClassGroup, OptionalProps, EagerProps, HiddenProps, RequiredEntityData, CheckCallback, IndexCallback, SimpleColumnMeta, Rel, Ref, ScalarRef, EntityRef, ISchemaGenerator, UmzugMigration, MigrateOptions, MigrationResult, MigrationRow, EntityKey, EntityValue, EntityDataValue, FilterKey, Opt, EntityType, FromEntityType, Selected, IsSubset, NoInfer, EntityProps, ExpandProperty, ExpandScalar, FilterItemValue, ExpandQuery, Scalar, ExpandHint, Hidden, FilterValue, MergeLoaded, MergeSelected, Config, DefineConfig, TypeConfig, ClearDatabaseOptions, CreateSchemaOptions, EnsureDatabaseOptions, UpdateSchemaOptions, DropSchemaOptions, RefreshDatabaseOptions, AutoPath, UnboxArray, MetadataProcessor, ImportsResolver, } from './typings';
6
6
  export * from './enums';
7
7
  export * from './errors';
8
8
  export * from './exceptions';
package/index.mjs CHANGED
@@ -182,11 +182,15 @@ export const compareBuffers = mod.compareBuffers;
182
182
  export const compareObjects = mod.compareObjects;
183
183
  export const createSqlFunction = mod.createSqlFunction;
184
184
  export const defineConfig = mod.defineConfig;
185
+ export const defineEntity = mod.defineEntity;
185
186
  export const equals = mod.equals;
187
+ export const expandDotPaths = mod.expandDotPaths;
188
+ export const getLoadingStrategy = mod.getLoadingStrategy;
186
189
  export const getOnConflictFields = mod.getOnConflictFields;
187
190
  export const getOnConflictReturningFields = mod.getOnConflictReturningFields;
188
191
  export const helper = mod.helper;
189
192
  export const parseJsonSafe = mod.parseJsonSafe;
193
+ export const quote = mod.quote;
190
194
  export const raw = mod.raw;
191
195
  export const ref = mod.ref;
192
196
  export const rel = mod.rel;
@@ -54,7 +54,6 @@ export declare class MetadataDiscovery {
54
54
  private initAutoincrement;
55
55
  private initCheckConstraints;
56
56
  private initGeneratedColumn;
57
- private createColumnMappingObject;
58
57
  private getDefaultVersionValue;
59
58
  private inferDefaultValue;
60
59
  private initDefaultValue;
@@ -622,7 +622,7 @@ class MetadataDiscovery {
622
622
  }
623
623
  data.properties[meta.name + '_owner'] = this.definePivotProperty(prop, meta.name + '_owner', meta.className, targetType + '_inverse', true, meta.className === targetType);
624
624
  data.properties[targetType + '_inverse'] = this.definePivotProperty(prop, targetType + '_inverse', targetType, meta.name + '_owner', false, meta.className === targetType);
625
- return this.metadata.set(data.className, data);
625
+ return this.metadata.set(data.className, EntitySchema_1.EntitySchema.fromMetadata(data).init().meta);
626
626
  }
627
627
  defineFixedOrderProperty(prop, targetType) {
628
628
  const pk = prop.fixedOrderColumn || this.namingStrategy.referenceColumnName();
@@ -825,9 +825,16 @@ class MetadataDiscovery {
825
825
  }
826
826
  return prop.embedded ? isParentObject(meta.properties[prop.embedded[0]]) : false;
827
827
  };
828
+ const isParentArray = (prop) => {
829
+ if (prop.array) {
830
+ return true;
831
+ }
832
+ return prop.embedded ? isParentArray(meta.properties[prop.embedded[0]]) : false;
833
+ };
828
834
  const rootProperty = getRootProperty(embeddedProp);
829
835
  const parentProperty = meta.properties[embeddedProp.embedded?.[0] ?? ''];
830
836
  const object = isParentObject(embeddedProp);
837
+ const array = isParentArray(embeddedProp);
831
838
  this.initFieldName(embeddedProp, rootProperty !== embeddedProp && object);
832
839
  // the prefix of the parent cannot be a boolean; it already passed here
833
840
  const prefix = this.getPrefix(embeddedProp, parentProperty);
@@ -840,7 +847,8 @@ class MetadataDiscovery {
840
847
  meta.propertyOrder.set(name, (order += 0.01));
841
848
  embeddedProp.embeddedProps[prop.name] = meta.properties[name];
842
849
  meta.properties[name].persist ??= embeddedProp.persist;
843
- if (embeddedProp.nullable) {
850
+ const refInArray = array && [enums_1.ReferenceKind.MANY_TO_ONE, enums_1.ReferenceKind.ONE_TO_ONE].includes(prop.kind) && prop.owner;
851
+ if (embeddedProp.nullable || refInArray) {
844
852
  meta.properties[name].nullable = true;
845
853
  }
846
854
  if (meta.properties[name].fieldNames) {
@@ -969,7 +977,7 @@ class MetadataDiscovery {
969
977
  }
970
978
  }
971
979
  initCheckConstraints(meta) {
972
- const map = this.createColumnMappingObject(meta);
980
+ const map = meta.createColumnMappingObject();
973
981
  for (const check of meta.checks) {
974
982
  const columns = check.property ? meta.properties[check.property].fieldNames : [];
975
983
  check.name ??= this.namingStrategy.indexName(meta.tableName, columns, 'check');
@@ -992,19 +1000,11 @@ class MetadataDiscovery {
992
1000
  }
993
1001
  return;
994
1002
  }
995
- const map = this.createColumnMappingObject(meta);
1003
+ const map = meta.createColumnMappingObject();
996
1004
  if (prop.generated instanceof Function) {
997
1005
  prop.generated = prop.generated(map);
998
1006
  }
999
1007
  }
1000
- createColumnMappingObject(meta) {
1001
- return Object.values(meta.properties).reduce((o, prop) => {
1002
- if (prop.fieldNames) {
1003
- o[prop.name] = prop.fieldNames[0];
1004
- }
1005
- return o;
1006
- }, {});
1007
- }
1008
1008
  getDefaultVersionValue(meta, prop) {
1009
1009
  if (typeof prop.defaultRaw !== 'undefined') {
1010
1010
  return prop.defaultRaw;
@@ -1058,7 +1058,7 @@ class MetadataDiscovery {
1058
1058
  prop.defaultRaw = this.platform.formatQuery(raw.sql, raw.params);
1059
1059
  return;
1060
1060
  }
1061
- if (prop.customType instanceof types_1.ArrayType && Array.isArray(prop.default)) {
1061
+ if (Array.isArray(prop.default) && prop.customType) {
1062
1062
  val = prop.customType.convertToDatabaseValue(prop.default, this.platform);
1063
1063
  }
1064
1064
  prop.defaultRaw = typeof val === 'string' ? `'${val}'` : '' + val;
@@ -1112,6 +1112,9 @@ class MetadataDiscovery {
1112
1112
  if (prop.kind === enums_1.ReferenceKind.SCALAR && !prop.customType && prop.columnTypes && ['json', 'jsonb'].includes(prop.columnTypes[0])) {
1113
1113
  prop.customType = new types_1.JsonType();
1114
1114
  }
1115
+ if (prop.kind === enums_1.ReferenceKind.EMBEDDED && !prop.customType && (prop.object || prop.array)) {
1116
+ prop.customType = new types_1.JsonType();
1117
+ }
1115
1118
  if (!prop.customType && prop.array && prop.items) {
1116
1119
  prop.customType = new types_1.EnumArrayType(`${meta.className}.${prop.name}`, prop.items);
1117
1120
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/core",
3
- "version": "6.4.17-dev.9",
3
+ "version": "6.4.17-dev.90",
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",
@@ -60,11 +60,11 @@
60
60
  },
61
61
  "dependencies": {
62
62
  "dataloader": "2.2.3",
63
- "dotenv": "16.5.0",
63
+ "dotenv": "17.2.1",
64
64
  "esprima": "4.0.1",
65
- "fs-extra": "11.3.0",
65
+ "fs-extra": "11.3.1",
66
66
  "globby": "11.1.0",
67
- "mikro-orm": "6.4.17-dev.9",
67
+ "mikro-orm": "6.4.17-dev.90",
68
68
  "reflect-metadata": "0.2.2"
69
69
  }
70
70
  }
@@ -173,7 +173,9 @@ export declare abstract class Platform {
173
173
  getExtension<T>(extensionName: string, extensionKey: string, moduleName: string, em: EntityManager): T;
174
174
  getSchemaGenerator(driver: IDatabaseDriver, em?: EntityManager): ISchemaGenerator;
175
175
  processDateProperty(value: unknown): string | number | Date;
176
- quoteIdentifier(id: string, quote?: string): string;
176
+ quoteIdentifier(id: string | {
177
+ toString: () => string;
178
+ }, quote?: string): string;
177
179
  quoteValue(value: any): string;
178
180
  escape(value: any): string;
179
181
  formatQuery(sql: string, params: readonly any[]): string;
@@ -1,7 +1,7 @@
1
1
  import { Type } from './Type';
2
2
  import type { Platform } from '../platforms';
3
3
  import type { EntityProperty } from '../typings';
4
- export declare class BooleanType extends Type<number | null | undefined, number | null | undefined> {
4
+ export declare class BooleanType extends Type<boolean | null | undefined, boolean | null | undefined> {
5
5
  getColumnType(prop: EntityProperty, platform: Platform): string;
6
6
  compareAsType(): string;
7
7
  ensureComparable(): boolean;
package/typings.d.ts CHANGED
@@ -6,7 +6,7 @@ import type { SerializationContext, SerializeOptions } from './serialization';
6
6
  import type { EntitySchema, MetadataStorage } from './metadata';
7
7
  import type { Type, types } from './types';
8
8
  import type { Platform } from './platforms';
9
- import type { Configuration } from './utils';
9
+ import type { Configuration, RawQueryFragment } from './utils';
10
10
  import type { EntityManager } from './EntityManager';
11
11
  import type { EmbeddedPrefixMode } from './decorators/Embedded';
12
12
  import type { EventSubscriber } from './events';
@@ -73,6 +73,7 @@ export type Primary<T> = IsAny<T> extends true ? any : T extends {
73
73
  } ? ReadonlyPrimary<PK> : T extends {
74
74
  id?: infer PK;
75
75
  } ? ReadonlyPrimary<PK> : T;
76
+ /** @internal */
76
77
  export type PrimaryProperty<T> = T extends {
77
78
  [PrimaryKeyProp]?: infer PK;
78
79
  } ? (PK extends keyof T ? PK : (PK extends any[] ? PK[number] : never)) : T extends {
@@ -287,8 +288,14 @@ export type EntityDTO<T, C extends TypeConfig = never> = {
287
288
  } & {
288
289
  [K in keyof T as DTOOptionalKeys<T, K>]?: EntityDTOProp<T, T[K], C> | AddOptional<T[K]>;
289
290
  };
290
- type CheckKey<T> = IsUnknown<T> extends false ? keyof T : string;
291
- export type CheckCallback<T> = (columns: Record<CheckKey<T>, string>) => string;
291
+ type PropertyName<T> = IsUnknown<T> extends false ? keyof T : string;
292
+ type TableName = {
293
+ name: string;
294
+ schema?: string;
295
+ toString: () => string;
296
+ };
297
+ export type IndexCallback<T> = (table: TableName, columns: Record<PropertyName<T>, string>) => string | RawQueryFragment;
298
+ export type CheckCallback<T> = (columns: Record<PropertyName<T>, string>) => string;
292
299
  export type GeneratedColumnCallback<T> = (columns: Record<keyof T, string>) => string;
293
300
  export interface CheckConstraint<T = any> {
294
301
  name?: string;
@@ -394,8 +401,9 @@ export declare class EntityMetadata<T = any> {
394
401
  constructor(meta?: Partial<EntityMetadata>);
395
402
  addProperty(prop: Partial<EntityProperty<T>>, sync?: boolean): void;
396
403
  removeProperty(name: string, sync?: boolean): void;
397
- getPrimaryProps(): EntityProperty<T>[];
404
+ getPrimaryProps(flatten?: boolean): EntityProperty<T>[];
398
405
  getPrimaryProp(): EntityProperty<T>;
406
+ createColumnMappingObject(): Dictionary<any>;
399
407
  get tableName(): string;
400
408
  set tableName(name: string);
401
409
  sync(initIndexes?: boolean): void;
@@ -447,18 +455,18 @@ export interface EntityMetadata<T = any> {
447
455
  uniqueProps: EntityProperty<T>[];
448
456
  getterProps: EntityProperty<T>[];
449
457
  indexes: {
450
- properties: EntityKey<T> | EntityKey<T>[];
458
+ properties?: EntityKey<T> | EntityKey<T>[];
451
459
  name?: string;
452
460
  type?: string;
453
461
  options?: Dictionary;
454
- expression?: string;
462
+ expression?: string | IndexCallback<T>;
455
463
  }[];
456
464
  uniques: {
457
- properties: EntityKey<T> | EntityKey<T>[];
465
+ properties?: EntityKey<T> | EntityKey<T>[];
458
466
  name?: string;
459
467
  options?: Dictionary;
460
- expression?: string;
461
- deferMode?: DeferMode;
468
+ expression?: string | IndexCallback<T>;
469
+ deferMode?: DeferMode | `${DeferMode}`;
462
470
  }[];
463
471
  checks: CheckConstraint<T>[];
464
472
  repositoryClass?: string;
@@ -690,6 +698,7 @@ export type PopulateOptions<T> = {
690
698
  strategy?: LoadStrategy;
691
699
  all?: boolean;
692
700
  filter?: boolean;
701
+ joinType?: 'inner join' | 'left join';
693
702
  children?: PopulateOptions<T[keyof T]>[];
694
703
  };
695
704
  type Loadable<T extends object> = Collection<T, any> | Reference<T> | Ref<T> | readonly T[];
package/typings.js CHANGED
@@ -47,12 +47,29 @@ class EntityMetadata {
47
47
  this.sync();
48
48
  }
49
49
  }
50
- getPrimaryProps() {
51
- return this.primaryKeys.map(pk => this.properties[pk]);
50
+ getPrimaryProps(flatten = false) {
51
+ const pks = this.primaryKeys.map(pk => this.properties[pk]);
52
+ if (flatten) {
53
+ return pks.flatMap(pk => {
54
+ if ([enums_1.ReferenceKind.MANY_TO_ONE, enums_1.ReferenceKind.ONE_TO_ONE].includes(pk.kind)) {
55
+ return pk.targetMeta.getPrimaryProps(true);
56
+ }
57
+ return [pk];
58
+ });
59
+ }
60
+ return pks;
52
61
  }
53
62
  getPrimaryProp() {
54
63
  return this.properties[this.primaryKeys[0]];
55
64
  }
65
+ createColumnMappingObject() {
66
+ return Object.values(this.properties).reduce((o, prop) => {
67
+ if (prop.fieldNames) {
68
+ o[prop.name] = prop.fieldNames[0];
69
+ }
70
+ return o;
71
+ }, {});
72
+ }
56
73
  get tableName() {
57
74
  return this.collection;
58
75
  }
@@ -72,7 +89,7 @@ class EntityMetadata {
72
89
  // `prop.userDefined` is either `undefined` or `false`
73
90
  const discriminator = this.root.discriminatorColumn === prop.name && prop.userDefined === false;
74
91
  // even if we don't have a setter, do not ignore value from database!
75
- const onlyGetter = prop.getter && !prop.setter;
92
+ const onlyGetter = prop.getter && !prop.setter && prop.persist === false;
76
93
  return !prop.inherited && prop.hydrate !== false && !discriminator && !prop.embedded && !onlyGetter;
77
94
  });
78
95
  this.trackingProps = this.hydrateProps
@@ -115,7 +132,7 @@ class EntityMetadata {
115
132
  wrapped.__data[prop.name] = entity_1.Reference.wrapReference(val, prop);
116
133
  // when propagation from inside hydration, we set the FK to the entity data immediately
117
134
  if (val && hydrator.isRunning() && wrapped.__originalEntityData && prop.owner) {
118
- wrapped.__originalEntityData[prop.name] = Utils_1.Utils.getPrimaryKeyValues(val, prop.targetMeta.primaryKeys, true);
135
+ wrapped.__originalEntityData[prop.name] = Utils_1.Utils.getPrimaryKeyValues(val, prop.targetMeta, true);
119
136
  }
120
137
  else {
121
138
  wrapped.__touched = !hydrator.isRunning();
@@ -4,6 +4,7 @@ import { type EntityFactory, type EntityValidator } from '../entity';
4
4
  import { type ChangeSet } from './ChangeSet';
5
5
  import { type Configuration } from '../utils';
6
6
  import type { DriverMethodOptions, IDatabaseDriver } from '../drivers';
7
+ import type { EntityManager } from '../EntityManager';
7
8
  export declare class ChangeSetPersister {
8
9
  private readonly driver;
9
10
  private readonly metadata;
@@ -11,10 +12,11 @@ export declare class ChangeSetPersister {
11
12
  private readonly factory;
12
13
  private readonly validator;
13
14
  private readonly config;
15
+ private readonly em;
14
16
  private readonly platform;
15
17
  private readonly comparator;
16
18
  private readonly usesReturningStatement;
17
- constructor(driver: IDatabaseDriver, metadata: MetadataStorage, hydrator: IHydrator, factory: EntityFactory, validator: EntityValidator, config: Configuration);
19
+ constructor(driver: IDatabaseDriver, metadata: MetadataStorage, hydrator: IHydrator, factory: EntityFactory, validator: EntityValidator, config: Configuration, em: EntityManager);
18
20
  executeInserts<T extends object>(changeSets: ChangeSet<T>[], options?: DriverMethodOptions, withSchema?: boolean): Promise<void>;
19
21
  executeUpdates<T extends object>(changeSets: ChangeSet<T>[], batched: boolean, options?: DriverMethodOptions, withSchema?: boolean): Promise<void>;
20
22
  executeDeletes<T extends object>(changeSets: ChangeSet<T>[], options?: DriverMethodOptions, withSchema?: boolean): Promise<void>;
@@ -22,7 +24,7 @@ export declare class ChangeSetPersister {
22
24
  private processProperties;
23
25
  private persistNewEntity;
24
26
  private persistNewEntities;
25
- private propagateSchemaFromMetadata;
27
+ private prepareOptions;
26
28
  private persistNewEntitiesBatch;
27
29
  private persistManagedEntity;
28
30
  private persistManagedEntities;
@@ -13,16 +13,18 @@ class ChangeSetPersister {
13
13
  factory;
14
14
  validator;
15
15
  config;
16
+ em;
16
17
  platform;
17
18
  comparator;
18
19
  usesReturningStatement;
19
- constructor(driver, metadata, hydrator, factory, validator, config) {
20
+ constructor(driver, metadata, hydrator, factory, validator, config, em) {
20
21
  this.driver = driver;
21
22
  this.metadata = metadata;
22
23
  this.hydrator = hydrator;
23
24
  this.factory = factory;
24
25
  this.validator = validator;
25
26
  this.config = config;
27
+ this.em = em;
26
28
  this.platform = this.driver.getPlatform();
27
29
  this.comparator = this.config.getComparator(this.metadata);
28
30
  this.usesReturningStatement = this.platform.usesReturningStatement() || this.platform.usesOutputStatement();
@@ -63,7 +65,7 @@ class ChangeSetPersister {
63
65
  for (let i = 0; i < changeSets.length; i += size) {
64
66
  const chunk = changeSets.slice(i, i + size);
65
67
  const pks = chunk.map(cs => cs.getPrimaryKey());
66
- options = this.propagateSchemaFromMetadata(meta, options);
68
+ options = this.prepareOptions(meta, options);
67
69
  await this.driver.nativeDelete(meta.root.className, { [pk]: { $in: pks } }, options);
68
70
  }
69
71
  }
@@ -91,7 +93,7 @@ class ChangeSetPersister {
91
93
  }
92
94
  async persistNewEntity(meta, changeSet, options) {
93
95
  const wrapped = (0, entity_1.helper)(changeSet.entity);
94
- options = this.propagateSchemaFromMetadata(meta, options, {
96
+ options = this.prepareOptions(meta, options, {
95
97
  convertCustomTypes: false,
96
98
  });
97
99
  const res = await this.driver.nativeInsertMany(meta.className, [changeSet.payload], options);
@@ -117,15 +119,17 @@ class ChangeSetPersister {
117
119
  }
118
120
  }
119
121
  }
120
- propagateSchemaFromMetadata(meta, options, additionalOptions) {
122
+ prepareOptions(meta, options, additionalOptions) {
123
+ const loggerContext = utils_1.Utils.merge({ id: this.em._id }, this.em.getLoggerContext({ disableContextResolution: true }));
121
124
  return {
122
125
  ...options,
123
126
  ...additionalOptions,
124
127
  schema: options?.schema ?? meta.schema,
128
+ loggerContext,
125
129
  };
126
130
  }
127
131
  async persistNewEntitiesBatch(meta, changeSets, options) {
128
- options = this.propagateSchemaFromMetadata(meta, options, {
132
+ options = this.prepareOptions(meta, options, {
129
133
  convertCustomTypes: false,
130
134
  processCollections: false,
131
135
  });
@@ -176,7 +180,7 @@ class ChangeSetPersister {
176
180
  }
177
181
  async persistManagedEntitiesBatch(meta, changeSets, options) {
178
182
  await this.checkOptimisticLocks(meta, changeSets, options);
179
- options = this.propagateSchemaFromMetadata(meta, options, {
183
+ options = this.prepareOptions(meta, options, {
180
184
  convertCustomTypes: false,
181
185
  processCollections: false,
182
186
  });
@@ -236,7 +240,7 @@ class ChangeSetPersister {
236
240
  }
237
241
  async updateEntity(meta, changeSet, options) {
238
242
  const cond = changeSet.getPrimaryKey(true);
239
- options = this.propagateSchemaFromMetadata(meta, options, {
243
+ options = this.prepareOptions(meta, options, {
240
244
  convertCustomTypes: false,
241
245
  });
242
246
  if (meta.concurrencyCheckKeys.size === 0 && (!meta.versionProperty || changeSet.entity[meta.versionProperty] == null)) {
@@ -263,7 +267,7 @@ class ChangeSetPersister {
263
267
  return cond;
264
268
  });
265
269
  const primaryKeys = meta.primaryKeys.concat(...meta.concurrencyCheckKeys);
266
- options = this.propagateSchemaFromMetadata(meta, options, {
270
+ options = this.prepareOptions(meta, options, {
267
271
  fields: primaryKeys,
268
272
  });
269
273
  const res = await this.driver.find(meta.root.className, { $or }, options);
@@ -322,12 +326,12 @@ class ChangeSetPersister {
322
326
  }
323
327
  return val;
324
328
  });
325
- options = this.propagateSchemaFromMetadata(meta, options, {
329
+ options = this.prepareOptions(meta, options, {
326
330
  fields: utils_1.Utils.unique(reloadProps.map(prop => prop.name)),
327
331
  });
328
332
  const data = await this.driver.find(meta.className, { [pk]: { $in: pks } }, options);
329
333
  const map = new Map();
330
- data.forEach(item => map.set(utils_1.Utils.getCompositeKeyHash(item, meta, true, this.platform, true), item));
334
+ data.forEach(item => map.set(utils_1.Utils.getCompositeKeyHash(item, meta, false, this.platform, true), item));
331
335
  for (const changeSet of changeSets) {
332
336
  const data = map.get((0, entity_1.helper)(changeSet.entity).getSerializedPrimaryKey());
333
337
  this.hydrator.hydrate(changeSet.entity, meta, data, this.factory, 'full', false, true);
@@ -38,7 +38,7 @@ export declare class UnitOfWork {
38
38
  /**
39
39
  * Returns entity from the identity map. For composite keys, you need to pass an array of PKs in the same order as they are defined in `meta.primaryKeys`.
40
40
  */
41
- getById<T extends object>(entityName: string, id: Primary<T> | Primary<T>[], schema?: string): T | undefined;
41
+ getById<T extends object>(entityName: string, id: Primary<T> | Primary<T>[], schema?: string, convertCustomTypes?: boolean): T | undefined;
42
42
  tryGetById<T extends object>(entityName: string, where: FilterQuery<T>, schema?: string, strict?: boolean): T | null;
43
43
  /**
44
44
  * Returns map of all managed entities.
@@ -42,7 +42,7 @@ class UnitOfWork {
42
42
  this.eventManager = this.em.getEventManager();
43
43
  this.comparator = this.em.getComparator();
44
44
  this.changeSetComputer = new ChangeSetComputer_1.ChangeSetComputer(this.em.getValidator(), this.collectionUpdates, this.metadata, this.platform, this.em.config, this.em);
45
- this.changeSetPersister = new ChangeSetPersister_1.ChangeSetPersister(this.em.getDriver(), this.metadata, this.em.config.getHydrator(this.metadata), this.em.getEntityFactory(), this.em.getValidator(), this.em.config);
45
+ this.changeSetPersister = new ChangeSetPersister_1.ChangeSetPersister(this.em.getDriver(), this.metadata, this.em.config.getHydrator(this.metadata), this.em.getEntityFactory(), this.em.getValidator(), this.em.config, this.em);
46
46
  }
47
47
  merge(entity, visited) {
48
48
  const wrapped = (0, entity_1.helper)(entity);
@@ -88,7 +88,7 @@ class UnitOfWork {
88
88
  }
89
89
  wrapped.__loadedProperties.add(key);
90
90
  if ([enums_1.ReferenceKind.MANY_TO_ONE, enums_1.ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils_1.Utils.isPlainObject(data[prop.name])) {
91
- data[prop.name] = Utils_1.Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta.primaryKeys, true);
91
+ data[prop.name] = Utils_1.Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta, true);
92
92
  }
93
93
  else if (prop.kind === enums_1.ReferenceKind.EMBEDDED && !prop.object && Utils_1.Utils.isPlainObject(data[prop.name])) {
94
94
  for (const p of prop.targetMeta.props) {
@@ -96,7 +96,7 @@ class UnitOfWork {
96
96
  const prefix = prop.prefix === false ? '' : prop.prefix === true ? prop.name + '_' : prop.prefix;
97
97
  data[prefix + p.name] = data[prop.name][p.name];
98
98
  }
99
- data[prop.name] = Utils_1.Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta.primaryKeys, true);
99
+ data[prop.name] = Utils_1.Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta, true);
100
100
  }
101
101
  if (forceUndefined) {
102
102
  if (data[key] === null) {
@@ -124,7 +124,7 @@ class UnitOfWork {
124
124
  /**
125
125
  * Returns entity from the identity map. For composite keys, you need to pass an array of PKs in the same order as they are defined in `meta.primaryKeys`.
126
126
  */
127
- getById(entityName, id, schema) {
127
+ getById(entityName, id, schema, convertCustomTypes) {
128
128
  if (id == null || (Array.isArray(id) && id.length === 0)) {
129
129
  return undefined;
130
130
  }
@@ -134,7 +134,16 @@ class UnitOfWork {
134
134
  hash = '' + id;
135
135
  }
136
136
  else {
137
- const keys = Array.isArray(id) ? Utils_1.Utils.flatten(id) : [id];
137
+ let keys = Array.isArray(id) ? Utils_1.Utils.flatten(id) : [id];
138
+ keys = meta.getPrimaryProps(true).map((p, i) => {
139
+ if (!convertCustomTypes && p.customType) {
140
+ return p.customType.convertToDatabaseValue(keys[i], this.platform, {
141
+ key: p.name,
142
+ mode: 'hydration',
143
+ });
144
+ }
145
+ return keys[i];
146
+ });
138
147
  hash = Utils_1.Utils.getPrimaryKeyHash(keys);
139
148
  }
140
149
  schema ??= meta.schema ?? this.em.config.getSchema();
@@ -312,9 +321,11 @@ class UnitOfWork {
312
321
  const platform = this.em.getPlatform();
313
322
  const runInTransaction = !this.em.isInTransaction() && platform.supportsTransactions() && this.em.config.get('implicitTransactions');
314
323
  if (runInTransaction) {
324
+ const loggerContext = Utils_1.Utils.merge({ id: this.em._id }, this.em.getLoggerContext({ disableContextResolution: true }));
315
325
  await this.em.getConnection('write').transactional(trx => this.persistToDatabase(groups, trx), {
316
326
  ctx: oldTx,
317
327
  eventBroadcaster: new events_1.TransactionEventBroadcaster(this.em, this),
328
+ loggerContext,
318
329
  });
319
330
  }
320
331
  else {
@@ -888,7 +899,12 @@ class UnitOfWork {
888
899
  }
889
900
  async commitCollectionUpdates(ctx) {
890
901
  this.filterCollectionUpdates();
891
- await this.em.getDriver().syncCollections(this.collectionUpdates, { ctx, schema: this.em.schema });
902
+ const loggerContext = Utils_1.Utils.merge({ id: this.em._id }, this.em.getLoggerContext({ disableContextResolution: true }));
903
+ await this.em.getDriver().syncCollections(this.collectionUpdates, {
904
+ ctx,
905
+ schema: this.em.schema,
906
+ loggerContext,
907
+ });
892
908
  for (const coll of this.collectionUpdates) {
893
909
  coll.takeSnapshot();
894
910
  }