@mikro-orm/entity-generator 6.3.14-dev.0 → 6.3.14-dev.2

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.
@@ -20,4 +20,5 @@ export declare class EntityGenerator {
20
20
  private generateBidirectionalRelations;
21
21
  private generateIdentifiedReferences;
22
22
  private generateAndAttachCustomBaseEntity;
23
+ private castNullDefaultsToUndefined;
23
24
  }
@@ -108,6 +108,9 @@ class EntityGenerator {
108
108
  if (options.customBaseEntityName) {
109
109
  this.generateAndAttachCustomBaseEntity(metadata, options.customBaseEntityName);
110
110
  }
111
+ if (options.undefinedDefaults) {
112
+ this.castNullDefaultsToUndefined(metadata);
113
+ }
111
114
  await options.onProcessedMetadata?.(metadata, this.platform);
112
115
  return metadata;
113
116
  }
@@ -226,6 +229,8 @@ class EntityGenerator {
226
229
  else if (prop.kind === core_1.ReferenceKind.ONE_TO_ONE && !prop.mappedBy) {
227
230
  newProp.kind = core_1.ReferenceKind.ONE_TO_ONE;
228
231
  newProp.nullable = true;
232
+ newProp.default = null;
233
+ newProp.defaultRaw = 'null';
229
234
  }
230
235
  else if (prop.kind === core_1.ReferenceKind.MANY_TO_MANY && !prop.mappedBy) {
231
236
  newProp.kind = core_1.ReferenceKind.MANY_TO_MANY;
@@ -268,5 +273,15 @@ class EntityGenerator {
268
273
  }));
269
274
  }
270
275
  }
276
+ castNullDefaultsToUndefined(metadata) {
277
+ for (const meta of metadata) {
278
+ for (const prop of Object.values(meta.properties)) {
279
+ if (prop.nullable && !prop.optional && prop.default === null && typeof prop.defaultRaw === 'undefined') {
280
+ prop.default = undefined;
281
+ prop.optional = true;
282
+ }
283
+ }
284
+ }
285
+ }
271
286
  }
272
287
  exports.EntityGenerator = EntityGenerator;
package/SourceFile.js CHANGED
@@ -204,7 +204,7 @@ class SourceFile {
204
204
  return `${padding}${propName}${hiddenType ? `: ${this.referenceCoreImport('Collection')}<${prop.type}>${hiddenType}` : ''} = new ${this.referenceCoreImport('Collection')}<${prop.type}>(this);\n`;
205
205
  }
206
206
  const isScalar = typeof prop.kind === 'undefined' || prop.kind === core_1.ReferenceKind.SCALAR;
207
- let hasITypeWrapper = false;
207
+ let breakdownOfIType;
208
208
  const propType = prop.mapToPk
209
209
  ? (() => {
210
210
  const runtimeTypes = prop.columnTypes.map((t, i) => (prop.customTypes?.[i] ?? this.platform.getMappedType(t)).runtimeType);
@@ -215,33 +215,43 @@ class SourceFile {
215
215
  if (prop.enum) {
216
216
  return prop.runtimeType;
217
217
  }
218
- const breakdownOfIType = this.breakdownOfIType(prop);
218
+ breakdownOfIType = this.breakdownOfIType(prop);
219
219
  if (typeof breakdownOfIType !== 'undefined') {
220
- hasITypeWrapper = true;
220
+ if (breakdownOfIType.length >= 3) {
221
+ hiddenType = '';
222
+ }
221
223
  return `${this.referenceCoreImport('IType')}<${breakdownOfIType.join(', ')}>`;
222
224
  }
223
225
  return prop.runtimeType;
224
226
  }
225
227
  return prop.type;
226
228
  })();
227
- const useDefault = prop.default != null && (propType !== 'unknown');
228
- const optional = prop.nullable ? '?' : (useDefault ? '' : '!');
229
- let ret = `${propName}${optional}: ${prop.ref ? `${this.referenceCoreImport('Ref')}<${propType}>` : `${(this.options.esmImport && !isScalar) ? `${this.referenceCoreImport('Rel')}<${propType}>` : propType}`}`;
230
- if (prop.array && (prop.kind === core_1.ReferenceKind.EMBEDDED || prop.enum)) {
231
- ret += '[]';
232
- }
229
+ const hasUsableNullDefault = (prop.nullable && !this.options.forceUndefined && prop.default === null);
230
+ const useDefault = hasUsableNullDefault || (!(typeof prop.default === 'undefined' || prop.default === null) && propType !== 'unknown' && typeof breakdownOfIType === 'undefined');
231
+ const optional = (prop.nullable && (this.options.forceUndefined || prop.optional)) ? '?' : (useDefault ? '' : '!');
232
+ let ret = `${propName}${optional}: `;
233
+ const isArray = prop.array && (prop.kind === core_1.ReferenceKind.EMBEDDED || prop.enum);
234
+ const complexType = isArray ? `${propType}[]` : propType;
235
+ let wrappedType = prop.ref
236
+ ? `${this.referenceCoreImport('Ref')}<${complexType}${(isScalar && prop.nullable && !this.options.forceUndefined) ? ' | null' : ''}>`
237
+ : ((this.options.esmImport && !isScalar) ? `${this.referenceCoreImport('Rel')}<${complexType}>` : complexType);
238
+ if (prop.nullable && !this.options.forceUndefined && (!isScalar || (!prop.ref && !wrappedType.includes(' | null')))) {
239
+ wrappedType += ' | null';
240
+ }
241
+ const optionalType = (optional !== '?' && prop.optional)
242
+ ? ` & ${this.referenceCoreImport('Opt')}`
243
+ : '';
244
+ ret += (!this.options.forceUndefined && prop.nullable && (hiddenType || optionalType)) ? `(${wrappedType})` : wrappedType;
233
245
  ret += hiddenType;
