@rvoh/dream 2.15.1 → 2.16.0

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 (187) hide show
  1. package/dist/cjs/src/decorators/class/STI.js +31 -2
  2. package/dist/cjs/src/dream-app/helpers/importers/importModels.js +61 -44
  3. package/dist/esm/src/decorators/class/STI.js +31 -2
  4. package/dist/esm/src/dream-app/helpers/importers/importModels.js +61 -44
  5. package/dist/types/src/decorators/class/STI.d.ts +1 -0
  6. package/docs/classes/db.DreamMigrationHelpers.html +11 -11
  7. package/docs/classes/db.KyselyQueryDriver.html +35 -35
  8. package/docs/classes/db.PostgresQueryDriver.html +36 -36
  9. package/docs/classes/db.QueryDriverBase.html +34 -34
  10. package/docs/classes/errors.CheckConstraintViolation.html +3 -3
  11. package/docs/classes/errors.ColumnOverflow.html +3 -3
  12. package/docs/classes/errors.CreateOrFindByFailedToCreateAndFind.html +3 -3
  13. package/docs/classes/errors.DataIncompatibleWithDatabaseField.html +3 -3
  14. package/docs/classes/errors.DataTypeColumnTypeMismatch.html +3 -3
  15. package/docs/classes/errors.DecryptionError.html +2 -2
  16. package/docs/classes/errors.DecryptionParseError.html +2 -2
  17. package/docs/classes/errors.DecryptionRotationError.html +3 -3
  18. package/docs/classes/errors.GlobalNameNotSet.html +3 -3
  19. package/docs/classes/errors.InvalidCalendarDate.html +2 -2
  20. package/docs/classes/errors.InvalidClockTime.html +2 -2
  21. package/docs/classes/errors.InvalidClockTimeTz.html +2 -2
  22. package/docs/classes/errors.InvalidDateTime.html +2 -2
  23. package/docs/classes/errors.MissingSerializersDefinition.html +3 -3
  24. package/docs/classes/errors.NonLoadedAssociation.html +3 -3
  25. package/docs/classes/errors.NotNullViolation.html +3 -3
  26. package/docs/classes/errors.RecordNotFound.html +3 -3
  27. package/docs/classes/errors.ValidationError.html +3 -3
  28. package/docs/classes/index.CalendarDate.html +33 -33
  29. package/docs/classes/index.ClockTime.html +32 -32
  30. package/docs/classes/index.ClockTimeTz.html +35 -35
  31. package/docs/classes/index.DateTime.html +86 -86
  32. package/docs/classes/index.Decorators.html +19 -19
  33. package/docs/classes/index.Dream.html +118 -118
  34. package/docs/classes/index.DreamApp.html +10 -10
  35. package/docs/classes/index.DreamTransaction.html +2 -2
  36. package/docs/classes/index.Env.html +2 -2
  37. package/docs/classes/index.Query.html +58 -58
  38. package/docs/classes/system.CliFileWriter.html +4 -4
  39. package/docs/classes/system.DreamBin.html +2 -2
  40. package/docs/classes/system.DreamCLI.html +7 -7
  41. package/docs/classes/system.DreamImporter.html +2 -2
  42. package/docs/classes/system.DreamLogos.html +2 -2
  43. package/docs/classes/system.DreamSerializerBuilder.html +11 -11
  44. package/docs/classes/system.ObjectSerializerBuilder.html +8 -8
  45. package/docs/classes/system.PathHelpers.html +3 -3
  46. package/docs/classes/utils.Encrypt.html +3 -3
  47. package/docs/classes/utils.Range.html +2 -2
  48. package/docs/functions/db.closeAllDbConnections.html +1 -1
  49. package/docs/functions/db.dreamDbConnections.html +1 -1
  50. package/docs/functions/db.untypedDb.html +1 -1
  51. package/docs/functions/db.validateColumn.html +1 -1
  52. package/docs/functions/db.validateTable.html +1 -1
  53. package/docs/functions/errors.pgErrorType.html +1 -1
  54. package/docs/functions/index.DreamSerializer.html +1 -1
  55. package/docs/functions/index.ObjectSerializer.html +1 -1
  56. package/docs/functions/index.ReplicaSafe.html +1 -1
  57. package/docs/functions/index.STI.html +1 -1
  58. package/docs/functions/index.SoftDelete.html +1 -1
  59. package/docs/functions/utils.camelize.html +1 -1
  60. package/docs/functions/utils.capitalize.html +1 -1
  61. package/docs/functions/utils.cloneDeepSafe.html +1 -1
  62. package/docs/functions/utils.compact.html +1 -1
  63. package/docs/functions/utils.groupBy.html +1 -1
  64. package/docs/functions/utils.hyphenize.html +1 -1
  65. package/docs/functions/utils.intersection.html +1 -1
  66. package/docs/functions/utils.isEmpty.html +1 -1
  67. package/docs/functions/utils.normalizeUnicode.html +1 -1
  68. package/docs/functions/utils.pascalize.html +1 -1
  69. package/docs/functions/utils.percent.html +1 -1
  70. package/docs/functions/utils.range.html +1 -1
  71. package/docs/functions/utils.round.html +1 -1
  72. package/docs/functions/utils.sanitizeString.html +1 -1
  73. package/docs/functions/utils.snakeify.html +1 -1
  74. package/docs/functions/utils.sort.html +1 -1
  75. package/docs/functions/utils.sortBy.html +1 -1
  76. package/docs/functions/utils.sortObjectByKey.html +1 -1
  77. package/docs/functions/utils.sortObjectByValue.html +1 -1
  78. package/docs/functions/utils.uncapitalize.html +1 -1
  79. package/docs/functions/utils.uniq.html +1 -1
  80. package/docs/interfaces/openapi.OpenapiDescription.html +2 -2
  81. package/docs/interfaces/openapi.OpenapiSchemaProperties.html +1 -1
  82. package/docs/interfaces/openapi.OpenapiSchemaPropertiesShorthand.html +1 -1
  83. package/docs/interfaces/openapi.OpenapiTypeFieldObject.html +1 -1
  84. package/docs/interfaces/types.BelongsToStatement.html +2 -2
  85. package/docs/interfaces/types.DecoratorContext.html +2 -2
  86. package/docs/interfaces/types.DreamAppInitOptions.html +2 -2
  87. package/docs/interfaces/types.DreamAppOpts.html +2 -2
  88. package/docs/interfaces/types.DreamDbConfig.html +5 -5
  89. package/docs/interfaces/types.DurationObject.html +2 -2
  90. package/docs/interfaces/types.EncryptOptions.html +2 -2
  91. package/docs/interfaces/types.InternalAnyTypedSerializerRendersMany.html +2 -2
  92. package/docs/interfaces/types.InternalAnyTypedSerializerRendersOne.html +2 -2
  93. package/docs/interfaces/types.SerializerRendererOpts.html +2 -2
  94. package/docs/types/openapi.CommonOpenapiSchemaObjectFields.html +1 -1
  95. package/docs/types/openapi.OpenapiAllTypes.html +1 -1
  96. package/docs/types/openapi.OpenapiFormats.html +1 -1
  97. package/docs/types/openapi.OpenapiNumberFormats.html +1 -1
  98. package/docs/types/openapi.OpenapiPrimitiveBaseTypes.html +1 -1
  99. package/docs/types/openapi.OpenapiPrimitiveTypes.html +1 -1
  100. package/docs/types/openapi.OpenapiSchemaArray.html +1 -1
  101. package/docs/types/openapi.OpenapiSchemaArrayShorthand.html +1 -1
  102. package/docs/types/openapi.OpenapiSchemaBase.html +1 -1
  103. package/docs/types/openapi.OpenapiSchemaBody.html +1 -1
  104. package/docs/types/openapi.OpenapiSchemaBodyShorthand.html +1 -1
  105. package/docs/types/openapi.OpenapiSchemaCommonFields.html +1 -1
  106. package/docs/types/openapi.OpenapiSchemaExpressionAllOf.html +2 -2
  107. package/docs/types/openapi.OpenapiSchemaExpressionAnyOf.html +2 -2
  108. package/docs/types/openapi.OpenapiSchemaExpressionOneOf.html +2 -2
  109. package/docs/types/openapi.OpenapiSchemaExpressionRef.html +2 -2
  110. package/docs/types/openapi.OpenapiSchemaExpressionRefSchemaShorthand.html +2 -2
  111. package/docs/types/openapi.OpenapiSchemaInteger.html +1 -1
  112. package/docs/types/openapi.OpenapiSchemaNull.html +2 -2
  113. package/docs/types/openapi.OpenapiSchemaNumber.html +1 -1
  114. package/docs/types/openapi.OpenapiSchemaObject.html +1 -1
  115. package/docs/types/openapi.OpenapiSchemaObjectAllOf.html +1 -1
  116. package/docs/types/openapi.OpenapiSchemaObjectAllOfShorthand.html +1 -1
  117. package/docs/types/openapi.OpenapiSchemaObjectAnyOf.html +1 -1
  118. package/docs/types/openapi.OpenapiSchemaObjectAnyOfShorthand.html +1 -1
  119. package/docs/types/openapi.OpenapiSchemaObjectBase.html +1 -1
  120. package/docs/types/openapi.OpenapiSchemaObjectBaseShorthand.html +1 -1
  121. package/docs/types/openapi.OpenapiSchemaObjectOneOf.html +1 -1
  122. package/docs/types/openapi.OpenapiSchemaObjectOneOfShorthand.html +1 -1
  123. package/docs/types/openapi.OpenapiSchemaObjectShorthand.html +1 -1
  124. package/docs/types/openapi.OpenapiSchemaPrimitiveGeneric.html +1 -1
  125. package/docs/types/openapi.OpenapiSchemaShorthandExpressionAllOf.html +2 -2
  126. package/docs/types/openapi.OpenapiSchemaShorthandExpressionAnyOf.html +2 -2
  127. package/docs/types/openapi.OpenapiSchemaShorthandExpressionOneOf.html +2 -2
  128. package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializableRef.html +2 -2
  129. package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializerRef.html +2 -2
  130. package/docs/types/openapi.OpenapiSchemaShorthandPrimitiveGeneric.html +1 -1
  131. package/docs/types/openapi.OpenapiSchemaString.html +1 -1
  132. package/docs/types/openapi.OpenapiShorthandAllTypes.html +1 -1
  133. package/docs/types/openapi.OpenapiShorthandPrimitiveBaseTypes.html +1 -1
  134. package/docs/types/openapi.OpenapiShorthandPrimitiveTypes.html +1 -1
  135. package/docs/types/openapi.OpenapiTypeField.html +1 -1
  136. package/docs/types/system.DreamAppAllowedPackageManagersEnum.html +1 -1
  137. package/docs/types/types.CalendarDateDurationUnit.html +1 -1
  138. package/docs/types/types.CalendarDateObject.html +1 -1
  139. package/docs/types/types.Camelized.html +1 -1
  140. package/docs/types/types.ClockTimeObject.html +1 -1
  141. package/docs/types/types.DbConnectionType.html +1 -1
  142. package/docs/types/types.DbTypes.html +1 -1
  143. package/docs/types/types.DreamAssociationMetadata.html +1 -1
  144. package/docs/types/types.DreamAttributes.html +1 -1
  145. package/docs/types/types.DreamClassAssociationAndStatement.html +1 -1
  146. package/docs/types/types.DreamClassColumn.html +1 -1
  147. package/docs/types/types.DreamColumn.html +1 -1
  148. package/docs/types/types.DreamColumnNames.html +1 -1
  149. package/docs/types/types.DreamLogLevel.html +1 -1
  150. package/docs/types/types.DreamLogger.html +2 -2
  151. package/docs/types/types.DreamModelSerializerType.html +1 -1
  152. package/docs/types/types.DreamOrViewModelClassSerializerKey.html +1 -1
  153. package/docs/types/types.DreamOrViewModelSerializerKey.html +1 -1
  154. package/docs/types/types.DreamParamSafeAttributes.html +1 -1
  155. package/docs/types/types.DreamParamSafeColumnNames.html +1 -1
  156. package/docs/types/types.DreamSerializable.html +1 -1
  157. package/docs/types/types.DreamSerializableArray.html +1 -1
  158. package/docs/types/types.DreamSerializerKey.html +1 -1
  159. package/docs/types/types.DreamSerializers.html +1 -1
  160. package/docs/types/types.DreamVirtualColumns.html +1 -1
  161. package/docs/types/types.DurationUnit.html +1 -1
  162. package/docs/types/types.EncryptAlgorithm.html +1 -1
  163. package/docs/types/types.HasManyStatement.html +1 -1
  164. package/docs/types/types.HasOneStatement.html +1 -1
  165. package/docs/types/types.Hyphenized.html +1 -1
  166. package/docs/types/types.Pascalized.html +1 -1
  167. package/docs/types/types.PrimaryKeyType.html +1 -1
  168. package/docs/types/types.RoundingPrecision.html +1 -1
  169. package/docs/types/types.SerializerCasing.html +1 -1
  170. package/docs/types/types.SimpleObjectSerializerType.html +1 -1
  171. package/docs/types/types.Snakeified.html +1 -1
  172. package/docs/types/types.StrictInterface.html +1 -1
  173. package/docs/types/types.UpdateableAssociationProperties.html +1 -1
  174. package/docs/types/types.UpdateableProperties.html +1 -1
  175. package/docs/types/types.ValidationType.html +1 -1
  176. package/docs/types/types.ViewModel.html +2 -2
  177. package/docs/types/types.ViewModelClass.html +1 -1
  178. package/docs/types/types.WeekdayName.html +1 -1
  179. package/docs/types/types.WhereStatementForDream.html +1 -1
  180. package/docs/types/types.WhereStatementForDreamClass.html +1 -1
  181. package/docs/variables/index.DreamConst.html +1 -1
  182. package/docs/variables/index.ops.html +1 -1
  183. package/docs/variables/openapi.openapiPrimitiveTypes.html +1 -1
  184. package/docs/variables/openapi.openapiShorthandPrimitiveTypes.html +1 -1
  185. package/docs/variables/system.DreamAppAllowedPackageManagersEnumValues.html +1 -1
  186. package/docs/variables/system.primaryKeyTypes.html +1 -1
  187. package/package.json +2 -2
