@rvoh/dream 2.0.4 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (215) hide show
  1. package/dist/cjs/src/bin/index.js +2 -0
  2. package/dist/cjs/src/db/helpers/dreamSchemaTypesFilenameForConnection.js +3 -0
  3. package/dist/cjs/src/db/helpers/syncDbTypesFiles.js +2 -89
  4. package/dist/cjs/src/dream/QueryDriver/Base.js +2 -2
  5. package/dist/cjs/src/dream/QueryDriver/Kysely.js +9 -19
  6. package/dist/cjs/src/dream/QueryDriver/Postgres.js +2 -2
  7. package/dist/cjs/src/dream-app/index.js +15 -0
  8. package/dist/cjs/src/helpers/cli/ASTBuilder.js +277 -0
  9. package/dist/cjs/src/helpers/cli/ASTConnectionBuilder.js +284 -0
  10. package/dist/cjs/src/helpers/cli/ASTGlobalSchemaBuilder.js +57 -0
  11. package/dist/cjs/src/helpers/cli/ASTKyselyCodegenEnhancer.js +236 -0
  12. package/dist/cjs/src/helpers/cli/ASTSchemaBuilder.js +304 -0
  13. package/dist/cjs/src/helpers/cli/DBClassDeprecation.js +60 -0
  14. package/dist/esm/src/bin/index.js +2 -0
  15. package/dist/esm/src/db/helpers/dreamSchemaTypesFilenameForConnection.js +3 -0
  16. package/dist/esm/src/db/helpers/syncDbTypesFiles.js +2 -89
  17. package/dist/esm/src/dream/QueryDriver/Base.js +2 -2
  18. package/dist/esm/src/dream/QueryDriver/Kysely.js +9 -19
  19. package/dist/esm/src/dream/QueryDriver/Postgres.js +2 -2
  20. package/dist/esm/src/dream-app/index.js +15 -0
  21. package/dist/esm/src/helpers/cli/ASTBuilder.js +277 -0
  22. package/dist/esm/src/helpers/cli/ASTConnectionBuilder.js +284 -0
  23. package/dist/esm/src/helpers/cli/ASTGlobalSchemaBuilder.js +57 -0
  24. package/dist/esm/src/helpers/cli/ASTKyselyCodegenEnhancer.js +236 -0
  25. package/dist/esm/src/helpers/cli/ASTSchemaBuilder.js +304 -0
  26. package/dist/esm/src/helpers/cli/DBClassDeprecation.js +60 -0
  27. package/dist/types/src/db/helpers/dreamSchemaTypesFilenameForConnection.d.ts +1 -0
  28. package/dist/types/src/dream/QueryDriver/Base.d.ts +3 -3
  29. package/dist/types/src/dream/QueryDriver/Kysely.d.ts +2 -14
  30. package/dist/types/src/dream/QueryDriver/Postgres.d.ts +2 -2
  31. package/dist/types/src/dream-app/index.d.ts +12 -2
  32. package/dist/types/src/helpers/cli/ASTBuilder.d.ts +159 -0
  33. package/dist/types/src/helpers/cli/ASTConnectionBuilder.d.ts +104 -0
  34. package/dist/types/src/helpers/cli/ASTGlobalSchemaBuilder.d.ts +28 -0
  35. package/dist/types/src/helpers/cli/ASTKyselyCodegenEnhancer.d.ts +68 -0
  36. package/dist/types/src/helpers/cli/ASTSchemaBuilder.d.ts +80 -0
  37. package/dist/types/src/helpers/cli/DBClassDeprecation.d.ts +14 -0
  38. package/docs/assets/search.js +1 -1
  39. package/docs/classes/db.DreamMigrationHelpers.html +9 -9
  40. package/docs/classes/db.KyselyQueryDriver.html +31 -44
  41. package/docs/classes/db.PostgresQueryDriver.html +32 -45
  42. package/docs/classes/db.QueryDriverBase.html +30 -30
  43. package/docs/classes/errors.CheckConstraintViolation.html +3 -3
  44. package/docs/classes/errors.ColumnOverflow.html +3 -3
  45. package/docs/classes/errors.CreateOrFindByFailedToCreateAndFind.html +3 -3
  46. package/docs/classes/errors.DataIncompatibleWithDatabaseField.html +3 -3
  47. package/docs/classes/errors.DataTypeColumnTypeMismatch.html +3 -3
  48. package/docs/classes/errors.GlobalNameNotSet.html +3 -3
  49. package/docs/classes/errors.InvalidCalendarDate.html +2 -2
  50. package/docs/classes/errors.MissingSerializersDefinition.html +3 -3
  51. package/docs/classes/errors.NonLoadedAssociation.html +3 -3
  52. package/docs/classes/errors.NotNullViolation.html +3 -3
  53. package/docs/classes/errors.RecordNotFound.html +3 -3
  54. package/docs/classes/errors.ValidationError.html +3 -3
  55. package/docs/classes/index.CalendarDate.html +2 -2
  56. package/docs/classes/index.Decorators.html +19 -19
  57. package/docs/classes/index.Dream.html +113 -113
  58. package/docs/classes/index.DreamApp.html +7 -6
  59. package/docs/classes/index.DreamTransaction.html +2 -2
  60. package/docs/classes/index.Env.html +2 -2
  61. package/docs/classes/index.Query.html +53 -53
  62. package/docs/classes/system.CliFileWriter.html +2 -2
  63. package/docs/classes/system.DreamBin.html +2 -2
  64. package/docs/classes/system.DreamCLI.html +5 -5
  65. package/docs/classes/system.DreamImporter.html +2 -2
  66. package/docs/classes/system.DreamLogos.html +2 -2
  67. package/docs/classes/system.DreamSerializerBuilder.html +8 -8
  68. package/docs/classes/system.ObjectSerializerBuilder.html +8 -8
  69. package/docs/classes/utils.Encrypt.html +2 -2
  70. package/docs/classes/utils.Range.html +2 -2
  71. package/docs/functions/db.closeAllDbConnections.html +1 -1
  72. package/docs/functions/db.dreamDbConnections.html +1 -1
  73. package/docs/functions/db.untypedDb.html +1 -1
  74. package/docs/functions/db.validateColumn.html +1 -1
  75. package/docs/functions/db.validateTable.html +1 -1
  76. package/docs/functions/errors.pgErrorType.html +1 -1
  77. package/docs/functions/index.DreamSerializer.html +1 -1
  78. package/docs/functions/index.ObjectSerializer.html +1 -1
  79. package/docs/functions/index.ReplicaSafe.html +1 -1
  80. package/docs/functions/index.STI.html +1 -1
  81. package/docs/functions/index.SoftDelete.html +1 -1
  82. package/docs/functions/utils.camelize.html +1 -1
  83. package/docs/functions/utils.capitalize.html +1 -1
  84. package/docs/functions/utils.cloneDeepSafe.html +1 -1
  85. package/docs/functions/utils.compact.html +1 -1
  86. package/docs/functions/utils.groupBy.html +1 -1
  87. package/docs/functions/utils.hyphenize.html +1 -1
  88. package/docs/functions/utils.intersection.html +1 -1
  89. package/docs/functions/utils.isEmpty.html +1 -1
  90. package/docs/functions/utils.normalizeUnicode.html +1 -1
  91. package/docs/functions/utils.pascalize.html +1 -1
  92. package/docs/functions/utils.percent.html +1 -1
  93. package/docs/functions/utils.range-1.html +1 -1
  94. package/docs/functions/utils.round.html +1 -1
  95. package/docs/functions/utils.sanitizeString.html +1 -1
  96. package/docs/functions/utils.snakeify.html +1 -1
  97. package/docs/functions/utils.sort.html +1 -1
  98. package/docs/functions/utils.sortBy.html +1 -1
  99. package/docs/functions/utils.sortObjectByKey.html +1 -1
  100. package/docs/functions/utils.sortObjectByValue.html +1 -1
  101. package/docs/functions/utils.uncapitalize.html +1 -1
  102. package/docs/functions/utils.uniq.html +1 -1
  103. package/docs/interfaces/openapi.OpenapiDescription.html +2 -2
  104. package/docs/interfaces/openapi.OpenapiSchemaProperties.html +1 -1
  105. package/docs/interfaces/openapi.OpenapiSchemaPropertiesShorthand.html +1 -1
  106. package/docs/interfaces/openapi.OpenapiTypeFieldObject.html +1 -1
  107. package/docs/interfaces/types.BelongsToStatement.html +2 -2
  108. package/docs/interfaces/types.DecoratorContext.html +2 -2
  109. package/docs/interfaces/types.DreamAppInitOptions.html +2 -2
  110. package/docs/interfaces/types.DreamAppOpts.html +2 -2
  111. package/docs/interfaces/types.EncryptOptions.html +2 -2
  112. package/docs/interfaces/types.InternalAnyTypedSerializerRendersMany.html +2 -2
  113. package/docs/interfaces/types.InternalAnyTypedSerializerRendersOne.html +2 -2
  114. package/docs/interfaces/types.SerializerRendererOpts.html +2 -2
  115. package/docs/modules/db.html +1 -1
  116. package/docs/modules/errors.html +1 -1
  117. package/docs/modules/index.html +1 -1
  118. package/docs/modules/openapi.html +1 -1
  119. package/docs/modules/system.html +1 -1
  120. package/docs/modules/types.html +1 -1
  121. package/docs/modules/utils.html +1 -1
  122. package/docs/types/index.DateTime.html +1 -1
  123. package/docs/types/openapi.CommonOpenapiSchemaObjectFields.html +1 -1
  124. package/docs/types/openapi.OpenapiAllTypes.html +1 -1
  125. package/docs/types/openapi.OpenapiFormats.html +1 -1
  126. package/docs/types/openapi.OpenapiNumberFormats.html +1 -1
  127. package/docs/types/openapi.OpenapiPrimitiveBaseTypes.html +1 -1
  128. package/docs/types/openapi.OpenapiPrimitiveTypes.html +1 -1
  129. package/docs/types/openapi.OpenapiSchemaArray.html +1 -1
  130. package/docs/types/openapi.OpenapiSchemaArrayShorthand.html +1 -1
  131. package/docs/types/openapi.OpenapiSchemaBase.html +1 -1
  132. package/docs/types/openapi.OpenapiSchemaBody.html +1 -1
  133. package/docs/types/openapi.OpenapiSchemaBodyShorthand.html +1 -1
  134. package/docs/types/openapi.OpenapiSchemaCommonFields.html +1 -1
  135. package/docs/types/openapi.OpenapiSchemaExpressionAllOf.html +1 -1
  136. package/docs/types/openapi.OpenapiSchemaExpressionAnyOf.html +1 -1
  137. package/docs/types/openapi.OpenapiSchemaExpressionOneOf.html +1 -1
  138. package/docs/types/openapi.OpenapiSchemaExpressionRef.html +1 -1
  139. package/docs/types/openapi.OpenapiSchemaExpressionRefSchemaShorthand.html +1 -1
  140. package/docs/types/openapi.OpenapiSchemaInteger.html +1 -1
  141. package/docs/types/openapi.OpenapiSchemaNull.html +1 -1
  142. package/docs/types/openapi.OpenapiSchemaNumber.html +1 -1
  143. package/docs/types/openapi.OpenapiSchemaObject.html +1 -1
  144. package/docs/types/openapi.OpenapiSchemaObjectAllOf.html +1 -1
  145. package/docs/types/openapi.OpenapiSchemaObjectAllOfShorthand.html +1 -1
  146. package/docs/types/openapi.OpenapiSchemaObjectAnyOf.html +1 -1
  147. package/docs/types/openapi.OpenapiSchemaObjectAnyOfShorthand.html +1 -1
  148. package/docs/types/openapi.OpenapiSchemaObjectBase.html +1 -1
  149. package/docs/types/openapi.OpenapiSchemaObjectBaseShorthand.html +1 -1
  150. package/docs/types/openapi.OpenapiSchemaObjectOneOf.html +1 -1
  151. package/docs/types/openapi.OpenapiSchemaObjectOneOfShorthand.html +1 -1
  152. package/docs/types/openapi.OpenapiSchemaObjectShorthand.html +1 -1
  153. package/docs/types/openapi.OpenapiSchemaPrimitiveGeneric.html +1 -1
  154. package/docs/types/openapi.OpenapiSchemaShorthandExpressionAllOf.html +1 -1
  155. package/docs/types/openapi.OpenapiSchemaShorthandExpressionAnyOf.html +1 -1
  156. package/docs/types/openapi.OpenapiSchemaShorthandExpressionOneOf.html +1 -1
  157. package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializableRef.html +1 -1
  158. package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializerRef.html +1 -1
  159. package/docs/types/openapi.OpenapiSchemaShorthandPrimitiveGeneric.html +1 -1
  160. package/docs/types/openapi.OpenapiSchemaString.html +1 -1
  161. package/docs/types/openapi.OpenapiShorthandAllTypes.html +1 -1
  162. package/docs/types/openapi.OpenapiShorthandPrimitiveBaseTypes.html +1 -1
  163. package/docs/types/openapi.OpenapiShorthandPrimitiveTypes.html +1 -1
  164. package/docs/types/openapi.OpenapiTypeField.html +1 -1
  165. package/docs/types/system.DreamAppAllowedPackageManagersEnum.html +1 -1
  166. package/docs/types/types.Camelized.html +1 -1
  167. package/docs/types/types.DbConnectionType.html +1 -1
  168. package/docs/types/types.DbTypes.html +1 -1
  169. package/docs/types/types.DreamAssociationMetadata.html +1 -1
  170. package/docs/types/types.DreamAttributes.html +1 -1
  171. package/docs/types/types.DreamClassAssociationAndStatement.html +1 -1
  172. package/docs/types/types.DreamClassColumn.html +1 -1
  173. package/docs/types/types.DreamColumn.html +1 -1
  174. package/docs/types/types.DreamColumnNames.html +1 -1
  175. package/docs/types/types.DreamLogLevel.html +1 -1
  176. package/docs/types/types.DreamLogger.html +1 -1
  177. package/docs/types/types.DreamModelSerializerType.html +1 -1
  178. package/docs/types/types.DreamOrViewModelClassSerializerKey.html +1 -1
  179. package/docs/types/types.DreamOrViewModelSerializerKey.html +1 -1
  180. package/docs/types/types.DreamParamSafeAttributes.html +1 -1
  181. package/docs/types/types.DreamParamSafeColumnNames.html +1 -1
  182. package/docs/types/types.DreamSerializable.html +1 -1
  183. package/docs/types/types.DreamSerializableArray.html +1 -1
  184. package/docs/types/types.DreamSerializerKey.html +1 -1
  185. package/docs/types/types.DreamSerializers.html +1 -1
  186. package/docs/types/types.DreamVirtualColumns.html +1 -1
  187. package/docs/types/types.EncryptAlgorithm.html +1 -1
  188. package/docs/types/types.HasManyStatement.html +1 -1
  189. package/docs/types/types.HasOneStatement.html +1 -1
  190. package/docs/types/types.Hyphenized.html +1 -1
  191. package/docs/types/types.Pascalized.html +1 -1
  192. package/docs/types/types.RoundingPrecision.html +1 -1
  193. package/docs/types/types.SerializerCasing.html +1 -1
  194. package/docs/types/types.SimpleObjectSerializerType.html +1 -1
  195. package/docs/types/types.Snakeified.html +1 -1
  196. package/docs/types/types.StrictInterface.html +1 -1
  197. package/docs/types/types.UpdateableAssociationProperties.html +1 -1
  198. package/docs/types/types.UpdateableProperties.html +1 -1
  199. package/docs/types/types.ValidationType.html +1 -1
  200. package/docs/types/types.ViewModel.html +1 -1
  201. package/docs/types/types.ViewModelClass.html +1 -1
  202. package/docs/types/types.WhereStatementForDream.html +1 -1
  203. package/docs/types/types.WhereStatementForDreamClass.html +1 -1
  204. package/docs/variables/index.DateTime-1.html +1 -1
  205. package/docs/variables/index.DreamConst.html +1 -1
  206. package/docs/variables/index.ops.html +1 -1
  207. package/docs/variables/openapi.openapiPrimitiveTypes-1.html +1 -1
  208. package/docs/variables/openapi.openapiShorthandPrimitiveTypes-1.html +1 -1
  209. package/docs/variables/system.DreamAppAllowedPackageManagersEnumValues.html +1 -1
  210. package/docs/variables/types.TRIGRAM_OPERATORS.html +1 -1
  211. package/docs/variables/types.primaryKeyTypes.html +1 -1
  212. package/package.json +1 -1
  213. package/dist/cjs/src/helpers/cli/SchemaBuilder.js +0 -408
  214. package/dist/esm/src/helpers/cli/SchemaBuilder.js +0 -408
  215. package/dist/types/src/helpers/cli/SchemaBuilder.d.ts +0 -44
