@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.
- package/dist/cjs/src/bin/index.js +2 -0
- package/dist/cjs/src/db/helpers/dreamSchemaTypesFilenameForConnection.js +3 -0
- package/dist/cjs/src/db/helpers/syncDbTypesFiles.js +2 -89
- package/dist/cjs/src/dream/QueryDriver/Base.js +2 -2
- package/dist/cjs/src/dream/QueryDriver/Kysely.js +9 -19
- package/dist/cjs/src/dream/QueryDriver/Postgres.js +2 -2
- package/dist/cjs/src/dream-app/index.js +15 -0
- package/dist/cjs/src/helpers/cli/ASTBuilder.js +277 -0
- package/dist/cjs/src/helpers/cli/ASTConnectionBuilder.js +284 -0
- package/dist/cjs/src/helpers/cli/ASTGlobalSchemaBuilder.js +57 -0
- package/dist/cjs/src/helpers/cli/ASTKyselyCodegenEnhancer.js +236 -0
- package/dist/cjs/src/helpers/cli/ASTSchemaBuilder.js +304 -0
- package/dist/cjs/src/helpers/cli/DBClassDeprecation.js +60 -0
- package/dist/esm/src/bin/index.js +2 -0
- package/dist/esm/src/db/helpers/dreamSchemaTypesFilenameForConnection.js +3 -0
- package/dist/esm/src/db/helpers/syncDbTypesFiles.js +2 -89
- package/dist/esm/src/dream/QueryDriver/Base.js +2 -2
- package/dist/esm/src/dream/QueryDriver/Kysely.js +9 -19
- package/dist/esm/src/dream/QueryDriver/Postgres.js +2 -2
- package/dist/esm/src/dream-app/index.js +15 -0
- package/dist/esm/src/helpers/cli/ASTBuilder.js +277 -0
- package/dist/esm/src/helpers/cli/ASTConnectionBuilder.js +284 -0
- package/dist/esm/src/helpers/cli/ASTGlobalSchemaBuilder.js +57 -0
- package/dist/esm/src/helpers/cli/ASTKyselyCodegenEnhancer.js +236 -0
- package/dist/esm/src/helpers/cli/ASTSchemaBuilder.js +304 -0
- package/dist/esm/src/helpers/cli/DBClassDeprecation.js +60 -0
- package/dist/types/src/db/helpers/dreamSchemaTypesFilenameForConnection.d.ts +1 -0
- package/dist/types/src/dream/QueryDriver/Base.d.ts +3 -3
- package/dist/types/src/dream/QueryDriver/Kysely.d.ts +2 -14
- package/dist/types/src/dream/QueryDriver/Postgres.d.ts +2 -2
- package/dist/types/src/dream-app/index.d.ts +12 -2
- package/dist/types/src/helpers/cli/ASTBuilder.d.ts +159 -0
- package/dist/types/src/helpers/cli/ASTConnectionBuilder.d.ts +104 -0
- package/dist/types/src/helpers/cli/ASTGlobalSchemaBuilder.d.ts +28 -0
- package/dist/types/src/helpers/cli/ASTKyselyCodegenEnhancer.d.ts +68 -0
- package/dist/types/src/helpers/cli/ASTSchemaBuilder.d.ts +80 -0
- package/dist/types/src/helpers/cli/DBClassDeprecation.d.ts +14 -0
- package/docs/assets/search.js +1 -1
- package/docs/classes/db.DreamMigrationHelpers.html +9 -9
- package/docs/classes/db.KyselyQueryDriver.html +31 -44
- package/docs/classes/db.PostgresQueryDriver.html +32 -45
- package/docs/classes/db.QueryDriverBase.html +30 -30
- package/docs/classes/errors.CheckConstraintViolation.html +3 -3
- package/docs/classes/errors.ColumnOverflow.html +3 -3
- package/docs/classes/errors.CreateOrFindByFailedToCreateAndFind.html +3 -3
- package/docs/classes/errors.DataIncompatibleWithDatabaseField.html +3 -3
- package/docs/classes/errors.DataTypeColumnTypeMismatch.html +3 -3
- package/docs/classes/errors.GlobalNameNotSet.html +3 -3
- package/docs/classes/errors.InvalidCalendarDate.html +2 -2
- package/docs/classes/errors.MissingSerializersDefinition.html +3 -3
- package/docs/classes/errors.NonLoadedAssociation.html +3 -3
- package/docs/classes/errors.NotNullViolation.html +3 -3
- package/docs/classes/errors.RecordNotFound.html +3 -3
- package/docs/classes/errors.ValidationError.html +3 -3
- package/docs/classes/index.CalendarDate.html +2 -2
- package/docs/classes/index.Decorators.html +19 -19
- package/docs/classes/index.Dream.html +113 -113
- package/docs/classes/index.DreamApp.html +7 -6
- package/docs/classes/index.DreamTransaction.html +2 -2
- package/docs/classes/index.Env.html +2 -2
- package/docs/classes/index.Query.html +53 -53
- package/docs/classes/system.CliFileWriter.html +2 -2
- package/docs/classes/system.DreamBin.html +2 -2
- package/docs/classes/system.DreamCLI.html +5 -5
- package/docs/classes/system.DreamImporter.html +2 -2
- package/docs/classes/system.DreamLogos.html +2 -2
- package/docs/classes/system.DreamSerializerBuilder.html +8 -8
- package/docs/classes/system.ObjectSerializerBuilder.html +8 -8
- package/docs/classes/utils.Encrypt.html +2 -2
- package/docs/classes/utils.Range.html +2 -2
- package/docs/functions/db.closeAllDbConnections.html +1 -1
- package/docs/functions/db.dreamDbConnections.html +1 -1
- package/docs/functions/db.untypedDb.html +1 -1
- package/docs/functions/db.validateColumn.html +1 -1
- package/docs/functions/db.validateTable.html +1 -1
- package/docs/functions/errors.pgErrorType.html +1 -1
- package/docs/functions/index.DreamSerializer.html +1 -1
- package/docs/functions/index.ObjectSerializer.html +1 -1
- package/docs/functions/index.ReplicaSafe.html +1 -1
- package/docs/functions/index.STI.html +1 -1
- package/docs/functions/index.SoftDelete.html +1 -1
- package/docs/functions/utils.camelize.html +1 -1
- package/docs/functions/utils.capitalize.html +1 -1
- package/docs/functions/utils.cloneDeepSafe.html +1 -1
- package/docs/functions/utils.compact.html +1 -1
- package/docs/functions/utils.groupBy.html +1 -1
- package/docs/functions/utils.hyphenize.html +1 -1
- package/docs/functions/utils.intersection.html +1 -1
- package/docs/functions/utils.isEmpty.html +1 -1
- package/docs/functions/utils.normalizeUnicode.html +1 -1
- package/docs/functions/utils.pascalize.html +1 -1
- package/docs/functions/utils.percent.html +1 -1
- package/docs/functions/utils.range-1.html +1 -1
- package/docs/functions/utils.round.html +1 -1
- package/docs/functions/utils.sanitizeString.html +1 -1
- package/docs/functions/utils.snakeify.html +1 -1
- package/docs/functions/utils.sort.html +1 -1
- package/docs/functions/utils.sortBy.html +1 -1
- package/docs/functions/utils.sortObjectByKey.html +1 -1
- package/docs/functions/utils.sortObjectByValue.html +1 -1
- package/docs/functions/utils.uncapitalize.html +1 -1
- package/docs/functions/utils.uniq.html +1 -1
- package/docs/interfaces/openapi.OpenapiDescription.html +2 -2
- package/docs/interfaces/openapi.OpenapiSchemaProperties.html +1 -1
- package/docs/interfaces/openapi.OpenapiSchemaPropertiesShorthand.html +1 -1
- package/docs/interfaces/openapi.OpenapiTypeFieldObject.html +1 -1
- package/docs/interfaces/types.BelongsToStatement.html +2 -2
- package/docs/interfaces/types.DecoratorContext.html +2 -2
- package/docs/interfaces/types.DreamAppInitOptions.html +2 -2
- package/docs/interfaces/types.DreamAppOpts.html +2 -2
- package/docs/interfaces/types.EncryptOptions.html +2 -2
- package/docs/interfaces/types.InternalAnyTypedSerializerRendersMany.html +2 -2
- package/docs/interfaces/types.InternalAnyTypedSerializerRendersOne.html +2 -2
- package/docs/interfaces/types.SerializerRendererOpts.html +2 -2
- package/docs/modules/db.html +1 -1
- package/docs/modules/errors.html +1 -1
- package/docs/modules/index.html +1 -1
- package/docs/modules/openapi.html +1 -1
- package/docs/modules/system.html +1 -1
- package/docs/modules/types.html +1 -1
- package/docs/modules/utils.html +1 -1
- package/docs/types/index.DateTime.html +1 -1
- package/docs/types/openapi.CommonOpenapiSchemaObjectFields.html +1 -1
- package/docs/types/openapi.OpenapiAllTypes.html +1 -1
- package/docs/types/openapi.OpenapiFormats.html +1 -1
- package/docs/types/openapi.OpenapiNumberFormats.html +1 -1
- package/docs/types/openapi.OpenapiPrimitiveBaseTypes.html +1 -1
- package/docs/types/openapi.OpenapiPrimitiveTypes.html +1 -1
- package/docs/types/openapi.OpenapiSchemaArray.html +1 -1
- package/docs/types/openapi.OpenapiSchemaArrayShorthand.html +1 -1
- package/docs/types/openapi.OpenapiSchemaBase.html +1 -1
- package/docs/types/openapi.OpenapiSchemaBody.html +1 -1
- package/docs/types/openapi.OpenapiSchemaBodyShorthand.html +1 -1
- package/docs/types/openapi.OpenapiSchemaCommonFields.html +1 -1
- package/docs/types/openapi.OpenapiSchemaExpressionAllOf.html +1 -1
- package/docs/types/openapi.OpenapiSchemaExpressionAnyOf.html +1 -1
- package/docs/types/openapi.OpenapiSchemaExpressionOneOf.html +1 -1
- package/docs/types/openapi.OpenapiSchemaExpressionRef.html +1 -1
- package/docs/types/openapi.OpenapiSchemaExpressionRefSchemaShorthand.html +1 -1
- package/docs/types/openapi.OpenapiSchemaInteger.html +1 -1
- package/docs/types/openapi.OpenapiSchemaNull.html +1 -1
- package/docs/types/openapi.OpenapiSchemaNumber.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObject.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectAllOf.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectAllOfShorthand.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectAnyOf.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectAnyOfShorthand.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectBase.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectBaseShorthand.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectOneOf.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectOneOfShorthand.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectShorthand.html +1 -1
- package/docs/types/openapi.OpenapiSchemaPrimitiveGeneric.html +1 -1
- package/docs/types/openapi.OpenapiSchemaShorthandExpressionAllOf.html +1 -1
- package/docs/types/openapi.OpenapiSchemaShorthandExpressionAnyOf.html +1 -1
- package/docs/types/openapi.OpenapiSchemaShorthandExpressionOneOf.html +1 -1
- package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializableRef.html +1 -1
- package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializerRef.html +1 -1
- package/docs/types/openapi.OpenapiSchemaShorthandPrimitiveGeneric.html +1 -1
- package/docs/types/openapi.OpenapiSchemaString.html +1 -1
- package/docs/types/openapi.OpenapiShorthandAllTypes.html +1 -1
- package/docs/types/openapi.OpenapiShorthandPrimitiveBaseTypes.html +1 -1
- package/docs/types/openapi.OpenapiShorthandPrimitiveTypes.html +1 -1
- package/docs/types/openapi.OpenapiTypeField.html +1 -1
- package/docs/types/system.DreamAppAllowedPackageManagersEnum.html +1 -1
- package/docs/types/types.Camelized.html +1 -1
- package/docs/types/types.DbConnectionType.html +1 -1
- package/docs/types/types.DbTypes.html +1 -1
- package/docs/types/types.DreamAssociationMetadata.html +1 -1
- package/docs/types/types.DreamAttributes.html +1 -1
- package/docs/types/types.DreamClassAssociationAndStatement.html +1 -1
- package/docs/types/types.DreamClassColumn.html +1 -1
- package/docs/types/types.DreamColumn.html +1 -1
- package/docs/types/types.DreamColumnNames.html +1 -1
- package/docs/types/types.DreamLogLevel.html +1 -1
- package/docs/types/types.DreamLogger.html +1 -1
- package/docs/types/types.DreamModelSerializerType.html +1 -1
- package/docs/types/types.DreamOrViewModelClassSerializerKey.html +1 -1
- package/docs/types/types.DreamOrViewModelSerializerKey.html +1 -1
- package/docs/types/types.DreamParamSafeAttributes.html +1 -1
- package/docs/types/types.DreamParamSafeColumnNames.html +1 -1
- package/docs/types/types.DreamSerializable.html +1 -1
- package/docs/types/types.DreamSerializableArray.html +1 -1
- package/docs/types/types.DreamSerializerKey.html +1 -1
- package/docs/types/types.DreamSerializers.html +1 -1
- package/docs/types/types.DreamVirtualColumns.html +1 -1
- package/docs/types/types.EncryptAlgorithm.html +1 -1
- package/docs/types/types.HasManyStatement.html +1 -1
- package/docs/types/types.HasOneStatement.html +1 -1
- package/docs/types/types.Hyphenized.html +1 -1
- package/docs/types/types.Pascalized.html +1 -1
- package/docs/types/types.RoundingPrecision.html +1 -1
- package/docs/types/types.SerializerCasing.html +1 -1
- package/docs/types/types.SimpleObjectSerializerType.html +1 -1
- package/docs/types/types.Snakeified.html +1 -1
- package/docs/types/types.StrictInterface.html +1 -1
- package/docs/types/types.UpdateableAssociationProperties.html +1 -1
- package/docs/types/types.UpdateableProperties.html +1 -1
- package/docs/types/types.ValidationType.html +1 -1
- package/docs/types/types.ViewModel.html +1 -1
- package/docs/types/types.ViewModelClass.html +1 -1
- package/docs/types/types.WhereStatementForDream.html +1 -1
- package/docs/types/types.WhereStatementForDreamClass.html +1 -1
- package/docs/variables/index.DateTime-1.html +1 -1
- package/docs/variables/index.DreamConst.html +1 -1
- package/docs/variables/index.ops.html +1 -1
- package/docs/variables/openapi.openapiPrimitiveTypes-1.html +1 -1
- package/docs/variables/openapi.openapiShorthandPrimitiveTypes-1.html +1 -1
- package/docs/variables/system.DreamAppAllowedPackageManagersEnumValues.html +1 -1
- package/docs/variables/types.TRIGRAM_OPERATORS.html +1 -1
- package/docs/variables/types.primaryKeyTypes.html +1 -1
- package/package.json +1 -1
- package/dist/cjs/src/helpers/cli/SchemaBuilder.js +0 -408
- package/dist/esm/src/helpers/cli/SchemaBuilder.js +0 -408
- package/dist/types/src/helpers/cli/SchemaBuilder.d.ts +0 -44
|
@@ -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
|
+
}
|
|
@@ -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();
|
|
@@ -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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
|
171
|
+
const newSchemaBuilder = new ASTSchemaBuilder(connectionName);
|
|
182
172
|
await DreamCLI.logger.logProgress(`building dream schema for connection ${connectionName}...`, async () => {
|
|
183
|
-
await
|
|
173
|
+
await newSchemaBuilder.build();
|
|
184
174
|
});
|
|
185
|
-
if (
|
|
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
|
|
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,
|
|
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 =
|
|
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;
|