234
- if (useDefault || (prop.optional && !prop.nullable)) {
235
- ret += ` & ${this.referenceCoreImport('Opt')}`;
236
- }
237
- if (!useDefault || hasITypeWrapper || prop.type === 'unknown') {
246
+ ret += optionalType;
247
+ if (!useDefault) {
238
248
  return `${padding}${ret};\n`;
239
249
  }
240
250
  if (prop.enum && typeof prop.default === 'string') {
241
251
  const enumVal = this.namingStrategy.enumValueToEnumProperty(prop.default, prop.fieldNames[0], this.meta.collection, this.meta.schema);
242
252
  return `${padding}${ret} = ${propType}${exports.identifierRegex.test(enumVal) ? `.${enumVal}` : `[${this.quote(enumVal)}]`};\n`;
243
253
  }
244
- if (prop.fieldNames.length > 1) {
254
+ if (prop.fieldNames?.length > 1) {
245
255
  // TODO: Composite FKs with default values require additions to default/defaultRaw that are not yet supported.
246
256
  return `${padding}${ret};\n`;
247
257
  }
@@ -249,6 +259,9 @@ class SourceFile {
249
259
  if (isScalar) {
250
260
  return `${padding}${ret} = ${prop.ref ? `${this.referenceCoreImport('ref')}(${defaultVal})` : defaultVal};\n`;
251
261
  }
262
+ if (hasUsableNullDefault) {
263
+ return `${padding}${ret} = null;\n`;
264
+ }
252
265
  return `${padding}${ret} = ${prop.ref ? this.referenceCoreImport('ref') : this.referenceCoreImport('rel')}(${propType}, ${defaultVal});\n`;
253
266
  }
254
267
  getEnumClassDefinition(prop, padLeft) {
@@ -414,7 +427,7 @@ class SourceFile {
414
427
  return ret;
415
428
  }
416
429
  getCommonDecoratorOptions(options, prop) {
417
- if (prop.nullable && !prop.mappedBy) {
430
+ if (!prop.mappedBy && (prop.nullable || prop.customTypes?.[0]?.prop?.nullable)) {
418
431
  options.nullable = true;
419
432
  }
420
433
  if (prop.primary && (prop.enum || !(typeof prop.kind === 'undefined' || prop.kind === core_1.ReferenceKind.SCALAR))) {
@@ -443,11 +456,11 @@ class SourceFile {
443
456
  }
444
457
  // TODO: Composite FKs with default values require additions to default/defaultRaw that are not yet supported.
445
458
  if (prop.fieldNames?.length <= 1) {
446
- if (typeof prop.defaultRaw !== 'undefined' && prop.defaultRaw !== 'null' &&
459
+ if (typeof prop.defaultRaw !== 'undefined' && prop.defaultRaw !== 'null' && prop.defaultRaw !== '' &&
447
460
  prop.defaultRaw !== (typeof prop.default === 'string' ? this.quote(prop.default) : `${prop.default}`)) {
448
461
  options.defaultRaw = `\`${prop.defaultRaw}\``;
449
462
  }
450
- else if (prop.default != null && (prop.ref || (!prop.enum && (typeof prop.kind === 'undefined' || prop.kind === core_1.ReferenceKind.SCALAR) && (prop.type === 'unknown' || typeof this.breakdownOfIType(prop) !== 'undefined')))) {
463
+ else if (!(typeof prop.default === 'undefined' || prop.default === null) && (prop.ref || (!prop.enum && (typeof prop.kind === 'undefined' || prop.kind === core_1.ReferenceKind.SCALAR) && (prop.type === 'unknown' || typeof this.breakdownOfIType(prop) !== 'undefined')))) {
451
464
  options.default = typeof prop.default === 'string' ? this.quote(prop.default) : prop.default;
452
465
  }
453
466
  }
@@ -472,7 +485,8 @@ class SourceFile {
472
485
  ? this.platform.getMappedType(prop.columnTypes[0])
473
486
  : mappedDeclaredType));
474
487
  const rawType = mappedRawType.runtimeType;
475
- const serializedType = (prop.customType ?? mappedRawType).runtimeType;
488
+ const mappedSerializedType = (prop.customType ?? mappedRawType);
489
+ const serializedType = mappedSerializedType.runtimeType;
476
490
  // Add non-lib imports where needed.
477
491
  for (const typeSpec of [prop.runtimeType, rawType, serializedType]) {
478
492
  const simplePropType = typeSpec.replace(/\[]+$/, '');
@@ -480,13 +494,37 @@ class SourceFile {
480
494
  this.entityImports.add(simplePropType);
481
495
  }
482
496
  }
483
- if (prop.runtimeType !== rawType || rawType !== serializedType) {
484
- if (rawType !== serializedType) {
497
+ const nullables = [
498
+ prop.nullable ?? false,
499
+ mappedRawType.prop?.nullable ?? prop.nullable ?? false,
500
+ mappedSerializedType.prop?.nullable ?? prop.nullable ?? false,
501
+ ];
502
+ const hasMixedNullability = (new Set(nullables)).size > 1;
503
+ if (prop.runtimeType !== rawType || rawType !== serializedType || hasMixedNullability) {
504
+ const nullType = this.options.forceUndefined ? ' | undefined' : ' | null';
505
+ if (rawType !== serializedType || nullables[1] !== nullables[2] || (prop.hidden && nullables[0] !== nullables[1])) {
485
506
  const r = [prop.runtimeType, rawType, serializedType];
507
+ if (hasMixedNullability || prop.hidden) {
508
+ for (let i = r.length - 1; i >= 0; --i) {
509
+ if (nullables[i]) {
510
+ r[i] += nullType;
511
+ }
512
+ }
513
+ if (prop.hidden) {
514
+ r[2] = `(${r[2]}) & ${this.referenceCoreImport('Hidden')}`;
515
+ }
516
+ }
486
517
  this.propTypeBreakdowns.set(prop, r);
487
518
  return r;
488
519
  }
489
520
  const r = [prop.runtimeType, rawType];
521
+ if (hasMixedNullability) {
522
+ for (let i = r.length - 1; i >= 0; --i) {
523
+ if (nullables[i]) {
524
+ r[i] += nullType;
525
+ }
526
+ }
527
+ }
490
528
  this.propTypeBreakdowns.set(prop, r);
491
529
  return r;
492
530
  }
@@ -519,8 +557,14 @@ class SourceFile {
519
557
  }
520
558
  else {
521
559
  if (this.options.scalarTypeInDecorator // always output type if forced by the generator options
522
- || prop.hidden || (prop.optional && (!prop.nullable || prop.default != null)) // also when there are prop type modifiers, because reflect-metadata can't extract the base
523
- || (new Set([mappedRuntimeType.name, mappedColumnType.name, mappedDeclaredType.name, this.platform.getMappedType(prop.runtimeType === 'Date' ? 'datetime' : prop.runtimeType).name])).size > 1 // also if there's any ambiguity in the type.
560
+ || (prop.nullable && !this.options.forceUndefined) // also when there is the "| null" type modifier (because reflect-metadata can't extract the base)
561
+ || prop.hidden // also when there is the "& Hidden" type modifier (because reflect-metadata can't extract the base)
562
+ || (new Set([mappedRuntimeType.name, mappedColumnType.name, mappedDeclaredType.name, this.platform.getMappedType(prop.runtimeType === 'Date' ? 'datetime' : prop.runtimeType).name])).size > 1 // also, if there's any ambiguity in the type
563
+ || (() => {
564
+ const hasUsableNullDefault = (prop.nullable && !this.options.forceUndefined && prop.default === null);
565
+ const useDefault = hasUsableNullDefault || !(typeof prop.default === 'undefined' || prop.default === null);
566
+ return ((useDefault && !hasUsableNullDefault) || (prop.optional && !prop.nullable));
567
+ })() // also when there is the "| Opt" type modifier (because reflect-metadata can't extract the base)
524
568
  ) {
525
569
  options.type = this.quote(prop.type);
526
570
  }
@@ -659,7 +703,7 @@ class SourceFile {
659
703
  if (prop.generated) {
660
704
  options.generated = typeof prop.generated === 'string' ? this.quote(prop.generated) : `${prop.generated}`;
661
705
  }
662
- if (prop.fieldNames.length > 1 && prop.default != null) {
706
+ if (prop.fieldNames.length > 1 && !(typeof prop.default === 'undefined' || prop.default === null)) {
663
707
  // TODO: Composite FKs with default values require additions to default/defaultRaw that are not yet supported.
664
708
  options.ignoreSchemaChanges = [this.quote('default')];
665
709
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/entity-generator",
3
- "version": "6.3.14-dev.0",
3
+ "version": "6.3.14-dev.2",
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",
@@ -58,13 +58,13 @@
58
58
  "access": "public"
59
59
  },
60
60
  "dependencies": {
61
- "@mikro-orm/knex": "6.3.14-dev.0",
61
+ "@mikro-orm/knex": "6.3.14-dev.2",
62
62
  "fs-extra": "11.2.0"
63
63
  },
64
64
  "devDependencies": {
65
65
  "@mikro-orm/core": "^6.3.13"
66
66
  },
67
67
  "peerDependencies": {
68
- "@mikro-orm/core": "6.3.14-dev.0"
68
+ "@mikro-orm/core": "6.3.14-dev.2"
69
69
  }
70
70
  }