@@ -1,6 +1,7 @@
1
1
  import DreamCLI from '../cli/index.js';
2
2
  import DreamApp from '../dream-app/index.js';
3
3
  import Query from '../dream/Query.js';
4
+ import DBClassDeprecation from '../helpers/cli/DBClassDeprecation.js';
4
5
  import generateDream from '../helpers/cli/generateDream.js';
5
6
  import sspawn from '../helpers/sspawn.js';
6
7
  export default class DreamBin {
@@ -9,6 +10,7 @@ export default class DreamBin {
9
10
  for (const connectionName of Object.keys(dreamApp.dbCredentials)) {
10
11
  await Query.dbDriverClass(connectionName).sync(connectionName, onSync, options);
11
12
  }
13
+ await new DBClassDeprecation().deprecate();
12
14
  }
13
15
  static async dbCreate() {
14
16
  const dreamApp = DreamApp.getOrFail();
@@ -0,0 +1,3 @@
1
+ export default function dreamSchemaTypesFilenameForConnection(connectionName) {
2
+ return connectionName === 'default' ? 'dream.ts' : `dream.${connectionName}.ts`;
3
+ }
@@ -1,14 +1,10 @@
1
- import * as fs from 'node:fs/promises';
2
1
  import * as path from 'node:path';
3
2
  import { CliFileWriter } from '../../cli/CliFileWriter.js';
4
3
  import DreamCLI from '../../cli/index.js';
5
4
  import colorize from '../../cli/logger/loggable/colorize.js';
6
5
  import DreamApp from '../../dream-app/index.js';
7
- import autogeneratedFileDisclaimer from '../../helpers/cli/autoGeneratedFileDisclaimer.js';
8
- import compact from '../../helpers/compact.js';
9
- import EnvInternal from '../../helpers/EnvInternal.js';
6
+ import ASTKyselyCodegenEnhancer from '../../helpers/cli/ASTKyselyCodegenEnhancer.js';
10
7
  import dreamPath from '../../helpers/path/dreamPath.js';
11
- import snakeify from '../../helpers/snakeify.js';
12
8
  import sspawn from '../../helpers/sspawn.js';
13
9
  import dbTypesFilenameForConnection from './dbTypesFilenameForConnection.js';
14
10
  export default async function syncDbTypesFiles(connectionName) {
@@ -26,88 +22,5 @@ export default async function syncDbTypesFiles(connectionName) {
26
22
  });
27
23
  },
28
24
  });
