@rvoh/dream 2.0.4 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/CHANGELOG.md +332 -0
  2. package/dist/cjs/src/bin/index.js +2 -0
  3. package/dist/cjs/src/db/helpers/dreamSchemaTypesFilenameForConnection.js +3 -0
  4. package/dist/cjs/src/db/helpers/syncDbTypesFiles.js +2 -89
  5. package/dist/cjs/src/dream/QueryDriver/Base.js +2 -2
  6. package/dist/cjs/src/dream/QueryDriver/Kysely.js +9 -19
  7. package/dist/cjs/src/dream/QueryDriver/Postgres.js +2 -2
  8. package/dist/cjs/src/dream-app/index.js +15 -0
  9. package/dist/cjs/src/helpers/cli/ASTBuilder.js +277 -0
  10. package/dist/cjs/src/helpers/cli/ASTConnectionBuilder.js +284 -0
  11. package/dist/cjs/src/helpers/cli/ASTGlobalSchemaBuilder.js +57 -0
  12. package/dist/cjs/src/helpers/cli/ASTKyselyCodegenEnhancer.js +236 -0
  13. package/dist/cjs/src/helpers/cli/ASTSchemaBuilder.js +304 -0
  14. package/dist/cjs/src/helpers/cli/DBClassDeprecation.js +60 -0
  15. package/dist/cjs/src/helpers/cli/generateDreamContent.js +5 -4
  16. package/dist/cjs/src/helpers/cli/generateFactoryContent.js +3 -2
  17. package/dist/cjs/src/helpers/cli/generateMigrationContent.js +6 -4
  18. package/dist/cjs/src/helpers/cli/generateSerializerContent.js +1 -1
  19. package/dist/esm/src/bin/index.js +2 -0
  20. package/dist/esm/src/db/helpers/dreamSchemaTypesFilenameForConnection.js +3 -0
  21. package/dist/esm/src/db/helpers/syncDbTypesFiles.js +2 -89
  22. package/dist/esm/src/dream/QueryDriver/Base.js +2 -2
  23. package/dist/esm/src/dream/QueryDriver/Kysely.js +9 -19
  24. package/dist/esm/src/dream/QueryDriver/Postgres.js +2 -2
  25. package/dist/esm/src/dream-app/index.js +15 -0
  26. package/dist/esm/src/helpers/cli/ASTBuilder.js +277 -0
  27. package/dist/esm/src/helpers/cli/ASTConnectionBuilder.js +284 -0
  28. package/dist/esm/src/helpers/cli/ASTGlobalSchemaBuilder.js +57 -0
  29. package/dist/esm/src/helpers/cli/ASTKyselyCodegenEnhancer.js +236 -0
  30. package/dist/esm/src/helpers/cli/ASTSchemaBuilder.js +304 -0
  31. package/dist/esm/src/helpers/cli/DBClassDeprecation.js +60 -0
  32. package/dist/esm/src/helpers/cli/generateDreamContent.js +5 -4
  33. package/dist/esm/src/helpers/cli/generateFactoryContent.js +3 -2
  34. package/dist/esm/src/helpers/cli/generateMigrationContent.js +6 -4
  35. package/dist/esm/src/helpers/cli/generateSerializerContent.js +1 -1
  36. package/dist/types/src/db/helpers/dreamSchemaTypesFilenameForConnection.d.ts +1 -0
  37. package/dist/types/src/dream/QueryDriver/Base.d.ts +3 -3
  38. package/dist/types/src/dream/QueryDriver/Kysely.d.ts +2 -14
  39. package/dist/types/src/dream/QueryDriver/Postgres.d.ts +2 -2
  40. package/dist/types/src/dream-app/index.d.ts +12 -2
  41. package/dist/types/src/helpers/cli/ASTBuilder.d.ts +159 -0
  42. package/dist/types/src/helpers/cli/ASTConnectionBuilder.d.ts +104 -0
  43. package/dist/types/src/helpers/cli/ASTGlobalSchemaBuilder.d.ts +28 -0
  44. package/dist/types/src/helpers/cli/ASTKyselyCodegenEnhancer.d.ts +68 -0
  45. package/dist/types/src/helpers/cli/ASTSchemaBuilder.d.ts +80 -0
  46. package/dist/types/src/helpers/cli/DBClassDeprecation.d.ts +14 -0
  47. package/docs/assets/search.js +1 -1
  48. package/docs/classes/db.DreamMigrationHelpers.html +9 -9
  49. package/docs/classes/db.KyselyQueryDriver.html +31 -44
  50. package/docs/classes/db.PostgresQueryDriver.html +32 -45
  51. package/docs/classes/db.QueryDriverBase.html +30 -30
  52. package/docs/classes/errors.CheckConstraintViolation.html +3 -3
  53. package/docs/classes/errors.ColumnOverflow.html +3 -3
  54. package/docs/classes/errors.CreateOrFindByFailedToCreateAndFind.html +3 -3
  55. package/docs/classes/errors.DataIncompatibleWithDatabaseField.html +3 -3
  56. package/docs/classes/errors.DataTypeColumnTypeMismatch.html +3 -3
  57. package/docs/classes/errors.GlobalNameNotSet.html +3 -3
  58. package/docs/classes/errors.InvalidCalendarDate.html +2 -2
  59. package/docs/classes/errors.MissingSerializersDefinition.html +3 -3
  60. package/docs/classes/errors.NonLoadedAssociation.html +3 -3
  61. package/docs/classes/errors.NotNullViolation.html +3 -3
  62. package/docs/classes/errors.RecordNotFound.html +3 -3
  63. package/docs/classes/errors.ValidationError.html +3 -3
  64. package/docs/classes/index.CalendarDate.html +2 -2
  65. package/docs/classes/index.Decorators.html +19 -19
  66. package/docs/classes/index.Dream.html +113 -113
  67. package/docs/classes/index.DreamApp.html +7 -6
  68. package/docs/classes/index.DreamTransaction.html +2 -2
  69. package/docs/classes/index.Env.html +2 -2
  70. package/docs/classes/index.Query.html +53 -53
  71. package/docs/classes/system.CliFileWriter.html +2 -2
  72. package/docs/classes/system.DreamBin.html +2 -2
  73. package/docs/classes/system.DreamCLI.html +5 -5
  74. package/docs/classes/system.DreamImporter.html +2 -2
  75. package/docs/classes/system.DreamLogos.html +2 -2
  76. package/docs/classes/system.DreamSerializerBuilder.html +8 -8
  77. package/docs/classes/system.ObjectSerializerBuilder.html +8 -8
  78. package/docs/classes/utils.Encrypt.html +2 -2
  79. package/docs/classes/utils.Range.html +2 -2
  80. package/docs/functions/db.closeAllDbConnections.html +1 -1
  81. package/docs/functions/db.dreamDbConnections.html +1 -1
  82. package/docs/functions/db.untypedDb.html +1 -1
  83. package/docs/functions/db.validateColumn.html +1 -1
  84. package/docs/functions/db.validateTable.html +1 -1
  85. package/docs/functions/errors.pgErrorType.html +1 -1
  86. package/docs/functions/index.DreamSerializer.html +1 -1
  87. package/docs/functions/index.ObjectSerializer.html +1 -1
  88. package/docs/functions/index.ReplicaSafe.html +1 -1
  89. package/docs/functions/index.STI.html +1 -1
  90. package/docs/functions/index.SoftDelete.html +1 -1
  91. package/docs/functions/utils.camelize.html +1 -1
  92. package/docs/functions/utils.capitalize.html +1 -1
  93. package/docs/functions/utils.cloneDeepSafe.html +1 -1
  94. package/docs/functions/utils.compact.html +1 -1
  95. package/docs/functions/utils.groupBy.html +1 -1
  96. package/docs/functions/utils.hyphenize.html +1 -1
  97. package/docs/functions/utils.intersection.html +1 -1
  98. package/docs/functions/utils.isEmpty.html +1 -1
  99. package/docs/functions/utils.normalizeUnicode.html +1 -1
  100. package/docs/functions/utils.pascalize.html +1 -1
  101. package/docs/functions/utils.percent.html +1 -1
  102. package/docs/functions/utils.range-1.html +1 -1
  103. package/docs/functions/utils.round.html +1 -1
  104. package/docs/functions/utils.sanitizeString.html +1 -1
  105. package/docs/functions/utils.snakeify.html +1 -1
  106. package/docs/functions/utils.sort.html +1 -1
  107. package/docs/functions/utils.sortBy.html +1 -1
  108. package/docs/functions/utils.sortObjectByKey.html +1 -1
  109. package/docs/functions/utils.sortObjectByValue.html +1 -1
  110. package/docs/functions/utils.uncapitalize.html +1 -1
  111. package/docs/functions/utils.uniq.html +1 -1
  112. package/docs/interfaces/openapi.OpenapiDescription.html +2 -2
  113. package/docs/interfaces/openapi.OpenapiSchemaProperties.html +1 -1
  114. package/docs/interfaces/openapi.OpenapiSchemaPropertiesShorthand.html +1 -1
  115. package/docs/interfaces/openapi.OpenapiTypeFieldObject.html +1 -1
  116. package/docs/interfaces/types.BelongsToStatement.html +2 -2
  117. package/docs/interfaces/types.DecoratorContext.html +2 -2
  118. package/docs/interfaces/types.DreamAppInitOptions.html +2 -2
  119. package/docs/interfaces/types.DreamAppOpts.html +2 -2
  120. package/docs/interfaces/types.EncryptOptions.html +2 -2
  121. package/docs/interfaces/types.InternalAnyTypedSerializerRendersMany.html +2 -2
  122. package/docs/interfaces/types.InternalAnyTypedSerializerRendersOne.html +2 -2
  123. package/docs/interfaces/types.SerializerRendererOpts.html +2 -2
  124. package/docs/modules/db.html +1 -1
  125. package/docs/modules/errors.html +1 -1
  126. package/docs/modules/index.html +1 -1
  127. package/docs/modules/openapi.html +1 -1
  128. package/docs/modules/system.html +1 -1
  129. package/docs/modules/types.html +1 -1
  130. package/docs/modules/utils.html +1 -1
  131. package/docs/types/index.DateTime.html +1 -1
  132. package/docs/types/openapi.CommonOpenapiSchemaObjectFields.html +1 -1
  133. package/docs/types/openapi.OpenapiAllTypes.html +1 -1
  134. package/docs/types/openapi.OpenapiFormats.html +1 -1
  135. package/docs/types/openapi.OpenapiNumberFormats.html +1 -1
  136. package/docs/types/openapi.OpenapiPrimitiveBaseTypes.html +1 -1
  137. package/docs/types/openapi.OpenapiPrimitiveTypes.html +1 -1
  138. package/docs/types/openapi.OpenapiSchemaArray.html +1 -1
  139. package/docs/types/openapi.OpenapiSchemaArrayShorthand.html +1 -1
  140. package/docs/types/openapi.OpenapiSchemaBase.html +1 -1
  141. package/docs/types/openapi.OpenapiSchemaBody.html +1 -1
  142. package/docs/types/openapi.OpenapiSchemaBodyShorthand.html +1 -1
  143. package/docs/types/openapi.OpenapiSchemaCommonFields.html +1 -1
  144. package/docs/types/openapi.OpenapiSchemaExpressionAllOf.html +1 -1
  145. package/docs/types/openapi.OpenapiSchemaExpressionAnyOf.html +1 -1
  146. package/docs/types/openapi.OpenapiSchemaExpressionOneOf.html +1 -1
  147. package/docs/types/openapi.OpenapiSchemaExpressionRef.html +1 -1
  148. package/docs/types/openapi.OpenapiSchemaExpressionRefSchemaShorthand.html +1 -1
  149. package/docs/types/openapi.OpenapiSchemaInteger.html +1 -1
  150. package/docs/types/openapi.OpenapiSchemaNull.html +1 -1
  151. package/docs/types/openapi.OpenapiSchemaNumber.html +1 -1
  152. package/docs/types/openapi.OpenapiSchemaObject.html +1 -1
  153. package/docs/types/openapi.OpenapiSchemaObjectAllOf.html +1 -1
  154. package/docs/types/openapi.OpenapiSchemaObjectAllOfShorthand.html +1 -1
  155. package/docs/types/openapi.OpenapiSchemaObjectAnyOf.html +1 -1
  156. package/docs/types/openapi.OpenapiSchemaObjectAnyOfShorthand.html +1 -1
  157. package/docs/types/openapi.OpenapiSchemaObjectBase.html +1 -1
  158. package/docs/types/openapi.OpenapiSchemaObjectBaseShorthand.html +1 -1
  159. package/docs/types/openapi.OpenapiSchemaObjectOneOf.html +1 -1
  160. package/docs/types/openapi.OpenapiSchemaObjectOneOfShorthand.html +1 -1
  161. package/docs/types/openapi.OpenapiSchemaObjectShorthand.html +1 -1
  162. package/docs/types/openapi.OpenapiSchemaPrimitiveGeneric.html +1 -1
  163. package/docs/types/openapi.OpenapiSchemaShorthandExpressionAllOf.html +1 -1
  164. package/docs/types/openapi.OpenapiSchemaShorthandExpressionAnyOf.html +1 -1
  165. package/docs/types/openapi.OpenapiSchemaShorthandExpressionOneOf.html +1 -1
  166. package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializableRef.html +1 -1
  167. package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializerRef.html +1 -1
  168. package/docs/types/openapi.OpenapiSchemaShorthandPrimitiveGeneric.html +1 -1
  169. package/docs/types/openapi.OpenapiSchemaString.html +1 -1
  170. package/docs/types/openapi.OpenapiShorthandAllTypes.html +1 -1
  171. package/docs/types/openapi.OpenapiShorthandPrimitiveBaseTypes.html +1 -1
  172. package/docs/types/openapi.OpenapiShorthandPrimitiveTypes.html +1 -1
  173. package/docs/types/openapi.OpenapiTypeField.html +1 -1
  174. package/docs/types/system.DreamAppAllowedPackageManagersEnum.html +1 -1
  175. package/docs/types/types.Camelized.html +1 -1
  176. package/docs/types/types.DbConnectionType.html +1 -1
  177. package/docs/types/types.DbTypes.html +1 -1
  178. package/docs/types/types.DreamAssociationMetadata.html +1 -1
  179. package/docs/types/types.DreamAttributes.html +1 -1
  180. package/docs/types/types.DreamClassAssociationAndStatement.html +1 -1
  181. package/docs/types/types.DreamClassColumn.html +1 -1
  182. package/docs/types/types.DreamColumn.html +1 -1
  183. package/docs/types/types.DreamColumnNames.html +1 -1
  184. package/docs/types/types.DreamLogLevel.html +1 -1
  185. package/docs/types/types.DreamLogger.html +1 -1
  186. package/docs/types/types.DreamModelSerializerType.html +1 -1
  187. package/docs/types/types.DreamOrViewModelClassSerializerKey.html +1 -1
  188. package/docs/types/types.DreamOrViewModelSerializerKey.html +1 -1
  189. package/docs/types/types.DreamParamSafeAttributes.html +1 -1
  190. package/docs/types/types.DreamParamSafeColumnNames.html +1 -1
  191. package/docs/types/types.DreamSerializable.html +1 -1
  192. package/docs/types/types.DreamSerializableArray.html +1 -1
  193. package/docs/types/types.DreamSerializerKey.html +1 -1
  194. package/docs/types/types.DreamSerializers.html +1 -1
  195. package/docs/types/types.DreamVirtualColumns.html +1 -1
  196. package/docs/types/types.EncryptAlgorithm.html +1 -1
  197. package/docs/types/types.HasManyStatement.html +1 -1
  198. package/docs/types/types.HasOneStatement.html +1 -1
  199. package/docs/types/types.Hyphenized.html +1 -1
  200. package/docs/types/types.Pascalized.html +1 -1
  201. package/docs/types/types.RoundingPrecision.html +1 -1
  202. package/docs/types/types.SerializerCasing.html +1 -1
  203. package/docs/types/types.SimpleObjectSerializerType.html +1 -1
  204. package/docs/types/types.Snakeified.html +1 -1
  205. package/docs/types/types.StrictInterface.html +1 -1
  206. package/docs/types/types.UpdateableAssociationProperties.html +1 -1
  207. package/docs/types/types.UpdateableProperties.html +1 -1
  208. package/docs/types/types.ValidationType.html +1 -1
  209. package/docs/types/types.ViewModel.html +1 -1
  210. package/docs/types/types.ViewModelClass.html +1 -1
  211. package/docs/types/types.WhereStatementForDream.html +1 -1
  212. package/docs/types/types.WhereStatementForDreamClass.html +1 -1
  213. package/docs/variables/index.DateTime-1.html +1 -1
  214. package/docs/variables/index.DreamConst.html +1 -1
  215. package/docs/variables/index.ops.html +1 -1
  216. package/docs/variables/openapi.openapiPrimitiveTypes-1.html +1 -1
  217. package/docs/variables/openapi.openapiShorthandPrimitiveTypes-1.html +1 -1
  218. package/docs/variables/system.DreamAppAllowedPackageManagersEnumValues.html +1 -1
  219. package/docs/variables/types.TRIGRAM_OPERATORS.html +1 -1
  220. package/docs/variables/types.primaryKeyTypes.html +1 -1
  221. package/package.json +7 -3
  222. package/dist/cjs/src/helpers/cli/SchemaBuilder.js +0 -408
  223. package/dist/esm/src/helpers/cli/SchemaBuilder.js +0 -408
  224. package/dist/types/src/helpers/cli/SchemaBuilder.d.ts +0 -44
