@mikro-orm/core 7.0.0-dev.312 → 7.0.0-dev.314

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
  <a href="https://mikro-orm.io"><img src="https://raw.githubusercontent.com/mikro-orm/mikro-orm/master/docs/static/img/logo-readme.svg?sanitize=true" alt="MikroORM" /></a>
3
3
  </h1>
4
4
 
5
- TypeScript ORM for Node.js based on Data Mapper, [Unit of Work](https://mikro-orm.io/docs/unit-of-work/) and [Identity Map](https://mikro-orm.io/docs/identity-map/) patterns. Supports MongoDB, MySQL, MariaDB, PostgreSQL and SQLite (including libSQL) databases.
5
+ TypeScript ORM for Node.js based on Data Mapper, [Unit of Work](https://mikro-orm.io/docs/unit-of-work/) and [Identity Map](https://mikro-orm.io/docs/identity-map/) patterns. Supports MongoDB, MySQL, MariaDB, PostgreSQL, SQLite (including libSQL), MSSQL and Oracle databases.
6
6
 
7
7
  > Heavily inspired by [Doctrine](https://www.doctrine-project.org/) and [Hibernate](https://hibernate.org/).
8
8
 
@@ -181,6 +181,7 @@ yarn add @mikro-orm/core @mikro-orm/mysql # for mysql/mariadb
181
181
  yarn add @mikro-orm/core @mikro-orm/mariadb # for mysql/mariadb
182
182
  yarn add @mikro-orm/core @mikro-orm/postgresql # for postgresql
183
183
  yarn add @mikro-orm/core @mikro-orm/mssql # for mssql
184
+ yarn add @mikro-orm/core @mikro-orm/oracledb # for oracle
184
185
  yarn add @mikro-orm/core @mikro-orm/sqlite # for sqlite
185
186
  yarn add @mikro-orm/core @mikro-orm/libsql # for libsql
186
187
  ```
@@ -522,16 +522,14 @@ export class EntityLoader {
522
522
  const options2 = { ...options, fields, exclude, populateFilter };
523
523
  ['limit', 'offset', 'first', 'last', 'before', 'after', 'overfetch'].forEach(prop => delete options2[prop]);
524
524
  options2.populate = populate?.children ?? [];
525
- if (prop.customType) {
526
- ids.forEach((id, idx) => (ids[idx] = QueryHelper.processCustomType(prop, id, this.driver.getPlatform())));
527
- }
528
525
  if (!Utils.isEmpty(prop.where)) {
529
526
  where = { $and: [where, prop.where] };
530
527
  }
531
528
  const map = await this.driver.loadFromPivotTable(prop, ids, where, orderBy, this.em.getTransactionContext(), options2, pivotJoin);
532
529
  const children = [];
533
- for (const entity of filtered) {
534
- const items = map[entity.__helper.getSerializedPrimaryKey()].map(item => {
530
+ for (let i = 0; i < filtered.length; i++) {
531
+ const entity = filtered[i];
532
+ const items = map[Utils.getPrimaryKeyHash(ids[i])].map(item => {
535
533
  if (pivotJoin) {
536
534
  return this.em.getReference(prop.targetMeta.class, item, {
537
535
  convertCustomTypes: true,
package/exceptions.js CHANGED
@@ -12,12 +12,14 @@ export class DriverException extends Error {
12
12
  Object.getOwnPropertyNames(previous).forEach(k => (this[k] = previous[k]));
13
13
  this.name = this.constructor.name;
14
14
  Error.captureStackTrace(this, this.constructor);
15
- this.stack +=
16
- '\n\n' +
17
- previous
18
- .stack.split('\n')
19
- .filter(l => l.trim().startsWith('at '))
20
- .join('\n');
15
+ if (previous.stack) {
16
+ this.stack +=
17
+ '\n\n' +
18
+ previous.stack
19
+ .split('\n')
20
+ .filter(l => l.trim().startsWith('at '))
21
+ .join('\n');
22
+ }
21
23
  }
22
24
  }
23
25
  /**
@@ -842,6 +842,7 @@ export class MetadataDiscovery {
842
842
  const primaryProp = {
843
843
  name: pk,
844
844
  type: 'number',
845
+ runtimeType: 'number',
845
846
  kind: ReferenceKind.SCALAR,
846
847
  primary: true,
847
848
  autoincrement: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/core",
3
- "version": "7.0.0-dev.312",
3
+ "version": "7.0.0-dev.314",
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
  "keywords": [
6
6
  "data-mapper",
@@ -1,6 +1,6 @@
1
1
  import { EntityRepository } from '../entity/EntityRepository.js';
2
2
  import { type NamingStrategy } from '../naming-strategy/NamingStrategy.js';
3
- import type { Constructor, EntityMetadata, EntityProperty, IPrimaryKey, ISchemaGenerator, PopulateOptions, Primary, SimpleColumnMeta } from '../typings.js';
3
+ import type { Constructor, EntityMetadata, EntityProperty, IPrimaryKey, ISchemaGenerator, PopulateOptions, Primary, SimpleColumnMeta, FilterQuery, EntityValue, EntityKey } from '../typings.js';
4
4
  import { ExceptionConverter } from './ExceptionConverter.js';
5
5
  import type { EntityManager } from '../EntityManager.js';
6
6
  import type { Configuration } from '../utils/Configuration.js';
@@ -61,6 +61,13 @@ export declare abstract class Platform {
61
61
  getDateTypeDeclarationSQL(length?: number): string;
62
62
  getTimeTypeDeclarationSQL(length?: number): string;
63
63
  getRegExpOperator(val?: unknown, flags?: string): string;
64
+ mapRegExpCondition(mappedKey: string, value: {
65
+ $re: string;
66
+ $flags?: string;
67
+ }): {
68
+ sql: string;
69
+ params: unknown[];
70
+ };
64
71
  getRegExpValue(val: RegExp): {
65
72
  $re: string;
66
73
  $flags?: string;
@@ -139,6 +146,11 @@ export declare abstract class Platform {
139
146
  getMappedType(type: string): Type<unknown>;
140
147
  getDefaultMappedType(type: string): Type<unknown>;
141
148
  supportsMultipleCascadePaths(): boolean;
149
+ /**
150
+ * Returns true if the platform supports ON UPDATE foreign key rules.
151
+ * Oracle doesn't support ON UPDATE rules.
152
+ */
153
+ supportsOnUpdate(): boolean;
142
154
  supportsMultipleStatements(): boolean;
143
155
  supportsUnionWhere(): boolean;
144
156
  getArrayDeclarationSQL(): string;
@@ -148,6 +160,8 @@ export declare abstract class Platform {
148
160
  getJsonDeclarationSQL(): string;
149
161
  getSearchJsonPropertySQL(path: string, type: string, aliased: boolean): string | Raw;
150
162
  getSearchJsonPropertyKey(path: string[], type: string, aliased: boolean, value?: unknown): string | Raw;
163
+ processJsonCondition<T extends object>(o: FilterQuery<T>, value: EntityValue<T>, path: EntityKey<T>[], alias: boolean): FilterQuery<T>;
164
+ protected getJsonValueType(value: unknown): string;
151
165
  getJsonIndexDefinition(index: {
152
166
  columnNames: string[];
153
167
  }): string[];
@@ -160,6 +174,14 @@ export declare abstract class Platform {
160
174
  convertDateToJSValue(value: string | Date): string;
161
175
  convertIntervalToJSValue(value: string): unknown;
162
176
  convertIntervalToDatabaseValue(value: unknown): unknown;
177
+ usesAsKeyword(): boolean;
178
+ /**
179
+ * Determines how UUID values are compared in the change set tracking.
180
+ * Return `'string'` for inline string comparison (fast), or `'any'` for deep comparison via type methods.
181
+ */
182
+ compareUuids(): string;
183
+ convertUuidToJSValue(value: unknown): unknown;
184
+ convertUuidToDatabaseValue(value: unknown): unknown;
163
185
  parseDate(value: string | number): Date;
164
186
  getRepositoryClass<T extends object>(): Constructor<EntityRepository<T>>;
165
187
  getDefaultCharset(): string;
@@ -3,7 +3,7 @@ import { EntityRepository } from '../entity/EntityRepository.js';
3
3
  import { UnderscoreNamingStrategy } from '../naming-strategy/UnderscoreNamingStrategy.js';
4
4
  import { ExceptionConverter } from './ExceptionConverter.js';
5
5
  import { ArrayType, BigIntType, BlobType, BooleanType, CharacterType, DateTimeType, DateType, DecimalType, DoubleType, EnumType, FloatType, IntegerType, IntervalType, JsonType, MediumIntType, SmallIntType, StringType, TextType, TimeType, TinyIntType, Type, Uint8ArrayType, UnknownType, UuidType, } from '../types/index.js';
6
- import { parseJsonSafe } from '../utils/Utils.js';
6
+ import { parseJsonSafe, Utils } from '../utils/Utils.js';
7
7
  import { ReferenceKind } from '../enums.js';
8
8
  import { Raw } from '../utils/RawQueryFragment.js';
9
9
  export const JsonProperty = Symbol('JsonProperty');
@@ -104,6 +104,11 @@ export class Platform {
104
104
  getRegExpOperator(val, flags) {
105
105
  return 'regexp';
106
106
  }
107
+ mapRegExpCondition(mappedKey, value) {
108
+ const operator = this.getRegExpOperator(value.$re, value.$flags);
109
+ const quotedKey = this.quoteIdentifier(mappedKey);
110
+ return { sql: `${quotedKey} ${operator} ?`, params: [value.$re] };
111
+ }
107
112
  getRegExpValue(val) {
108
113
  if (val.flags.includes('i')) {
109
114
  return { $re: `(?i)${val.source}` };
@@ -156,7 +161,7 @@ export class Platform {
156
161
  return 'interval' + (column.length ? `(${column.length})` : '');
157
162
  }
158
163
  getTextTypeDeclarationSQL(_column) {
159
- return `text`;
164
+ return 'text';
160
165
  }
161
166
  getEnumTypeDeclarationSQL(column) {
162
167
  if (column.items?.every(item => typeof item === 'string')) {
@@ -255,6 +260,13 @@ export class Platform {
255
260
  supportsMultipleCascadePaths() {
256
261
  return true;
257
262
  }
263
+ /**
264
+ * Returns true if the platform supports ON UPDATE foreign key rules.
265
+ * Oracle doesn't support ON UPDATE rules.
266
+ */
267
+ supportsOnUpdate() {
268
+ return true;
269
+ }
258
270
  supportsMultipleStatements() {
259
271
  return this.config.get('multipleStatements');
260
272
  }
@@ -285,6 +297,31 @@ export class Platform {
285
297
  getSearchJsonPropertyKey(path, type, aliased, value) {
286
298
  return path.join('.');
287
299
  }
300
+ processJsonCondition(o, value, path, alias) {
301
+ if (Utils.isPlainObject(value) && !Object.keys(value).some(k => Utils.isOperator(k))) {
302
+ Utils.keys(value).forEach(k => {
303
+ this.processJsonCondition(o, value[k], [...path, k], alias);
304
+ });
305
+ return o;
306
+ }
307
+ if (path.length === 1) {
308
+ o[path[0]] = value;
309
+ return o;
310
+ }
311
+ const type = this.getJsonValueType(value);
312
+ const k = this.getSearchJsonPropertyKey(path, type, alias, value);
313
+ o[k] = value;
314
+ return o;
315
+ }
316
+ getJsonValueType(value) {
317
+ if (Array.isArray(value)) {
318
+ return typeof value[0];
319
+ }
320
+ if (Utils.isPlainObject(value) && Object.keys(value).every(k => Utils.isOperator(k))) {
321
+ return this.getJsonValueType(Object.values(value)[0]);
322
+ }
323
+ return typeof value;
324
+ }
288
325
  /* v8 ignore next */
289
326
  getJsonIndexDefinition(index) {
290
327
  return index.columnNames;
@@ -316,6 +353,22 @@ export class Platform {
316
353
  convertIntervalToDatabaseValue(value) {
317
354
  return value;
318
355
  }
356
+ usesAsKeyword() {
357
+ return true;
358
+ }
359
+ /**
360
+ * Determines how UUID values are compared in the change set tracking.
361
+ * Return `'string'` for inline string comparison (fast), or `'any'` for deep comparison via type methods.
362
+ */
363
+ compareUuids() {
364
+ return 'string';
365
+ }
366
+ convertUuidToJSValue(value) {
367
+ return value;
368
+ }
369
+ convertUuidToDatabaseValue(value) {
370
+ return value;
371
+ }
319
372
  parseDate(value) {
320
373
  const date = new Date(value);
321
374
  /* v8 ignore next */
@@ -4,5 +4,7 @@ import type { EntityProperty } from '../typings.js';
4
4
  export declare class UuidType extends Type<string | null | undefined> {
5
5
  getColumnType(prop: EntityProperty, platform: Platform): string;
6
6
  compareAsType(): string;
7
+ convertToDatabaseValue(value: string | null | undefined, platform: Platform): string | null;
8
+ convertToJSValue(value: string | null | undefined, platform: Platform): string | null | undefined;
7
9
  ensureComparable(): boolean;
8
10
  }
package/types/UuidType.js CHANGED
@@ -4,9 +4,21 @@ export class UuidType extends Type {
4
4
  return platform.getUuidTypeDeclarationSQL(prop);
5
5
  }
6
6
  compareAsType() {
7
- return 'string';
7
+ return this.platform?.compareUuids() ?? 'string';
8
+ }
9
+ convertToDatabaseValue(value, platform) {
10
+ if (value == null) {
11
+ return value;
12
+ }
13
+ return platform.convertUuidToDatabaseValue(value);
14
+ }
15
+ convertToJSValue(value, platform) {
16
+ if (value == null) {
17
+ return value;
18
+ }
19
+ return platform.convertUuidToJSValue(value);
8
20
  }
9
21
  ensureComparable() {
10
- return false;
22
+ return this.platform?.compareUuids() !== 'string';
11
23
  }
12
24
  }
@@ -123,7 +123,7 @@ export class ChangeSetPersister {
123
123
  // Use changeSet's own meta for STI entities to get correct field mappings
124
124
  const res = await this.driver.nativeInsertMany(changeSet.meta.class, [changeSet.payload], options);
125
125
  if (!wrapped.hasPrimaryKey()) {
126
- this.mapPrimaryKey(meta, res.insertId, changeSet);
126
+ this.mapPrimaryKey(meta, res.insertId ?? res.row?.[meta.primaryKeys[0]], changeSet);
127
127
  }
128
128
  this.mapReturnedValues(changeSet.entity, changeSet.payload, res.row, meta);
129
129
  this.markAsPopulated(changeSet, meta);
@@ -891,6 +891,7 @@ export interface Options<Driver extends IDatabaseDriver = IDatabaseDriver, EM ex
891
891
  * When not set, no rule is emitted and the database uses its native default (NO ACTION/RESTRICT).
892
892
  */
893
893
  defaultDeleteRule?: 'cascade' | 'no action' | 'set null' | 'set default' | 'restrict';
894
+ tableSpace?: string;
894
895
  };
895
896
  /**
896
897
  * Embeddable entity configuration options.
@@ -25,7 +25,6 @@ export declare class QueryHelper {
25
25
  static processCustomType<T extends object>(prop: EntityProperty<T>, cond: FilterQuery<T>, platform: Platform, key?: string, fromQuery?: boolean): FilterQuery<T>;
26
26
  private static isSupportedOperator;
27
27
  private static processJsonCondition;
28
- private static getValueType;
29
28
  static findProperty<T>(fieldName: string, options: ProcessWhereOptions<T>): EntityProperty<T> | undefined;
30
29
  /**
31
30
  * Converts entity references for composite FK properties into flat arrays
@@ -186,7 +186,7 @@ export class QueryHelper {
186
186
  value = QueryHelper.processCustomType(prop, value, platform, undefined, true);
187
187
  }
188
188
  // oxfmt-ignore
189
- const isJsonProperty = prop?.customType instanceof JsonType && Utils.isPlainObject(value) && !isRaw(value) && Object.keys(value)[0] !== '$eq';
189
+ const isJsonProperty = prop?.customType instanceof JsonType && !isRaw(value) && (Utils.isPlainObject(value) ? Object.keys(value)[0] !== '$eq' : !Array.isArray(value));
190
190
  if (isJsonProperty && prop?.kind !== ReferenceKind.EMBEDDED) {
191
191
  return this.processJsonCondition(o, value, [prop.fieldNames[0]], platform, aliased);
192
192
  }
@@ -283,29 +283,7 @@ export class QueryHelper {
283
283
  return !!QueryHelper.SUPPORTED_OPERATORS.find(op => key === op);
284
284
  }
285
285
  static processJsonCondition(o, value, path, platform, alias) {
286
- if (Utils.isPlainObject(value) && !Object.keys(value).some(k => Utils.isOperator(k))) {
287
- Utils.keys(value).forEach(k => {
288
- this.processJsonCondition(o, value[k], [...path, k], platform, alias);
289
- });
290
- return o;
291
- }
292
- if (path.length === 1) {
293
- o[path[0]] = value;
294
- return o;
295
- }
296
- const type = this.getValueType(value);
297
- const k = platform.getSearchJsonPropertyKey(path, type, alias, value);
298
- o[k] = value;
299
- return o;
300
- }
301
- static getValueType(value) {
302
- if (Array.isArray(value)) {
303
- return typeof value[0];
304
- }
305
- if (Utils.isPlainObject(value) && Object.keys(value).every(k => Utils.isOperator(k))) {
306
- return this.getValueType(Object.values(value)[0]);
307
- }
308
- return typeof value;
286
+ return platform.processJsonCondition(o, value, path, alias);
309
287
  }
310
288
  static findProperty(fieldName, options) {
311
289
  const parts = fieldName.split('.');
package/utils/Utils.js CHANGED
@@ -123,7 +123,7 @@ export function parseJsonSafe(value) {
123
123
  }
124
124
  export class Utils {
125
125
  static PK_SEPARATOR = '~~~';
126
- static #ORM_VERSION = '7.0.0-dev.312';
126
+ static #ORM_VERSION = '7.0.0-dev.314';
127
127
  /**
128
128
  * Checks if the argument is instance of `Object`. Returns false for arrays.
129
129
  */