@mikro-orm/entity-generator 7.2.0-dev.2 → 7.2.0-dev.21

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.
@@ -38,6 +38,9 @@ export class DefineEntitySourceFile extends EntitySchemaSourceFile {
38
38
  if (this.meta.uniques.length > 0) {
39
39
  entitySchemaOptions.uniques = this.meta.uniques.map(index => this.getUniqueOptions(index));
40
40
  }
41
+ if (this.meta.checks.length > 0) {
42
+ entitySchemaOptions.checks = this.meta.checks.map(check => this.getCheckOptions(check));
43
+ }
41
44
  entitySchemaOptions.properties = Object.fromEntries(Object.entries(this.meta.properties).map(([name, prop]) => [name, this.getPropertyBuilder(prop)]));
42
45
  // Force top level and properties to be indented, regardless of line length
43
46
  entitySchemaOptions[Config] = true;
@@ -7,6 +7,8 @@ export declare class EntityGenerator {
7
7
  static register(orm: MikroORM): void;
8
8
  generate(options?: GenerateOptions): Promise<string[]>;
9
9
  private getEntityMetadata;
10
+ /** Carries introspected RLS state (policies + enablement) from the table onto the entity metadata. */
11
+ private applyRowLevelSecurity;
10
12
  private cleanUpReferentialIntegrityRules;
11
13
  private matchName;
12
14
  private detectManyToManyRelations;
@@ -1,7 +1,7 @@
1
1
  import { EntitySchema, ReferenceKind, types, Utils, } from '@mikro-orm/core';
2
2
  import { DatabaseSchema, } from '@mikro-orm/sql';
3
3
  import { fs } from '@mikro-orm/core/fs-utils';
4
- import { dirname, join } from 'node:path';
4
+ import { dirname, join, relative, resolve } from 'node:path';
5
5
  import { writeFile } from 'node:fs/promises';
6
6
  import { DefineEntitySourceFile } from './DefineEntitySourceFile.js';
7
7
  import { EntitySchemaSourceFile } from './EntitySchemaSourceFile.js';
@@ -62,6 +62,15 @@ export class EntityGenerator {
62
62
  }
63
63
  const files = this.#sources.map(file => [file.getBaseName(), file.generate()]);
64
64
  if (options.save) {
65
+ // generated files may only land in the project folder, or under the configured path when
66
+ // that points elsewhere, so a file name can never reach an arbitrary filesystem location
67
+ const allowedRoots = [resolve(this.#config.get('baseDir')), resolve(baseDir)];
68
+ for (const [fileName] of files) {
69
+ const target = resolve(baseDir, fileName);
70
+ if (!allowedRoots.some(root => !relative(root, target).startsWith('..'))) {
71
+ throw new Error(`Cannot generate '${fileName}', it resolves outside of the project folder`);
72
+ }
73
+ }
65
74
  fs.ensureDir(baseDir);
66
75
  const promises = [];
67
76
  for (const [fileName, data] of files) {
@@ -91,7 +100,9 @@ export class EntityGenerator {
91
100
  }
92
101
  }
93
102
  }
94
- return table.getEntityDeclaration(this.#namingStrategy, this.#helper, options.scalarPropertiesForRelations);
103
+ const meta = table.getEntityDeclaration(this.#namingStrategy, this.#helper, options.scalarPropertiesForRelations);
104
+ this.applyRowLevelSecurity(meta, table);
105
+ return meta;
95
106
  });
96
107
  for (const meta of metadata) {
97
108
  for (const prop of meta.relations) {
@@ -150,6 +161,28 @@ export class EntityGenerator {
150
161
  await options.onProcessedMetadata?.(metadata, this.#platform);
151
162
  return metadata;
152
163
  }
164
+ /** Carries introspected RLS state (policies + enablement) from the table onto the entity metadata. */
165
+ applyRowLevelSecurity(meta, table) {
166
+ meta.policies = table.getPolicies().map(policy => ({
167
+ name: policy.name,
168
+ command: policy.command,
169
+ type: policy.type,
170
+ roles: policy.roles,
171
+ ...(policy.using != null ? { using: policy.using } : {}),
172
+ ...(policy.check != null ? { check: policy.check } : {}),
173
+ }));
174
+ if (table.rlsForced) {
175
+ meta.rowLevelSecurity = 'force';
176
+ }
177
+ else if (table.rlsEnabled) {
178
+ meta.rowLevelSecurity = true;
179
+ }
180
+ else if (meta.policies.length > 0) {
181
+ // policies staged but RLS disabled — record it explicitly so a reload does not re-enable RLS via the
182
+ // policies-imply-RLS default
183
+ meta.rowLevelSecurity = false;
184
+ }
185
+ }
153
186
  cleanUpReferentialIntegrityRules(metadata) {
154
187
  // Clear FK rules that match defaults for:
155
188
  // 1. FK-as-PK entities (all PKs are FKs) - cascade for both update and delete
@@ -33,6 +33,9 @@ export class EntitySchemaSourceFile extends SourceFile {
33
33
  if (this.meta.uniques.length > 0) {
34
34
  entitySchemaOptions.uniques = this.meta.uniques.map(index => this.getUniqueOptions(index));
35
35
  }
36
+ if (this.meta.checks.length > 0) {
37
+ entitySchemaOptions.checks = this.meta.checks.map(check => this.getCheckOptions(check));
38
+ }
36
39
  entitySchemaOptions.properties = Object.fromEntries(Object.entries(this.meta.properties).map(([name, prop]) => [name, this.getPropertyOptions(prop)]));
37
40
  // Force top level and properties to be indented, regardless of line length
38
41
  entitySchemaOptions[Config] = true;
@@ -64,7 +67,7 @@ export class EntitySchemaSourceFile extends SourceFile {
64
67
  }
65
68
  }
66
69
  if (primaryProps.length > 0) {
67
- const primaryPropNames = primaryProps.map(prop => `'${prop.name}'`);
70
+ const primaryPropNames = primaryProps.map(prop => this.quoteKey(prop.name));
68
71
  if (primaryProps.length > 1) {
69
72
  classBody += `${' '.repeat(2)}[${this.referenceCoreImport('PrimaryKeyProp')}]?: [${primaryPropNames.join(', ')}];\n`;
70
73
  }
@@ -73,7 +76,7 @@ export class EntitySchemaSourceFile extends SourceFile {
73
76
  }
74
77
  }
75
78
  if (eagerProperties.length > 0) {
76
- const eagerPropertyNames = eagerProperties.map(prop => `'${prop.name}'`).sort();
79
+ const eagerPropertyNames = eagerProperties.map(prop => this.quoteKey(prop.name)).sort();
77
80
  classBody += `${' '.repeat(2)}[${this.referenceCoreImport('EagerProps')}]?: ${eagerPropertyNames.join(' | ')};\n`;
78
81
  }
79
82
  classBody += props.join('');
@@ -24,10 +24,10 @@ export class NativeEnumSourceFile extends SourceFile {
24
24
  for (const enumValue of enumValues) {
25
25
  const enumName = this.namingStrategy.enumValueToEnumProperty(enumValue, this.nativeEnum.name, '', this.nativeEnum.schema);
26
26
  if (enumMode === 'dictionary') {
27
- ret += `${padding}${identifierRegex.test(enumName) ? enumName : this.quote(enumName)}: ${this.quote(enumValue)},\n`;
27
+ ret += `${padding}${identifierRegex.test(enumName) ? enumName : this.quoteKey(enumName)}: ${this.quote(enumValue)},\n`;
28
28
  }
29
29
  else {
30
- ret += `${padding}${identifierRegex.test(enumName) ? enumName : this.quote(enumName)} = ${this.quote(enumValue)},\n`;
30
+ ret += `${padding}${identifierRegex.test(enumName) ? enumName : this.quoteKey(enumName)} = ${this.quote(enumValue)},\n`;
31
31
  }
32
32
  }
33
33
  if (enumMode === 'dictionary') {
@@ -42,6 +42,9 @@ export class NativeEnumSourceFile extends SourceFile {
42
42
  return ret;
43
43
  }
44
44
  getBaseName(extension = '.ts') {
45
- return `${this.options.fileName(this.nativeEnum.name)}${extension}`;
45
+ // the enum name comes from the database and ends up in a path, so path separators
46
+ // (and anything else that cannot appear in a file name) collapse to `_`
47
+ const name = this.nativeEnum.name.replaceAll(/[^\p{L}\p{N}$_-]+/gu, '_');
48
+ return `${this.options.fileName(name)}${extension}`;
46
49
  }
47
50
  }
@@ -20,7 +20,9 @@ function quoteMultiline(val) {
20
20
  }
21
21
  function toPascalCase(name) {
22
22
  const pascal = name
23
- .split(/[_\s-]+/)
23
+ // anything that cannot appear in an identifier acts as a word separator, which keeps
24
+ // path separators out of both the emitted const name and the generated file name
25
+ .split(/[^\p{L}\p{N}$]+/u)
24
26
  .filter(Boolean)
25
27
  .map(part => part.charAt(0).toUpperCase() + part.slice(1))
26
28
  .join('');
package/SourceFile.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type Dictionary, type EmbeddableOptions, type EntityMetadata, type EntityOptions, type EntityPartitionBy, type EntityProperty, type GenerateOptions, type IndexOptions, type NamingStrategy, type OneToOneOptions, type Platform, type UniqueOptions } from '@mikro-orm/core';
1
+ import { type CheckConstraint, type Dictionary, type EmbeddableOptions, type EntityMetadata, type EntityOptions, type EntityPartitionBy, type EntityProperty, type GenerateOptions, type IndexOptions, type NamingStrategy, type OneToOneOptions, type Platform, type UniqueOptions } from '@mikro-orm/core';
2
2
  /**
3
3
  * @see https://github.com/tc39/proposal-regexp-unicode-property-escapes#other-examples
4
4
  */
@@ -21,10 +21,13 @@ export declare class SourceFile {
21
21
  private getColumnOptions;
22
22
  protected getIndexOptions(index: EntityMetadata['indexes'][number], isAtEntityLevel?: boolean): IndexOptions<Dictionary, string>;
23
23
  protected getUniqueOptions(index: EntityMetadata['uniques'][number], isAtEntityLevel?: boolean): UniqueOptions<Dictionary, string>;
24
+ protected getCheckOptions(check: EntityMetadata['checks'][number]): CheckConstraint<Dictionary>;
24
25
  protected generateImports(): string;
25
26
  protected getEntityClass(classBody: string): string;
26
27
  getBaseName(extension?: string): string;
27
28
  protected quote(val: string): string;
29
+ /** For positions that reject a template literal: object keys, import bindings/specifiers, string literal types. */
30
+ protected quoteKey(val: string): string;
28
31
  protected getPropertyDefinition(prop: EntityProperty, padLeft: number): string;
29
32
  protected getEnumClassDefinition(prop: EntityProperty, padLeft: number): string;
30
33
  protected serializeObject(options: {}, wordwrap?: number, spaces?: number, level?: number): string;
@@ -32,6 +35,7 @@ export declare class SourceFile {
32
35
  protected getEntityDeclOptions(): EntityOptions<unknown>;
33
36
  private isDiscriminatorPropertyUserDefined;
34
37
  protected getPartitionByDecl(partitionBy: EntityPartitionBy): Dictionary;
38
+ protected getPolicyDecl(policy: EntityMetadata['policies'][number]): Dictionary;
35
39
  protected getEmbeddableDeclOptions(): EmbeddableOptions<unknown>;
36
40
  private getCollectionDecl;
37
41
  private getPropertyDecorator;
package/SourceFile.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Cascade, Config, DecimalType, ReferenceKind, SCALAR_TYPES, UnknownType, Utils, inspect, } from '@mikro-orm/core';
2
+ import { DatabaseTable } from '@mikro-orm/sql';
2
3
  import { parse, relative } from 'node:path';
3
4
  import { POSSIBLE_TYPE_IMPORTS } from './CoreImportsHelper.js';
4
5
  /**
@@ -26,11 +27,13 @@ export class SourceFile {
26
27
  if (this.meta.embeddable || this.meta.collection) {
27
28
  if (this.meta.embeddable) {
28
29
  const options = this.getEmbeddableDeclOptions();
29
- ret += `@${this.referenceDecoratorImport('Embeddable')}(${Utils.hasObjectKeys(options) ? this.serializeObject(options) : ''})\n`;
30
+ const decl = `@${this.referenceDecoratorImport('Embeddable')}(`;
31
+ ret += `${decl}${Utils.hasObjectKeys(options) ? this.serializeObject(options, 80 - decl.length, 0) : ''})\n`;
30
32
  }
31
33
  else {
32
34
  const options = this.getEntityDeclOptions();
33
- ret += `@${this.referenceDecoratorImport('Entity')}(${Utils.hasObjectKeys(options) ? this.serializeObject(options) : ''})\n`;
35
+ const decl = `@${this.referenceDecoratorImport('Entity')}(`;
36
+ ret += `${decl}${Utils.hasObjectKeys(options) ? this.serializeObject(options, 80 - decl.length, 0) : ''})\n`;
34
37
  }
35
38
  }
36
39
  for (const index of this.meta.indexes) {
@@ -45,6 +48,9 @@ export class SourceFile {
45
48
  }
46
49
  ret += `@${this.referenceDecoratorImport('Unique')}(${this.serializeObject(this.getUniqueOptions(index))})\n`;
47
50
  }
51
+ for (const check of this.meta.checks) {
52
+ ret += `@${this.referenceDecoratorImport('Check')}(${this.serializeObject(this.getCheckOptions(check))})\n`;
53
+ }
48
54
  let classHead = '';
49
55
  if (this.meta.className === this.options.customBaseEntityName) {
50
56
  const defineConfigTypeSettings = {};
@@ -79,7 +85,7 @@ export class SourceFile {
79
85
  }
80
86
  });
81
87
  if (primaryProps.length > 0) {
82
- const primaryPropNames = primaryProps.map(prop => `'${prop.name}'`);
88
+ const primaryPropNames = primaryProps.map(prop => this.quoteKey(prop.name));
83
89
  if (primaryProps.length > 1) {
84
90
  classHead += `\n${' '.repeat(2)}[${this.referenceCoreImport('PrimaryKeyProp')}]?: [${primaryPropNames.join(', ')}];\n`;
85
91
  }
@@ -88,7 +94,7 @@ export class SourceFile {
88
94
  }
89
95
  }
90
96
  if (eagerProperties.length > 0) {
91
- const eagerPropertyNames = eagerProperties.map(prop => `'${prop.name}'`).sort();
97
+ const eagerPropertyNames = eagerProperties.map(prop => this.quoteKey(prop.name)).sort();
92
98
  classHead += `\n${' '.repeat(2)}[${this.referenceCoreImport('EagerProps')}]?: ${eagerPropertyNames.join(' | ')};\n`;
93
99
  }
94
100
  ret += this.getEntityClass(classBody ? `${classHead}\n${classBody}` : classHead);
@@ -198,6 +204,14 @@ export class SourceFile {
198
204
  }
199
205
  return uniqueOpt;
200
206
  }
207
+ getCheckOptions(check) {
208
+ const checkOpt = {};
209
+ if (typeof check.name === 'string') {
210
+ checkOpt.name = this.quote(check.name);
211
+ }
212
+ checkOpt.expression = this.quote(check.expression);
213
+ return checkOpt;
214
+ }
201
215
  generateImports() {
202
216
  const imports = new Set();
203
217
  if (this.coreImports.size > 0) {
@@ -242,22 +256,22 @@ export class SourceFile {
242
256
  if (file.name === '') {
243
257
  continue;
244
258
  }
245
- importMap.set(file.path, `import ${this.quote(file.name)};`);
259
+ importMap.set(file.path, `import ${this.quoteKey(file.name)};`);
246
260
  continue;
247
261
  }
248
262
  if (file.name === '') {
249
- importMap.set(file.path, `import * as ${entity} from ${this.quote(file.path)};`);
263
+ importMap.set(file.path, `import * as ${entity} from ${this.quoteKey(file.path)};`);
250
264
  continue;
251
265
  }
252
266
  if (file.name === 'default') {
253
- importMap.set(file.path, `import ${entity} from ${this.quote(file.path)};`);
267
+ importMap.set(file.path, `import ${entity} from ${this.quoteKey(file.path)};`);
254
268
  continue;
255
269
  }
256
270
  if (file.name === entity) {
257
- importMap.set(file.path, `import { ${entity} } from ${this.quote(file.path)};`);
271
+ importMap.set(file.path, `import { ${entity} } from ${this.quoteKey(file.path)};`);
258
272
  continue;
259
273
  }
260
- importMap.set(file.path, `import { ${identifierRegex.test(file.name) ? file.name : this.quote(file.name)} as ${entity} } from ${this.quote(file.path)};`);
274
+ importMap.set(file.path, `import { ${identifierRegex.test(file.name) ? file.name : this.quoteKey(file.name)} as ${entity} } from ${this.quoteKey(file.path)};`);
261
275
  }
262
276
  if (this.enumImports.size) {
263
277
  for (const [name, exports] of this.enumImports.entries()) {
@@ -265,7 +279,7 @@ export class SourceFile {
265
279
  path: `${basePath}/${this.options.fileName(name)}${extension}`,
266
280
  name,
267
281
  };
268
- importMap.set(file.path, `import { ${exports.join(', ')} } from ${this.quote(file.path)};`);
282
+ importMap.set(file.path, `import { ${exports.join(', ')} } from ${this.quoteKey(file.path)};`);
269
283
  }
270
284
  }
271
285
  for (const key of [...importMap.keys()].sort()) {
@@ -294,12 +308,26 @@ export class SourceFile {
294
308
  }
295
309
  quote(val) {
296
310
  const backtick = val.startsWith(`'`) || val.includes('\n');
297
- /* v8 ignore next */
298
- return backtick ? `\`${val.replaceAll('`', '\\``')}\`` : `'${val.replaceAll(`'`, `\\'`)}'`;
311
+ // Backslashes first, so the escapes added below don't get neutralized by a preceding `\`.
312
+ // A raw `\r` is a syntax error in a string literal and silently normalizes to `\n` in a template one.
313
+ const escaped = val.replaceAll('\\', '\\\\').replaceAll('\r', '\\r');
314
+ return backtick
315
+ ? `\`${escaped.replaceAll('`', '\\`').replaceAll('${', '\\${')}\``
316
+ : `'${escaped.replaceAll(`'`, `\\'`)}'`;
317
+ }
318
+ /** For positions that reject a template literal: object keys, import bindings/specifiers, string literal types. */
319
+ quoteKey(val) {
320
+ const escaped = val
321
+ .replaceAll('\\', '\\\\')
322
+ .replaceAll('\r', '\\r')
323
+ .replaceAll('\n', '\\n')
324
+ .replaceAll('\t', '\\t')
325
+ .replaceAll(`'`, `\\'`);
326
+ return `'${escaped}'`;
299
327
  }
300
328
  getPropertyDefinition(prop, padLeft) {
301
329
  const padding = ' '.repeat(padLeft);
302
- const propName = identifierRegex.test(prop.name) ? prop.name : this.quote(prop.name);
330
+ const propName = identifierRegex.test(prop.name) ? prop.name : this.quoteKey(prop.name);
303
331
  const enumMode = this.options.enumMode;
304
332
  let hiddenType = '';
305
333
  if (prop.hidden) {
@@ -419,10 +447,10 @@ export class SourceFile {
419
447
  for (const enumValue of enumValues) {
420
448
  const enumName = this.namingStrategy.enumValueToEnumProperty(enumValue, prop.fieldNames[0], this.meta.collection, this.meta.schema);
421
449
  if (enumMode === 'dictionary') {
422
- ret += `${padding}${identifierRegex.test(enumName) ? enumName : this.quote(enumName)}: ${formatValue(enumValue)},\n`;
450
+ ret += `${padding}${identifierRegex.test(enumName) ? enumName : this.quoteKey(enumName)}: ${formatValue(enumValue)},\n`;
423
451
  }
424
452
  else {
425
- ret += `${padding}${identifierRegex.test(enumName) ? enumName : this.quote(enumName)} = ${formatValue(enumValue)},\n`;
453
+ ret += `${padding}${identifierRegex.test(enumName) ? enumName : this.quoteKey(enumName)} = ${formatValue(enumValue)},\n`;
426
454
  }
427
455
  }
428
456
  if (enumMode === 'dictionary') {
@@ -452,7 +480,7 @@ export class SourceFile {
452
480
  const entries = Object.entries(options);
453
481
  return `{${doIndent ? `\n${' '.repeat(spaces)}` : ' '}${entries
454
482
  .map(([opt, val]) => {
455
- const key = identifierRegex.test(opt) ? opt : this.quote(opt);
483
+ const key = identifierRegex.test(opt) ? opt : this.quoteKey(opt);
456
484
  return `${doIndent ? ' '.repeat(level * 2 + (spaces + 2)) : ''}${key}: ${this.serializeValue(val, typeof nextWordwrap === 'number' ? nextWordwrap - key.length - 2 /* ': '.length*/ : undefined, doIndent ? spaces : undefined, level + 1)}`;
457
485
  })
458
486
  .join(sep)}${doIndent ? `${entries.length > 0 ? ',\n' : ''}${' '.repeat(spaces + level * 2)}` : ' '}}`;
@@ -487,6 +515,21 @@ export class SourceFile {
487
515
  if (this.meta.partitionBy) {
488
516
  options.partitionBy = this.getPartitionByDecl(this.meta.partitionBy);
489
517
  }
518
+ // policies imply RLS on reload, so only emit `rowLevelSecurity` when it adds information:
519
+ // `'force'` always, plain `true` only for a deny-all table (enabled with no policies),
520
+ // and explicit `false` only when policies are staged but RLS is disabled
521
+ if (this.meta.rowLevelSecurity === 'force') {
522
+ options.rowLevelSecurity = this.quote('force');
523
+ }
524
+ else if (this.meta.rowLevelSecurity === true && this.meta.policies.length === 0) {
525
+ options.rowLevelSecurity = true;
526
+ }
527
+ else if (this.meta.rowLevelSecurity === false && this.meta.policies.length > 0) {
528
+ options.rowLevelSecurity = false;
529
+ }
530
+ if (this.meta.policies.length > 0) {
531
+ options.policies = this.meta.policies.map(policy => this.getPolicyDecl(policy));
532
+ }
490
533
  if (this.meta.readonly && !this.meta.virtual) {
491
534
  options.readonly = this.meta.readonly;
492
535
  }
@@ -537,6 +580,27 @@ export class SourceFile {
537
580
  }
538
581
  return result;
539
582
  }
583
+ getPolicyDecl(policy) {
584
+ // introspected names are always explicit; the rest is emitted only when it differs from the default
585
+ const result = { name: this.quote(policy.name) };
586
+ if (policy.command && policy.command !== 'all') {
587
+ result.command = this.quote(policy.command);
588
+ }
589
+ if (policy.type && policy.type !== 'permissive') {
590
+ result.type = this.quote(policy.type);
591
+ }
592
+ const roles = policy.roles;
593
+ if (roles && !DatabaseTable.isDefaultPolicyRoles(roles)) {
594
+ result.roles = roles.map(role => this.quote(role));
595
+ }
596
+ if (typeof policy.using === 'string') {
597
+ result.using = this.quote(policy.using);
598
+ }
599
+ if (typeof policy.check === 'string') {
600
+ result.check = this.quote(policy.check);
601
+ }
602
+ return result;
603
+ }
540
604
  getEmbeddableDeclOptions() {
541
605
  const options = {};
542
606
  return this.getCollectionDecl(options, 'discriminator');
@@ -673,7 +737,8 @@ export class SourceFile {
673
737
  prop.defaultRaw !== 'null' &&
674
738
  prop.defaultRaw !== '' &&
675
739
  prop.defaultRaw !== (typeof prop.default === 'string' ? this.quote(prop.default) : `${prop.default}`)) {
676
- options.defaultRaw = `\`${prop.defaultRaw}\``;
740
+ // kept as a template literal for readability, but raw SQL may contain `${`, which would otherwise interpolate
741
+ options.defaultRaw = `\`${prop.defaultRaw.replaceAll('\\', '\\\\').replaceAll('`', '\\`').replaceAll('${', '\\${')}\``;
677
742
  }
678
743
  else if (!(typeof prop.default === 'undefined' || prop.default === null) &&
679
744
  (prop.ref ||
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/entity-generator",
3
- "version": "7.2.0-dev.2",
3
+ "version": "7.2.0-dev.21",
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",
@@ -47,13 +47,13 @@
47
47
  "copy": "node ../../scripts/copy.mjs"
48
48
  },
49
49
  "dependencies": {
50
- "@mikro-orm/sql": "7.2.0-dev.2"
50
+ "@mikro-orm/sql": "7.2.0-dev.21"
51
51
  },
52
52
  "devDependencies": {
53
- "@mikro-orm/core": "^7.1.7"
53
+ "@mikro-orm/core": "^7.1.15"
54
54
  },
55
55
  "peerDependencies": {
56
- "@mikro-orm/core": "7.2.0-dev.2"
56
+ "@mikro-orm/core": "7.2.0-dev.21"
57
57
  },
58
58
  "engines": {
59
59
  "node": ">= 22.17.0"