@@ -0,0 +1,236 @@
1
+ import ts from 'typescript';
2
+ import { CliFileWriter } from '../../cli/CliFileWriter.js';
3
+ import camelize from '../camelize.js';
4
+ import ASTConnectionBuilder from './ASTConnectionBuilder.js';
5
+ import autogeneratedFileDisclaimer from './autoGeneratedFileDisclaimer.js';
6
+ const f = ts.factory;
7
+ /**
8
+ * Responsible for enhancing the kysely-codegen output, which can be found at
9
+ * types/db.ts. If you are leveraging multiple db connections,
10
+ * then this file will also be responsible for building all variants,
11
+ * i.e. types/db.alternateConnection.ts, etc...
12
+ *
13
+ * This class leverages internal AST building mechanisms built into
14
+ * typescript to manually build up object literals and interfaces
15
+ * for our app to consume.
16
+ */
17
+ export default class ASTKyselyCodegenEnhancer extends ASTConnectionBuilder {
18
+ /**
19
+ * enhances the kysely codegen output for the given connection name
20
+ * by reading the relevant db.ts file into AST nodes, then enhancing them
21
+ * with a variety of transformations necessary to lock this file in with
22
+ * our other schema files, allowing types to flow correctly throughout the app.
23
+ */
24
+ async enhance() {
25
+ let dbSourceFile = await this.getDbSourceFile();
26
+ dbSourceFile = this.camelizeKeys(dbSourceFile);
27
+ dbSourceFile = this.replaceTimestampExport(dbSourceFile);
28
+ dbSourceFile = this.addMissingImports(dbSourceFile);
29
+ dbSourceFile = this.replaceInt8Export(dbSourceFile);
30
+ dbSourceFile = this.sortExportedInterfacesTransformer(dbSourceFile);
31
+ dbSourceFile = await this.addEnumValueExports(dbSourceFile);
32
+ dbSourceFile = this.addDeprecatedDbClassExportForBackwardsCompatibility(dbSourceFile);
33
+ const output = this.printOutput(dbSourceFile);
34
+ const finalOutput = await this.prettier(`\
35
+ ${autogeneratedFileDisclaimer()}
36
+ ${output}`);
37
+ await CliFileWriter.write(this.dbPath(), finalOutput);
38
+ }
39
+ addDeprecatedDbClassExportForBackwardsCompatibility(dbSourceFile) {
40
+ const transformer = () => {
41
+ return sourceFile => {
42
+ const dbInterface = this.findDbExport(sourceFile, 'DB');
43
+ if (!dbInterface)
44
+ return sourceFile;
45
+ const classDec = ts.factory.createClassDeclaration([ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], ts.factory.createIdentifier('DBClass'), undefined, [], dbInterface.members.filter(ts.isPropertySignature).map(propertySignature => {
46
+ return f.createPropertyDeclaration([], propertySignature.name, undefined, propertySignature.type, undefined);
47
+ }));
48
+ return ts.factory.updateSourceFile(sourceFile, [...sourceFile.statements, classDec], sourceFile.isDeclarationFile, sourceFile.referencedFiles, sourceFile.typeReferenceDirectives, undefined);
49
+ };
50
+ };
51
+ const result = ts.transform(dbSourceFile, [transformer]);
52
+ return result.transformed[0];
53
+ }
54
+ /**
55
+ * @internal
56
+ *
57
+ * returns the output of the provided dbSourceFile, ensuring that all exports
58
+ * have a new line above them.
59
+ */
60
+ printOutput(dbSourceFile) {
61
+ const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
62
+ const output = printer.printNode(ts.EmitHint.SourceFile, dbSourceFile, dbSourceFile);
63
+ return output.replace(/export /g, '\nexport ');
64
+ }
65
+ /**
66
+ * @internal
67
+ *
68
+ * ensures that the `Timestamp` exported from db.ts points correctly to either
69
+ * the DateTime or CalendarDate class, depending on the db type.
70
+ */
71
+ replaceTimestampExport(dbSourceFile) {
72
+ const transformer = context => {
73
+ return rootNode => {
74
+ const visit = (node) => {
75
+ const typeAlias = this.exportedTypeAliasOrNull(node, 'Timestamp');
76
+ if (typeAlias) {
77
+ const updatedNode = f.updateTypeAliasDeclaration(typeAlias, typeAlias.modifiers, typeAlias.name, typeAlias.typeParameters, f.createTypeReferenceNode('ColumnType', [
78
+ f.createUnionTypeNode([
79
+ f.createTypeReferenceNode(f.createIdentifier('DateTime')),
80
+ f.createTypeReferenceNode(f.createIdentifier('CalendarDate')),
81
+ ]),
82
+ ]));
83
+ return updatedNode;
84
+ }
85
+ return ts.visitEachChild(node, visit, context);
86
+ };
87
+ return ts.visitNode(rootNode, visit);
88
+ };
89
+ };
90
+ const result = ts.transform(dbSourceFile, [transformer]);
91
+ return result.transformed[0];
92
+ }
93
+ /**
94
+ * @internal
95
+ *
96
+ * massages the `Int8` exported from db.ts to make it more flexible
97
+ */
98
+ replaceInt8Export(dbSourceFile) {
99
+ const transformer = context => {
100
+ return rootNode => {
101
+ const visit = (node) => {
102
+ const typeAlias = this.exportedTypeAliasOrNull(node, 'Int8');
103
+ if (typeAlias) {
104
+ return f.updateTypeAliasDeclaration(typeAlias, typeAlias.modifiers, typeAlias.name, typeAlias.typeParameters, f.createTypeReferenceNode('ColumnType', [
105
+ f.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
106
+ f.createUnionTypeNode([
107
+ f.createKeywordTypeNode(ts.SyntaxKind.BigIntKeyword),
108
+ f.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
109
+ f.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
110
+ ]),
111
+ f.createUnionTypeNode([
112
+ f.createKeywordTypeNode(ts.SyntaxKind.BigIntKeyword),
113
+ f.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
114
+ f.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
115
+ ]),
116
+ ]));
117
+ }
118
+ return ts.visitEachChild(node, visit, context);
119
+ };
120
+ return ts.visitNode(rootNode, visit);
121
+ };
122
+ };
123
+ const result = ts.transform(dbSourceFile, [transformer]);
124
+ return result.transformed[0];
125
+ }
126
+ /**
127
+ * @internal
128
+ *
129
+ * injects missing CalendarDate and DateTime imports from dream
130
+ */
131
+ addMissingImports(dbSourceFile) {
132
+ const transformer = () => {
133
+ return (sourceFile) => f.updateSourceFile(sourceFile, [...this.dateAndDateTimeImports(), ...sourceFile.statements]);
134
+ };
135
+ const result = ts.transform(dbSourceFile, [transformer]);
136
+ return result.transformed[0];
137
+ }
138
+ /**
139
+ * @internal
140
+ *
141
+ * sorts all exported interfaces and puts them above the DB interface
142
+ */
143
+ sortExportedInterfacesTransformer(dbSourceFile) {
144
+ const transformer = () => {
145
+ return (sourceFile) => {
146
+ const sortedInterfaceStatements = [];
147
+ const finalInterfaceStatements = [];
148
+ const otherStatements = [];
149
+ sourceFile.statements.forEach(statement => {
150
+ if (ts.isInterfaceDeclaration(statement) &&
151
+ statement.modifiers?.some(m => m.kind === ts.SyntaxKind.ExportKeyword)) {
152
+ if (statement.name.text !== 'DB') {
153
+ sortedInterfaceStatements.push(statement);
154
+ }
155
+ else {
156
+ finalInterfaceStatements.push(statement);
157
+ }
158
+ }
159
+ else {
160
+ otherStatements.push(statement);
161
+ }
162
+ });
163
+ sortedInterfaceStatements.sort((a, b) => a.name.text.localeCompare(b.name.text));
164
+ return f.updateSourceFile(sourceFile, [...otherStatements, ...sortedInterfaceStatements, ...finalInterfaceStatements], sourceFile.isDeclarationFile, sourceFile.referencedFiles);
165
+ };
166
+ };
167
+ const result = ts.transform(dbSourceFile, [transformer]);
168
+ return result.transformed[0];
169
+ }
170
+ /**
171
+ * @internal
172
+ *
173
+ * camelizes the keys on all interfaces except the DB interface
174
+ * (since the DB interface is indexed by table name, which must not be camelized)
175
+ */
176
+ camelizeKeys(dbSourceFile) {
177
+ // @ts-expect-error cannot lock this type down, though implementation is correct
178
+ const transformer = context => {
179
+ const visit = node => {
180
+ const interfaceNode = this.exportedInterfaceOrNull(node);
181
+ if (interfaceNode &&
182
+ !['DB'].includes(interfaceNode.name.text) // Check exclusion list
183
+ ) {
184
+ const updatedMembers = interfaceNode.members.map(member => {
185
+ if (ts.isPropertySignature(member) && ts.isIdentifier(member.name)) {
186
+ const camelizedKey = camelize(member.name.text);
187
+ if (member.name.text !== camelizedKey) {
188
+ return f.updatePropertySignature(member, member.modifiers, f.createIdentifier(camelizedKey), member.questionToken, member.type);
189
+ }
190
+ }
191
+ return member;
192
+ });
193
+ return f.updateInterfaceDeclaration(interfaceNode, interfaceNode.modifiers, interfaceNode.name, interfaceNode.typeParameters, interfaceNode.heritageClauses, updatedMembers);
194
+ }
195
+ return ts.visitEachChild(node, visit, context);
196
+ };
197
+ return node => ts.visitNode(node, visit);
198
+ };
199
+ const result = ts.transform(dbSourceFile, [transformer]);
200
+ return result.transformed[0];
201
+ }
202
+ /**
203
+ * @internal
204
+ *
205
+ * for each found enum in the app (i.e. LocalizedTextsEnum), this will also
206
+ * inject below it a `LocalizedTextsEnumValues` const, which can be used
207
+ * at runtime to grab the actual enum values.
208
+ */
209
+ async addEnumValueExports(dbSourceFile) {
210
+ const enums = await this.getAllEnumValueNames();
211
+ const enumTypes = enums.map(e => e.enumType);
212
+ // @ts-expect-error cannot lock this type down, though implementation is correct
213
+ const transformer = context => {
214
+ const visit = (node) => {
215
+ const typeAlias = this.exportedTypeAliasOrNull(node);
216
+ const isEnum = typeAlias ? enumTypes.includes(typeAlias.name.text) : false;
217
+ if (typeAlias && isEnum) {
218
+ const literals = this.extractStringLiteralTypeNodesFromTypeOrUnion(typeAlias).map(node => node.literal.text);
219
+ if (literals.length > 0) {
220
+ return [
221
+ typeAlias,
222
+ f.createVariableStatement([f.createModifier(ts.SyntaxKind.ExportKeyword)], f.createVariableDeclarationList([
223
+ f.createVariableDeclaration(f.createIdentifier(`${typeAlias.name.text}Values`), undefined, undefined, f.createAsExpression(f.createArrayLiteralExpression(literals.map(literal => f.createStringLiteral(literal)), true // multiLine
224
+ ), f.createKeywordTypeNode(ts.SyntaxKind.ConstKeyword))),
225
+ ], ts.NodeFlags.Const)),
226
+ ];
227
+ }
228
+ }
229
+ return ts.visitEachChild(node, visit, context);
230
+ };
231
+ return node => ts.visitNode(node, visit);
232
+ };
233
+ const result = ts.transform(dbSourceFile, [transformer]);
234
+ return result.transformed[0];
235
+ }
236
+ }
@@ -0,0 +1,304 @@
1
+ import ts from 'typescript';
2
+ import { CliFileWriter } from '../../cli/CliFileWriter.js';
3
+ import { DreamConst } from '../../dream/constants.js';
4
+ import compact from '../compact.js';
5
+ import uniq from '../uniq.js';
6
+ import ASTConnectionBuilder from './ASTConnectionBuilder.js';
7
+ import autogeneratedFileDisclaimer from './autoGeneratedFileDisclaimer.js';
8
+ const f = ts.factory;
9
+ /**
10
+ * Responsible for building dream schema, which can be found at
11
+ * types/dream.ts. If you are leveraging multiple db connections,
12
+ * then this file will also be responsible for building all variants,
13
+ * i.e. types/dream.alternateConnection.ts, etc...
14
+ *
15
+ * This class leverages internal AST building mechanisms built into
16
+ * typescript to manually build up object literals and interfaces
17
+ * for our app to consume.
18
+ */
19
+ export default class ASTSchemaBuilder extends ASTConnectionBuilder {
20
+ /**
21
+ * builds the new contents for the dream schema file (i.e. types/dream.ts
22
+ * for default connection), and writes it to the file. This is automatically
23
+ * done anytime the sync cli command is called, which happens when migrating,
24
+ * rolling back, and when manually calling the sync command via CLI.
25
+ */
26
+ async build() {
27
+ // build a new, blank source file to populate with our output
28
+ const sourceFile = ts.createSourceFile('', '', ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
29
+ const { importedTypes, importedVariables, schemaConst, passthroughColumns, allDefaultScopeNames } = await this.buildSchemaConst();
30
+ const output = await this.prettier(this.printStatements([
31
+ ...this.dateAndDateTimeImports(),
32
+ this.dbImports(importedTypes, importedVariables),
33
+ this.newLine(),
34
+ schemaConst,
35
+ this.newLine(),
36
+ this.buildConnectionTypeConfigConst(passthroughColumns, allDefaultScopeNames),
37
+ ], sourceFile));
38
+ await CliFileWriter.write(this.schemaPath(), output);
39
+ }
40
+ /**
41
+ * @internal
42
+ *
43
+ * builds up the `export const schema = ...` statement within the dream.ts
44
+ * file. It does this by leveraging low-level AST utils built into typescript
45
+ * to manually build up an object literal, cast it as a const, and write it to
46
+ * an exported variable.
47
+ */
48
+ async buildSchemaConst() {
49
+ const schemaData = await this.getSchemaData();
50
+ const importedTypes = [];
51
+ const importedVariables = [];
52
+ let passthroughColumns = [];
53
+ let allDefaultScopeNames = [];
54
+ const dbSourceFile = await this.getDbSourceFile();
55
+ const schemaObjectLiteral = f.createObjectLiteralExpression(Object.keys(schemaData).map(tableName => {
56
+ const tableData = schemaData[tableName];
57
+ allDefaultScopeNames = [...allDefaultScopeNames, ...tableData.scopes.default];
58
+ return f.createPropertyAssignment(f.createIdentifier(tableName), f.createObjectLiteralExpression([
59
+ f.createPropertyAssignment(f.createIdentifier('serializerKeys'), f.createArrayLiteralExpression([...(tableData?.serializerKeys || [])].sort().map(key => f.createStringLiteral(key)))),
60
+ f.createPropertyAssignment(f.createIdentifier('scopes'), f.createObjectLiteralExpression([
61
+ f.createPropertyAssignment(f.createIdentifier('default'), f.createArrayLiteralExpression((tableData?.scopes.default).sort().map(key => f.createStringLiteral(key)))),
62
+ f.createPropertyAssignment(f.createIdentifier('named'), f.createArrayLiteralExpression((tableData?.scopes.named).sort().map(key => f.createStringLiteral(key)))),
63
+ ], true // multiline
64
+ )),
65
+ f.createPropertyAssignment(f.createIdentifier('nonJsonColumnNames'), f.createArrayLiteralExpression(Object.keys(tableData?.columns || {})
66
+ .filter(columnName => !['json', 'jsonb', 'json[]', 'jsonb[]'].includes(tableData.columns[columnName].dbType))
67
+ .sort()
68
+ .map(key => f.createStringLiteral(key)))),
69
+ f.createPropertyAssignment(f.createIdentifier('columns'), f.createObjectLiteralExpression(Object.keys(tableData?.columns || {})
70
+ .sort()
71
+ .map(columnName => {
72
+ const columnData = tableData.columns[columnName];
73
+ // any enums for these columns will need to be imported
74
+ // from the db.ts file in the same folder, so as we detect
75
+ // them, we push them into the importedModules array.
76
+ if (columnData.enumType) {
77
+ importedTypes.push(columnData.enumType);
78
+ importedVariables.push(columnData.enumType + 'Values');
79
+ }
80
+ const enumTypeNode = columnData.enumType
81
+ ? f.createTypeReferenceNode(f.createIdentifier(columnData.enumType), undefined // No type arguments needed here
82
+ )
83
+ : null;
84
+ const enumValuesNode = columnData.enumType
85
+ ? f.createIdentifier(columnData.enumType + 'Values')
86
+ : f.createNull();
87
+ const coercedType = this.getCoercedTypeForTableColumn(dbSourceFile, tableName, columnName, tableData, importedTypes);
88
+ return f.createPropertyAssignment(f.createIdentifier(columnName), f.createObjectLiteralExpression([
89
+ f.createPropertyAssignment(f.createIdentifier('coercedType'), f.createAsExpression(f.createObjectLiteralExpression(), coercedType)),
90
+ f.createPropertyAssignment(f.createIdentifier('enumType'), enumTypeNode
91
+ ? f.createAsExpression(f.createObjectLiteralExpression(), enumTypeNode)
92
+ : f.createNull()),
93
+ f.createPropertyAssignment(f.createIdentifier('enumArrayType'), enumTypeNode
94
+ ? f.createAsExpression(f.createArrayLiteralExpression(), f.createArrayTypeNode(enumTypeNode))
95
+ : f.createNull()),
96
+ f.createPropertyAssignment(f.createIdentifier('enumValues'), enumValuesNode),
97
+ f.createPropertyAssignment(f.createIdentifier('dbType'), f.createStringLiteral(columnData.dbType)),
98
+ f.createPropertyAssignment(f.createIdentifier('allowNull'), columnData.allowNull ? f.createTrue() : f.createFalse()),
99
+ f.createPropertyAssignment(f.createIdentifier('isArray'), columnData.isArray ? f.createTrue() : f.createFalse()),
100
+ ], true // multiline
101
+ ));
102
+ }), true // multiline
103
+ )),
104
+ f.createPropertyAssignment(f.createIdentifier('virtualColumns'), f.createArrayLiteralExpression(tableData?.virtualColumns
105
+ ?.sort()
106
+ ?.map(columnName => f.createStringLiteral(columnName)))),
107
+ f.createPropertyAssignment(f.createIdentifier('associations'), f.createObjectLiteralExpression(Object.keys(tableData?.associations || {})
108
+ .sort()
109
+ .map(associationName => {
110
+ const associationMetadata = tableData.associations[associationName];
111
+ const andStatement = associationMetadata.and;
112
+ const requiredAndClauses = andStatement === null
113
+ ? []
114
+ : Object.keys(andStatement).filter(column => andStatement[column] === DreamConst.required);
115
+ const passthroughAndClauses = andStatement === null
116
+ ? []
117
+ : Object.keys(andStatement).filter(column => andStatement[column] === DreamConst.passthrough);
118
+ passthroughColumns = [...passthroughColumns, ...passthroughAndClauses];
119
+ return f.createPropertyAssignment(f.createIdentifier(associationName), f.createObjectLiteralExpression([
120
+ f.createPropertyAssignment(f.createIdentifier('type'), f.createStringLiteral(associationMetadata.type)),
121
+ f.createPropertyAssignment(f.createIdentifier('foreignKey'), associationMetadata.foreignKey
122
+ ? f.createStringLiteral(associationMetadata.foreignKey)
123
+ : f.createNull()),
124
+ f.createPropertyAssignment(f.createIdentifier('foreignKeyTypeColumn'), associationMetadata.foreignKeyTypeColumn
125
+ ? f.createStringLiteral(associationMetadata.foreignKeyTypeColumn)
126
+ : f.createNull()),
127
+ f.createPropertyAssignment(f.createIdentifier('tables'), f.createArrayLiteralExpression(associationMetadata.tables.sort().map(table => f.createStringLiteral(table)))),
128
+ f.createPropertyAssignment(f.createIdentifier('optional'), associationMetadata.optional === null
129
+ ? f.createNull()
130
+ : associationMetadata.optional
131
+ ? f.createTrue()
132
+ : f.createFalse()),
133
+ f.createPropertyAssignment(f.createIdentifier('requiredAndClauses'), requiredAndClauses.length === 0
134
+ ? f.createNull()
135
+ : f.createArrayLiteralExpression(requiredAndClauses.sort().map(clause => f.createStringLiteral(clause)))),
136
+ f.createPropertyAssignment(f.createIdentifier('passthroughAndClauses'), passthroughAndClauses.length === 0
137
+ ? f.createNull()
138
+ : f.createArrayLiteralExpression(passthroughAndClauses.sort().map(clause => f.createStringLiteral(clause)))),
139
+ ], true // multiline
140
+ ));
141
+ }), true // multiline
142
+ )),
143
+ ], true // multiline
144
+ ));
145
+ }), true // multiLine
146
+ );
147
+ // add "as const" to the end of the schema object we
148
+ // have built before returning it
149
+ const constAssertion = f.createAsExpression(schemaObjectLiteral, f.createKeywordTypeNode(ts.SyntaxKind.ConstKeyword));
150
+ const schemaConst = f.createVariableStatement([f.createModifier(ts.SyntaxKind.ExportKeyword)], f.createVariableDeclarationList([f.createVariableDeclaration(f.createIdentifier('schema'), undefined, undefined, constAssertion)], ts.NodeFlags.Const));
151
+ return {
152
+ schemaConst,
153
+ importedTypes: uniq(importedTypes).sort(),
154
+ importedVariables: uniq(importedVariables).sort(),
155
+ passthroughColumns: uniq(passthroughColumns).sort(),
156
+ allDefaultScopeNames: uniq(allDefaultScopeNames).sort(),
157
+ };
158
+ }
159
+ /**
160
+ * @internal
161
+ *
162
+ * builds up the `export const connectionTypeConfig = ...` statement within the dream.ts
163
+ * file. It does this by leveraging low-level AST utils built into typescript
164
+ * to manually build up an object literal, cast it as a const, and write it to
165
+ * an exported variable.
166
+ */
167
+ buildConnectionTypeConfigConst(passthroughColumns, allDefaultScopeNames) {
168
+ const connectionTypeConfigObjectLiteral = f.createObjectLiteralExpression([
169
+ f.createPropertyAssignment(f.createIdentifier('passthroughColumns'), f.createArrayLiteralExpression(passthroughColumns.sort().map(column => f.createStringLiteral(column)), true // multiline
170
+ )),
171
+ f.createPropertyAssignment(f.createIdentifier('allDefaultScopeNames'), f.createArrayLiteralExpression(allDefaultScopeNames.sort().map(column => f.createStringLiteral(column)), true // multiline
172
+ )),
173
+ f.createPropertyAssignment(f.createIdentifier('globalNames'), f.createObjectLiteralExpression([
174
+ f.createPropertyAssignment(f.createIdentifier('models'), f.createObjectLiteralExpression(this.globalModelNames()
175
+ .sort()
176
+ .map(([globalName, tableName]) => f.createPropertyAssignment(f.createStringLiteral(globalName), f.createStringLiteral(tableName))), true // multiline
177
+ )),
178
+ ], true // multiline
179
+ )),
180
+ ], true // multiline
181
+ );
182
+ // add "as const" to the end of the schema object we
183
+ // have built before returning it
184
+ const constAssertion = f.createAsExpression(connectionTypeConfigObjectLiteral, f.createKeywordTypeNode(ts.SyntaxKind.ConstKeyword));
185
+ const connectionTypeConfigObjectLiteralConst = f.createVariableStatement([f.createModifier(ts.SyntaxKind.ExportKeyword)], f.createVariableDeclarationList([
186
+ f.createVariableDeclaration(f.createIdentifier('connectionTypeConfig'), undefined, undefined, constAssertion),
187
+ ], ts.NodeFlags.Const));
188
+ return connectionTypeConfigObjectLiteralConst;
189
+ }
190
+ /**
191
+ * @internal
192
+ *
193
+ * writes the compiled statements to string. Will also manually inject new lines
194
+ * into the import statements, since otherwise, they are forced into a single line
195
+ * and are completely unreadable that way.
196
+ *
197
+ * prettier is used in a later step to optimize output, but the user may not have
198
+ * prettier installed, in which case it will do nothing, and we don't want to leave
199
+ * the imports unformatted in those cases.
200
+ */
201
+ printStatements(statements, sourceFile) {
202
+ const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed, omitTrailingSemicolon: true });
203
+ const result = printer.printList(ts.ListFormat.SourceFileStatements, f.createNodeArray(statements), sourceFile);
204
+ // manually replace single-line db imports with multi-line import
205
+ const output = result
206
+ .replace(/import\s*{\s*([^}]+)\s*}\s*from\s*"\.\/db.js"/, (_, names) => {
207
+ // Split items, trim them, and rejoin with newlines + indentation
208
+ const formatted = names
209
+ .split(',')
210
+ .map((n) => n.trim())
211
+ .map((n) => ` ${n},`)
212
+ .join('\n');
213
+ return `import {\n${formatted}\n} from "./db.js"`;
214
+ })
215
+ .replaceAll(/from ([^;]*);/g, 'from $1');
216
+ return `\
217
+ ${autogeneratedFileDisclaimer()}
218
+ ${output}`;
219
+ }
220
+ /**
221
+ * @internal
222
+ *
223
+ * builds up an AST statement representing the DB imports that the dream.ts
224
+ * file will need in order to render without import errors. It takes the aggregated
225
+ * list of imported types and imported variables built up as the schema was being
226
+ * built, and uses them to build AST import nodes, which can be rendered into the
227
+ * schema source file.
228
+ */
229
+ dbImports(importedTypes, importedVariables) {
230
+ const namedImports = f.createNamedImports([
231
+ ...importedTypes.map(importName => f.createImportSpecifier(true, undefined, f.createIdentifier(importName))),
232
+ ...importedVariables.map(importName => f.createImportSpecifier(false, undefined, f.createIdentifier(importName))),
233
+ ]);
234
+ const importClause = f.createImportClause(false, undefined, namedImports);
235
+ const importDeclaration = f.createImportDeclaration(undefined, importClause, f.createStringLiteral('./db.js'), undefined);
236
+ return importDeclaration;
237
+ }
238
+ /**
239
+ * @internal
240
+ *
241
+ * given a column and table, this method returns the coerced type representation
242
+ * of whatever type was found in the db.ts file. In most cases, it will simply
243
+ * return the same type as was found, but in some cases it will perform coercion
244
+ * to provide consistent and useful types to the underlying application.
245
+ *
246
+ * Amongst other things, it will convert Numeric -> number, Int8 -> string, etc...
247
+ * Timestamp will be carefully converted to either CalendarDate or DateTime, depending
248
+ * on if the type set in the db is a date or datetime field.
249
+ */
250
+ getCoercedTypeForTableColumn(dbSourceFile, tableName, columnName, tableData, importedModules) {
251
+ const columnData = tableData.columns[columnName];
252
+ const tableNode = this.getTableInterfaceDeclaration(dbSourceFile, tableName);
253
+ const propertyNode = this.getPropertyFromInterface(tableNode, columnName);
254
+ const coercedTypes = this.coercedType(dbSourceFile, propertyNode, columnData.dbType, importedModules);
255
+ return coercedTypes.length === 1 ? coercedTypes[0] : f.createUnionTypeNode(coercedTypes);
256
+ }
257
+ /**
258
+ * @internal
259
+ *
260
+ * used by the getCoercedTypeForTableColumn to get the specific type for a column
261
+ * if no coercion is necessary, the original type node will be returned
262
+ */
263
+ coercedType(dbSourceFile, propertySignature, dbType, importedModules) {
264
+ const extractedPropertyTypes = this.extractTypeNodesFromTypeOrUnion(propertySignature);
265
+ const isDate = /^date[[\]]*$/.test(dbType);
266
+ const types = compact(extractedPropertyTypes.map(typeNode => {
267
+ const typeText = typeNode.getText(dbSourceFile);
268
+ let defaultReturnNode = /^Generated/.test(typeText) ? this.getFirstGenericType(typeNode) : typeNode;
269
+ const modifiedText = defaultReturnNode.getText(dbSourceFile);
270
+ defaultReturnNode = /^ArrayType/.test(modifiedText)
271
+ ? f.createArrayTypeNode(this.getFirstGenericType(defaultReturnNode))
272
+ : defaultReturnNode;
273
+ const sanitized = typeText
274
+ .replace(/\s/g, '')
275
+ .replace(/Generated<(.*)>/g, '$1')
276
+ .replace(/ArrayType<(.*)>/g, '$1[]');
277
+ if (sanitized === '')
278
+ return null;
279
+ switch (sanitized) {
280
+ case 'Numeric':
281
+ return f.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);
282
+ case 'Numeric[]':
283
+ return f.createArrayTypeNode(f.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword));
284
+ case 'Timestamp':
285
+ return isDate ? f.createTypeReferenceNode('CalendarDate') : f.createTypeReferenceNode('DateTime');
286
+ case 'Timestamp[]':
287
+ return isDate
288
+ ? f.createArrayTypeNode(f.createTypeReferenceNode('CalendarDate'))
289
+ : f.createArrayTypeNode(f.createTypeReferenceNode('DateTime'));
290
+ case 'Int8':
291
+ return f.createKeywordTypeNode(ts.SyntaxKind.StringKeyword);
292
+ case 'Int8[]':
293
+ return f.createArrayTypeNode(f.createKeywordTypeNode(ts.SyntaxKind.StringKeyword));
294
+ case 'Json':
295
+ case 'Json[]':
296
+ importedModules.push('Json');
297
+ return defaultReturnNode;
298
+ default:
299
+ return defaultReturnNode;
300
+ }
301
+ }));
302
+ return types;
303
+ }
304
+ }
@@ -0,0 +1,60 @@
1
+ import * as fsSync from 'node:fs';
2
+ import * as fs from 'node:fs/promises';
3
+ import * as path from 'node:path';
4
+ import DreamCLI from '../../cli/index.js';
5
+ import DreamApp from '../../dream-app/index.js';
6
+ /**
7
+ * Originally, psychic-workers tapped into the types produced by psychic,
8
+ * modifying the psychicTypes to include type configurations for workers
9
+ * as well. Since Psychic no longer supports this method of augmenting
10
+ * types, psychic-workers has been refactored to produce its own types
11
+ * file.
12
+ *
13
+ * This service is responsible for identifying applications that are still
14
+ * reliant on the types produced by psychic, and refactoring them so that their
15
+ * imports are now in the correct places.
16
+ */
17
+ export default class DBClassDeprecation {
18
+ async deprecate() {
19
+ const dreamApp = DreamApp.getOrFail();
20
+ if (dreamApp.bypassDeprecationChecks)
21
+ return;
22
+ const files = [
23
+ path.join(process.cwd(), DreamApp.system.dreamPath('models'), 'ApplicationModel.ts'),
24
+ path.join(process.cwd(), DreamApp.system.dreamPath('models'), 'ApplicationBackgroundedModel.ts'),
25
+ ];
26
+ try {
27
+ for (const file of files) {
28
+ const exists = fsSync.existsSync(file);
29
+ if (!exists)
30
+ continue;
31
+ const fileContent = (await fs.readFile(file)).toString();
32
+ if (fileContent.includes('DBClass')) {
33
+ await DreamCLI.logger.logProgress(`[dream] patching deprecated DBClass type for ${file.split(path.sep).at(-1)}`, async () => {
34
+ await fs.writeFile(file, fileContent.replace(/DBClass/g, 'DB'));
35
+ });
36
+ }
37
+ }
38
+ }
39
+ catch (err) {
40
+ console.error(err);
41
+ console.log(`
42
+ ATTENTION:
43
+
44
+ The dream package has formally deprecated the DBClass export from all dream schema files. Any usage
45
+ of the DBClass export throughout your app should be replaced with the "DB" export, which provides an
46
+ identical structure to the original DBClass export.
47
+
48
+ An automated script is meant to manually catch and fix this for you any time you sync, but for some
49
+ reason it failed. Make sure to replace all DBClass imports throughout your app with the DB export, like so:
50
+
51
+ import { DB } from '@src/types/db.js'
52
+
53
+ export default class ApplicationModel extends Dream {
54
+ declare public DB: DB
55
+ ...
56
+ }
57
+ `);
58
+ }
59
+ }
60
+ }
@@ -94,11 +94,12 @@ export function processAttribute(attribute, modelClassName) {
94
94
  if (!attributeType) {
95
95
  throw new Error(`must pass a column type for ${attributeName} (i.e. ${attributeName}:string)`);
96
96
  }
97
- switch (attributeType) {
98
- case 'belongs_to':
97
+ const processedAttrType = camelize(attributeType).toLowerCase();
98
+ switch (processedAttrType) {
99
+ case 'belongsto':
99
100
  return createBelongsToAttribute(attributeName, descriptors, modelClassName);
100
- case 'has_one':
101
- case 'has_many':
101
+ case 'hasone':
102
+ case 'hasmany':
102
103
  return { content: '', imports: [] };
103
104
  case 'encrypted':
104
105
  return createEncryptedAttribute(attributeName, attribute, modelClassName);
@@ -30,8 +30,9 @@ export default function generateFactoryContent({ fullyQualifiedModelName, column
30
30
  continue;
31
31
  if (!attributeType)
32
32
  throw new Error(`Must pass a column type for ${attributeName} (i.e. ${attributeName}:string)`);
33
- switch (attributeType) {
34
- case 'belongs_to': {
33
+ const safeAttributeType = camelize(attributeType)?.toLowerCase();
34
+ switch (safeAttributeType) {
35
+ case 'belongsto': {
35
36
  const attributeVariable = camelize(attributeName.split('/').pop());
36
37
  const fullyQualifiedAssociatedModelName = standardizeFullyQualifiedModelName(attributeName);
37
38
  const associationModelName = globalClassNameFromFullyQualifiedModelName(fullyQualifiedAssociatedModelName);