@rvoh/dream 2.16.0 → 2.17.1

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 (214) hide show
  1. package/dist/cjs/src/db/migration-helpers/DreamMigrationHelpers.js +6 -3
  2. package/dist/cjs/src/db/testDatabasePool.js +12 -3
  3. package/dist/cjs/src/decorators/class/STI.js +4 -32
  4. package/dist/cjs/src/decorators/class/SoftDelete.js +1 -1
  5. package/dist/cjs/src/decorators/field/association/BelongsTo.js +6 -1
  6. package/dist/cjs/src/decorators/field/association/HasMany.js +6 -1
  7. package/dist/cjs/src/decorators/field/association/HasOne.js +6 -1
  8. package/dist/cjs/src/decorators/field/association/shared.js +16 -0
  9. package/dist/cjs/src/dream/constants.js +1 -1
  10. package/dist/cjs/src/dream-app/helpers/importers/importModels.js +0 -2
  11. package/dist/cjs/src/dream-app/index.js +5 -6
  12. package/dist/cjs/src/helpers/cli/generateMigrationContent.js +5 -1
  13. package/dist/esm/src/db/migration-helpers/DreamMigrationHelpers.js +6 -3
  14. package/dist/esm/src/db/testDatabasePool.js +12 -3
  15. package/dist/esm/src/decorators/class/STI.js +4 -32
  16. package/dist/esm/src/decorators/class/SoftDelete.js +1 -1
  17. package/dist/esm/src/decorators/field/association/BelongsTo.js +6 -1
  18. package/dist/esm/src/decorators/field/association/HasMany.js +6 -1
  19. package/dist/esm/src/decorators/field/association/HasOne.js +6 -1
  20. package/dist/esm/src/decorators/field/association/shared.js +16 -0
  21. package/dist/esm/src/dream/constants.js +1 -1
  22. package/dist/esm/src/dream-app/helpers/importers/importModels.js +0 -2
  23. package/dist/esm/src/dream-app/index.js +5 -6
  24. package/dist/esm/src/helpers/cli/generateMigrationContent.js +5 -1
  25. package/dist/types/src/db/migration-helpers/DreamMigrationHelpers.d.ts +6 -3
  26. package/dist/types/src/db/testDatabasePool.d.ts +7 -0
  27. package/dist/types/src/decorators/class/STI.d.ts +1 -2
  28. package/dist/types/src/decorators/class/SoftDelete.d.ts +1 -1
  29. package/dist/types/src/decorators/field/association/shared.d.ts +4 -0
  30. package/dist/types/src/dream/constants.d.ts +1 -1
  31. package/dist/types/src/types/db.d.ts +1 -1
  32. package/dist/types/src/types/types/db.ts +1 -1
  33. package/docs/classes/db.DreamMigrationHelpers.html +17 -14
  34. package/docs/classes/db.KyselyQueryDriver.html +34 -34
  35. package/docs/classes/db.PostgresQueryDriver.html +35 -35
  36. package/docs/classes/db.QueryDriverBase.html +33 -33
  37. package/docs/classes/errors.CheckConstraintViolation.html +3 -3
  38. package/docs/classes/errors.ColumnOverflow.html +3 -3
  39. package/docs/classes/errors.CreateOrFindByFailedToCreateAndFind.html +3 -3
  40. package/docs/classes/errors.DataIncompatibleWithDatabaseField.html +3 -3
  41. package/docs/classes/errors.DataTypeColumnTypeMismatch.html +3 -3
  42. package/docs/classes/errors.DecryptionError.html +2 -2
  43. package/docs/classes/errors.DecryptionParseError.html +2 -2
  44. package/docs/classes/errors.DecryptionRotationError.html +3 -3
  45. package/docs/classes/errors.GlobalNameNotSet.html +3 -3
  46. package/docs/classes/errors.InvalidCalendarDate.html +2 -2
  47. package/docs/classes/errors.InvalidClockTime.html +2 -2
  48. package/docs/classes/errors.InvalidClockTimeTz.html +2 -2
  49. package/docs/classes/errors.InvalidDateTime.html +2 -2
  50. package/docs/classes/errors.MissingSerializersDefinition.html +3 -3
  51. package/docs/classes/errors.NonLoadedAssociation.html +3 -3
  52. package/docs/classes/errors.NotNullViolation.html +3 -3
  53. package/docs/classes/errors.RecordNotFound.html +3 -3
  54. package/docs/classes/errors.ValidationError.html +3 -3
  55. package/docs/classes/index.CalendarDate.html +33 -33
  56. package/docs/classes/index.ClockTime.html +32 -32
  57. package/docs/classes/index.ClockTimeTz.html +35 -35
  58. package/docs/classes/index.DateTime.html +86 -86
  59. package/docs/classes/index.Decorators.html +19 -19
  60. package/docs/classes/index.Dream.html +118 -118
  61. package/docs/classes/index.DreamApp.html +10 -10
  62. package/docs/classes/index.DreamTransaction.html +2 -2
  63. package/docs/classes/index.Env.html +2 -2
  64. package/docs/classes/index.Query.html +57 -57
  65. package/docs/classes/system.CliFileWriter.html +4 -4
  66. package/docs/classes/system.DreamBin.html +2 -2
  67. package/docs/classes/system.DreamCLI.html +7 -7
  68. package/docs/classes/system.DreamImporter.html +2 -2
  69. package/docs/classes/system.DreamLogos.html +2 -2
  70. package/docs/classes/system.DreamSerializerBuilder.html +11 -11
  71. package/docs/classes/system.ObjectSerializerBuilder.html +8 -8
  72. package/docs/classes/system.PathHelpers.html +3 -3
  73. package/docs/classes/utils.Encrypt.html +3 -3
  74. package/docs/classes/utils.Range.html +2 -2
  75. package/docs/functions/db.closeAllDbConnections.html +1 -1
  76. package/docs/functions/db.dreamDbConnections.html +1 -1
  77. package/docs/functions/db.untypedDb.html +1 -1
  78. package/docs/functions/db.validateColumn.html +1 -1
  79. package/docs/functions/db.validateTable.html +1 -1
  80. package/docs/functions/errors.pgErrorType.html +1 -1
  81. package/docs/functions/index.DreamSerializer.html +1 -1
  82. package/docs/functions/index.ObjectSerializer.html +1 -1
  83. package/docs/functions/index.ReplicaSafe.html +1 -1
  84. package/docs/functions/index.STI.html +1 -1
  85. package/docs/functions/index.SoftDelete.html +2 -2
  86. package/docs/functions/utils.camelize.html +1 -1
  87. package/docs/functions/utils.capitalize.html +1 -1
  88. package/docs/functions/utils.cloneDeepSafe.html +1 -1
  89. package/docs/functions/utils.compact.html +1 -1
  90. package/docs/functions/utils.groupBy.html +1 -1
  91. package/docs/functions/utils.hyphenize.html +1 -1
  92. package/docs/functions/utils.intersection.html +1 -1
  93. package/docs/functions/utils.isEmpty.html +1 -1
  94. package/docs/functions/utils.normalizeUnicode.html +1 -1
  95. package/docs/functions/utils.pascalize.html +1 -1
  96. package/docs/functions/utils.percent.html +1 -1
  97. package/docs/functions/utils.range.html +1 -1
  98. package/docs/functions/utils.round.html +1 -1
  99. package/docs/functions/utils.sanitizeString.html +1 -1
  100. package/docs/functions/utils.snakeify.html +1 -1
  101. package/docs/functions/utils.sort.html +1 -1
  102. package/docs/functions/utils.sortBy.html +1 -1
  103. package/docs/functions/utils.sortObjectByKey.html +1 -1
  104. package/docs/functions/utils.sortObjectByValue.html +1 -1
  105. package/docs/functions/utils.uncapitalize.html +1 -1
  106. package/docs/functions/utils.uniq.html +1 -1
  107. package/docs/interfaces/openapi.OpenapiDescription.html +2 -2
  108. package/docs/interfaces/openapi.OpenapiSchemaProperties.html +1 -1
  109. package/docs/interfaces/openapi.OpenapiSchemaPropertiesShorthand.html +1 -1
  110. package/docs/interfaces/openapi.OpenapiTypeFieldObject.html +1 -1
  111. package/docs/interfaces/types.BelongsToStatement.html +2 -2
  112. package/docs/interfaces/types.DecoratorContext.html +2 -2
  113. package/docs/interfaces/types.DreamAppInitOptions.html +2 -2
  114. package/docs/interfaces/types.DreamAppOpts.html +2 -2
  115. package/docs/interfaces/types.DreamDbConfig.html +5 -5
  116. package/docs/interfaces/types.DurationObject.html +2 -2
  117. package/docs/interfaces/types.EncryptOptions.html +2 -2
  118. package/docs/interfaces/types.InternalAnyTypedSerializerRendersMany.html +2 -2
  119. package/docs/interfaces/types.InternalAnyTypedSerializerRendersOne.html +2 -2
  120. package/docs/interfaces/types.SerializerRendererOpts.html +2 -2
  121. package/docs/types/openapi.CommonOpenapiSchemaObjectFields.html +1 -1
  122. package/docs/types/openapi.OpenapiAllTypes.html +1 -1
  123. package/docs/types/openapi.OpenapiFormats.html +1 -1
  124. package/docs/types/openapi.OpenapiNumberFormats.html +1 -1
  125. package/docs/types/openapi.OpenapiPrimitiveBaseTypes.html +1 -1
  126. package/docs/types/openapi.OpenapiPrimitiveTypes.html +1 -1
  127. package/docs/types/openapi.OpenapiSchemaArray.html +1 -1
  128. package/docs/types/openapi.OpenapiSchemaArrayShorthand.html +1 -1
  129. package/docs/types/openapi.OpenapiSchemaBase.html +1 -1
  130. package/docs/types/openapi.OpenapiSchemaBody.html +1 -1
  131. package/docs/types/openapi.OpenapiSchemaBodyShorthand.html +1 -1
  132. package/docs/types/openapi.OpenapiSchemaCommonFields.html +1 -1
  133. package/docs/types/openapi.OpenapiSchemaExpressionAllOf.html +2 -2
  134. package/docs/types/openapi.OpenapiSchemaExpressionAnyOf.html +2 -2
  135. package/docs/types/openapi.OpenapiSchemaExpressionOneOf.html +2 -2
  136. package/docs/types/openapi.OpenapiSchemaExpressionRef.html +2 -2
  137. package/docs/types/openapi.OpenapiSchemaExpressionRefSchemaShorthand.html +2 -2
  138. package/docs/types/openapi.OpenapiSchemaInteger.html +1 -1
  139. package/docs/types/openapi.OpenapiSchemaNull.html +2 -2
  140. package/docs/types/openapi.OpenapiSchemaNumber.html +1 -1
  141. package/docs/types/openapi.OpenapiSchemaObject.html +1 -1
  142. package/docs/types/openapi.OpenapiSchemaObjectAllOf.html +1 -1
  143. package/docs/types/openapi.OpenapiSchemaObjectAllOfShorthand.html +1 -1
  144. package/docs/types/openapi.OpenapiSchemaObjectAnyOf.html +1 -1
  145. package/docs/types/openapi.OpenapiSchemaObjectAnyOfShorthand.html +1 -1
  146. package/docs/types/openapi.OpenapiSchemaObjectBase.html +1 -1
  147. package/docs/types/openapi.OpenapiSchemaObjectBaseShorthand.html +1 -1
  148. package/docs/types/openapi.OpenapiSchemaObjectOneOf.html +1 -1
  149. package/docs/types/openapi.OpenapiSchemaObjectOneOfShorthand.html +1 -1
  150. package/docs/types/openapi.OpenapiSchemaObjectShorthand.html +1 -1
  151. package/docs/types/openapi.OpenapiSchemaPrimitiveGeneric.html +1 -1
  152. package/docs/types/openapi.OpenapiSchemaShorthandExpressionAllOf.html +2 -2
  153. package/docs/types/openapi.OpenapiSchemaShorthandExpressionAnyOf.html +2 -2
  154. package/docs/types/openapi.OpenapiSchemaShorthandExpressionOneOf.html +2 -2
  155. package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializableRef.html +2 -2
  156. package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializerRef.html +2 -2
  157. package/docs/types/openapi.OpenapiSchemaShorthandPrimitiveGeneric.html +1 -1
  158. package/docs/types/openapi.OpenapiSchemaString.html +1 -1
  159. package/docs/types/openapi.OpenapiShorthandAllTypes.html +1 -1
  160. package/docs/types/openapi.OpenapiShorthandPrimitiveBaseTypes.html +1 -1
  161. package/docs/types/openapi.OpenapiShorthandPrimitiveTypes.html +1 -1
  162. package/docs/types/openapi.OpenapiTypeField.html +1 -1
  163. package/docs/types/system.DreamAppAllowedPackageManagersEnum.html +1 -1
  164. package/docs/types/types.CalendarDateDurationUnit.html +1 -1
  165. package/docs/types/types.CalendarDateObject.html +1 -1
  166. package/docs/types/types.Camelized.html +1 -1
  167. package/docs/types/types.ClockTimeObject.html +1 -1
  168. package/docs/types/types.DbConnectionType.html +1 -1
  169. package/docs/types/types.DbTypes.html +1 -1
  170. package/docs/types/types.DreamAssociationMetadata.html +1 -1
  171. package/docs/types/types.DreamAttributes.html +1 -1
  172. package/docs/types/types.DreamClassAssociationAndStatement.html +1 -1
  173. package/docs/types/types.DreamClassColumn.html +1 -1
  174. package/docs/types/types.DreamColumn.html +1 -1
  175. package/docs/types/types.DreamColumnNames.html +1 -1
  176. package/docs/types/types.DreamLogLevel.html +1 -1
  177. package/docs/types/types.DreamLogger.html +2 -2
  178. package/docs/types/types.DreamModelSerializerType.html +1 -1
  179. package/docs/types/types.DreamOrViewModelClassSerializerKey.html +1 -1
  180. package/docs/types/types.DreamOrViewModelSerializerKey.html +1 -1
  181. package/docs/types/types.DreamParamSafeAttributes.html +1 -1
  182. package/docs/types/types.DreamParamSafeColumnNames.html +1 -1
  183. package/docs/types/types.DreamSerializable.html +1 -1
  184. package/docs/types/types.DreamSerializableArray.html +1 -1
  185. package/docs/types/types.DreamSerializerKey.html +1 -1
  186. package/docs/types/types.DreamSerializers.html +1 -1
  187. package/docs/types/types.DreamVirtualColumns.html +1 -1
  188. package/docs/types/types.DurationUnit.html +1 -1
  189. package/docs/types/types.EncryptAlgorithm.html +1 -1
  190. package/docs/types/types.HasManyStatement.html +1 -1
  191. package/docs/types/types.HasOneStatement.html +1 -1
  192. package/docs/types/types.Hyphenized.html +1 -1
  193. package/docs/types/types.Pascalized.html +1 -1
  194. package/docs/types/types.PrimaryKeyType.html +1 -1
  195. package/docs/types/types.RoundingPrecision.html +1 -1
  196. package/docs/types/types.SerializerCasing.html +1 -1
  197. package/docs/types/types.SimpleObjectSerializerType.html +1 -1
  198. package/docs/types/types.Snakeified.html +1 -1
  199. package/docs/types/types.StrictInterface.html +1 -1
  200. package/docs/types/types.UpdateableAssociationProperties.html +1 -1
  201. package/docs/types/types.UpdateableProperties.html +1 -1
  202. package/docs/types/types.ValidationType.html +1 -1
  203. package/docs/types/types.ViewModel.html +2 -2
  204. package/docs/types/types.ViewModelClass.html +1 -1
  205. package/docs/types/types.WeekdayName.html +1 -1
  206. package/docs/types/types.WhereStatementForDream.html +1 -1
  207. package/docs/types/types.WhereStatementForDreamClass.html +1 -1
  208. package/docs/variables/index.DreamConst.html +1 -1
  209. package/docs/variables/index.ops.html +1 -1
  210. package/docs/variables/openapi.openapiPrimitiveTypes.html +1 -1
  211. package/docs/variables/openapi.openapiShorthandPrimitiveTypes.html +1 -1
  212. package/docs/variables/system.DreamAppAllowedPackageManagersEnumValues.html +1 -1
  213. package/docs/variables/system.primaryKeyTypes.html +1 -1
  214. package/package.json +1 -1