@@ -6,8 +6,6 @@ export const STI_SCOPE_NAME = 'dream:STI';
6
6
  export default function STI(dreamClass) {
7
7
  return function (stiChildClass) {
8
8
  const baseClass = dreamClass['sti'].baseClass || dreamClass;
9
- if (Object.getOwnPropertyDescriptor(stiChildClass, 'associationMetadataByType'))
10
- throw new StiChildCannotDefineNewAssociations(baseClass, stiChildClass);
11
9
  if (Object.getOwnPropertyDescriptor(stiChildClass, 'replicaSafe'))
12
10
  throw new StiChildIncompatibleWithReplicaSafeDecorator(stiChildClass);
13
11
  if (Object.getOwnPropertyDescriptor(stiChildClass, 'softDelete'))
@@ -28,3 +26,34 @@ export default function STI(dreamClass) {
28
26
  scopeImplementation(stiChildClass, STI_SCOPE_NAME, { default: true });
29
27
  };
30
28
  }
29
+ export function validateStiChildAssociations(dreamClasses) {
30
+ dreamClasses.forEach(dreamClass => {
31
+ if (!dreamClass?.isDream)
32
+ return;
33
+ if (!dreamClass['sti'].active)
34
+ return;
35
+ const baseClass = dreamClass['sti'].baseClass;
36
+ if (!baseClass)
37
+ return;
38
+ if (hasAssociationsUnavailableOnBase(baseClass, dreamClass))
39
+ throw new StiChildCannotDefineNewAssociations(baseClass, dreamClass);
40
+ });
41
+ }
42
+ function hasAssociationsUnavailableOnBase(baseClass, stiChildClass) {
43
+ const baseAssociationKeys = associationKeysByTypeAndName(baseClass['associationMetadataByType']);
44
+ const childAssociationKeys = associationKeysByTypeAndName(stiChildClass['associationMetadataByType']);
45
+ for (const associationKey of childAssociationKeys) {
46
+ if (!baseAssociationKeys.has(associationKey))
47
+ return true;
48
+ }
49
+ return false;
50
+ }
51
+ function associationKeysByTypeAndName(associationMetadataByType) {
52
+ const res = new Set();
53
+ Object.entries(associationMetadataByType).forEach(([associationType, associations]) => {
54
+ associations.forEach((association) => {
55
+ res.add(`${associationType}:${association.as}`);
56
+ });
57
+ });
58
+ return res;
59
+ }
@@ -1,11 +1,21 @@
1
1
  import Dream from '../../../Dream.js';
2
+ import { validateStiChildAssociations } from '../../../decorators/class/STI.js';
2
3
  import DreamMissingRequiredOverride from '../../../errors/DreamMissingRequiredOverride.js';
3
4
  import DreamImporter from '../DreamImporter.js';
4
5
  import globalModelKeyFromPath from '../globalModelKeyFromPath.js';
5
6
  let _models;
7
+ let _importModelsPromise;
6
8
  export default async function importModels(modelsPath, modelImportCb) {
7
9
  if (_models)
8
10
  return _models;
11
+ if (_importModelsPromise)
12
+ return await _importModelsPromise;
13
+ _importModelsPromise = importModelsUncached(modelsPath, modelImportCb).finally(() => {
14
+ _importModelsPromise = undefined;
15
+ });
16
+ return await _importModelsPromise;
17
+ }
18
+ async function importModelsUncached(modelsPath, modelImportCb) {
9
19
  const modelClasses = await DreamImporter.importDreams(modelsPath, modelImportCb);
10
20
  /**
11
21
  * Certain features (e.g. passing a Dream instance to `create` so that it automatically destructures polymorphic type and primary key)
@@ -14,58 +24,65 @@ export default async function importModels(modelsPath, modelImportCb) {
14
24
  * to only apply static values once, on boot, `globallyInitializingDecorators` is set to true on Dream, and all Dream models are instantiated.
15
25
  */
16
26
  Dream['globallyInitializingDecorators'] = true;
17
- _models = {};
18
- for (const [modelPath, modelClass] of modelClasses) {
19
- // `?` in case modelClass is undefined (e.g. a file without a default export exists in the models directory hierarchy)
20
- if (modelClass?.isDream) {
21
- try {
22
- // Don't create a global lookup for ApplicationModel
23
- // ApplicationModel does not have a table
24
- if (modelClass.table) {
25
- modelClass['defineAttributeAccessors']();
26
- const modelKey = globalModelKeyFromPath(modelPath, modelsPath);
27
- modelClass['setGlobalName'](modelKey);
28
- _models[modelKey] = modelClass;
27
+ const models = {};
28
+ try {
29
+ for (const [modelPath, modelClass] of modelClasses) {
30
+ // `?` in case modelClass is undefined (e.g. a file without a default export exists in the models directory hierarchy)
31
+ if (modelClass?.isDream) {
32
+ try {
33
+ // Don't create a global lookup for ApplicationModel
34
+ // ApplicationModel does not have a table
35
+ if (modelClass.table) {
36
+ modelClass['defineAttributeAccessors']();
37
+ const modelKey = globalModelKeyFromPath(modelPath, modelsPath);
38
+ modelClass['setGlobalName'](modelKey);
39
+ models[modelKey] = modelClass;
40
+ }
41
+ }
42
+ catch (error) {
43
+ // ApplicationModel will automatically raise an exception here,
44
+ // since it does not have a table.
45
+ if (!(error instanceof DreamMissingRequiredOverride))
46
+ throw error;
29
47
  }
30
- }
31
- catch (error) {
32
- // ApplicationModel will automatically raise an exception here,
33
- // since it does not have a table.
34
- if (!(error instanceof DreamMissingRequiredOverride))
35
- throw error;
36
48
  }
37
49
  }
38
- }
39
- for (const [, modelClass] of modelClasses) {
40
- // `?` in case modelClass is undefined (e.g. a file without a default export exists in the models directory hierarchy)
41
- if (modelClass?.isDream) {
42
- try {
43
- /**
44
- * Certain features (e.g. passing a Dream instance to `create` so that it automatically destructures polymorphic type and primary key)
45
- * need static access to things set up by decorators (e.g. associations). Stage 3 Decorators change the context that is available
46
- * at decoration time such that the class of a property being decorated is only avilable during instance instantiation. In order
47
- * to only apply static values once, on boot, `globallyInitializingDecorators` is set to true on Dream, and all Dream models are instantiated.
48
- */
49
- new modelClass({}, { _internalUseOnly: true });
50
- }
51
- catch (error) {
52
- // ApplicationModel will automatically raise an exception here,
53
- // since it does not have a table.
54
- if (!(error instanceof DreamMissingRequiredOverride))
55
- throw error;
50
+ for (const [, modelClass] of modelClasses) {
51
+ // `?` in case modelClass is undefined (e.g. a file without a default export exists in the models directory hierarchy)
52
+ if (modelClass?.isDream) {
53
+ try {
54
+ /**
55
+ * Certain features (e.g. passing a Dream instance to `create` so that it automatically destructures polymorphic type and primary key)
56
+ * need static access to things set up by decorators (e.g. associations). Stage 3 Decorators change the context that is available
57
+ * at decoration time such that the class of a property being decorated is only avilable during instance instantiation. In order
58
+ * to only apply static values once, on boot, `globallyInitializingDecorators` is set to true on Dream, and all Dream models are instantiated.
59
+ */
60
+ new modelClass({}, { _internalUseOnly: true });
61
+ }
62
+ catch (error) {
63
+ // ApplicationModel will automatically raise an exception here,
64
+ // since it does not have a table.
65
+ if (!(error instanceof DreamMissingRequiredOverride))
66
+ throw error;
67
+ }
56
68
  }
57
69
  }
70
+ validateStiChildAssociations(modelClasses.map(([, modelClass]) => modelClass));
71
+ _models = models;
72
+ return _models;
73
+ }
74
+ finally {
75
+ /**
76
+ * Certain features (e.g. passing a Dream instance to `create` so that it automatically destructures polymorphic type and primary key)
77
+ * need static access to things set up by decorators (e.g. associations). Stage 3 Decorators change the context that is available
78
+ * at decoration time such that the class of a property being decorated is only avilable during instance instantiation. In order
79
+ * to only apply static values once, on boot, `globallyInitializingDecorators` is set to true on Dream, and all Dream models are instantiated.
80
+ */
81
+ Dream['globallyInitializingDecorators'] = false;
58
82
  }
59
- /**
60
- * Certain features (e.g. passing a Dream instance to `create` so that it automatically destructures polymorphic type and primary key)
61
- * need static access to things set up by decorators (e.g. associations). Stage 3 Decorators change the context that is available
62
- * at decoration time such that the class of a property being decorated is only avilable during instance instantiation. In order
63
- * to only apply static values once, on boot, `globallyInitializingDecorators` is set to true on Dream, and all Dream models are instantiated.
64
- */
65
- Dream['globallyInitializingDecorators'] = false;
66
- return _models;
67
83
  }
68
84
  export function setCachedModels(models) {
85
+ _importModelsPromise = undefined;
69
86
  _models = models;
70
87
  }
71
88
  export function getModelsOrFail() {
@@ -6,8 +6,6 @@ export const STI_SCOPE_NAME = 'dream:STI';
6
6
  export default function STI(dreamClass) {
7
7
  return function (stiChildClass) {
8
8
  const baseClass = dreamClass['sti'].baseClass || dreamClass;
9
- if (Object.getOwnPropertyDescriptor(stiChildClass, 'associationMetadataByType'))
10
- throw new StiChildCannotDefineNewAssociations(baseClass, stiChildClass);
11
9
  if (Object.getOwnPropertyDescriptor(stiChildClass, 'replicaSafe'))
12
10
  throw new StiChildIncompatibleWithReplicaSafeDecorator(stiChildClass);
13
11
  if (Object.getOwnPropertyDescriptor(stiChildClass, 'softDelete'))
@@ -28,3 +26,34 @@ export default function STI(dreamClass) {
28
26
  scopeImplementation(stiChildClass, STI_SCOPE_NAME, { default: true });
29
27
  };
30
28
  }
29
+ export function validateStiChildAssociations(dreamClasses) {
30
+ dreamClasses.forEach(dreamClass => {
31
+ if (!dreamClass?.isDream)
32
+ return;
33
+ if (!dreamClass['sti'].active)
34
+ return;
35
+ const baseClass = dreamClass['sti'].baseClass;
36
+ if (!baseClass)
37
+ return;
38
+ if (hasAssociationsUnavailableOnBase(baseClass, dreamClass))
39
+ throw new StiChildCannotDefineNewAssociations(baseClass, dreamClass);
40
+ });
41
+ }
42
+ function hasAssociationsUnavailableOnBase(baseClass, stiChildClass) {
43
+ const baseAssociationKeys = associationKeysByTypeAndName(baseClass['associationMetadataByType']);
44
+ const childAssociationKeys = associationKeysByTypeAndName(stiChildClass['associationMetadataByType']);
45
+ for (const associationKey of childAssociationKeys) {
46
+ if (!baseAssociationKeys.has(associationKey))
47
+ return true;
48
+ }
49
+ return false;
50
+ }
51
+ function associationKeysByTypeAndName(associationMetadataByType) {
52
+ const res = new Set();
53
+ Object.entries(associationMetadataByType).forEach(([associationType, associations]) => {
54
+ associations.forEach((association) => {
55
+ res.add(`${associationType}:${association.as}`);
56
+ });
57
+ });
58
+ return res;
59
+ }
@@ -1,11 +1,21 @@
1
1
  import Dream from '../../../Dream.js';
2
+ import { validateStiChildAssociations } from '../../../decorators/class/STI.js';
2
3
  import DreamMissingRequiredOverride from '../../../errors/DreamMissingRequiredOverride.js';
3
4
  import DreamImporter from '../DreamImporter.js';
4
5
  import globalModelKeyFromPath from '../globalModelKeyFromPath.js';
5
6
  let _models;
7
+ let _importModelsPromise;
6
8
  export default async function importModels(modelsPath, modelImportCb) {
7
9
  if (_models)
8
10
  return _models;
11
+ if (_importModelsPromise)
12
+ return await _importModelsPromise;
13
+ _importModelsPromise = importModelsUncached(modelsPath, modelImportCb).finally(() => {
14
+ _importModelsPromise = undefined;
15
+ });
16
+ return await _importModelsPromise;
17
+ }
18
+ async function importModelsUncached(modelsPath, modelImportCb) {
9
19
  const modelClasses = await DreamImporter.importDreams(modelsPath, modelImportCb);
10
20
  /**
11
21
  * Certain features (e.g. passing a Dream instance to `create` so that it automatically destructures polymorphic type and primary key)
@@ -14,58 +24,65 @@ export default async function importModels(modelsPath, modelImportCb) {
14
24
  * to only apply static values once, on boot, `globallyInitializingDecorators` is set to true on Dream, and all Dream models are instantiated.
15
25
  */
16
26
  Dream['globallyInitializingDecorators'] = true;
17
- _models = {};
18
- for (const [modelPath, modelClass] of modelClasses) {
19
- // `?` in case modelClass is undefined (e.g. a file without a default export exists in the models directory hierarchy)
20
- if (modelClass?.isDream) {
21
- try {
22
- // Don't create a global lookup for ApplicationModel
23
- // ApplicationModel does not have a table
24
- if (modelClass.table) {
25
- modelClass['defineAttributeAccessors']();
26
- const modelKey = globalModelKeyFromPath(modelPath, modelsPath);
27
- modelClass['setGlobalName'](modelKey);
28
- _models[modelKey] = modelClass;
27
+ const models = {};
28
+ try {
29
+ for (const [modelPath, modelClass] of modelClasses) {
30
+ // `?` in case modelClass is undefined (e.g. a file without a default export exists in the models directory hierarchy)
31
+ if (modelClass?.isDream) {
32
+ try {
33
+ // Don't create a global lookup for ApplicationModel
34
+ // ApplicationModel does not have a table
35
+ if (modelClass.table) {
36
+ modelClass['defineAttributeAccessors']();
37
+ const modelKey = globalModelKeyFromPath(modelPath, modelsPath);
38
+ modelClass['setGlobalName'](modelKey);
39
+ models[modelKey] = modelClass;
40
+ }
41
+ }
42
+ catch (error) {
43
+ // ApplicationModel will automatically raise an exception here,
44
+ // since it does not have a table.
45
+ if (!(error instanceof DreamMissingRequiredOverride))
46
+ throw error;
29
47
  }
30
- }
31
- catch (error) {
32
- // ApplicationModel will automatically raise an exception here,
33
- // since it does not have a table.
34
- if (!(error instanceof DreamMissingRequiredOverride))
35
- throw error;
36
48
  }
37
49
  }
38
- }
39
- for (const [, modelClass] of modelClasses) {
40
- // `?` in case modelClass is undefined (e.g. a file without a default export exists in the models directory hierarchy)
41
- if (modelClass?.isDream) {
42
- try {
43
- /**
44
- * Certain features (e.g. passing a Dream instance to `create` so that it automatically destructures polymorphic type and primary key)
45
- * need static access to things set up by decorators (e.g. associations). Stage 3 Decorators change the context that is available
46
- * at decoration time such that the class of a property being decorated is only avilable during instance instantiation. In order
47
- * to only apply static values once, on boot, `globallyInitializingDecorators` is set to true on Dream, and all Dream models are instantiated.
48
- */
49
- new modelClass({}, { _internalUseOnly: true });
50
- }
51
- catch (error) {
52
- // ApplicationModel will automatically raise an exception here,
53
- // since it does not have a table.
54
- if (!(error instanceof DreamMissingRequiredOverride))
55
- throw error;
50
+ for (const [, modelClass] of modelClasses) {
51
+ // `?` in case modelClass is undefined (e.g. a file without a default export exists in the models directory hierarchy)
52
+ if (modelClass?.isDream) {
53
+ try {
54
+ /**
55
+ * Certain features (e.g. passing a Dream instance to `create` so that it automatically destructures polymorphic type and primary key)
56
+ * need static access to things set up by decorators (e.g. associations). Stage 3 Decorators change the context that is available
57
+ * at decoration time such that the class of a property being decorated is only avilable during instance instantiation. In order
58
+ * to only apply static values once, on boot, `globallyInitializingDecorators` is set to true on Dream, and all Dream models are instantiated.
59
+ */
60
+ new modelClass({}, { _internalUseOnly: true });
61
+ }
62
+ catch (error) {
63
+ // ApplicationModel will automatically raise an exception here,
64
+ // since it does not have a table.
65
+ if (!(error instanceof DreamMissingRequiredOverride))
66
+ throw error;
67
+ }
56
68
  }
57
69
  }
70
+ validateStiChildAssociations(modelClasses.map(([, modelClass]) => modelClass));
71
+ _models = models;
72
+ return _models;
73
+ }
74
+ finally {
75
+ /**
76
+ * Certain features (e.g. passing a Dream instance to `create` so that it automatically destructures polymorphic type and primary key)
77
+ * need static access to things set up by decorators (e.g. associations). Stage 3 Decorators change the context that is available
78
+ * at decoration time such that the class of a property being decorated is only avilable during instance instantiation. In order
79
+ * to only apply static values once, on boot, `globallyInitializingDecorators` is set to true on Dream, and all Dream models are instantiated.
80
+ */
81
+ Dream['globallyInitializingDecorators'] = false;
58
82
  }
59
- /**
60
- * Certain features (e.g. passing a Dream instance to `create` so that it automatically destructures polymorphic type and primary key)
61
- * need static access to things set up by decorators (e.g. associations). Stage 3 Decorators change the context that is available
62
- * at decoration time such that the class of a property being decorated is only avilable during instance instantiation. In order
63
- * to only apply static values once, on boot, `globallyInitializingDecorators` is set to true on Dream, and all Dream models are instantiated.
64
- */
65
- Dream['globallyInitializingDecorators'] = false;
66
- return _models;
67
83
  }
68
84
  export function setCachedModels(models) {
85
+ _importModelsPromise = undefined;
69
86
  _models = models;
70
87
  }
71
88
  export function getModelsOrFail() {
@@ -1,3 +1,4 @@
1
1
  import Dream from '../../Dream.js';
2
2
  export declare const STI_SCOPE_NAME = "dream:STI";
3
3
  export default function STI(dreamClass: typeof Dream): (stiChildClass: typeof Dream) => void;
4
+ export declare function validateStiChildAssociations(dreamClasses: (typeof Dream)[]): void;