@rvoh/dream 2.0.0-alpha.1 → 2.0.0-alpha.11

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 (254) hide show
  1. package/dist/cjs/src/Dream.js +5 -105
  2. package/dist/cjs/src/cli/index.js +15 -1
  3. package/dist/cjs/src/db/migration-helpers/DreamMigrationHelpers.js +6 -2
  4. package/dist/cjs/src/dream/DreamClassTransactionBuilder.js +0 -48
  5. package/dist/cjs/src/dream/DreamInstanceTransactionBuilder.js +0 -50
  6. package/dist/cjs/src/dream/LeftJoinLoadBuilder.js +0 -49
  7. package/dist/cjs/src/dream/Query.js +0 -57
  8. package/dist/cjs/src/dream/QueryDriver/Kysely.js +2 -0
  9. package/dist/cjs/src/dream-app/helpers/globalSerializerKeyFromPath.js +1 -1
  10. package/dist/cjs/src/dream-app/index.js +50 -0
  11. package/dist/cjs/src/helpers/cli/generateDreamContent.js +5 -5
  12. package/dist/cjs/src/helpers/cli/generateFactoryContent.js +5 -2
  13. package/dist/cjs/src/helpers/cli/generateMigrationContent.js +11 -4
  14. package/dist/cjs/src/helpers/sanitizeString.js +25 -0
  15. package/dist/cjs/src/package-exports/index.js +0 -1
  16. package/dist/cjs/src/package-exports/system.js +8 -0
  17. package/dist/cjs/src/package-exports/utils.js +1 -0
  18. package/dist/cjs/src/serializer/builders/DreamSerializerBuilder.js +1 -1
  19. package/dist/esm/src/Dream.js +5 -105
  20. package/dist/esm/src/cli/index.js +15 -1
  21. package/dist/esm/src/db/migration-helpers/DreamMigrationHelpers.js +6 -2
  22. package/dist/esm/src/dream/DreamClassTransactionBuilder.js +0 -48
  23. package/dist/esm/src/dream/DreamInstanceTransactionBuilder.js +0 -50
  24. package/dist/esm/src/dream/LeftJoinLoadBuilder.js +0 -49
  25. package/dist/esm/src/dream/Query.js +0 -57
  26. package/dist/esm/src/dream/QueryDriver/Kysely.js +2 -0
  27. package/dist/esm/src/dream-app/helpers/globalSerializerKeyFromPath.js +1 -1
  28. package/dist/esm/src/dream-app/index.js +50 -0
  29. package/dist/esm/src/helpers/cli/generateDreamContent.js +5 -5
  30. package/dist/esm/src/helpers/cli/generateFactoryContent.js +5 -2
  31. package/dist/esm/src/helpers/cli/generateMigrationContent.js +11 -4
  32. package/dist/esm/src/helpers/sanitizeString.js +25 -0
  33. package/dist/esm/src/package-exports/index.js +0 -1
  34. package/dist/esm/src/package-exports/system.js +8 -0
  35. package/dist/esm/src/package-exports/utils.js +1 -0
  36. package/dist/esm/src/serializer/builders/DreamSerializerBuilder.js +1 -1
  37. package/dist/types/src/Dream.d.ts +1 -107
  38. package/dist/types/src/cli/index.d.ts +18 -0
  39. package/dist/types/src/db/migration-helpers/DreamMigrationHelpers.d.ts +2 -1
  40. package/dist/types/src/dream/DreamClassTransactionBuilder.d.ts +0 -55
  41. package/dist/types/src/dream/DreamInstanceTransactionBuilder.d.ts +0 -48
  42. package/dist/types/src/dream/LeftJoinLoadBuilder.d.ts +1 -48
  43. package/dist/types/src/dream/Query.d.ts +0 -54
  44. package/dist/types/src/dream/QueryDriver/Kysely.d.ts +2 -0
  45. package/dist/types/src/dream-app/index.d.ts +45 -0
  46. package/dist/types/src/helpers/sanitizeString.d.ts +1 -0
  47. package/dist/types/src/package-exports/index.d.ts +0 -1
  48. package/dist/types/src/package-exports/system.d.ts +8 -0
  49. package/dist/types/src/package-exports/types.d.ts +1 -0
  50. package/dist/types/src/package-exports/utils.d.ts +1 -0
  51. package/dist/types/src/serializer/builders/DreamSerializerBuilder.d.ts +11 -20
  52. package/dist/types/src/serializer/builders/ObjectSerializerBuilder.d.ts +8 -8
  53. package/dist/types/src/types/utils.d.ts +3 -0
  54. package/dist/types/src/types/utils.ts +7 -0
  55. package/docs/assets/navigation.js +1 -1
  56. package/docs/assets/search.js +1 -1
  57. package/docs/classes/db.DreamMigrationHelpers.html +10 -9
  58. package/docs/classes/db.KyselyQueryDriver.html +30 -30
  59. package/docs/classes/db.PostgresQueryDriver.html +31 -31
  60. package/docs/classes/db.QueryDriverBase.html +29 -29
  61. package/docs/classes/errors.CheckConstraintViolation.html +3 -3
  62. package/docs/classes/errors.ColumnOverflow.html +3 -3
  63. package/docs/classes/errors.CreateOrFindByFailedToCreateAndFind.html +3 -3
  64. package/docs/classes/errors.DataIncompatibleWithDatabaseField.html +3 -3
  65. package/docs/classes/errors.DataTypeColumnTypeMismatch.html +3 -3
  66. package/docs/classes/errors.GlobalNameNotSet.html +3 -3
  67. package/docs/classes/errors.InvalidCalendarDate.html +2 -2
  68. package/docs/classes/errors.MissingSerializersDefinition.html +3 -3
  69. package/docs/classes/errors.NonLoadedAssociation.html +3 -3
  70. package/docs/classes/errors.NotNullViolation.html +3 -3
  71. package/docs/classes/errors.RecordNotFound.html +3 -3
  72. package/docs/classes/errors.ValidationError.html +3 -3
  73. package/docs/classes/index.CalendarDate.html +2 -2
  74. package/docs/classes/index.Decorators.html +19 -19
  75. package/docs/classes/index.Dream.html +189 -230
  76. package/docs/classes/index.DreamApp.html +16 -4
  77. package/docs/classes/index.DreamTransaction.html +2 -2
  78. package/docs/classes/index.Env.html +2 -2
  79. package/docs/classes/index.Query.html +66 -87
  80. package/docs/classes/system.CliFileWriter.html +8 -0
  81. package/docs/classes/system.DreamBin.html +11 -0
  82. package/docs/classes/{index.DreamCLI.html → system.DreamCLI.html} +11 -8
  83. package/docs/classes/system.DreamImporter.html +5 -0
  84. package/docs/classes/system.DreamLogos.html +4 -0
  85. package/docs/classes/system.DreamSerializerBuilder.html +76 -0
  86. package/docs/classes/system.ObjectSerializerBuilder.html +75 -0
  87. package/docs/classes/utils.Encrypt.html +2 -2
  88. package/docs/classes/utils.Range.html +2 -2
  89. package/docs/functions/db.closeAllDbConnections.html +1 -1
  90. package/docs/functions/db.dreamDbConnections.html +1 -1
  91. package/docs/functions/db.untypedDb.html +1 -1
  92. package/docs/functions/db.validateColumn.html +1 -1
  93. package/docs/functions/db.validateTable.html +1 -1
  94. package/docs/functions/errors.pgErrorType.html +1 -1
  95. package/docs/functions/index.DreamSerializer.html +1 -1
  96. package/docs/functions/index.ObjectSerializer.html +1 -1
  97. package/docs/functions/index.ReplicaSafe.html +1 -1
  98. package/docs/functions/index.STI.html +1 -1
  99. package/docs/functions/index.SoftDelete.html +1 -1
  100. package/docs/functions/utils.camelize.html +1 -1
  101. package/docs/functions/utils.capitalize.html +1 -1
  102. package/docs/functions/utils.cloneDeepSafe.html +1 -1
  103. package/docs/functions/utils.compact.html +1 -1
  104. package/docs/functions/utils.groupBy.html +1 -1
  105. package/docs/functions/utils.hyphenize.html +1 -1
  106. package/docs/functions/utils.intersection.html +1 -1
  107. package/docs/functions/utils.isEmpty.html +1 -1
  108. package/docs/functions/utils.normalizeUnicode.html +1 -1
  109. package/docs/functions/utils.pascalize.html +1 -1
  110. package/docs/functions/utils.percent.html +1 -1
  111. package/docs/functions/utils.range-1.html +1 -1
  112. package/docs/functions/utils.round.html +1 -1
  113. package/docs/functions/utils.sanitizeString.html +1 -0
  114. package/docs/functions/utils.snakeify.html +1 -1
  115. package/docs/functions/utils.sort.html +1 -1
  116. package/docs/functions/utils.sortBy.html +1 -1
  117. package/docs/functions/utils.sortObjectByKey.html +1 -1
  118. package/docs/functions/utils.sortObjectByValue.html +1 -1
  119. package/docs/functions/utils.uncapitalize.html +1 -1
  120. package/docs/functions/utils.uniq.html +1 -1
  121. package/docs/interfaces/openapi.OpenapiDescription.html +2 -2
  122. package/docs/interfaces/openapi.OpenapiSchemaProperties.html +1 -1
  123. package/docs/interfaces/openapi.OpenapiSchemaPropertiesShorthand.html +1 -1
  124. package/docs/interfaces/openapi.OpenapiTypeFieldObject.html +1 -1
  125. package/docs/interfaces/types.BelongsToStatement.html +2 -2
  126. package/docs/interfaces/types.DecoratorContext.html +2 -2
  127. package/docs/interfaces/types.DreamAppInitOptions.html +2 -2
  128. package/docs/interfaces/types.DreamAppOpts.html +2 -2
  129. package/docs/interfaces/types.EncryptOptions.html +2 -2
  130. package/docs/interfaces/types.InternalAnyTypedSerializerRendersMany.html +2 -2
  131. package/docs/interfaces/types.InternalAnyTypedSerializerRendersOne.html +2 -2
  132. package/docs/interfaces/types.SerializerRendererOpts.html +2 -2
  133. package/docs/modules/db.html +1 -1
  134. package/docs/modules/errors.html +1 -1
  135. package/docs/modules/index.html +1 -2
  136. package/docs/modules/openapi.html +1 -1
  137. package/docs/modules/system.html +10 -0
  138. package/docs/modules/types.html +2 -1
  139. package/docs/modules/utils.html +2 -1
  140. package/docs/types/index.DateTime.html +1 -1
  141. package/docs/types/openapi.CommonOpenapiSchemaObjectFields.html +1 -1
  142. package/docs/types/openapi.OpenapiAllTypes.html +1 -1
  143. package/docs/types/openapi.OpenapiFormats.html +1 -1
  144. package/docs/types/openapi.OpenapiNumberFormats.html +1 -1
  145. package/docs/types/openapi.OpenapiPrimitiveBaseTypes.html +1 -1
  146. package/docs/types/openapi.OpenapiPrimitiveTypes.html +1 -1
  147. package/docs/types/openapi.OpenapiSchemaArray.html +1 -1
  148. package/docs/types/openapi.OpenapiSchemaArrayShorthand.html +1 -1
  149. package/docs/types/openapi.OpenapiSchemaBase.html +1 -1
  150. package/docs/types/openapi.OpenapiSchemaBody.html +1 -1
  151. package/docs/types/openapi.OpenapiSchemaBodyShorthand.html +1 -1
  152. package/docs/types/openapi.OpenapiSchemaCommonFields.html +1 -1
  153. package/docs/types/openapi.OpenapiSchemaExpressionAllOf.html +1 -1
  154. package/docs/types/openapi.OpenapiSchemaExpressionAnyOf.html +1 -1
  155. package/docs/types/openapi.OpenapiSchemaExpressionOneOf.html +1 -1
  156. package/docs/types/openapi.OpenapiSchemaExpressionRef.html +1 -1
  157. package/docs/types/openapi.OpenapiSchemaExpressionRefSchemaShorthand.html +1 -1
  158. package/docs/types/openapi.OpenapiSchemaInteger.html +1 -1
  159. package/docs/types/openapi.OpenapiSchemaNull.html +1 -1
  160. package/docs/types/openapi.OpenapiSchemaNumber.html +1 -1
  161. package/docs/types/openapi.OpenapiSchemaObject.html +1 -1
  162. package/docs/types/openapi.OpenapiSchemaObjectAllOf.html +1 -1
  163. package/docs/types/openapi.OpenapiSchemaObjectAllOfShorthand.html +1 -1
  164. package/docs/types/openapi.OpenapiSchemaObjectAnyOf.html +1 -1
  165. package/docs/types/openapi.OpenapiSchemaObjectAnyOfShorthand.html +1 -1
  166. package/docs/types/openapi.OpenapiSchemaObjectBase.html +1 -1
  167. package/docs/types/openapi.OpenapiSchemaObjectBaseShorthand.html +1 -1
  168. package/docs/types/openapi.OpenapiSchemaObjectOneOf.html +1 -1
  169. package/docs/types/openapi.OpenapiSchemaObjectOneOfShorthand.html +1 -1
  170. package/docs/types/openapi.OpenapiSchemaObjectShorthand.html +1 -1
  171. package/docs/types/openapi.OpenapiSchemaPrimitiveGeneric.html +1 -1
  172. package/docs/types/openapi.OpenapiSchemaShorthandExpressionAllOf.html +1 -1
  173. package/docs/types/openapi.OpenapiSchemaShorthandExpressionAnyOf.html +1 -1
  174. package/docs/types/openapi.OpenapiSchemaShorthandExpressionOneOf.html +1 -1
  175. package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializableRef.html +1 -1
  176. package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializerRef.html +1 -1
  177. package/docs/types/openapi.OpenapiSchemaShorthandPrimitiveGeneric.html +1 -1
  178. package/docs/types/openapi.OpenapiSchemaString.html +1 -1
  179. package/docs/types/openapi.OpenapiShorthandAllTypes.html +1 -1
  180. package/docs/types/openapi.OpenapiShorthandPrimitiveBaseTypes.html +1 -1
  181. package/docs/types/openapi.OpenapiShorthandPrimitiveTypes.html +1 -1
  182. package/docs/types/openapi.OpenapiTypeField.html +1 -1
  183. package/docs/types/system.DreamAppAllowedPackageManagersEnum.html +1 -0
  184. package/docs/types/types.Camelized.html +1 -1
  185. package/docs/types/types.DbConnectionType.html +1 -1
  186. package/docs/types/types.DbTypes.html +1 -1
  187. package/docs/types/types.DreamAssociationMetadata.html +1 -1
  188. package/docs/types/types.DreamAttributes.html +1 -1
  189. package/docs/types/types.DreamClassAssociationAndStatement.html +1 -1
  190. package/docs/types/types.DreamClassColumn.html +1 -1
  191. package/docs/types/types.DreamColumn.html +1 -1
  192. package/docs/types/types.DreamColumnNames.html +1 -1
  193. package/docs/types/types.DreamLogLevel.html +1 -1
  194. package/docs/types/types.DreamLogger.html +1 -1
  195. package/docs/types/types.DreamModelSerializerType.html +1 -1
  196. package/docs/types/types.DreamOrViewModelClassSerializerKey.html +1 -1
  197. package/docs/types/types.DreamOrViewModelSerializerKey.html +1 -1
  198. package/docs/types/types.DreamParamSafeAttributes.html +1 -1
  199. package/docs/types/types.DreamParamSafeColumnNames.html +1 -1
  200. package/docs/types/types.DreamSerializable.html +1 -1
  201. package/docs/types/types.DreamSerializableArray.html +1 -1
  202. package/docs/types/types.DreamSerializerKey.html +1 -1
  203. package/docs/types/types.DreamSerializers.html +1 -1
  204. package/docs/types/types.DreamVirtualColumns.html +1 -1
  205. package/docs/types/types.EncryptAlgorithm.html +1 -1
  206. package/docs/types/types.HasManyStatement.html +1 -1
  207. package/docs/types/types.HasOneStatement.html +1 -1
  208. package/docs/types/types.Hyphenized.html +1 -1
  209. package/docs/types/types.Pascalized.html +1 -1
  210. package/docs/types/types.RoundingPrecision.html +1 -1
  211. package/docs/types/types.SerializerCasing.html +1 -1
  212. package/docs/types/types.SimpleObjectSerializerType.html +1 -1
  213. package/docs/types/types.Snakeified.html +1 -1
  214. package/docs/types/types.StrictInterface.html +1 -0
  215. package/docs/types/types.UpdateableAssociationProperties.html +1 -1
  216. package/docs/types/types.UpdateableProperties.html +1 -1
  217. package/docs/types/types.ValidationType.html +1 -1
  218. package/docs/types/types.ViewModel.html +1 -1
  219. package/docs/types/types.ViewModelClass.html +1 -1
  220. package/docs/types/types.WhereStatementForDream.html +1 -1
  221. package/docs/types/types.WhereStatementForDreamClass.html +1 -1
  222. package/docs/variables/index.DateTime-1.html +1 -1
  223. package/docs/variables/index.DreamConst.html +1 -1
  224. package/docs/variables/index.ops.html +1 -1
  225. package/docs/variables/openapi.openapiPrimitiveTypes-1.html +1 -1
  226. package/docs/variables/openapi.openapiShorthandPrimitiveTypes-1.html +1 -1
  227. package/docs/variables/system.DreamAppAllowedPackageManagersEnumValues.html +1 -0
  228. package/docs/variables/types.TRIGRAM_OPERATORS.html +1 -1
  229. package/docs/variables/types.primaryKeyTypes.html +1 -1
  230. package/package.json +5 -5
  231. package/dist/cjs/src/package-exports/internal.js +0 -18
  232. package/dist/esm/src/package-exports/internal.js +0 -18
  233. package/dist/types/src/package-exports/internal.d.ts +0 -18
  234. package/docs/classes/internal.CliFileWriter.html +0 -8
  235. package/docs/classes/internal.DreamBin.html +0 -11
  236. package/docs/classes/internal.DreamImporter.html +0 -5
  237. package/docs/classes/internal.DreamLogos.html +0 -4
  238. package/docs/classes/internal.DreamSerializerBuilder.html +0 -76
  239. package/docs/classes/internal.ObjectSerializerBuilder.html +0 -75
  240. package/docs/functions/internal.absoluteDreamPath.html +0 -1
  241. package/docs/functions/internal.dreamPath.html +0 -1
  242. package/docs/functions/internal.expandStiClasses.html +0 -1
  243. package/docs/functions/internal.generateDream.html +0 -1
  244. package/docs/functions/internal.globalClassNameFromFullyQualifiedModelName.html +0 -1
  245. package/docs/functions/internal.inferSerializerFromDreamOrViewModel.html +0 -1
  246. package/docs/functions/internal.inferSerializersFromDreamClassOrViewModelClass.html +0 -1
  247. package/docs/functions/internal.isDreamSerializer.html +0 -1
  248. package/docs/functions/internal.loadRepl.html +0 -1
  249. package/docs/functions/internal.lookupClassByGlobalName.html +0 -1
  250. package/docs/functions/internal.serializerNameFromFullyQualifiedModelName.html +0 -1
  251. package/docs/functions/internal.standardizeFullyQualifiedModelName.html +0 -1
  252. package/docs/modules/internal.html +0 -21
  253. package/docs/types/internal.DreamAppAllowedPackageManagersEnum.html +0 -1
  254. package/docs/variables/internal.DreamAppAllowedPackageManagersEnumValues.html +0 -1