29
- // intentionally bypassing helpers here, since they often end up referencing
30
- // from the dist folder, whereas dirname here is pointing to true src folder.
31
- const file = (await fs.readFile(absoluteDbSyncPath)).toString();
32
- const enhancedSchema = enhanceSchema(file);
33
- await CliFileWriter.write(absoluteDbSyncPath, enhancedSchema);
34
- }
35
- // begin: schema helpers
36
- function enhanceSchema(file) {
37
- file = removeUnwantedExports(file);
38
- file = replaceInt8Type(file);
39
- file = replaceJsonType(file);
40
- const interfaces = file.split(/export interface /g);
41
- const results = interfaces.slice(1, interfaces.length);
42
- const dbInterface = results.find(str => /^DB \{/.test(str));
43
- const camelDbInterface = camelcasify(dbInterface);
44
- file = camelcasify(file);
45
- file = file.replace(camelDbInterface, dbInterface);
46
- file = addCustomImports(file);
47
- const transformedNames = compact(results.map(result => transformName(result)));
48
- const fileWithCoercedTypes = exportedEnumTypesToExportedTypeValues(file);
49
- // BEGIN FILE CONTENTS BUILDING
50
- const newFileContents = `${fileWithCoercedTypes}
51
-
52
- export class DBClass {
53
- ${transformedNames
54
- .map(name => `${snakeify(name)}: ${name}`)
55
- .sort()
56
- .join('\n ')}
57
- }
58
- `;
59
- const sortedFileContents = alphaSortInterfaceProperties(newFileContents);
60
- return sortedFileContents;
61
- }
62
- function removeUnwantedExports(file) {
63
- return file.replace(/\nexport type Timestamp = ColumnType<.*/, `export type Timestamp = ColumnType<DateTime | CalendarDate>`);
64
- }
65
- function addCustomImports(file) {
66
- const customImports = EnvInternal.boolean('DREAM_CORE_DEVELOPMENT')
67
- ? "import type CalendarDate from '../../src/helpers/CalendarDate.js'\nimport { type DateTime } from '../../src/helpers/DateTime.js'"
68
- : "import { type CalendarDate, type DateTime } from '@rvoh/dream'";
69
- return `${autogeneratedFileDisclaimer()}${customImports}
70
- ${file}`;
71
- }
72
- function replaceInt8Type(str) {
73
- return str.replace('export type Int8 = ColumnType<string, bigint | number | string>', 'export type Int8 = ColumnType<string, bigint | number | string, bigint | number | string>');
74
- }
75
- function replaceJsonType(str) {
76
- return str.replace('export type Json = ColumnType<JsonValue, string, string>', 'export type Json = ColumnType<JsonValue, string | JsonValue, string | JsonValue>');
77
- }
78
- function camelcasify(str) {
79
- return _camelcasify(str);
80
- }
81
- function _camelcasify(str) {
82
- const camelString = str.replace(/([( .])([a-z][a-zA-Z0-9]*)_([a-z0-9])([a-z0-9]*)/g, (match, p1, p2, p3, p4) => `${p1}${p2}${p3.toUpperCase()}${p4}`);
83
- return camelString === str ? camelString : _camelcasify(camelString);
84
- }
85
- function alphaSortInterfaceProperties(str) {
86
- return str.replace(/(export interface [^\n{]+){\n([^}]+)\n}/g, (_match, interfaceDeclaration, lines) => {
87
- const props = lines.split(/\n/);
88
- return `${interfaceDeclaration}{
89
- ${props.sort().join('\n')}
90
- }`;
91
- });
92
- }
93
- function exportedEnumTypesToExportedTypeValues(str) {
94
- const ommitedTypes = ['Generated<T>', 'Json', 'JsonArray', 'JsonObject', 'JsonPrimitive', 'JsonValue'];
95
- return str.replace(/export type ([^=]*) = ((?!ColumnType)[^;\n]*);/g, (_match, typeDeclaration, types) => {
96
- const originalType = `export type ${typeDeclaration} = ${types};`;
97
- if (ommitedTypes.some(type => type === typeDeclaration)) {
98
- return originalType;
99
- }
100
- return `\
101
- ${originalType}
102
- export const ${typeDeclaration}Values = [
103
- ${types.split(' | ').join(',\n ')}
104
- ] as const
105
- `;
106
- });
107
- }
108
- function transformName(str) {
109
- const name = str.split(' {')[0]?.replace(/\s/g, '');
110
- if (name === undefined || name === 'DB')
111
- return null;
112
- return name;
25
+ await new ASTKyselyCodegenEnhancer(connectionName).enhance();
113
26
  }
@@ -90,7 +90,7 @@ export default class QueryDriverBase {
90
90
  * this file is extremely complex and messy, and will be difficult
91
91
  * to achieve.
92
92
  * 2. generate a types/dream.ts file in the same shape as the existing
93
- * one. This is normally done using `await new SchemaBuilder().build()`,
93
+ * one. This is normally done using the ASTSchemaBuilder
94
94
  * but this will likely need to be overridden to tailor to your custom
95
95
  * database engine.
96
96
  */
@@ -172,7 +172,7 @@ export default class QueryDriverBase {
172
172
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
173
173
  tableName,
174
174
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
175
- associationData) {
175
+ allTableAssociationData) {
176
176
  throw new Error('implement getColumnData in child class');
177
177
  }
178
178
  static serializeDbType(type, val) {
@@ -34,8 +34,9 @@ import NotNullViolation from '../../errors/db/NotNullViolation.js';
34
34
  import UnexpectedUndefined from '../../errors/UnexpectedUndefined.js';
35
35
  import CalendarDate from '../../helpers/CalendarDate.js';
36
36
  import camelize from '../../helpers/camelize.js';
37
+ import ASTGlobalSchemaBuilder from '../../helpers/cli/ASTGlobalSchemaBuilder.js';
38
+ import ASTSchemaBuilder from '../../helpers/cli/ASTSchemaBuilder.js';
37
39
  import generateMigration from '../../helpers/cli/generateMigration.js';
38
- import SchemaBuilder from '../../helpers/cli/SchemaBuilder.js';
39
40
  import compact from '../../helpers/compact.js';
40
41
  import { DateTime } from '../../helpers/DateTime.js';
41
42
  import EnvInternal from '../../helpers/EnvInternal.js';
@@ -158,31 +159,20 @@ export default class KyselyQueryDriver extends QueryDriverBase {
158
159
  /**
159
160
  * defines the syncing behavior for dream and psychic,
160
161
  * which is run whenever the `sync` command is called.
161
- * This is an important step, and will be incredibly
162
- * comlpex to override. You will need to do the following
163
- * when overriding this method:
164
- *
165
- * 1. introspect the db and use it to generate a db.ts file in the
166
- * same shape as the existing one. Currently, the process for generating
167
- * this file is extremely complex and messy, and will be difficult
168
- * to achieve.
169
- * 2. generate a types/dream.ts file in the same shape as the existing
170
- * one. This is normally done using `await new SchemaBuilder().build()`,
171
- * but this will likely need to be overridden to tailor to your custom
172
- * database engine.
173
- */
162
+ * */
174
163
  static async sync(connectionName, onSync, options = {}) {
175
164
  try {
176
165
  if (!options?.schemaOnly) {
177
166
  await DreamCLI.logger.logProgress(`introspecting db for connection: ${connectionName}...`, async () => {
167
+ // this calls kysely-codegen under the hood
178
168
  await syncDbTypesFiles(connectionName);
179
169
  });
180
170
  }
181
- const schemaBuilder = new SchemaBuilder(connectionName);
171
+ const newSchemaBuilder = new ASTSchemaBuilder(connectionName);
182
172
  await DreamCLI.logger.logProgress(`building dream schema for connection ${connectionName}...`, async () => {
183
- await schemaBuilder.build();
173
+ await newSchemaBuilder.build();
184
174
  });
185
- if (schemaBuilder.hasForeignKeyError && !options?.schemaOnly) {
175
+ if (newSchemaBuilder.hasForeignKeyError && !options?.schemaOnly) {
186
176
  await DreamCLI.logger.logProgress('triggering resync to correct for foreign key errors...', async () => {
187
177
  // TODO: make this customizable to enable dream apps to separate
188
178
  const cliCmd = EnvInternal.boolean('DREAM_CORE_DEVELOPMENT') ? 'dream' : 'psy';
@@ -196,7 +186,7 @@ export default class KyselyQueryDriver extends QueryDriverBase {
196
186
  });
197
187
  });
198
188
  }
199
- await SchemaBuilder.buildGlobalTypes();
189
+ await new ASTGlobalSchemaBuilder().build();
200
190
  if (!options?.schemaOnly) {
201
191
  // intentionally leaving logs off here, since it allows other
202
192
  // onSync handlers to determine their own independent logging approach
@@ -205,7 +195,7 @@ export default class KyselyQueryDriver extends QueryDriverBase {
205
195
  }
206
196
  catch (error) {
207
197
  console.error(error);
208
- await DreamCLI.logger.logProgress('sync failed, reverting file contents...', async () => {
198
+ await DreamCLI.logger.logProgress('[dream] sync failed, reverting file contents...', async () => {
209
199
  await CliFileWriter.revert();
210
200
  });
211
201
  }
@@ -111,7 +111,7 @@ export default class PostgresQueryDriver extends KyselyQueryDriver {
111
111
  * this is used by the SchemaBuilder to store column data permanently
112
112
  * within the types/dream.ts file.
113
113
  */
114
- static async getColumnData(connectionName, tableName, associationData) {
114
+ static async getColumnData(connectionName, tableName, allTableAssociationData) {
115
115
  const db = this.dbFor(connectionName, 'primary');
116
116
  const sqlQuery = sql `SELECT column_name, udt_name::regtype, is_nullable, data_type FROM information_schema.columns WHERE table_name = ${tableName}`;
117
117
  const columnToDBTypeMap = await sqlQuery.execute(db);
@@ -120,7 +120,7 @@ export default class PostgresQueryDriver extends KyselyQueryDriver {
120
120
  rows.forEach(row => {
121
121
  const isEnum = ['USER-DEFINED', 'ARRAY'].includes(row.dataType) && !isPrimitiveDataType(row.udtName);
122
122
  const isArray = ['ARRAY'].includes(row.dataType);
123
- const associationMetadata = associationData[row.columnName];
123
+ const associationMetadata = allTableAssociationData[row.columnName];
124
124
  columnData[camelize(row.columnName)] = {
125
125
  dbType: row.udtName,
126
126
  allowNull: row.isNullable === 'YES',
@@ -6,6 +6,7 @@ import Encrypt from '../encrypt/index.js';
6
6
  import DreamAppInitMissingCallToLoadModels from '../errors/dream-app/DreamAppInitMissingCallToLoadModels.js';
7
7
  import DreamAppInitMissingMissingProjectRoot from '../errors/dream-app/DreamAppInitMissingMissingProjectRoot.js';
8
8
  import CalendarDate from '../helpers/CalendarDate.js';
9
+ import autogeneratedFileDisclaimer from '../helpers/cli/autoGeneratedFileDisclaimer.js';
9
10
  import { DateTime, Settings } from '../helpers/DateTime.js';
10
11
  import EnvInternal from '../helpers/EnvInternal.js';
11
12
  import globalClassNameFromFullyQualifiedModelName from '../helpers/globalClassNameFromFullyQualifiedModelName.js';
@@ -92,6 +93,7 @@ export default class DreamApp {
92
93
  inferSerializersFromDreamClassOrViewModelClass,
93
94
  isDreamSerializer,
94
95
  serializerNameFromFullyQualifiedModelName,
96
+ autogeneratedFileDisclaimer,
95
97
  };
96
98
  }
97
99
  /**
@@ -233,6 +235,16 @@ Try setting it to something valid, like:
233
235
  get importExtension() {
234
236
  return this._importExtension;
235
237
  }
238
+ /**
239
+ * if set to true, it will bypass deprecation checks that run
240
+ * during the sync hook. Defaults to false, we only recommend
241
+ * overriding this if you are having issues with the deprecation
242
+ * check.
243
+ */
244
+ _bypassDeprecationChecks = false;
245
+ get bypassDeprecationChecks() {
246
+ return this._bypassDeprecationChecks;
247
+ }
236
248
  loadedModels = false;
237
249
  constructor(opts) {
238
250
  if (opts?.db)
@@ -317,6 +329,9 @@ Try setting it to something valid, like:
317
329
  }
318
330
  set(applyOption, options, secondaryOptions) {
319
331
  switch (applyOption) {
332
+ case 'bypassDeprecationChecks':
333
+ this._bypassDeprecationChecks = options;
334
+ break;
320
335
  case 'db':
321
336
  if (typeof options === 'string') {
322
337
  this._dbCredentials[options] = secondaryOptions;
@@ -0,0 +1,277 @@
1
+ import * as path from 'node:path';
2
+ import ts from 'typescript';
3
+ import DreamApp from '../../dream-app/index.js';
4
+ import EnvInternal from '../EnvInternal.js';
5
+ const f = ts.factory;
6
+ /**
7
+ * @internal
8
+ *
9
+ * This is a base class, which is inherited by the ASTSchemaBuilder,
10
+ * the ASTKyselyCodegenEnhancer, and the ASTGlobalSchemaBuilder,
11
+ * each of which is responsible for building up the output of the various
12
+ * type files consumed by dream internally.
13
+ *
14
+ * This base class is just a container for common methods used by all
15
+ * classes.
16
+ */
17
+ export default class ASTBuilder {
18
+ /**
19
+ * @internal
20
+ *
21
+ * builds a new line, useful for injecting new lines into AST statements
22
+ */
23
+ newLine() {
24
+ return f.createIdentifier('\n');
25
+ }
26
+ /**
27
+ * @internal
28
+ *
29
+ * given an interface declaration, it will extrace the relevant property statement
30
+ * by the given property name.
31
+ */
32
+ getPropertyFromInterface(interfaceNode, propertyName) {
33
+ for (const member of interfaceNode.members) {
34
+ if (ts.isPropertySignature(member)) {
35
+ if (ts.isIdentifier(member.name) && member.name.text === propertyName) {
36
+ return member;
37
+ }
38
+ }
39
+ }
40
+ return null;
41
+ }
42
+ /**
43
+ * @internal
44
+ *
45
+ * returns an array of string type literals which were extracted from
46
+ * either a type or type union, depending on what is provided
47
+ * for the typeAlias. this allows you to safely and easily collect
48
+ * an array of types given an alias
49
+ */
50
+ extractStringLiteralTypeNodesFromTypeOrUnion(typeAlias) {
51
+ const literals = [];
52
+ if (ts.isUnionTypeNode(typeAlias.type)) {
53
+ typeAlias.type.types.forEach(typeNode => {
54
+ if (ts.isLiteralTypeNode(typeNode) && ts.isStringLiteral(typeNode.literal)) {
55
+ literals.push(typeNode);
56
+ }
57
+ });
58
+ }
59
+ else if (ts.isLiteralTypeNode(typeAlias.type) && ts.isStringLiteral(typeAlias.type.literal)) {
60
+ literals.push(typeAlias.type);
61
+ }
62
+ return literals;
63
+ }
64
+ /**
65
+ * @internal
66
+ *
67
+ * returns an array of type literals which were extracted from
68
+ * either a type or type union, depending on what is provided
69
+ * for the typeAlias. this allows you to safely and easily collect
70
+ * an array of types given an alias
71
+ */
72
+ extractTypeNodesFromTypeOrUnion(typeAlias) {
73
+ const literals = [];
74
+ if (typeAlias.type && ts.isUnionTypeNode(typeAlias.type)) {
75
+ typeAlias.type.types.forEach(typeNode => {
76
+ literals.push(typeNode);
77
+ });
78
+ }
79
+ else if (typeAlias.type) {
80
+ literals.push(typeAlias.type);
81
+ }
82
+ return literals;
83
+ }
84
+ /**
85
+ * @internal
86
+ *
87
+ * returns the provided node iff
88
+ * a.) the node is an exported type alias
89
+ * b.) the exported name matches the provided name (or else there was no name provided)
90
+ *
91
+ * otherwise, returns null
92
+ */
93
+ exportedTypeAliasOrNull(node, exportName) {
94
+ if (ts.isTypeAliasDeclaration(node) &&
95
+ node?.modifiers?.some(m => m.kind === ts.SyntaxKind.ExportKeyword) &&
96
+ (!exportName ? true : node.name.text === exportName))
97
+ return node;
98
+ return null;
99
+ }
100
+ /**
101
+ * @internal
102
+ *
103
+ * returns the provided node iff
104
+ * a.) the node is an exported interface
105
+ * b.) the exported name matches the provided name (or else there was no name provided)
106
+ *
107
+ * otherwise, returns null
108
+ */
109
+ exportedInterfaceOrNull(node, exportName) {
110
+ if (ts.isInterfaceDeclaration(node) &&
111
+ node?.modifiers?.some(m => m.kind === ts.SyntaxKind.ExportKeyword) &&
112
+ (!exportName ? true : node.name.text === exportName))
113
+ return node;
114
+ return null;
115
+ }
116
+ /**
117
+ * @internal
118
+ *
119
+ * extracts the exportName from the provided dbSourceFile
120
+ */
121
+ findDbExport(dbSourceFile, exportName) {
122
+ let foundNode;
123
+ ts.forEachChild(dbSourceFile, node => {
124
+ const hasModifiers = ts.isFunctionDeclaration(node) ||
125
+ ts.isClassDeclaration(node) ||
126
+ ts.isInterfaceDeclaration(node) ||
127
+ ts.isVariableStatement(node) ||
128
+ ts.isTypeAliasDeclaration(node);
129
+ if (hasModifiers) {
130
+ const isExported = node.modifiers?.some(modifier => modifier.kind === ts.SyntaxKind.ExportKeyword);
131
+ if (isExported && ts.isVariableStatement(node)) {
132
+ const declarations = node.declarationList.declarations;
133
+ const name = declarations?.[0]?.name;
134
+ if (declarations.length > 0 && ts.isIdentifier(name) && name?.text === exportName) {
135
+ foundNode = node;
136
+ return true; // Stop traversal
137
+ }
138
+ }
139
+ const declarationWithName = node;
140
+ if (isExported &&
141
+ declarationWithName.name &&
142
+ ts.isIdentifier(declarationWithName.name) &&
143
+ declarationWithName.name.text === exportName) {
144
+ foundNode = node;
145
+ return true; // Stop traversal
146
+ }
147
+ }
148
+ });
149
+ return foundNode;
150
+ }
151
+ /**
152
+ * @internal
153
+ *
154
+ * returns the path to the dream.globals.ts file
155
+ */
156
+ globalSchemaPath() {
157
+ const dreamApp = DreamApp.getOrFail();
158
+ return path.join(dreamApp.projectRoot, dreamApp.paths.types, 'dream.globals.ts');
159
+ }
160
+ /**
161
+ * @internal
162
+ *
163
+ * safely runs prettier against the provided output. If prettier
164
+ * is not installed, then the original output is returned
165
+ */
166
+ async prettier(output) {
167
+ try {
168
+ // dynamically, safely bring in prettier.
169
+ // ini the event that it fails, we will return the
170
+ // original output, unformatted, since prettier
171
+ // is technically not a real dependency of dream,
172
+ // though psychic and dream apps are provisioned
173
+ // with prettier by default, so this should usually work
174
+ const prettier = (await import('prettier')).default;
175
+ const results = await prettier.format(output, {
176
+ parser: 'typescript',
177
+ semi: false,
178
+ singleQuote: true,
179
+ tabWidth: 2,
180
+ lineWidth: 80,
181
+ });
182
+ return typeof results === 'string' ? results : output;
183
+ }
184
+ catch {
185
+ // intentional noop, we don't want to raise if prettier
186
+ // fails, since it is possible for the end user to not
187
+ // want to use prettier, and it is not a required peer
188
+ // dependency of dream
189
+ return output;
190
+ }
191
+ }
192
+ /**
193
+ * @internal
194
+ *
195
+ * given a type node, it will send back the first found generic
196
+ * provided to that type.
197
+ */
198
+ getFirstGenericType(node) {
199
+ if (ts.isTypeReferenceNode(node)) {
200
+ if (node.typeArguments && node.typeArguments.length > 0) {
201
+ return node.typeArguments[0];
202
+ }
203
+ }
204
+ else if (ts.isCallExpression(node)) {
205
+ if (node.typeArguments && node.typeArguments.length > 0) {
206
+ return node.typeArguments[0];
207
+ }
208
+ }
209
+ return null;
210
+ }
211
+ /**
212
+ * @internal
213
+ *
214
+ * returns the DateTime and CalendarDate imports. This is fairly
215
+ * tricky, since it considers whether or not we are in the dream
216
+ * internals (i.e. when testing dream). If we are, it will return
217
+ * valid internal import paths to those files. Otherwise, it will
218
+ * import them both from @rvoh/dream.
219
+ */
220
+ dateAndDateTimeImports() {
221
+ if (EnvInternal.boolean('DREAM_CORE_DEVELOPMENT')) {
222
+ const calendarImport = ts.factory.createImportClause(true, f.createIdentifier('CalendarDate'), undefined);
223
+ const calendarImportDeclaration = ts.factory.createImportDeclaration(undefined, calendarImport, ts.factory.createStringLiteral('../../src/helpers/CalendarDate.js'));
224
+ const dateTimeNamedImports = ts.factory.createNamedImports([
225
+ f.createImportSpecifier(true, undefined, ts.factory.createIdentifier('DateTime')),
226
+ ]);
227
+ const dateTimeImportClause = ts.factory.createImportClause(false, // isTypeOnly: false for the clause itself if not all imports are type only
228
+ undefined, // name: undefined for default import
229
+ dateTimeNamedImports // namedBindings
230
+ );
231
+ const dateTimeImportDeclaration = ts.factory.createImportDeclaration(undefined, dateTimeImportClause, ts.factory.createStringLiteral('../../src/helpers/DateTime.js'));
232
+ return [calendarImportDeclaration, dateTimeImportDeclaration];
233
+ }
234
+ else {
235
+ const namedImports = ts.factory.createNamedImports(['CalendarDate', 'DateTime'].map(importName => f.createImportSpecifier(true, undefined, ts.factory.createIdentifier(importName))));
236
+ const importClause = ts.factory.createImportClause(false, // isTypeOnly: false for the clause itself if not all imports are type only
237
+ undefined, // name: undefined for default import
238
+ namedImports // namedBindings
239
+ );
240
+ const importDeclaration = ts.factory.createImportDeclaration(undefined, // modifiers: e.g., 'export' or 'declare'
241
+ importClause, ts.factory.createStringLiteral('@rvoh/dream'));
242
+ return [importDeclaration];
243
+ }
244
+ }
245
+ /**
246
+ * @internal
247
+ *
248
+ * for a given table name (i.e. balloon_lines), it will return the exported
249
+ * `BalloonLines` interface within the dbSourceFile
250
+ */
251
+ getTableInterfaceDeclaration(dbSourceFile, tableName) {
252
+ const DB = this.findDbExport(dbSourceFile, 'DB');
253
+ let targetProperty = null;
254
+ for (const member of DB.members) {
255
+ if (ts.isPropertySignature(member) && member.name.getText(dbSourceFile) === tableName) {
256
+ targetProperty = member;
257
+ break;
258
+ }
259
+ }
260
+ const tableInterfaceName = (targetProperty?.type)
261
+ .typeName?.escapedText;
262
+ if (!tableInterfaceName)
263
+ throw new Error(`failed to find table interface for table: ${tableName}`);
264
+ const tableInterface = this.findDbExport(dbSourceFile, tableInterfaceName);
265
+ return tableInterface;
266
+ }
267
+ /**
268
+ * @internal
269
+ *
270
+ * returns an array of global names for all serializers in the app
271
+ */
272
+ globalSerializerNames() {
273
+ const dreamApp = DreamApp.getOrFail();
274
+ const serializers = dreamApp.serializers;
275
+ return Object.keys(serializers);
276
+ }
277
+ }