@@ -7,9 +7,12 @@ export default class DreamMigrationHelpers {
7
7
  * This method renames the table, its primary key index (`{tablename}_pkey`),
8
8
  * and its primary key sequence (`{tablename}_id_seq`) to keep them in sync.
9
9
  *
10
- * The sequence rename is skipped for tables with UUID primary keys (which have
11
- * no associated sequence). The primary key index is always renamed since
12
- * PostgreSQL does not automatically rename it when the table is renamed.
10
+ * The sequence rename applies to both legacy `serial`/`bigserial` columns and
11
+ * modern `GENERATED ... AS IDENTITY` columns: identity columns are also backed
12
+ * by a `{tablename}_id_seq` sequence, so they need the same rename. It is
13
+ * skipped only for tables with UUID primary keys (which have no associated
14
+ * sequence). The primary key index is always renamed since PostgreSQL does not
15
+ * automatically rename it when the table is renamed.
13
16
  *
14
17
  * @param db - The Kysely database object passed into the migration up/down function
15
18
  * @param from - The current name of the table to rename
@@ -58,11 +58,20 @@ const state = {
58
58
  * probe so they always agree on the index range.
59
59
  */
60
60
  export function testDatabasePoolSize(parallelTests) {
61
- const n = typeof parallelTests === 'number' && Number.isFinite(parallelTests) && parallelTests > 0
62
- ? Math.floor(parallelTests)
63
- : 1;
61
+ const n = normalizeTestDatabaseParallelism(parallelTests);
64
62
  return 2 * Math.max(1, n) + POOL_MARGIN;
65
63
  }
64
+ /**
65
+ * Normalize configured test parallelism to the minimum safe pool width input.
66
+ * Even a serial vitest run can overlap old/new worker processes, so missing,
67
+ * invalid, zero, or fractional-below-one values all mean "one active worker",
68
+ * not "disable the per-live-worker database pool".
69
+ */
70
+ export function normalizeTestDatabaseParallelism(parallelTests) {
71
+ return typeof parallelTests === 'number' && Number.isFinite(parallelTests) && parallelTests > 0
72
+ ? Math.max(1, Math.floor(parallelTests))
73
+ : 1;
74
+ }
66
75
  /**
67
76
  * The database name for a pool index given the un-suffixed base name. Index 1
68
77
  * is the base itself (no suffix); higher indexes are `<base>_<index>`. This is
@@ -1,11 +1,14 @@
1
1
  import StiChildCannotDefineNewAssociations from '../../errors/sti/StiChildCannotDefineNewAssociations.js';
2
2
  import StiChildIncompatibleWithReplicaSafeDecorator from '../../errors/sti/StiChildIncompatibleWithReplicaSafeDecorator.js';
3
3
  import StiChildIncompatibleWithSoftDeleteDecorator from '../../errors/sti/StiChildIncompatibleWithSoftDeleteDecorator.js';
4
+ import { associationDeclarationNamesFromMetadata } from '../field/association/shared.js';
4
5
  import { scopeImplementation } from '../static-method/Scope.js';
5
6
  export const STI_SCOPE_NAME = 'dream:STI';
6
7
  export default function STI(dreamClass) {
7
- return function (stiChildClass) {
8
+ return function (stiChildClass, context) {
8
9
  const baseClass = dreamClass['sti'].baseClass || dreamClass;
10
+ if (associationDeclarationNamesFromMetadata(context?.metadata).length)
11
+ throw new StiChildCannotDefineNewAssociations(baseClass, stiChildClass);
9
12
  if (Object.getOwnPropertyDescriptor(stiChildClass, 'replicaSafe'))
10
13
  throw new StiChildIncompatibleWithReplicaSafeDecorator(stiChildClass);
11
14
  if (Object.getOwnPropertyDescriptor(stiChildClass, 'softDelete'))
@@ -26,34 +29,3 @@ export default function STI(dreamClass) {
26
29
  scopeImplementation(stiChildClass, STI_SCOPE_NAME, { default: true });
27
30
  };
28
31
  }
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
- }
@@ -14,7 +14,7 @@ export const SOFT_DELETE_SCOPE_NAME = 'dream:SoftDelete';
14
14
  * export async function up(db: Kysely<any>): Promise<void> {
15
15
  * await db.schema
16
16
  * .createTable('posts')
17
- * .addColumn('id', 'bigserial', col => col.primaryKey())
17
+ * .addColumn('id', 'bigint', col => col.primaryKey().generatedByDefaultAsIdentity())
18
18
  * .addColumn('deleted_at', 'timestamp', col => col.defaultTo(null))
19
19
  * .addColumn('created_at', 'timestamp', col => col.notNull())
20
20
  * .addColumn('updated_at', 'timestamp', col => col.notNull())
@@ -1,7 +1,7 @@
1
1
  import lookupModelByGlobalNameOrNames from '../../../dream-app/helpers/lookupModelByGlobalNameOrNames.js';
2
2
  import ArrayTargetOnlyOnPolymorphicBelongsTo from '../../../errors/associations/ArrayTargetOnlyOnPolymorphicBelongsTo.js';
3
3
  import { validatesImplementation } from '../validation/Validates.js';
4
- import { applyGetterAndSetter, associationPrimaryKeyAccessors, blankAssociationsFactory, finalForeignKey, foreignKeyTypeField, } from './shared.js';
4
+ import { applyGetterAndSetter, associationPrimaryKeyAccessors, blankAssociationsFactory, finalForeignKey, foreignKeyTypeField, markAssociationDeclaration, } from './shared.js';
5
5
  /**
6
6
  * Establishes a "BelongsTo" association between the base dream
7
7
  * and the child dream, where the base dream has a foreign key
@@ -56,6 +56,7 @@ import { applyGetterAndSetter, associationPrimaryKeyAccessors, blankAssociations
56
56
  export default function BelongsTo(globalAssociationNameOrNames, opts = {}) {
57
57
  const { on: foreignKey, optional = false, polymorphic = false, primaryKeyOverride = null, withoutDefaultScopes, } = opts;
58
58
  return function (_, context) {
59
+ markAssociationDeclaration(context);
59
60
  const key = context.name;
60
61
  context.addInitializer(function () {
61
62
  const target = this;
@@ -93,6 +94,10 @@ export default function BelongsTo(globalAssociationNameOrNames, opts = {}) {
93
94
  return foreignKeyTypeField(foreignKey, dreamClass, partialAssociation);
94
95
  },
95
96
  };
97
+ if (dreamClass['isSTIChild']) {
98
+ applyGetterAndSetter(target, association, { isBelongsTo: true, foreignKeyBase: foreignKey });
99
+ return;
100
+ }
96
101
  if (!Object.getOwnPropertyDescriptor(dreamClass, 'associationMetadataByType'))
97
102
  dreamClass['associationMetadataByType'] = blankAssociationsFactory(dreamClass);
98
103
  dreamClass['associationMetadataByType']['belongsTo'].push(association);
@@ -1,5 +1,5 @@
1
1
  import lookupModelByGlobalNameOrNames from '../../../dream-app/helpers/lookupModelByGlobalNameOrNames.js';
2
- import { applyGetterAndSetter, associationPrimaryKeyAccessors, blankAssociationsFactory, finalForeignKey, foreignKeyTypeField, validateHasStatementArgs, } from './shared.js';
2
+ import { applyGetterAndSetter, associationPrimaryKeyAccessors, blankAssociationsFactory, finalForeignKey, foreignKeyTypeField, markAssociationDeclaration, validateHasStatementArgs, } from './shared.js';
3
3
  /**
4
4
  * Establishes a "HasMany" association between the base dream
5
5
  * and the child dream, where the child dream has a foreign key
@@ -36,6 +36,7 @@ import { applyGetterAndSetter, associationPrimaryKeyAccessors, blankAssociations
36
36
  export default function HasMany(globalAssociationNameOrNames, opts = {}) {
37
37
  const { dependent, distinct, on: foreignKey, and, andNot, andAny, order, polymorphic = false, primaryKeyOverride = null, selfAnd, selfAndNot, source, through, withoutDefaultScopes, } = opts;
38
38
  return function (_, context) {
39
+ markAssociationDeclaration(context);
39
40
  const key = context.name;
40
41
  context.addInitializer(function () {
41
42
  const target = this;
@@ -86,6 +87,10 @@ export default function HasMany(globalAssociationNameOrNames, opts = {}) {
86
87
  return foreignKeyTypeField(foreignKey, dreamClass, partialAssociation);
87
88
  },
88
89
  };
90
+ if (dreamClass['isSTIChild']) {
91
+ applyGetterAndSetter(target, association);
92
+ return;
93
+ }
89
94
  if (!Object.getOwnPropertyDescriptor(dreamClass, 'associationMetadataByType'))
90
95
  dreamClass['associationMetadataByType'] = blankAssociationsFactory(dreamClass);
91
96
  dreamClass['associationMetadataByType']['hasMany'].push(association);
@@ -1,5 +1,5 @@
1
1
  import lookupModelByGlobalNameOrNames from '../../../dream-app/helpers/lookupModelByGlobalNameOrNames.js';
2
- import { applyGetterAndSetter, associationPrimaryKeyAccessors, blankAssociationsFactory, finalForeignKey, foreignKeyTypeField, validateHasStatementArgs, } from './shared.js';
2
+ import { applyGetterAndSetter, associationPrimaryKeyAccessors, blankAssociationsFactory, finalForeignKey, foreignKeyTypeField, markAssociationDeclaration, validateHasStatementArgs, } from './shared.js';
3
3
  /**
4
4
  * Establishes a "HasOne" association between the base dream
5
5
  * and the child dream, where the child dream has a foreign key
@@ -34,6 +34,7 @@ import { applyGetterAndSetter, associationPrimaryKeyAccessors, blankAssociations
34
34
  export default function HasOne(globalAssociationNameOrNames, opts = {}) {
35
35
  const { dependent, on: foreignKey, and, andNot, andAny, polymorphic = false, primaryKeyOverride = null, selfAnd, selfAndNot, source, through, withoutDefaultScopes, } = opts;
36
36
  return function (_, context) {
37
+ markAssociationDeclaration(context);
37
38
  const key = context.name;
38
39
  context.addInitializer(function () {
39
40
  const target = this;
@@ -82,6 +83,10 @@ export default function HasOne(globalAssociationNameOrNames, opts = {}) {
82
83
  return foreignKeyTypeField(foreignKey, dreamClass, partialAssociation);
83
84
  },
84
85
  };
86
+ if (dreamClass['isSTIChild']) {
87
+ applyGetterAndSetter(target, association);
88
+ return;
89
+ }
85
90
  if (!Object.getOwnPropertyDescriptor(dreamClass, 'associationMetadataByType'))
86
91
  dreamClass['associationMetadataByType'] = blankAssociationsFactory(dreamClass);
87
92
  dreamClass['associationMetadataByType']['hasOne'].push(association);
@@ -8,6 +8,22 @@ import CannotDefineAssociationWithBothDependentAndRequiredAndClause from '../../
8
8
  import camelize from '../../../helpers/camelize.js';
9
9
  import freezeBaseClassArrayMap from '../../helpers/freezeBaseClassArrayMap.js';
10
10
  import associationToGetterSetterProp from './associationToGetterSetterProp.js';
11
+ export const ASSOCIATION_DECLARATION_METADATA_KEY = Symbol('dream:associationDeclarationNames');
12
+ export function markAssociationDeclaration(context) {
13
+ const metadata = context.metadata;
14
+ if (!metadata)
15
+ return;
16
+ const existingDeclarationNames = Object.getOwnPropertyDescriptor(metadata, ASSOCIATION_DECLARATION_METADATA_KEY)?.value || [];
17
+ Object.defineProperty(metadata, ASSOCIATION_DECLARATION_METADATA_KEY, {
18
+ configurable: true,
19
+ value: [...existingDeclarationNames, context.name],
20
+ });
21
+ }
22
+ export function associationDeclarationNamesFromMetadata(metadata) {
23
+ if (!metadata)
24
+ return [];
25
+ return (Object.getOwnPropertyDescriptor(metadata, ASSOCIATION_DECLARATION_METADATA_KEY)?.value || []);
26
+ }
11
27
  export function blankAssociationsFactory(dreamClass, { freeze = false, } = {}) {
12
28
  // This pattern allows associations to be defined on a base STI class and on
13
29
  // child STI classes. The new `associationsMap` property will be created
@@ -1,4 +1,4 @@
1
- export const primaryKeyTypes = ['uuid7', 'uuid4', 'bigserial', 'bigint', 'integer'];
1
+ export const primaryKeyTypes = ['uuid7', 'uuid4', 'bigint', 'integer'];
2
2
  export const TRIGRAM_OPERATORS = ['%', '<%', '<<%'];
3
3
  export const RECURSIVE_SERIALIZATION_MAX_REPEATS = 4;
4
4
  export const RECURSIVE_DESTROY_PRELOAD_MAX_REPEATS = RECURSIVE_SERIALIZATION_MAX_REPEATS;
@@ -1,5 +1,4 @@
1
1
  import Dream from '../../../Dream.js';
2
- import { validateStiChildAssociations } from '../../../decorators/class/STI.js';
3
2
  import DreamMissingRequiredOverride from '../../../errors/DreamMissingRequiredOverride.js';
4
3
  import DreamImporter from '../DreamImporter.js';
5
4
  import globalModelKeyFromPath from '../globalModelKeyFromPath.js';
@@ -67,7 +66,6 @@ async function importModelsUncached(modelsPath, modelImportCb) {
67
66
  }
68
67
  }
69
68
  }
70
- validateStiChildAssociations(modelClasses.map(([, modelClass]) => modelClass));
71
69
  _models = models;
72
70
  return _models;
73
71
  }
@@ -1,5 +1,5 @@
1
1
  import * as util from 'node:util';
2
- import { claimedTestDatabaseIndexOrNull, claimTestDatabase, testDatabaseNameForIndex, } from '../db/testDatabasePool.js';
2
+ import { claimedTestDatabaseIndexOrNull, claimTestDatabase, normalizeTestDatabaseParallelism, testDatabaseNameForIndex, } from '../db/testDatabasePool.js';
3
3
  import validateTable from '../db/validators/validateTable.js';
4
4
  import Query from '../dream/Query.js';
5
5
  import PostgresQueryDriver from '../dream/QueryDriver/Postgres.js';
@@ -208,7 +208,7 @@ A new key can also be generated from the CLI:
208
208
  }
209
209
  _parallelTests;
210
210
  get parallelTests() {
211
- return process.env.NODE_ENV === 'test' ? this._parallelTests : undefined;
211
+ return process.env.NODE_ENV === 'test' ? normalizeTestDatabaseParallelism(this._parallelTests) : undefined;
212
212
  }
213
213
  _unicodeNormalization = 'NFC';
214
214
  get unicodeNormalization() {
@@ -218,7 +218,7 @@ A new key can also be generated from the CLI:
218
218
  get paginationPageSize() {
219
219
  return this._paginationPageSize;
220
220
  }
221
- _primaryKeyType = 'bigserial';
221
+ _primaryKeyType = 'bigint';
222
222
  get primaryKeyType() {
223
223
  return this._primaryKeyType;
224
224
  }
@@ -276,7 +276,7 @@ A new key can also be generated from the CLI:
276
276
  this._inflections = opts.inflections;
277
277
  if (opts?.serializerCasing)
278
278
  this._serializerCasing = opts.serializerCasing;
279
- if (opts?.parallelTests)
279
+ if (opts?.parallelTests !== undefined)
280
280
  this._parallelTests = opts.parallelTests;
281
281
  this._paths = {
282
282
  conf: opts?.paths?.conf || 'src/conf',
@@ -483,9 +483,8 @@ A new key can also be generated from the CLI:
483
483
  };
484
484
  break;
485
485
  case 'parallelTests':
486
- if (process.env.NODE_ENV === 'test' && !Number.isNaN(Number(options)) && Number(options) > 1) {
486
+ if (process.env.NODE_ENV === 'test')
487
487
  this._parallelTests = options;
488
- }
489
488
  break;
490
489
  case 'unicodeNormalization':
491
490
  this._unicodeNormalization = options;
@@ -361,8 +361,12 @@ function generateIdStr({ primaryKeyType }) {
361
361
  .primaryKey()
362
362
  .defaultTo(sql\`uuid_generate_v4()\`),
363
363
  )`;
364
+ case 'integer':
365
+ return `.addColumn('id', 'integer', col => col.primaryKey().generatedByDefaultAsIdentity())`;
366
+ case 'bigint':
367
+ case 'bigserial':
364
368
  default:
365
- return `.addColumn('id', '${primaryKeyType}', col => col.primaryKey())`;
369
+ return `.addColumn('id', 'bigint', col => col.primaryKey().generatedByDefaultAsIdentity())`;
366
370
  }
367
371
  }
368
372
  /**
@@ -7,9 +7,12 @@ export default class DreamMigrationHelpers {
7
7
  * This method renames the table, its primary key index (`{tablename}_pkey`),
8
8
  * and its primary key sequence (`{tablename}_id_seq`) to keep them in sync.
9
9
  *
10
- * The sequence rename is skipped for tables with UUID primary keys (which have
11
- * no associated sequence). The primary key index is always renamed since
12
- * PostgreSQL does not automatically rename it when the table is renamed.
10
+ * The sequence rename applies to both legacy `serial`/`bigserial` columns and
11
+ * modern `GENERATED ... AS IDENTITY` columns: identity columns are also backed
12
+ * by a `{tablename}_id_seq` sequence, so they need the same rename. It is
13
+ * skipped only for tables with UUID primary keys (which have no associated
14
+ * sequence). The primary key index is always renamed since PostgreSQL does not
15
+ * automatically rename it when the table is renamed.
13
16
  *
14
17
  * @param db - The Kysely database object passed into the migration up/down function
15
18
  * @param from - The current name of the table to rename
@@ -58,11 +58,20 @@ const state = {
58
58
  * probe so they always agree on the index range.
59
59
  */
60
60
  export function testDatabasePoolSize(parallelTests) {
61
- const n = typeof parallelTests === 'number' && Number.isFinite(parallelTests) && parallelTests > 0
62
- ? Math.floor(parallelTests)
63
- : 1;
61
+ const n = normalizeTestDatabaseParallelism(parallelTests);
64
62
  return 2 * Math.max(1, n) + POOL_MARGIN;
65
63
  }
64
+ /**
65
+ * Normalize configured test parallelism to the minimum safe pool width input.
66
+ * Even a serial vitest run can overlap old/new worker processes, so missing,
67
+ * invalid, zero, or fractional-below-one values all mean "one active worker",
68
+ * not "disable the per-live-worker database pool".
69
+ */
70
+ export function normalizeTestDatabaseParallelism(parallelTests) {
71
+ return typeof parallelTests === 'number' && Number.isFinite(parallelTests) && parallelTests > 0
72
+ ? Math.max(1, Math.floor(parallelTests))
73
+ : 1;
74
+ }
66
75
  /**
67
76
  * The database name for a pool index given the un-suffixed base name. Index 1
68
77
  * is the base itself (no suffix); higher indexes are `<base>_<index>`. This is
@@ -1,11 +1,14 @@
1
1
  import StiChildCannotDefineNewAssociations from '../../errors/sti/StiChildCannotDefineNewAssociations.js';
2
2
  import StiChildIncompatibleWithReplicaSafeDecorator from '../../errors/sti/StiChildIncompatibleWithReplicaSafeDecorator.js';
3
3
  import StiChildIncompatibleWithSoftDeleteDecorator from '../../errors/sti/StiChildIncompatibleWithSoftDeleteDecorator.js';
4
+ import { associationDeclarationNamesFromMetadata } from '../field/association/shared.js';
4
5
  import { scopeImplementation } from '../static-method/Scope.js';
5
6
  export const STI_SCOPE_NAME = 'dream:STI';
6
7
  export default function STI(dreamClass) {
7
- return function (stiChildClass) {
8
+ return function (stiChildClass, context) {
8
9
  const baseClass = dreamClass['sti'].baseClass || dreamClass;
10
+ if (associationDeclarationNamesFromMetadata(context?.metadata).length)
11
+ throw new StiChildCannotDefineNewAssociations(baseClass, stiChildClass);
9
12
  if (Object.getOwnPropertyDescriptor(stiChildClass, 'replicaSafe'))
10
13
  throw new StiChildIncompatibleWithReplicaSafeDecorator(stiChildClass);
11
14
  if (Object.getOwnPropertyDescriptor(stiChildClass, 'softDelete'))
@@ -26,34 +29,3 @@ export default function STI(dreamClass) {
26
29
  scopeImplementation(stiChildClass, STI_SCOPE_NAME, { default: true });
27
30
  };
28
31
  }
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
- }
@@ -14,7 +14,7 @@ export const SOFT_DELETE_SCOPE_NAME = 'dream:SoftDelete';
14
14
  * export async function up(db: Kysely<any>): Promise<void> {
15
15
  * await db.schema
16
16
  * .createTable('posts')
17
- * .addColumn('id', 'bigserial', col => col.primaryKey())
17
+ * .addColumn('id', 'bigint', col => col.primaryKey().generatedByDefaultAsIdentity())
18
18
  * .addColumn('deleted_at', 'timestamp', col => col.defaultTo(null))
19
19
  * .addColumn('created_at', 'timestamp', col => col.notNull())
20
20
  * .addColumn('updated_at', 'timestamp', col => col.notNull())
@@ -1,7 +1,7 @@
1
1
  import lookupModelByGlobalNameOrNames from '../../../dream-app/helpers/lookupModelByGlobalNameOrNames.js';
2
2
  import ArrayTargetOnlyOnPolymorphicBelongsTo from '../../../errors/associations/ArrayTargetOnlyOnPolymorphicBelongsTo.js';
3
3
  import { validatesImplementation } from '../validation/Validates.js';
4
- import { applyGetterAndSetter, associationPrimaryKeyAccessors, blankAssociationsFactory, finalForeignKey, foreignKeyTypeField, } from './shared.js';
4
+ import { applyGetterAndSetter, associationPrimaryKeyAccessors, blankAssociationsFactory, finalForeignKey, foreignKeyTypeField, markAssociationDeclaration, } from './shared.js';
5
5
  /**
6
6
  * Establishes a "BelongsTo" association between the base dream
7
7
  * and the child dream, where the base dream has a foreign key
@@ -56,6 +56,7 @@ import { applyGetterAndSetter, associationPrimaryKeyAccessors, blankAssociations
56
56
  export default function BelongsTo(globalAssociationNameOrNames, opts = {}) {
57
57
  const { on: foreignKey, optional = false, polymorphic = false, primaryKeyOverride = null, withoutDefaultScopes, } = opts;
58
58
  return function (_, context) {
59
+ markAssociationDeclaration(context);
59
60
  const key = context.name;
60
61
  context.addInitializer(function () {
61
62
  const target = this;
@@ -93,6 +94,10 @@ export default function BelongsTo(globalAssociationNameOrNames, opts = {}) {
93
94
  return foreignKeyTypeField(foreignKey, dreamClass, partialAssociation);
94
95
  },
95
96
  };
97
+ if (dreamClass['isSTIChild']) {
98
+ applyGetterAndSetter(target, association, { isBelongsTo: true, foreignKeyBase: foreignKey });
99
+ return;
100
+ }
96
101
  if (!Object.getOwnPropertyDescriptor(dreamClass, 'associationMetadataByType'))
97
102
  dreamClass['associationMetadataByType'] = blankAssociationsFactory(dreamClass);
98
103
  dreamClass['associationMetadataByType']['belongsTo'].push(association);
@@ -1,5 +1,5 @@
1
1
  import lookupModelByGlobalNameOrNames from '../../../dream-app/helpers/lookupModelByGlobalNameOrNames.js';
2
- import { applyGetterAndSetter, associationPrimaryKeyAccessors, blankAssociationsFactory, finalForeignKey, foreignKeyTypeField, validateHasStatementArgs, } from './shared.js';
2
+ import { applyGetterAndSetter, associationPrimaryKeyAccessors, blankAssociationsFactory, finalForeignKey, foreignKeyTypeField, markAssociationDeclaration, validateHasStatementArgs, } from './shared.js';
3
3
  /**
4
4
  * Establishes a "HasMany" association between the base dream
5
5
  * and the child dream, where the child dream has a foreign key
@@ -36,6 +36,7 @@ import { applyGetterAndSetter, associationPrimaryKeyAccessors, blankAssociations
36
36
  export default function HasMany(globalAssociationNameOrNames, opts = {}) {
37
37
  const { dependent, distinct, on: foreignKey, and, andNot, andAny, order, polymorphic = false, primaryKeyOverride = null, selfAnd, selfAndNot, source, through, withoutDefaultScopes, } = opts;
38
38
  return function (_, context) {
39
+ markAssociationDeclaration(context);
39
40
  const key = context.name;
40
41
  context.addInitializer(function () {
41
42
  const target = this;
@@ -86,6 +87,10 @@ export default function HasMany(globalAssociationNameOrNames, opts = {}) {
86
87
  return foreignKeyTypeField(foreignKey, dreamClass, partialAssociation);
87
88
  },
88
89
  };
90
+ if (dreamClass['isSTIChild']) {
91
+ applyGetterAndSetter(target, association);
92
+ return;
93
+ }
89
94
  if (!Object.getOwnPropertyDescriptor(dreamClass, 'associationMetadataByType'))
90
95
  dreamClass['associationMetadataByType'] = blankAssociationsFactory(dreamClass);
91
96
  dreamClass['associationMetadataByType']['hasMany'].push(association);
@@ -1,5 +1,5 @@
1
1
  import lookupModelByGlobalNameOrNames from '../../../dream-app/helpers/lookupModelByGlobalNameOrNames.js';
2
- import { applyGetterAndSetter, associationPrimaryKeyAccessors, blankAssociationsFactory, finalForeignKey, foreignKeyTypeField, validateHasStatementArgs, } from './shared.js';
2
+ import { applyGetterAndSetter, associationPrimaryKeyAccessors, blankAssociationsFactory, finalForeignKey, foreignKeyTypeField, markAssociationDeclaration, validateHasStatementArgs, } from './shared.js';
3
3
  /**
4
4
  * Establishes a "HasOne" association between the base dream
5
5
  * and the child dream, where the child dream has a foreign key
@@ -34,6 +34,7 @@ import { applyGetterAndSetter, associationPrimaryKeyAccessors, blankAssociations
34
34
  export default function HasOne(globalAssociationNameOrNames, opts = {}) {
35
35
  const { dependent, on: foreignKey, and, andNot, andAny, polymorphic = false, primaryKeyOverride = null, selfAnd, selfAndNot, source, through, withoutDefaultScopes, } = opts;
36
36
  return function (_, context) {
37
+ markAssociationDeclaration(context);
37
38
  const key = context.name;
38
39
  context.addInitializer(function () {
39
40
  const target = this;
@@ -82,6 +83,10 @@ export default function HasOne(globalAssociationNameOrNames, opts = {}) {
82
83
  return foreignKeyTypeField(foreignKey, dreamClass, partialAssociation);
83
84
  },
84
85
  };
86
+ if (dreamClass['isSTIChild']) {
87
+ applyGetterAndSetter(target, association);
88
+ return;
89
+ }
85
90
  if (!Object.getOwnPropertyDescriptor(dreamClass, 'associationMetadataByType'))
86
91
  dreamClass['associationMetadataByType'] = blankAssociationsFactory(dreamClass);
87
92
  dreamClass['associationMetadataByType']['hasOne'].push(association);
@@ -8,6 +8,22 @@ import CannotDefineAssociationWithBothDependentAndRequiredAndClause from '../../
8
8
  import camelize from '../../../helpers/camelize.js';
9
9
  import freezeBaseClassArrayMap from '../../helpers/freezeBaseClassArrayMap.js';
10
10
  import associationToGetterSetterProp from './associationToGetterSetterProp.js';
11
+ export const ASSOCIATION_DECLARATION_METADATA_KEY = Symbol('dream:associationDeclarationNames');
12
+ export function markAssociationDeclaration(context) {
13
+ const metadata = context.metadata;
14
+ if (!metadata)
15
+ return;
16
+ const existingDeclarationNames = Object.getOwnPropertyDescriptor(metadata, ASSOCIATION_DECLARATION_METADATA_KEY)?.value || [];
17
+ Object.defineProperty(metadata, ASSOCIATION_DECLARATION_METADATA_KEY, {
18
+ configurable: true,
19
+ value: [...existingDeclarationNames, context.name],
20
+ });
21
+ }
22
+ export function associationDeclarationNamesFromMetadata(metadata) {
23
+ if (!metadata)
24
+ return [];
25
+ return (Object.getOwnPropertyDescriptor(metadata, ASSOCIATION_DECLARATION_METADATA_KEY)?.value || []);
26
+ }
11
27
  export function blankAssociationsFactory(dreamClass, { freeze = false, } = {}) {
12
28
  // This pattern allows associations to be defined on a base STI class and on
13
29
  // child STI classes. The new `associationsMap` property will be created
@@ -1,4 +1,4 @@
1
- export const primaryKeyTypes = ['uuid7', 'uuid4', 'bigserial', 'bigint', 'integer'];
1
+ export const primaryKeyTypes = ['uuid7', 'uuid4', 'bigint', 'integer'];
2
2
  export const TRIGRAM_OPERATORS = ['%', '<%', '<<%'];
3
3
  export const RECURSIVE_SERIALIZATION_MAX_REPEATS = 4;
4
4
  export const RECURSIVE_DESTROY_PRELOAD_MAX_REPEATS = RECURSIVE_SERIALIZATION_MAX_REPEATS;
@@ -1,5 +1,4 @@
1
1
  import Dream from '../../../Dream.js';
2
- import { validateStiChildAssociations } from '../../../decorators/class/STI.js';
3
2
  import DreamMissingRequiredOverride from '../../../errors/DreamMissingRequiredOverride.js';
4
3
  import DreamImporter from '../DreamImporter.js';
5
4
  import globalModelKeyFromPath from '../globalModelKeyFromPath.js';
@@ -67,7 +66,6 @@ async function importModelsUncached(modelsPath, modelImportCb) {
67
66
  }
68
67
  }
69
68
  }
70
- validateStiChildAssociations(modelClasses.map(([, modelClass]) => modelClass));
71
69
  _models = models;
72
70
  return _models;
73
71
  }
@@ -1,5 +1,5 @@
1
1
  import * as util from 'node:util';
2
- import { claimedTestDatabaseIndexOrNull, claimTestDatabase, testDatabaseNameForIndex, } from '../db/testDatabasePool.js';
2
+ import { claimedTestDatabaseIndexOrNull, claimTestDatabase, normalizeTestDatabaseParallelism, testDatabaseNameForIndex, } from '../db/testDatabasePool.js';
3
3
  import validateTable from '../db/validators/validateTable.js';
4
4
  import Query from '../dream/Query.js';
5
5
  import PostgresQueryDriver from '../dream/QueryDriver/Postgres.js';
@@ -208,7 +208,7 @@ A new key can also be generated from the CLI:
208
208
  }
209
209
  _parallelTests;
210
210
  get parallelTests() {
211
- return process.env.NODE_ENV === 'test' ? this._parallelTests : undefined;
211
+ return process.env.NODE_ENV === 'test' ? normalizeTestDatabaseParallelism(this._parallelTests) : undefined;
212
212
  }
213
213
  _unicodeNormalization = 'NFC';
214
214
  get unicodeNormalization() {
@@ -218,7 +218,7 @@ A new key can also be generated from the CLI:
218
218
  get paginationPageSize() {
219
219
  return this._paginationPageSize;
220
220
  }
221
- _primaryKeyType = 'bigserial';
221
+ _primaryKeyType = 'bigint';
222
222
  get primaryKeyType() {
223
223
  return this._primaryKeyType;
224
224
  }
@@ -276,7 +276,7 @@ A new key can also be generated from the CLI:
276
276
  this._inflections = opts.inflections;
277
277
  if (opts?.serializerCasing)
278
278
  this._serializerCasing = opts.serializerCasing;
279
- if (opts?.parallelTests)
279
+ if (opts?.parallelTests !== undefined)
280
280
  this._parallelTests = opts.parallelTests;
281
281
  this._paths = {
282
282
  conf: opts?.paths?.conf || 'src/conf',
@@ -483,9 +483,8 @@ A new key can also be generated from the CLI:
483
483
  };
484
484
  break;
485
485
  case 'parallelTests':
486
- if (process.env.NODE_ENV === 'test' && !Number.isNaN(Number(options)) && Number(options) > 1) {
486
+ if (process.env.NODE_ENV === 'test')
487
487
  this._parallelTests = options;
488
- }
489
488
  break;
490
489
  case 'unicodeNormalization':
491
490
  this._unicodeNormalization = options;
@@ -361,8 +361,12 @@ function generateIdStr({ primaryKeyType }) {
361
361
  .primaryKey()
362
362
  .defaultTo(sql\`uuid_generate_v4()\`),
363
363
  )`;
364
+ case 'integer':
365
+ return `.addColumn('id', 'integer', col => col.primaryKey().generatedByDefaultAsIdentity())`;
366
+ case 'bigint':
367
+ case 'bigserial':
364
368
  default:
365
- return `.addColumn('id', '${primaryKeyType}', col => col.primaryKey())`;
369
+ return `.addColumn('id', 'bigint', col => col.primaryKey().generatedByDefaultAsIdentity())`;
366
370
  }
367
371
  }
368
372
  /**
@@ -6,9 +6,12 @@ export default class DreamMigrationHelpers {
6
6
  * This method renames the table, its primary key index (`{tablename}_pkey`),
7
7
  * and its primary key sequence (`{tablename}_id_seq`) to keep them in sync.
8
8
  *
9
- * The sequence rename is skipped for tables with UUID primary keys (which have
10
- * no associated sequence). The primary key index is always renamed since
11
- * PostgreSQL does not automatically rename it when the table is renamed.
9
+ * The sequence rename applies to both legacy `serial`/`bigserial` columns and
10
+ * modern `GENERATED ... AS IDENTITY` columns: identity columns are also backed
11
+ * by a `{tablename}_id_seq` sequence, so they need the same rename. It is
12
+ * skipped only for tables with UUID primary keys (which have no associated
13
+ * sequence). The primary key index is always renamed since PostgreSQL does not
14
+ * automatically rename it when the table is renamed.
12
15
  *
13
16
  * @param db - The Kysely database object passed into the migration up/down function
14
17
  * @param from - The current name of the table to rename
@@ -5,6 +5,13 @@ import type DreamApp from '../dream-app/index.js';
5
5
  * probe so they always agree on the index range.
6
6
  */
7
7
  export declare function testDatabasePoolSize(parallelTests: number | undefined): number;
8
+ /**
9
+ * Normalize configured test parallelism to the minimum safe pool width input.
10
+ * Even a serial vitest run can overlap old/new worker processes, so missing,
11
+ * invalid, zero, or fractional-below-one values all mean "one active worker",
12
+ * not "disable the per-live-worker database pool".
13
+ */
14
+ export declare function normalizeTestDatabaseParallelism(parallelTests: number | undefined): number;
8
15
  /**
9
16
  * The database name for a pool index given the un-suffixed base name. Index 1
10
17
  * is the base itself (no suffix); higher indexes are `<base>_<index>`. This is
@@ -1,4 +1,3 @@
1
1
  import Dream from '../../Dream.js';
2
2
  export declare const STI_SCOPE_NAME = "dream:STI";
3
- export default function STI(dreamClass: typeof Dream): (stiChildClass: typeof Dream) => void;
4
- export declare function validateStiChildAssociations(dreamClasses: (typeof Dream)[]): void;
3
+ export default function STI(dreamClass: typeof Dream): (stiChildClass: typeof Dream, context?: ClassDecoratorContext) => void;
@@ -13,7 +13,7 @@ export declare const SOFT_DELETE_SCOPE_NAME = "dream:SoftDelete";
13
13
  * export async function up(db: Kysely<any>): Promise<void> {
14
14
  * await db.schema
15
15
  * .createTable('posts')
16
- * .addColumn('id', 'bigserial', col => col.primaryKey())
16
+ * .addColumn('id', 'bigint', col => col.primaryKey().generatedByDefaultAsIdentity())
17
17
  * .addColumn('deleted_at', 'timestamp', col => col.defaultTo(null))
18
18
  * .addColumn('created_at', 'timestamp', col => col.notNull())
19
19
  * .addColumn('updated_at', 'timestamp', col => col.notNull())