@@ -1403,56 +1403,6 @@ export default class Dream {
1403
1403
  static preloadFor(serializerKey, modifierFn) {
1404
1404
  return this.query().preloadFor(serializerKey, modifierFn);
1405
1405
  }
1406
- /**
1407
- * Recursively preloads all Dream associations referenced by `rendersOne` and `rendersMany`
1408
- * in a DreamSerializer using left join preloading. This traverses the entire content tree
1409
- * of serializers to automatically load all necessary associations in a single query,
1410
- * eliminating N+1 query problems and removing the need to manually remember which
1411
- * associations to preload for serialization.
1412
- *
1413
- * This method decouples data loading code from data rendering code by having the serializer
1414
- * (rendering code) inform the query (loading code) about which associations are needed.
1415
- * As serializers evolve over time - adding new `rendersOne` and `rendersMany` calls or
1416
- * modifying existing ones - the loading code automatically adapts without requiring
1417
- * corresponding modifications to left join preload statements.
1418
- *
1419
- * This method analyzes the serializer (specified by `serializerKey` or 'default') and
1420
- * automatically left join preloads all associations that will be needed during serialization.
1421
- *
1422
- * Note: Left join preloading loads all data in a single SQL query but has trade-offs compared
1423
- * to regular preloading. See {@link Dream.leftJoinPreload} for details about limitations.
1424
- *
1425
- * ```ts
1426
- * // Instead of manually specifying all associations:
1427
- * await User.leftJoinPreload('posts', 'comments', 'replies').all()
1428
- *
1429
- * // Automatically left join preload everything needed for serialization:
1430
- * await User.leftJoinPreloadFor('summary').all()
1431
- *
1432
- * // Add where conditions to specific associations during left join preloading:
1433
- * await User.leftJoinPreloadFor('detailed', (associationName, dreamClass) => {
1434
- * if (dreamClass.typeof(Post) && associationName === 'comments') {
1435
- * return { and: { published: true } }
1436
- * }
1437
- * }).all()
1438
- *
1439
- * // Skip left join preloading specific associations to handle them manually:
1440
- * await User.leftJoinPreloadFor('summary', (associationName, dreamClass) => {
1441
- * if (dreamClass.typeof(User) && associationName === 'posts') {
1442
- * return 'omit' // Handle posts preloading separately with custom logic
1443
- * }
1444
- * })
1445
- * .preload('posts', { and: { featured: true } }) // Custom preloading instead
1446
- * .all()
1447
- * ```
1448
- *
1449
- * @param serializerKey - The serializer key to use for determining which associations to preload.
1450
- * @param modifierFn - Optional callback function to modify or omit specific associations during preloading. Called for each association with the Dream class and association name. Return an object with `and`, `andAny`, or `andNot` properties to add where conditions, return 'omit' to skip preloading that association (useful when you want to handle it manually), or return undefined to use default preloading
1451
- * @returns A Query with all serialization associations left join preloaded
1452
- */
1453
- static leftJoinPreloadFor(serializerKey, modifierFn) {
1454
- return this.query().leftJoinPreloadFor(serializerKey, modifierFn);
1455
- }
1456
1406
  /**
1457
1407
  * Returns a new Query instance with the provided
1458
1408
  * inner join statement attached
@@ -2667,7 +2617,7 @@ export default class Dream {
2667
2617
  *
2668
2618
  * ```ts
2669
2619
  * const user = User.new({ email: 'how@yadoin' })
2670
- * user.attributes()
2620
+ * user.getAttributes()
2671
2621
  * // {
2672
2622
  * // email: 'how@yadoin',
2673
2623
  * // ...
@@ -2998,9 +2948,10 @@ export default class Dream {
2998
2948
  * @returns A boolean
2999
2949
  */
3000
2950
  equals(other) {
3001
- if (!(other instanceof Dream))
3002
- return false;
3003
- return this.comparisonKey === other.comparisonKey;
2951
+ return (!!(other instanceof Dream) &&
2952
+ this.isPersisted &&
2953
+ other.isPersisted &&
2954
+ this.comparisonKey === other.comparisonKey);
3004
2955
  }
3005
2956
  get comparisonKey() {
3006
2957
  return `${this.constructor.globalName}:${this.primaryKeyValue()}`;
@@ -3374,57 +3325,6 @@ export default class Dream {
3374
3325
  leftJoinLoad(...args) {
3375
3326
  return new LeftJoinLoadBuilder(this).leftJoinLoad(...args);
3376
3327
  }
3377
- /**
3378
- * Recursively loads all Dream associations referenced by `rendersOne` and `rendersMany`
3379
- * in a DreamSerializer. This traverses the entire content tree of serializers to automatically
3380
- * load all necessary associations, eliminating N+1 query problems and removing the need to
3381
- * manually remember which associations to preload for serialization.
3382
- *
3383
- * This method decouples data loading code from data rendering code by having the serializer
3384
- * (rendering code) inform the query (loading code) about which associations are needed.
3385
- * As serializers evolve over time - adding new `rendersOne` and `rendersMany` calls or
3386
- * modifying existing ones - the loading code automatically adapts without requiring
3387
- * corresponding modifications to preload statements.
3388
- *
3389
- * This method analyzes the serializer (specified by `serializerKey` or 'default') and
3390
- * automatically preloads all associations that will be needed during serialization.
3391
- *
3392
- * Note: Left join loading loads all data in a single SQL query but has trade-offs compared
3393
- * to regular preloading. See {@link Dream.leftJoinPreload} for details about limitations.
3394
- *
3395
- * ```ts
3396
- * // Instead of manually specifying all associations:
3397
- * await User.preload('posts', 'comments', 'replies').all()
3398
- *
3399
- * // Automatically preload everything needed for serialization:
3400
- * await user.leftJoinLoadFor('summary').execute()
3401
- *
3402
- * // Add where conditions to specific associations during preloading:
3403
- * await user.leftJoinLoadFor('detailed', (associationName, dreamClass) => {
3404
- * if (dreamClass.typeof(Post) && associationName === 'comments') {
3405
- * return { and: { published: true } }
3406
- * }
3407
- * })
3408
- * .execute()
3409
- *
3410
- * // Skip preloading specific associations to handle them manually:
3411
- * await user
3412
- * .loadFor('summary', (associationName, dreamClass) => {
3413
- * if (dreamClass.typeof(User) && associationName === 'posts') {
3414
- * return 'omit' // Handle posts preloading separately with custom logic
3415
- * }
3416
- * })
3417
- * .load('posts', { and: { featured: true } }) // Custom preloading
3418
- * .execute()
3419
- * ```
3420
- *
3421
- * @param serializerKey - The serializer key to use for determining which associations to preload.
3422
- * @param modifierFn - Optional callback function to modify or omit specific associations during preloading. Called for each association with the Dream class and association name. Return an object with `and`, `andAny`, or `andNot` properties to add where conditions, return 'omit' to skip preloading that association (useful when you want to handle it manually), or return undefined to use default preloading
3423
- * @returns A Query with all serialization associations preloaded
3424
- */
3425
- leftJoinLoadFor(serializerKey, modifierFn) {
3426
- return new LeftJoinLoadBuilder(this)['leftJoinLoadFor'](serializerKey, modifierFn);
3427
- }
3428
3328
  /**
3429
3329
  * Returns true if the association specified has
3430
3330
  * been loaded on this instance
@@ -1,7 +1,9 @@
1
1
  import { InvalidArgumentError } from 'commander';
2
2
  import DreamBin from '../bin/index.js';
3
3
  import DreamApp from '../dream-app/index.js';
4
+ import generateDream from '../helpers/cli/generateDream.js';
4
5
  import EnvInternal from '../helpers/EnvInternal.js';
6
+ import loadRepl from '../helpers/loadRepl.js';
5
7
  import sspawn from '../helpers/sspawn.js';
6
8
  import DreamCliLogger from './logger/DreamCliLogger.js';
7
9
  const INDENT = ' ';
@@ -61,6 +63,12 @@ ${INDENT}
61
63
  ${INDENT} include the fully qualified model name, e.g., if the Coach model is in src/app/models/Health/Coach:
62
64
  ${INDENT} Health/Coach:belongs_to`;
63
65
  export default class DreamCLI {
66
+ /**
67
+ * Starts the Dream console
68
+ */
69
+ static async loadRepl(context) {
70
+ return await loadRepl(context);
71
+ }
64
72
  /**
65
73
  * use this method for initializing a standalone dream application. If using Psychic and Dream together,
66
74
  * a different pattern is used, which leverages the `generateDreamCli` method instead.
@@ -81,6 +89,12 @@ export default class DreamCLI {
81
89
  onSync: () => { },
82
90
  });
83
91
  }
92
+ /**
93
+ * @internal
94
+ */
95
+ static async generateDream(opts) {
96
+ await generateDream(opts);
97
+ }
84
98
  /**
85
99
  * called under the hood when provisioning both psychic and dream applications.
86
100
  */
@@ -89,7 +103,7 @@ export default class DreamCLI {
89
103
  .command('generate:migration')
90
104
  .alias('g:migration')
91
105
  .description('create a new migration')
92
- .argument('<migrationName>', 'end with -to-table-name to prepopulate with an alterTable command')
106
+ .argument('<migrationName>', 'end with -to-table-name or -from-table-name to prepopulate with an alterTable command')
93
107
  .option('--connection-name <connectionName>', 'the connection name you wish to use for your migration')
94
108
  .argument('[columnsWithTypes...]', columnsWithTypesDescriptionForMigration)
95
109
  .action(async (migrationName, columnsWithTypes, options) => {
@@ -17,7 +17,10 @@ export default class DreamMigrationHelpers {
17
17
  */
18
18
  static async renameTable(db, from, to) {
19
19
  await db.schema.alterTable(from).renameTo(to).execute();
20
- await sql `ALTER SEQUENCE ${from}_id_seq RENAME TO ${to}_id_seq`.execute(db);
20
+ const fromSequenceName = `${from}_id_seq`;
21
+ const toSequenceName = `${to}_id_seq`;
22
+ const sqlStatement = `ALTER SEQUENCE ${fromSequenceName} RENAME TO ${toSequenceName}`;
23
+ await sql.raw(sqlStatement).execute(db);
21
24
  }
22
25
  /**
23
26
  * Unique indexes cannot be populated by the same value even within a transaction,
@@ -148,7 +151,8 @@ export default class DreamMigrationHelpers {
148
151
  */
149
152
  static newTransaction() { }
150
153
  /**
151
- * Drop a value from an enum and replace it (or optionally remove it from array columns)
154
+ * Drop a value from an enum and replace it with a different enum already
155
+ * present in the enum type (or optionally remove it from array columns).
152
156
  *
153
157
  * @param db - The Kysely database object passed into the migration up/down function
154
158
  * @param __namedParameters - The options for dropping the enum value
@@ -362,54 +362,6 @@ export default class DreamClassTransactionBuilder {
362
362
  leftJoinPreload(...args) {
363
363
  return this.queryInstance().leftJoinPreload(...args);
364
364
  }
365
- /**
366
- * Recursively left-join-preloads all Dream associations referenced by `rendersOne` and `rendersMany`
367
- * in a DreamSerializer. This traverses the entire content tree of serializers to automatically
368
- * load all necessary associations, eliminating N+1 query problems and removing the need to
369
- * manually remember which associations to preload for serialization.
370
- *
371
- * This method decouples data loading code from data rendering code by having the serializer
372
- * (rendering code) inform the query (loading code) about which associations are needed.
373
- * As serializers evolve over time - adding new `rendersOne` and `rendersMany` calls or
374
- * modifying existing ones - the loading code automatically adapts without requiring
375
- * corresponding modifications to preload statements.
376
- *
377
- * This method analyzes the serializer (specified by `serializerKey` or 'default') and
378
- * automatically preloads all associations that will be needed during serialization.
379
- *
380
- * ```ts
381
- * await ApplicationModel.transaction(async txn => {
382
- * // Instead of manually specifying all associations:
383
- * await User.txn(txn).preload('posts', 'comments', 'replies').all()
384
- *
385
- * // Automatically preload everything needed for serialization:
386
- * await User.txn(txn).preloadFor('summary').all()
387
- *
388
- * // Add where conditions to specific associations during preloading:
389
- * await User.txn(txn).leftJoinPreloadFor('detailed', (associationName, dreamClass) => {
390
- * if (dreamClass.typeof(Post) && associationName === 'comments') {
391
- * return { and: { published: true } }
392
- * }
393
- * }).all()
394
- *
395
- * // Skip preloading specific associations to handle them manually:
396
- * await User.txn(txn).leftJoinPreloadFor('summary', (associationName, dreamClass) => {
397
- * if (dreamClass.typeof(User) && associationName === 'posts') {
398
- * return 'omit' // Handle posts preloading separately with custom logic
399
- * }
400
- * })
401
- * .preload('posts', { and: { featured: true } }) // Custom preloading
402
- * .all()
403
- * })
404
- * ```
405
- *
406
- * @param serializerKey - The serializer key to use for determining which associations to preload.
407
- * @param modifierFn - Optional callback function to modify or omit specific associations during preloading. Called for each association with the Dream class and association name. Return an object with `and`, `andAny`, or `andNot` properties to add where conditions, return 'omit' to skip preloading that association (useful when you want to handle it manually), or return undefined to use default preloading
408
- * @returns A Query with all serialization associations preloaded
409
- */
410
- leftJoinPreloadFor(serializerKey, modifierFn) {
411
- return this.queryInstance().leftJoinPreloadFor(serializerKey, modifierFn);
412
- }
413
365
  /**
414
366
  * Applies preload statement to a Query scoped to this model.
415
367
  * Upon instantiating records of this model type,
@@ -143,56 +143,6 @@ export default class DreamInstanceTransactionBuilder {
143
143
  leftJoinLoad(...args) {
144
144
  return new LeftJoinLoadBuilder(this.dreamInstance, this.dreamTransaction).leftJoinLoad(...args);
145
145
  }
146
- /**
147
- * Recursively loads all Dream associations referenced by `rendersOne` and `rendersMany`
148
- * in a DreamSerializer. This traverses the entire content tree of serializers to automatically
149
- * load all necessary associations, eliminating N+1 query problems and removing the need to
150
- * manually remember which associations to preload for serialization.
151
- *
152
- * This method decouples data loading code from data rendering code by having the serializer
153
- * (rendering code) inform the query (loading code) about which associations are needed.
154
- * As serializers evolve over time - adding new `rendersOne` and `rendersMany` calls or
155
- * modifying existing ones - the loading code automatically adapts without requiring
156
- * corresponding modifications to preload statements.
157
- *
158
- * This method analyzes the serializer (specified by `serializerKey` or 'default') and
159
- * automatically preloads all associations that will be needed during serialization.
160
- *
161
- * ```ts
162
- * await ApplicationModel.transaction(async txn => {
163
- * // Instead of manually specifying all associations:
164
- * await User.txn(txn).preload('posts', 'comments', 'replies').all()
165
- *
166
- * // Automatically preload everything needed for serialization:
167
- * await user.txn(txn).leftJoinLoadFor('summary').execute()
168
- *
169
- * // Add where conditions to specific associations during preloading:
170
- * await user.txn(txn).leftJoinLoadFor('detailed', (associationName, dreamClass) => {
171
- * if (dreamClass.typeof(Post) && associationName === 'comments') {
172
- * return { and: { published: true } }
173
- * }
174
- * }).execute()
175
- *
176
- * // Skip preloading specific associations to handle them manually:
177
- * await user
178
- * .txn(txn)
179
- * .leftJoinLoadFor('summary', (associationName, dreamClass) => {
180
- * if (dreamClass.typeof(User) && associationName === 'posts') {
181
- * return 'omit' // Handle posts preloading separately with custom logic
182
- * }
183
- * })
184
- * .load('posts', { and: { featured: true } }) // Custom preloading
185
- * .execute()
186
- * })
187
- * ```
188
- *
189
- * @param serializerKey - The serializer key to use for determining which associations to preload.
190
- * @param modifierFn - Optional callback function to modify or omit specific associations during preloading. Called for each association with the Dream class and association name. Return an object with `and`, `andAny`, or `andNot` properties to add where conditions, return 'omit' to skip preloading that association (useful when you want to handle it manually), or return undefined to use default preloading
191
- * @returns A Query with all serialization associations preloaded
192
- */
193
- leftJoinLoadFor(serializerKey, modifierFn) {
194
- return new LeftJoinLoadBuilder(this.dreamInstance, this.dreamTransaction)['leftJoinLoadFor'](serializerKey, modifierFn);
195
- }
196
146
  /**
197
147
  * Returns a new Query instance with the provided
198
148
  * inner join statement attached
@@ -38,55 +38,6 @@ export default class LeftJoinLoadBuilder {
38
38
  this.query = this.query.leftJoinPreload(...args);
39
39
  return this;
40
40
  }
41
- /**
42
- * Recursively loads all Dream associations referenced by `rendersOne` and `rendersMany`
43
- * in a DreamSerializer. This traverses the entire content tree of serializers to automatically
44
- * load all necessary associations, eliminating N+1 query problems and removing the need to
45
- * manually remember which associations to preload for serialization.
46
- *
47
- * This method decouples data loading code from data rendering code by having the serializer
48
- * (rendering code) inform the query (loading code) about which associations are needed.
49
- * As serializers evolve over time - adding new `rendersOne` and `rendersMany` calls or
50
- * modifying existing ones - the loading code automatically adapts without requiring
51
- * corresponding modifications to preload statements.
52
- *
53
- * This method analyzes the serializer (specified by `serializerKey` or 'default') and
54
- * automatically preloads all associations that will be needed during serialization.
55
- *
56
- * ```ts
57
- * // Instead of manually specifying all associations:
58
- * await User.preload('posts', 'comments', 'replies').all()
59
- *
60
- * // Automatically preload everything needed for serialization:
61
- * await user.leftJoinLoadFor('summary').execute()
62
- *
63
- * // Add where conditions to specific associations during preloading:
64
- * await user.leftJoinLoadFor('detailed', (associationName, dreamClass) => {
65
- * if (dreamClass.typeof(Post) && associationName === 'comments') {
66
- * return { and: { published: true } }
67
- * }
68
- * })
69
- * .execute()
70
- *
71
- * // Skip preloading specific associations to handle them manually:
72
- * await user
73
- * .leftJoinLoadFor('summary', (associationName, dreamClass) => {
74
- * if (dreamClass.typeof(User) && associationName === 'posts') {
75
- * return 'omit' // Handle posts preloading separately with custom logic
76
- * }
77
- * })
78
- * .load('posts', { and: { featured: true } }) // Custom preloading
79
- * .execute()
80
- * ```
81
- *
82
- * @param serializerKey - The serializer key to use for determining which associations to preload.
83
- * @param modifierFn - Optional callback function to modify or omit specific associations during preloading. Called for each association with the Dream class and association name. Return an object with `and`, `andAny`, or `andNot` properties to add where conditions, return 'omit' to skip preloading that association (useful when you want to handle it manually), or return undefined to use default preloading
84
- * @returns A Query with all serialization associations preloaded
85
- */
86
- leftJoinLoadFor(serializerKey, modifierFn) {
87
- this.query = this.query.leftJoinPreloadFor(serializerKey, modifierFn);
88
- return this;
89
- }
90
41
  /**
91
42
  * executes a load builder query, binding
92
43
  * all associations to their respective model
@@ -530,63 +530,6 @@ export default class Query {
530
530
  });
531
531
  return query;
532
532
  }
533
- /**
534
- * Recursively preloads all Dream associations referenced by `rendersOne` and `rendersMany`
535
- * in a DreamSerializer using left join preloading. This traverses the entire content tree
536
- * of serializers to automatically load all necessary associations in a single query,
537
- * eliminating N+1 query problems and removing the need to manually remember which
538
- * associations to preload for serialization.
539
- *
540
- * This method decouples data loading code from data rendering code by having the serializer
541
- * (rendering code) inform the query (loading code) about which associations are needed.
542
- * As serializers evolve over time - adding new `rendersOne` and `rendersMany` calls or
543
- * modifying existing ones - the loading code automatically adapts without requiring
544
- * corresponding modifications to left join preload statements.
545
- *
546
- * This method analyzes the serializer (specified by `serializerKey` or 'default') and
547
- * automatically left join preloads all associations that will be needed during serialization.
548
- *
549
- * Note: Left join preloading loads all data in a single SQL query but has trade-offs compared
550
- * to regular preloading. See {@link Dream.leftJoinPreload} for details about limitations.
551
- *
552
- * ```ts
553
- * // Instead of manually specifying all associations:
554
- * await User.leftJoinPreload('posts', 'comments', 'replies').all()
555
- *
556
- * // Automatically left join preload everything needed for serialization:
557
- * await User.leftJoinPreloadFor('summary').all()
558
- *
559
- * // Add where conditions to specific associations during left join preloading:
560
- * await User.leftJoinPreloadFor('detailed', (associationName, dreamClass) => {
561
- * if (dreamClass.typeof(Post) && associationName === 'comments') {
562
- * return { and: { published: true } }
563
- * }
564
- * })
565
- * .all()
566
- *
567
- * // Skip left join preloading specific associations to handle them manually:
568
- * await User.leftJoinPreloadFor('summary', (associationName, dreamClass) => {
569
- * if (dreamClass.typeof(User) && associationName === 'posts') {
570
- * return 'omit' // Handle posts preloading separately with custom logic
571
- * }
572
- * })
573
- * .preload('posts', { and: { featured: true } }) // Custom preloading instead
574
- * .all()
575
- * ```
576
- *
577
- * @param serializerKey - The serializer key to use for determining which associations to preload.
578
- * @param modifierFn - Optional callback function to modify or omit specific associations during preloading. Called for each association with the Dream class and association name. Return an object with `and`, `andAny`, or `andNot` properties to add where conditions, return 'omit' to skip preloading that association (useful when you want to handle it manually), or return undefined to use default preloading
579
- * @returns A Query with all serialization associations left join preloaded
580
- */
581
- leftJoinPreloadFor(serializerKey, modifierFn) {
582
- const preloadArgs = extractNestedPaths(this.dreamClass['serializationMap'](serializerKey));
583
- let query = this;
584
- const counter = { count: 0 };
585
- preloadArgs.forEach(dreamClassAndAssociationNameTupleArray => {
586
- query = query.leftJoinPreload(...convertDreamClassAndAssociationNameTupleArrayToPreloadArgs(dreamClassAndAssociationNameTupleArray, modifierFn, counter));
587
- });
588
- return query;
589
- }
590
533
  /**
591
534
  * Returns a new Query instance, with the provided
592
535
  * joins statement attached
@@ -392,6 +392,8 @@ export default class KyselyQueryDriver extends QueryDriverBase {
392
392
  return null;
393
393
  }
394
394
  /**
395
+ * @internal
396
+ *
395
397
  * Retrieves an array containing all records matching the Query.
396
398
  * Be careful using this, since it will attempt to pull every
397
399
  * record into memory at once. When querying might return a large
@@ -9,6 +9,6 @@ export default function globalSerializerKeyFromPath(filepath, dirPath, exportKey
9
9
  }
10
10
  else {
11
11
  const namePrefixFromPath = defaultExport.replace(/[^/]+\/?$/, '');
12
- return namePrefixFromPath + exportKey.replace(new RegExp(`^${namePrefixFromPath.replace(/\/$/, '')}`), '');
12
+ return namePrefixFromPath + exportKey.replace(new RegExp(`^${namePrefixFromPath.replace(/\//g, '')}`), '');
13
13
  }
14
14
  }
@@ -8,9 +8,18 @@ import DreamAppInitMissingMissingProjectRoot from '../errors/dream-app/DreamAppI
8
8
  import CalendarDate from '../helpers/CalendarDate.js';
9
9
  import { DateTime, Settings } from '../helpers/DateTime.js';
10
10
  import EnvInternal from '../helpers/EnvInternal.js';
11
+ import globalClassNameFromFullyQualifiedModelName from '../helpers/globalClassNameFromFullyQualifiedModelName.js';
12
+ import absoluteDreamPath from '../helpers/path/absoluteDreamPath.js';
13
+ import dreamPath from '../helpers/path/dreamPath.js';
14
+ import standardizeFullyQualifiedModelName from '../helpers/standardizeFullyQualifiedModelName.js';
15
+ import expandStiClasses from '../helpers/sti/expandStiClasses.js';
16
+ import inferSerializerFromDreamOrViewModel, { inferSerializersFromDreamClassOrViewModelClass, } from '../serializer/helpers/inferSerializerFromDreamOrViewModel.js';
17
+ import isDreamSerializer from '../serializer/helpers/isDreamSerializer.js';
18
+ import serializerNameFromFullyQualifiedModelName from '../serializer/helpers/serializerNameFromFullyQualifiedModelName.js';
11
19
  import { cacheDreamApp, getCachedDreamAppOrFail } from './cache.js';
12
20
  import importModels, { getModelsOrFail } from './helpers/importers/importModels.js';
13
21
  import importSerializers, { getSerializersOrFail, setCachedSerializers, } from './helpers/importers/importSerializers.js';
22
+ import lookupClassByGlobalName from './helpers/lookupClassByGlobalName.js';
14
23
  // this needs to be done top-level to ensure proper configuration
15
24
  Settings.defaultZone = 'UTC';
16
25
  export default class DreamApp {
@@ -44,6 +53,47 @@ export default class DreamApp {
44
53
  });
45
54
  return dreamApp;
46
55
  }
56
+ /**
57
+ * Since javascript is inherently vulnerable to circular dependencies,
58
+ * this function provides a workaround by enabling you to dynamically
59
+ * bring in classes that, if imported directly, would result in circular
60
+ * dependency issues.
61
+ *
62
+ * NOTE: You should only use this as a last resort, since it can create quite
63
+ * a headache for you when leaning into your editor to apply renames, etc...
64
+ *
65
+ * @param name - the global name you are trying to look up, i.e. 'User', or 'UserSerializer'.
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * // this pattern is safe from circular imports, since _UserSerializer
70
+ * // is only being used to type something else, which will not result
71
+ * // in the circular dependency issue.
72
+ *
73
+ * import _UserSerializer from '../serializers/UserSerializer.js'
74
+ * const UserSerializer = PsychicApp.lookupClassByGlobalName('UserSerializer') as _UserSerializer
75
+ * ```
76
+ */
77
+ static lookupClassByGlobalName(name) {
78
+ return lookupClassByGlobalName(name);
79
+ }
80
+ /**
81
+ * @internal
82
+ *
83
+ */
84
+ static get system() {
85
+ return {
86
+ globalClassNameFromFullyQualifiedModelName,
87
+ absoluteDreamPath,
88
+ dreamPath,
89
+ standardizeFullyQualifiedModelName,
90
+ expandStiClasses,
91
+ inferSerializerFromDreamOrViewModel,
92
+ inferSerializersFromDreamClassOrViewModelClass,
93
+ isDreamSerializer,
94
+ serializerNameFromFullyQualifiedModelName,
95
+ };
96
+ }
47
97
  /**
48
98
  * @internal
49
99
  *
@@ -11,9 +11,10 @@ export default function generateDreamContent({ fullyQualifiedModelName, columnsW
11
11
  fullyQualifiedModelName = standardizeFullyQualifiedModelName(fullyQualifiedModelName);
12
12
  const modelClassName = globalClassNameFromFullyQualifiedModelName(fullyQualifiedModelName);
13
13
  let parentModelClassName;
14
- const dreamImports = ['Decorators', 'DreamColumn'];
14
+ const dreamTypeImports = ['DreamColumn'];
15
+ const dreamImports = ['Decorators'];
15
16
  if (serializer)
16
- dreamImports.push('DreamSerializers');
17
+ dreamTypeImports.push('DreamSerializers');
17
18
  const isSTI = !!fullyQualifiedParentName;
18
19
  if (isSTI) {
19
20
  fullyQualifiedParentName = standardizeFullyQualifiedModelName(fullyQualifiedParentName);
@@ -49,9 +50,8 @@ public ${associationForeignKey}: DreamColumn<${modelClassName}, '${associationNa
49
50
  case 'has_many':
50
51
  return '';
51
52
  case 'encrypted':
52
- dreamImports.push('Encrypted');
53
53
  return `
54
- @Encrypted()
54
+ @deco.Encrypted()
55
55
  public ${camelize(attributeName)}: ${getAttributeType(attribute, modelClassName)}\
56
56
  `;
57
57
  default:
@@ -77,7 +77,7 @@ public ${camelize(attributeName)}: ${getAttributeType(attribute, modelClassName)
77
77
  timestamps = timestamps.replace(/\n$/, '');
78
78
  const tableName = snakeify(pluralize(fullyQualifiedModelName.replace(/\//g, '_')));
79
79
  return `\
80
- import { ${uniq(dreamImports).join(', ')} } from '@rvoh/dream'${uniq(modelImportStatements).join('')}
80
+ ${dreamImports.length ? `import { ${uniq(dreamImports).join(', ')} } from '@rvoh/dream'\n` : ''}import { ${uniq(dreamTypeImports).join(', ')} } from '@rvoh/dream/types'${uniq(modelImportStatements).join('')}
81
81
 
82
82
  const deco = new Decorators<typeof ${modelClassName}>()
83
83
 
@@ -6,7 +6,8 @@ import uniq from '../uniq.js';
6
6
  import { optionalFromDescriptors } from './generateMigrationContent.js';
7
7
  export default function generateFactoryContent({ fullyQualifiedModelName, columnsWithTypes, }) {
8
8
  fullyQualifiedModelName = standardizeFullyQualifiedModelName(fullyQualifiedModelName);
9
- const dreamImports = ['UpdateableProperties'];
9
+ const dreamTypeImports = ['UpdateableProperties'];
10
+ const dreamImports = [];
10
11
  const additionalImports = [];
11
12
  const belongsToNames = [];
12
13
  const belongsToTypedNames = [];
@@ -23,6 +24,8 @@ export default function generateFactoryContent({ fullyQualifiedModelName, column
23
24
  if (optional)
24
25
  continue;
25
26
  const attributeVariable = camelize(attributeName.replace(/\//g, ''));
27
+ if (/^type$/.test(attributeName))
28
+ continue;
26
29
  if (/(_type|_id)$/.test(attributeName))
27
30
  continue;
28
31
  if (!attributeType)
@@ -101,7 +104,7 @@ export default function generateFactoryContent({ fullyQualifiedModelName, column
101
104
  const relativePath = absoluteDreamPath('models', fullyQualifiedModelName);
102
105
  const modelClassName = globalClassNameFromFullyQualifiedModelName(fullyQualifiedModelName);
103
106
  return `\
104
- import { ${uniq(dreamImports).join(', ')} } from '@rvoh/dream'
107
+ ${dreamImports.length ? `import { ${uniq(dreamImports).join(', ')} } from '@rvoh/dream'\n` : ''}import { ${uniq(dreamTypeImports).join(', ')} } from '@rvoh/dream/types'
105
108
  import ${modelClassName} from '${relativePath}'${additionalImports.length ? '\n' + uniq(additionalImports).join('\n') : ''}
106
109
  ${counterVariableIncremented ? '\nlet counter = 0\n' : ''}
107
110
  export default async function create${modelClassName}(attrs: UpdateableProperties<${modelClassName}> = {}) {
@@ -11,7 +11,12 @@ export default function generateMigrationContent({ connectionName = 'default', t
11
11
  const checkConstraints = [];
12
12
  const { columnDefs, columnDrops, indexDefs, indexDrops } = columnsWithTypes.reduce((acc, attributeDeclaration) => {
13
13
  const { columnDefs, columnDrops, indexDefs, indexDrops } = acc;
14
- const [nonStandardAttributeName, attributeType, ...descriptors] = attributeDeclaration.split(':');
14
+ const [nonStandardAttributeName, _attributeType, ...descriptors] = attributeDeclaration.split(':');
15
+ /**
16
+ * Automatically set email columns to citext since different casings of
17
+ * email address are the same email address
18
+ */
19
+ const attributeType = nonStandardAttributeName === 'email' ? 'citext' : _attributeType;
15
20
  const userWantsThisOptional = optionalFromDescriptors(descriptors);
16
21
  // when creating a migration for an STI child, we don't want to include notNull;
17
22
  // instead, we'll add a check constraint that uses the STI child class name
@@ -116,9 +121,9 @@ export async function down(db: Kysely<any>): Promise<void> {
116
121
  ? ` await DreamMigrationHelpers.createExtension(db, 'citext')\n\n`
117
122
  : '';
118
123
  const kyselyImports = ['Kysely', 'sql'];
119
- const dreamImports = [];
124
+ const dreamDbImports = [];
120
125
  if (requireCitextExtension)
121
- dreamImports.push('DreamMigrationHelpers');
126
+ dreamDbImports.push('DreamMigrationHelpers');
122
127
  const newlineIndent = '\n ';
123
128
  const newlineDoubleIndent = '\n ';
124
129
  const doubleNewlineIndent = '\n\n ';
@@ -127,7 +132,7 @@ export async function down(db: Kysely<any>): Promise<void> {
127
132
  ? newlineDoubleIndent + columnDrops.join(newlineDoubleIndent) + newlineDoubleIndent
128
133
  : '';
129
134
  return `\
130
- ${dreamImports.length ? `import { ${dreamImports.join(', ')} } from '@rvoh/dream'\n` : ''}import { ${kyselyImports.join(', ')} } from 'kysely'
135
+ ${dreamDbImports.length ? `import { ${dreamDbImports.join(', ')} } from '@rvoh/dream/db'\n` : ''}import { ${kyselyImports.join(', ')} } from 'kysely'
131
136
 
132
137
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
133
138
  export async function up(db: Kysely<any>): Promise<void> {
@@ -231,6 +236,8 @@ function generateColumnStr(attributeName, attributeType, descriptors, { omitInli
231
236
  returnStr += ', col => col';
232
237
  if (notNull)
233
238
  returnStr += '.notNull()';
239
+ if (attributeName === 'email' || /token$/.test(attributeName))
240
+ returnStr += '.unique()';
234
241
  if (providedDefault)
235
242
  returnStr += `.defaultTo('${providedDefault}')`;
236
243
  else if (isArray)