@rvoh/dream 2.36.0 → 2.37.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/Dream.js +3 -1
- package/dist/cjs/src/db/dataTypes.js +0 -8
- package/dist/cjs/src/decorators/field/Encrypted.js +8 -3
- package/dist/cjs/src/dream/QueryDriver/Base.js +17 -24
- package/dist/cjs/src/dream/QueryDriver/Kysely.js +22 -23
- package/dist/cjs/src/dream/QueryDriver/Postgres.js +113 -31
- package/dist/cjs/src/encrypt/InternalEncrypt.js +28 -0
- package/dist/cjs/src/helpers/cli/ASTBuilder.js +11 -202
- package/dist/cjs/src/helpers/cli/ASTConnectionBuilder.js +97 -75
- package/dist/cjs/src/helpers/cli/ASTDbTypesBuilder.js +132 -0
- package/dist/cjs/src/helpers/cli/ASTSchemaBuilder.js +37 -81
- package/dist/cjs/src/helpers/cli/dbTypesNaming.js +90 -0
- package/dist/cjs/src/helpers/cli/tableMatchesPattern.js +21 -0
- package/dist/esm/src/Dream.js +3 -1
- package/dist/esm/src/db/dataTypes.js +0 -8
- package/dist/esm/src/decorators/field/Encrypted.js +8 -3
- package/dist/esm/src/dream/QueryDriver/Base.js +17 -24
- package/dist/esm/src/dream/QueryDriver/Kysely.js +22 -23
- package/dist/esm/src/dream/QueryDriver/Postgres.js +113 -31
- package/dist/esm/src/encrypt/InternalEncrypt.js +28 -0
- package/dist/esm/src/helpers/cli/ASTBuilder.js +11 -202
- package/dist/esm/src/helpers/cli/ASTConnectionBuilder.js +97 -75
- package/dist/esm/src/helpers/cli/ASTDbTypesBuilder.js +132 -0
- package/dist/esm/src/helpers/cli/ASTSchemaBuilder.js +37 -81
- package/dist/esm/src/helpers/cli/dbTypesNaming.js +90 -0
- package/dist/esm/src/helpers/cli/tableMatchesPattern.js +21 -0
- package/dist/types/src/Dream.d.ts +3 -1
- package/dist/types/src/db/dataTypes.d.ts +0 -2
- package/dist/types/src/dream/QueryDriver/Base.d.ts +16 -18
- package/dist/types/src/dream/QueryDriver/Kysely.d.ts +0 -9
- package/dist/types/src/dream/QueryDriver/Postgres.d.ts +9 -9
- package/dist/types/src/dream-app/index.d.ts +12 -12
- package/dist/types/src/encrypt/InternalEncrypt.d.ts +9 -0
- package/dist/types/src/helpers/cli/ASTBuilder.d.ts +11 -101
- package/dist/types/src/helpers/cli/ASTConnectionBuilder.d.ts +40 -37
- package/dist/types/src/helpers/cli/ASTDbTypesBuilder.d.ts +26 -0
- package/dist/types/src/helpers/cli/ASTSchemaBuilder.d.ts +5 -15
- package/dist/types/src/helpers/cli/dbTypesNaming.d.ts +37 -0
- package/dist/types/src/helpers/cli/tableMatchesPattern.d.ts +15 -0
- package/dist/types/src/package-exports/types.d.ts +1 -1
- package/dist/types/src/types/db.d.ts +71 -0
- package/dist/types/src/types/types/db.ts +91 -0
- package/docs/assets/hierarchy.js +1 -1
- package/docs/assets/navigation.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/classes/db.DreamMigrationHelpers.html +11 -11
- package/docs/classes/db.KyselyQueryDriver.html +55 -54
- package/docs/classes/db.PostgresQueryDriver.html +56 -56
- package/docs/classes/db.QueryDriverBase.html +60 -59
- package/docs/classes/errors.CannotSaveMissingDream.html +2 -2
- 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.DecryptionError.html +2 -2
- package/docs/classes/errors.DecryptionParseError.html +2 -2
- package/docs/classes/errors.DecryptionRotationError.html +3 -3
- package/docs/classes/errors.GlobalNameNotSet.html +3 -3
- package/docs/classes/errors.InvalidCalendarDate.html +2 -2
- package/docs/classes/errors.InvalidClockTime.html +2 -2
- package/docs/classes/errors.InvalidClockTimeTz.html +2 -2
- package/docs/classes/errors.InvalidDateTime.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.SortableScopeDidNotStabilize.html +3 -3
- package/docs/classes/errors.SortableScopeLockWaitTimedOut.html +3 -3
- package/docs/classes/errors.ValidationError.html +3 -3
- package/docs/classes/index.CalendarDate.html +33 -33
- package/docs/classes/index.ClockTime.html +32 -32
- package/docs/classes/index.ClockTimeTz.html +35 -35
- package/docs/classes/index.DateTime.html +86 -86
- package/docs/classes/index.Decorators.html +19 -19
- package/docs/classes/index.Dream.html +125 -125
- package/docs/classes/index.DreamApp.html +11 -11
- package/docs/classes/index.DreamTransaction.html +3 -3
- package/docs/classes/index.Env.html +5 -5
- package/docs/classes/index.Query.html +65 -65
- package/docs/classes/system.CliFileWriter.html +4 -4
- package/docs/classes/system.DreamBin.html +3 -3
- package/docs/classes/system.DreamCLI.html +7 -7
- package/docs/classes/system.DreamImporter.html +2 -2
- package/docs/classes/system.DreamLogos.html +2 -2
- package/docs/classes/system.DreamSerializerBuilder.html +11 -11
- package/docs/classes/system.ObjectSerializerBuilder.html +8 -8
- package/docs/classes/system.PathHelpers.html +3 -3
- package/docs/classes/utils.Encrypt.html +4 -4
- 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.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/hierarchy.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.DecryptCallbacks.html +2 -2
- package/docs/interfaces/types.DreamAppInitOptions.html +2 -2
- package/docs/interfaces/types.DreamAppOpts.html +2 -2
- package/docs/interfaces/types.DreamDbConfig.html +6 -6
- package/docs/interfaces/types.DurationObject.html +2 -2
- package/docs/interfaces/types.EncryptOptions.html +2 -2
- package/docs/interfaces/types.EncryptionLegacyKeyUsedEvent.html +4 -4
- package/docs/interfaces/types.InternalAnyTypedSerializerRendersMany.html +2 -2
- package/docs/interfaces/types.InternalAnyTypedSerializerRendersOne.html +2 -2
- package/docs/interfaces/types.IntrospectedColumn.html +17 -0
- package/docs/interfaces/types.IntrospectedDatabase.html +7 -0
- package/docs/interfaces/types.IntrospectedEnum.html +5 -0
- package/docs/interfaces/types.IntrospectedTable.html +11 -0
- package/docs/interfaces/types.SerializerRendererOpts.html +2 -2
- package/docs/modules/types.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.OpenapiSchemaCombinatorFields.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 +2 -2
- package/docs/types/openapi.OpenapiSchemaExpressionRefSchemaShorthand.html +2 -2
- package/docs/types/openapi.OpenapiSchemaInteger.html +1 -1
- package/docs/types/openapi.OpenapiSchemaNull.html +2 -2
- 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.OpenapiSchemaObjectBase.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectBaseShorthand.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 +2 -2
- package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializerRef.html +2 -2
- 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.CalendarDateDurationUnit.html +1 -1
- package/docs/types/types.CalendarDateObject.html +1 -1
- package/docs/types/types.Camelized.html +1 -1
- package/docs/types/types.ClockTimeObject.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 +2 -2
- 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.DurationUnit.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.IntrospectedValueType.html +5 -0
- package/docs/types/types.Pascalized.html +1 -1
- package/docs/types/types.PrimaryKeyType.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 +2 -2
- package/docs/types/types.ViewModelClass.html +1 -1
- package/docs/types/types.WeekdayName.html +1 -1
- package/docs/types/types.WhereStatementForDream.html +1 -1
- package/docs/types/types.WhereStatementForDreamClass.html +1 -1
- package/docs/variables/index.DreamConst.html +1 -1
- package/docs/variables/index.ops.html +1 -1
- package/docs/variables/openapi.openapiPrimitiveTypes.html +1 -1
- package/docs/variables/openapi.openapiShorthandPrimitiveTypes.html +1 -1
- package/docs/variables/system.DreamAppAllowedPackageManagersEnumValues.html +1 -1
- package/docs/variables/system.primaryKeyTypes.html +1 -1
- package/package.json +6 -3
- package/dist/cjs/src/db/helpers/syncDbTypesFiles.js +0 -41
- package/dist/cjs/src/helpers/cli/ASTKyselyCodegenEnhancer.js +0 -380
- package/dist/esm/src/db/helpers/syncDbTypesFiles.js +0 -41
- package/dist/esm/src/helpers/cli/ASTKyselyCodegenEnhancer.js +0 -380
- package/dist/types/src/db/helpers/syncDbTypesFiles.d.ts +0 -1
- package/dist/types/src/helpers/cli/ASTKyselyCodegenEnhancer.d.ts +0 -94
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
import * as fs from 'node:fs/promises';
|
|
2
1
|
import * as path from 'node:path';
|
|
3
|
-
import ts from 'typescript';
|
|
4
2
|
import dbTypesFilenameForConnection from '../../db/helpers/dbTypesFilenameForConnection.js';
|
|
5
3
|
import dreamSchemaTypesFilenameForConnection from '../../db/helpers/dreamSchemaTypesFilenameForConnection.js';
|
|
6
4
|
import DreamApp from '../../dream-app/index.js';
|
|
7
5
|
import Query from '../../dream/Query.js';
|
|
8
6
|
import { ExplicitForeignKeyRequired, InvalidComputedForeignKey, } from '../../errors/associations/InvalidComputedForeignKey.js';
|
|
9
7
|
import FailedToIdentifyAssociation from '../../errors/schema-builder/FailedToIdentifyAssociation.js';
|
|
8
|
+
import camelize from '../camelize.js';
|
|
10
9
|
import intersection from '../intersection.js';
|
|
11
10
|
import sortBy from '../sortBy.js';
|
|
12
11
|
import uniq from '../uniq.js';
|
|
13
12
|
import ASTBuilder from './ASTBuilder.js';
|
|
13
|
+
import { dbTypesName, dbTypesReservedNames } from './dbTypesNaming.js';
|
|
14
14
|
import resolveIgnoredColumns from './resolveIgnoredColumns.js';
|
|
15
|
+
import tableMatchesPattern from './tableMatchesPattern.js';
|
|
15
16
|
/**
|
|
16
17
|
* @internal
|
|
17
18
|
*
|
|
18
19
|
* This is a base class, which is inherited by the ASTSchemaBuilder and
|
|
19
|
-
* the
|
|
20
|
-
*
|
|
20
|
+
* the ASTDbTypesBuilder, each of which builds one of the type files a
|
|
21
|
+
* connection's sync writes, from the same introspection of the connection.
|
|
21
22
|
*
|
|
22
23
|
* This base class is just a container for common methods used by both
|
|
23
24
|
* classes. It requires a connectionName to be provided, unlike the underlying
|
|
@@ -27,9 +28,71 @@ import resolveIgnoredColumns from './resolveIgnoredColumns.js';
|
|
|
27
28
|
export default class ASTConnectionBuilder extends ASTBuilder {
|
|
28
29
|
connectionName;
|
|
29
30
|
hasForeignKeyError = false;
|
|
30
|
-
|
|
31
|
+
introspection;
|
|
32
|
+
introspectionFrom;
|
|
33
|
+
/**
|
|
34
|
+
* @param connectionName - the connection whose type file the builder writes
|
|
35
|
+
* @param opts.introspectionFrom - another builder of the same connection,
|
|
36
|
+
* whose reading of it this builder takes instead of reading the connection
|
|
37
|
+
* again, so that a sync reads each connection once for both type files
|
|
38
|
+
*/
|
|
39
|
+
constructor(connectionName, opts = {}) {
|
|
31
40
|
super();
|
|
32
41
|
this.connectionName = connectionName;
|
|
42
|
+
this.introspectionFrom = opts.introspectionFrom;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* @internal
|
|
46
|
+
*
|
|
47
|
+
* the connection's tables, sorted by their key in the DB interface, and its
|
|
48
|
+
* enums, read through the query driver once, by this builder or by the one
|
|
49
|
+
* it takes its introspection from. The tables that `tableIncludePattern`
|
|
50
|
+
* leaves out, or `tableExcludePattern` names, are left out.
|
|
51
|
+
*/
|
|
52
|
+
async introspectedDatabase() {
|
|
53
|
+
this.introspection ||=
|
|
54
|
+
this.introspectionFrom?.introspectedDatabase() ??
|
|
55
|
+
(async () => {
|
|
56
|
+
const dbDriverClass = Query.dbDriverClass(this.connectionName);
|
|
57
|
+
const database = await dbDriverClass.introspectDatabase(this.connectionName);
|
|
58
|
+
const credentials = DreamApp.getOrFail().dbCredentialsFor(this.connectionName);
|
|
59
|
+
const includePattern = credentials?.tableIncludePattern;
|
|
60
|
+
const excludePattern = credentials?.tableExcludePattern;
|
|
61
|
+
return {
|
|
62
|
+
...database,
|
|
63
|
+
tables: database.tables
|
|
64
|
+
.filter(table => (!includePattern || tableMatchesPattern(table, includePattern)) &&
|
|
65
|
+
!(excludePattern && tableMatchesPattern(table, excludePattern)))
|
|
66
|
+
.sort((a, b) => this.tableKey(a).localeCompare(this.tableKey(b))),
|
|
67
|
+
};
|
|
68
|
+
})();
|
|
69
|
+
return await this.introspection;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* @internal
|
|
73
|
+
*
|
|
74
|
+
* the table's key in the DB interface and in Dream's schema: its name, or
|
|
75
|
+
* `<schema>.<name>` outside the connection's default schema
|
|
76
|
+
*/
|
|
77
|
+
tableKey(table) {
|
|
78
|
+
return table.inDefaultSchema ? table.name : `${table.schema}.${table.name}`;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* @internal
|
|
82
|
+
*
|
|
83
|
+
* the TypeScript name of each enum the connection's tables use, keyed by
|
|
84
|
+
* the enum's database name (see dbTypesName), with a number added when it
|
|
85
|
+
* would repeat an earlier enum's name or a name types/db.ts reserves
|
|
86
|
+
*/
|
|
87
|
+
async enumTypeNames() {
|
|
88
|
+
const database = await this.introspectedDatabase();
|
|
89
|
+
const usedEnumNames = new Set(database.tables.flatMap(table => table.columns.map(column => column.enumName).filter(name => !!name)));
|
|
90
|
+
const takenNames = new Set(dbTypesReservedNames(database.tables));
|
|
91
|
+
const typeNames = new Map();
|
|
92
|
+
for (const enumName of [...usedEnumNames].sort()) {
|
|
93
|
+
typeNames.set(enumName, dbTypesName(enumName, takenNames));
|
|
94
|
+
}
|
|
95
|
+
return typeNames;
|
|
33
96
|
}
|
|
34
97
|
/**
|
|
35
98
|
* @internal
|
|
@@ -55,26 +118,6 @@ export default class ASTConnectionBuilder extends ASTBuilder {
|
|
|
55
118
|
const dreamApp = DreamApp.getOrFail();
|
|
56
119
|
return path.join(dreamApp.projectRoot, dreamApp.paths.types, dbTypesFilenameForConnection(this.connectionName));
|
|
57
120
|
}
|
|
58
|
-
/**
|
|
59
|
-
* @internal
|
|
60
|
-
*
|
|
61
|
-
* returns the db source file for the given connectionName, injecting
|
|
62
|
-
* the source file with the actual file contents, so that AST nodes
|
|
63
|
-
* can be built through ingesting.
|
|
64
|
-
*/
|
|
65
|
-
async getDbSourceFile() {
|
|
66
|
-
const fileContent = await this.loadDbSyncFile();
|
|
67
|
-
return ts.createSourceFile('./db.js', fileContent, ts.ScriptTarget.Latest, true);
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* @internal
|
|
71
|
-
*
|
|
72
|
-
* reads the db source file for the given connection, returning the contents
|
|
73
|
-
* as a raw string
|
|
74
|
-
*/
|
|
75
|
-
async loadDbSyncFile() {
|
|
76
|
-
return (await fs.readFile(this.dbPath())).toString();
|
|
77
|
-
}
|
|
78
121
|
/**
|
|
79
122
|
* @internal
|
|
80
123
|
*
|
|
@@ -82,53 +125,14 @@ export default class ASTConnectionBuilder extends ASTBuilder {
|
|
|
82
125
|
* can be read and injected into AST nodes.
|
|
83
126
|
*/
|
|
84
127
|
async getSchemaData() {
|
|
85
|
-
const
|
|
128
|
+
const database = await this.introspectedDatabase();
|
|
129
|
+
const enumTypeNames = await this.enumTypeNames();
|
|
86
130
|
const schemaData = {};
|
|
87
|
-
for (const table of tables) {
|
|
88
|
-
schemaData[table] =
|
|
131
|
+
for (const table of database.tables) {
|
|
132
|
+
schemaData[this.tableKey(table)] = this.tableData(table, enumTypeNames);
|
|
89
133
|
}
|
|
90
134
|
return schemaData;
|
|
91
135
|
}
|
|
92
|
-
/**
|
|
93
|
-
* @internal
|
|
94
|
-
*
|
|
95
|
-
* used by getSchemaData to build up all table data
|
|
96
|
-
*/
|
|
97
|
-
async getTables() {
|
|
98
|
-
const fileContents = await this.loadDbSyncFile();
|
|
99
|
-
const tableLines = /export interface DB {([^}]*)}/.exec(fileContents)[1];
|
|
100
|
-
if (tableLines === undefined)
|
|
101
|
-
return [];
|
|
102
|
-
const tables = tableLines
|
|
103
|
-
.split('\n')
|
|
104
|
-
.map(line => {
|
|
105
|
-
const stingArray = line.split(':');
|
|
106
|
-
const substring = stingArray[0];
|
|
107
|
-
if (substring === undefined)
|
|
108
|
-
return '';
|
|
109
|
-
return substring.replace(/\s*/, '');
|
|
110
|
-
})
|
|
111
|
-
.filter(line => !!line);
|
|
112
|
-
return tables;
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* @internal
|
|
116
|
-
*
|
|
117
|
-
* finds all enums used by the app, and returns information
|
|
118
|
-
* about those enums that can be used for type generating purpposes
|
|
119
|
-
*/
|
|
120
|
-
async getAllEnumValueNames() {
|
|
121
|
-
const schemaData = await this.getSchemaData();
|
|
122
|
-
const enumValueNames = Object.values(schemaData)
|
|
123
|
-
.map(tableData => Object.keys(tableData.columns)
|
|
124
|
-
.filter(columnName => !!tableData.columns[columnName]?.enumValues)
|
|
125
|
-
.map(columnName => ({
|
|
126
|
-
enumValues: tableData.columns[columnName].enumValues,
|
|
127
|
-
enumType: tableData.columns[columnName].enumType,
|
|
128
|
-
})))
|
|
129
|
-
.flat();
|
|
130
|
-
return enumValueNames;
|
|
131
|
-
}
|
|
132
136
|
/**
|
|
133
137
|
* @internal
|
|
134
138
|
*
|
|
@@ -233,7 +237,8 @@ export default class ASTConnectionBuilder extends ASTBuilder {
|
|
|
233
237
|
* retrieves the table data for an individual table.
|
|
234
238
|
* Can be used to build up types
|
|
235
239
|
*/
|
|
236
|
-
|
|
240
|
+
tableData(table, enumTypeNames) {
|
|
241
|
+
const tableName = this.tableKey(table);
|
|
237
242
|
const dreamApp = DreamApp.getOrFail();
|
|
238
243
|
const models = Object.values(dreamApp.models).filter(model => model.table === tableName);
|
|
239
244
|
const maybeModel = models[0];
|
|
@@ -266,7 +271,7 @@ may need to update the table getter in the corresponding Dream.
|
|
|
266
271
|
default: uniq(models.flatMap(model => model['scopes'].default.map(scopeStatement => scopeStatement.method))),
|
|
267
272
|
named: uniq(models.flatMap(model => model['scopes'].named.map(scopeStatement => scopeStatement.method))),
|
|
268
273
|
},
|
|
269
|
-
columns: this.withoutIgnoredColumns(
|
|
274
|
+
columns: this.withoutIgnoredColumns(this.columnData(table, associationData, enumTypeNames), tableName),
|
|
270
275
|
virtualColumns: uniq(models.flatMap(model => model['virtualAttributes'].map(prop => prop.property) || [])),
|
|
271
276
|
associations: associationData,
|
|
272
277
|
serializerKeys,
|
|
@@ -311,11 +316,28 @@ may need to update the table getter in the corresponding Dream.
|
|
|
311
316
|
/**
|
|
312
317
|
* @internal
|
|
313
318
|
*
|
|
314
|
-
*
|
|
315
|
-
*
|
|
319
|
+
* the columns of an introspected table, as Dream's schema records them,
|
|
320
|
+
* keyed by camelized column name
|
|
316
321
|
*/
|
|
317
|
-
|
|
318
|
-
const
|
|
319
|
-
|
|
322
|
+
columnData(table, allTableAssociationData, enumTypeNames) {
|
|
323
|
+
const columnData = {};
|
|
324
|
+
for (const column of table.columns) {
|
|
325
|
+
const enumType = column.enumName ? enumTypeNames.get(column.enumName) : null;
|
|
326
|
+
columnData[camelize(column.name)] = {
|
|
327
|
+
dbType: column.dbType,
|
|
328
|
+
valueType: column.valueType,
|
|
329
|
+
allowNull: column.allowNull,
|
|
330
|
+
enumType,
|
|
331
|
+
enumValues: enumType ? `${enumType}Values` : null,
|
|
332
|
+
isArray: column.isArray,
|
|
333
|
+
foreignKey: allTableAssociationData[column.name]?.foreignKey || null,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
return Object.keys(columnData)
|
|
337
|
+
.sort()
|
|
338
|
+
.reduce((acc, key) => {
|
|
339
|
+
acc[key] = columnData[key];
|
|
340
|
+
return acc;
|
|
341
|
+
}, {});
|
|
320
342
|
}
|
|
321
343
|
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import { CliFileWriter } from '../../cli/CliFileWriter.js';
|
|
3
|
+
import camelize from '../camelize.js';
|
|
4
|
+
import { propertyName } from './ASTBuilder.js';
|
|
5
|
+
import ASTConnectionBuilder from './ASTConnectionBuilder.js';
|
|
6
|
+
import autogeneratedFileDisclaimer from './autoGeneratedFileDisclaimer.js';
|
|
7
|
+
import { dbTypesHelperNames, dbTypesName, dbTypesReservedNames, HELPER_TYPE_DECLARATIONS, PLAIN_ARRAY_VALUE_TYPES, } from './dbTypesNaming.js';
|
|
8
|
+
const f = ts.factory;
|
|
9
|
+
/**
|
|
10
|
+
* Writes a connection's types/db.ts (types/db.<connectionName>.ts for any
|
|
11
|
+
* connection but default) from its introspection: the Kysely `DB`
|
|
12
|
+
* interface, an interface for each table, each enum the tables use as a
|
|
13
|
+
* union of its values with a `<Enum>Values` const of them, and the column
|
|
14
|
+
* types those declare. Columns that the table's models ignore are left out,
|
|
15
|
+
* so that code still referring to one fails to compile.
|
|
16
|
+
*/
|
|
17
|
+
export default class ASTDbTypesBuilder extends ASTConnectionBuilder {
|
|
18
|
+
async build() {
|
|
19
|
+
const database = await this.introspectedDatabase();
|
|
20
|
+
const enumTypeNames = await this.enumTypeNames();
|
|
21
|
+
const helperNames = dbTypesHelperNames(database.tables);
|
|
22
|
+
const takenNames = new Set([...dbTypesReservedNames(database.tables), ...enumTypeNames.values()]);
|
|
23
|
+
const tables = database.tables.map(table => ({
|
|
24
|
+
key: this.tableKey(table),
|
|
25
|
+
interfaceName: dbTypesName(this.tableKey(table), takenNames),
|
|
26
|
+
columns: this.columns(table, enumTypeNames),
|
|
27
|
+
}));
|
|
28
|
+
const enumValues = new Map(database.enums.map(databaseEnum => [databaseEnum.name, databaseEnum.values]));
|
|
29
|
+
const typeDeclarations = [
|
|
30
|
+
...helperNames.map(name => ({ name, statements: [helperTypeDeclaration(name)] })),
|
|
31
|
+
...[...enumTypeNames].map(([enumName, typeName]) => ({
|
|
32
|
+
name: typeName,
|
|
33
|
+
statements: enumDeclarations(typeName, [...(enumValues.get(enumName) ?? [])].sort((a, b) => a.localeCompare(b))),
|
|
34
|
+
})),
|
|
35
|
+
];
|
|
36
|
+
const tableInterfaces = [...tables]
|
|
37
|
+
.sort((a, b) => a.interfaceName.localeCompare(b.interfaceName))
|
|
38
|
+
.map(table => f.createInterfaceDeclaration([f.createModifier(ts.SyntaxKind.ExportKeyword)], table.interfaceName, undefined, undefined, table.columns.map(column => f.createPropertySignature(undefined, propertyName(column.key), undefined, column.type))));
|
|
39
|
+
const dbMembers = tables.map(table => ({
|
|
40
|
+
name: propertyName(table.key),
|
|
41
|
+
type: f.createTypeReferenceNode(table.interfaceName),
|
|
42
|
+
}));
|
|
43
|
+
const statements = [
|
|
44
|
+
...typeDeclarations
|
|
45
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
46
|
+
.flatMap(declaration => declaration.statements),
|
|
47
|
+
...tableInterfaces,
|
|
48
|
+
f.createInterfaceDeclaration([f.createModifier(ts.SyntaxKind.ExportKeyword)], 'DB', undefined, undefined, dbMembers.map(member => f.createPropertySignature(undefined, member.name, undefined, member.type))),
|
|
49
|
+
f.createClassDeclaration([f.createModifier(ts.SyntaxKind.ExportKeyword)], 'DBClass', undefined, undefined, dbMembers.map(member => f.createPropertyDeclaration(undefined, member.name, undefined, member.type, undefined))),
|
|
50
|
+
];
|
|
51
|
+
const sourceFile = ts.createSourceFile('', '', ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
|
|
52
|
+
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed, omitTrailingSemicolon: true });
|
|
53
|
+
const print = (node) => printer.printNode(ts.EmitHint.Unspecified, node, sourceFile);
|
|
54
|
+
const output = await this.prettier(`\
|
|
55
|
+
${autogeneratedFileDisclaimer()}
|
|
56
|
+
${this.imports(helperNames).map(print).join('\n')}
|
|
57
|
+
|
|
58
|
+
${statements.map(print).join('\n\n')}
|
|
59
|
+
`);
|
|
60
|
+
await CliFileWriter.write(this.dbPath(), output);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* @internal
|
|
64
|
+
*
|
|
65
|
+
* the table's columns, minus those its models ignore, sorted by name, each
|
|
66
|
+
* with its key (the camelized column name) and its type
|
|
67
|
+
*/
|
|
68
|
+
columns(table, enumTypeNames) {
|
|
69
|
+
const ignoredColumns = this.ignoredColumnsForTable(this.tableKey(table));
|
|
70
|
+
return [...table.columns]
|
|
71
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
72
|
+
.map(column => ({ key: camelize(column.name), type: columnType(column, enumTypeNames) }))
|
|
73
|
+
.filter(column => !ignoredColumns.has(column.key));
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* @internal
|
|
77
|
+
*
|
|
78
|
+
* the file's imports: Dream's date and time classes, Kysely's ColumnType,
|
|
79
|
+
* and postgres-interval's type when a column is an interval
|
|
80
|
+
*/
|
|
81
|
+
imports(helperNames) {
|
|
82
|
+
return [
|
|
83
|
+
...this.dateAndDateTimeImports(),
|
|
84
|
+
typeImport('ColumnType', 'kysely'),
|
|
85
|
+
...(helperNames.includes('Interval') ? [typeImport('IPostgresInterval', 'postgres-interval')] : []),
|
|
86
|
+
];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* The column's type in its table's interface: its value type (an array of
|
|
91
|
+
* them for an array column), `| null` when it allows null, all wrapped in
|
|
92
|
+
* `Generated<>` when an insert may leave it out.
|
|
93
|
+
*/
|
|
94
|
+
function columnType(column, enumTypeNames) {
|
|
95
|
+
const valueType = f.createTypeReferenceNode(column.valueType === 'enum' ? enumTypeNames.get(column.enumName) : column.valueType);
|
|
96
|
+
let type = valueType;
|
|
97
|
+
if (column.isArray) {
|
|
98
|
+
type = PLAIN_ARRAY_VALUE_TYPES.includes(column.valueType)
|
|
99
|
+
? f.createArrayTypeNode(valueType)
|
|
100
|
+
: f.createTypeReferenceNode('ArrayType', [valueType]);
|
|
101
|
+
}
|
|
102
|
+
if (column.allowNull)
|
|
103
|
+
type = f.createUnionTypeNode([type, f.createLiteralTypeNode(f.createNull())]);
|
|
104
|
+
if (column.hasDefault)
|
|
105
|
+
type = f.createTypeReferenceNode('Generated', [type]);
|
|
106
|
+
return type;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* An enum's type, the union of its values (`never` when it has none), and
|
|
110
|
+
* its `<Enum>Values` const, which lists them.
|
|
111
|
+
*/
|
|
112
|
+
function enumDeclarations(typeName, values) {
|
|
113
|
+
const exportModifier = f.createModifier(ts.SyntaxKind.ExportKeyword);
|
|
114
|
+
return [
|
|
115
|
+
f.createTypeAliasDeclaration([exportModifier], typeName, undefined, values.length
|
|
116
|
+
? f.createUnionTypeNode(values.map(value => f.createLiteralTypeNode(f.createStringLiteral(value))))
|
|
117
|
+
: f.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword)),
|
|
118
|
+
f.createVariableStatement([exportModifier], f.createVariableDeclarationList([
|
|
119
|
+
f.createVariableDeclaration(`${typeName}Values`, undefined, undefined, f.createAsExpression(f.createArrayLiteralExpression(values.map(value => f.createStringLiteral(value))), f.createKeywordTypeNode(ts.SyntaxKind.ConstKeyword))),
|
|
120
|
+
], ts.NodeFlags.Const)),
|
|
121
|
+
];
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* A type types/db.ts declares for its columns, parsed from its declaration,
|
|
125
|
+
* which is fixed rather than built from the database.
|
|
126
|
+
*/
|
|
127
|
+
function helperTypeDeclaration(name) {
|
|
128
|
+
return ts.createSourceFile('', HELPER_TYPE_DECLARATIONS[name], ts.ScriptTarget.Latest, false, ts.ScriptKind.TS).statements[0];
|
|
129
|
+
}
|
|
130
|
+
function typeImport(name, moduleName) {
|
|
131
|
+
return f.createImportDeclaration(undefined, f.createImportClause(true, undefined, f.createNamedImports([f.createImportSpecifier(false, undefined, f.createIdentifier(name))])), f.createStringLiteral(moduleName));
|
|
132
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
2
|
import { CliFileWriter } from '../../cli/CliFileWriter.js';
|
|
3
3
|
import { DreamConst } from '../../dream/constants.js';
|
|
4
|
-
import compact from '../compact.js';
|
|
5
4
|
import uniq from '../uniq.js';
|
|
5
|
+
import { propertyName } from './ASTBuilder.js';
|
|
6
6
|
import ASTConnectionBuilder from './ASTConnectionBuilder.js';
|
|
7
7
|
import autogeneratedFileDisclaimer from './autoGeneratedFileDisclaimer.js';
|
|
8
8
|
const f = ts.factory;
|
|
@@ -51,11 +51,10 @@ export default class ASTSchemaBuilder extends ASTConnectionBuilder {
|
|
|
51
51
|
const importedVariables = [];
|
|
52
52
|
let passthroughColumns = [];
|
|
53
53
|
let allDefaultScopeNames = [];
|
|
54
|
-
const dbSourceFile = await this.getDbSourceFile();
|
|
55
54
|
const schemaObjectLiteral = f.createObjectLiteralExpression(Object.keys(schemaData).map(tableName => {
|
|
56
55
|
const tableData = schemaData[tableName];
|
|
57
56
|
allDefaultScopeNames = [...allDefaultScopeNames, ...tableData.scopes.default];
|
|
58
|
-
return f.createPropertyAssignment(
|
|
57
|
+
return f.createPropertyAssignment(propertyName(tableName), f.createObjectLiteralExpression([
|
|
59
58
|
f.createPropertyAssignment(f.createIdentifier('serializerKeys'), f.createArrayLiteralExpression([...(tableData?.serializerKeys || [])].sort().map(key => f.createStringLiteral(key)))),
|
|
60
59
|
f.createPropertyAssignment(f.createIdentifier('scopes'), f.createObjectLiteralExpression([
|
|
61
60
|
f.createPropertyAssignment(f.createIdentifier('default'), f.createArrayLiteralExpression((tableData?.scopes.default).sort().map(key => f.createStringLiteral(key)))),
|
|
@@ -84,8 +83,8 @@ export default class ASTSchemaBuilder extends ASTConnectionBuilder {
|
|
|
84
83
|
const enumValuesNode = columnData.enumType
|
|
85
84
|
? f.createIdentifier(columnData.enumType + 'Values')
|
|
86
85
|
: f.createNull();
|
|
87
|
-
const coercedType = this.
|
|
88
|
-
return f.createPropertyAssignment(
|
|
86
|
+
const coercedType = this.coercedType(columnData, importedTypes);
|
|
87
|
+
return f.createPropertyAssignment(propertyName(columnName), f.createObjectLiteralExpression([
|
|
89
88
|
f.createPropertyAssignment(f.createIdentifier('coercedType'), f.createAsExpression(f.createObjectLiteralExpression(), coercedType)),
|
|
90
89
|
f.createPropertyAssignment(f.createIdentifier('enumType'), enumTypeNode
|
|
91
90
|
? f.createAsExpression(f.createObjectLiteralExpression(), enumTypeNode)
|
|
@@ -238,83 +237,40 @@ ${output}`;
|
|
|
238
237
|
/**
|
|
239
238
|
* @internal
|
|
240
239
|
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
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.
|
|
240
|
+
* the type Dream gives the column's values: Int8 (bigint) values are
|
|
241
|
+
* strings, Numeric values numbers, and a Timestamp is a CalendarDate for a
|
|
242
|
+
* date column and a DateTime otherwise. Types declared in the db.ts file
|
|
243
|
+
* (Json and the like) are added to importedTypes.
|
|
249
244
|
*/
|
|
250
|
-
|
|
251
|
-
const
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
245
|
+
coercedType(columnData, importedTypes) {
|
|
246
|
+
const valueType = this.coercedValueType(columnData, importedTypes);
|
|
247
|
+
const type = columnData.isArray ? f.createArrayTypeNode(valueType) : valueType;
|
|
248
|
+
return columnData.allowNull
|
|
249
|
+
? f.createUnionTypeNode([type, f.createLiteralTypeNode(f.createNull())])
|
|
250
|
+
: type;
|
|
256
251
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
.
|
|
277
|
-
|
|
278
|
-
.
|
|
279
|
-
|
|
280
|
-
return null;
|
|
281
|
-
switch (sanitized) {
|
|
282
|
-
case 'Numeric':
|
|
283
|
-
return f.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);
|
|
284
|
-
case 'Numeric[]':
|
|
285
|
-
return f.createArrayTypeNode(f.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword));
|
|
286
|
-
case 'Timestamp':
|
|
287
|
-
return isDate ? f.createTypeReferenceNode('CalendarDate') : f.createTypeReferenceNode('DateTime');
|
|
288
|
-
case 'Timestamp[]':
|
|
289
|
-
return isDate
|
|
290
|
-
? f.createArrayTypeNode(f.createTypeReferenceNode('CalendarDate'))
|
|
291
|
-
: f.createArrayTypeNode(f.createTypeReferenceNode('DateTime'));
|
|
292
|
-
case 'string':
|
|
293
|
-
// Kysely-codegen types TIME columns as string, we need to check dbType
|
|
294
|
-
if (isTime)
|
|
295
|
-
return f.createTypeReferenceNode('ClockTime');
|
|
296
|
-
if (isTimeTz)
|
|
297
|
-
return f.createTypeReferenceNode('ClockTimeTz');
|
|
298
|
-
return defaultReturnNode;
|
|
299
|
-
case 'string[]':
|
|
300
|
-
// Kysely-codegen types TIME[] columns as string[], we need to check dbType
|
|
301
|
-
if (isTime)
|
|
302
|
-
return f.createArrayTypeNode(f.createTypeReferenceNode('ClockTime'));
|
|
303
|
-
if (isTimeTz)
|
|
304
|
-
return f.createArrayTypeNode(f.createTypeReferenceNode('ClockTimeTz'));
|
|
305
|
-
return defaultReturnNode;
|
|
306
|
-
case 'Int8':
|
|
307
|
-
return f.createKeywordTypeNode(ts.SyntaxKind.StringKeyword);
|
|
308
|
-
case 'Int8[]':
|
|
309
|
-
return f.createArrayTypeNode(f.createKeywordTypeNode(ts.SyntaxKind.StringKeyword));
|
|
310
|
-
case 'Json':
|
|
311
|
-
case 'Json[]':
|
|
312
|
-
importedModules.push('Json');
|
|
313
|
-
return defaultReturnNode;
|
|
314
|
-
default:
|
|
315
|
-
return defaultReturnNode;
|
|
316
|
-
}
|
|
317
|
-
}));
|
|
318
|
-
return types;
|
|
252
|
+
coercedValueType(columnData, importedTypes) {
|
|
253
|
+
switch (columnData.valueType) {
|
|
254
|
+
case 'string':
|
|
255
|
+
case 'Int8':
|
|
256
|
+
return f.createKeywordTypeNode(ts.SyntaxKind.StringKeyword);
|
|
257
|
+
case 'number':
|
|
258
|
+
case 'Numeric':
|
|
259
|
+
return f.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);
|
|
260
|
+
case 'boolean':
|
|
261
|
+
return f.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword);
|
|
262
|
+
case 'Timestamp':
|
|
263
|
+
return f.createTypeReferenceNode(this.isDateDbType(columnData.dbType) ? 'CalendarDate' : 'DateTime');
|
|
264
|
+
case 'enum':
|
|
265
|
+
return f.createTypeReferenceNode(columnData.enumType);
|
|
266
|
+
case 'Json':
|
|
267
|
+
case 'Interval':
|
|
268
|
+
case 'Point':
|
|
269
|
+
case 'Circle':
|
|
270
|
+
importedTypes.push(columnData.valueType);
|
|
271
|
+
return f.createTypeReferenceNode(columnData.valueType);
|
|
272
|
+
default:
|
|
273
|
+
return f.createTypeReferenceNode(columnData.valueType);
|
|
274
|
+
}
|
|
319
275
|
}
|
|
320
276
|
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import pascalize from '../pascalize.js';
|
|
2
|
+
/**
|
|
3
|
+
* @internal
|
|
4
|
+
*
|
|
5
|
+
* The value types an array column lists in a plain array in types/db.ts. Any
|
|
6
|
+
* other is listed through `ArrayType`, which turns a `ColumnType` (such as
|
|
7
|
+
* `Int8`) into a `ColumnType` of arrays.
|
|
8
|
+
*/
|
|
9
|
+
export const PLAIN_ARRAY_VALUE_TYPES = ['string', 'number', 'boolean', 'ClockTime', 'ClockTimeTz'];
|
|
10
|
+
/**
|
|
11
|
+
* @internal
|
|
12
|
+
*
|
|
13
|
+
* The declaration of each type that types/db.ts declares for its columns.
|
|
14
|
+
*/
|
|
15
|
+
export const HELPER_TYPE_DECLARATIONS = {
|
|
16
|
+
ArrayType: 'export type ArrayType<T> = ArrayTypeImpl<T> extends (infer U)[] ? U[] : ArrayTypeImpl<T>',
|
|
17
|
+
ArrayTypeImpl: 'export type ArrayTypeImpl<T> = T extends ColumnType<infer S, infer I, infer U> ? ColumnType<S[], I[], U[]> : T[]',
|
|
18
|
+
Circle: 'export type Circle = { x: number; y: number; radius: number }',
|
|
19
|
+
Generated: 'export type Generated<T> = T extends ColumnType<infer S, infer I, infer U> ? ColumnType<S, I | undefined, U> : ColumnType<T, T | undefined, T>',
|
|
20
|
+
Int8: 'export type Int8 = ColumnType<string, bigint | number | string, bigint | number | string>',
|
|
21
|
+
Interval: 'export type Interval = ColumnType<IPostgresInterval, IPostgresInterval | number | string, IPostgresInterval | number | string>',
|
|
22
|
+
Json: 'export type Json = JsonValue',
|
|
23
|
+
JsonArray: 'export type JsonArray = JsonValue[]',
|
|
24
|
+
JsonObject: 'export type JsonObject = {\n [x: string]: JsonValue | undefined\n}',
|
|
25
|
+
JsonPrimitive: 'export type JsonPrimitive = boolean | number | string | null',
|
|
26
|
+
JsonValue: 'export type JsonValue = JsonArray | JsonObject | JsonPrimitive',
|
|
27
|
+
Numeric: 'export type Numeric = ColumnType<string, number | string, number | string>',
|
|
28
|
+
Point: 'export type Point = { x: number; y: number }',
|
|
29
|
+
Timestamp: 'export type Timestamp = ColumnType<DateTime | CalendarDate>',
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* @internal
|
|
33
|
+
*
|
|
34
|
+
* The types types/db.ts declares for the given tables' columns.
|
|
35
|
+
*/
|
|
36
|
+
export function dbTypesHelperNames(tables) {
|
|
37
|
+
const names = new Set();
|
|
38
|
+
for (const column of tables.flatMap(table => table.columns)) {
|
|
39
|
+
if (column.hasDefault)
|
|
40
|
+
names.add('Generated');
|
|
41
|
+
if (column.isArray && !PLAIN_ARRAY_VALUE_TYPES.includes(column.valueType)) {
|
|
42
|
+
names.add('ArrayType').add('ArrayTypeImpl');
|
|
43
|
+
}
|
|
44
|
+
if (column.valueType === 'Json') {
|
|
45
|
+
names.add('Json').add('JsonArray').add('JsonObject').add('JsonPrimitive').add('JsonValue');
|
|
46
|
+
}
|
|
47
|
+
if (HELPER_TYPE_DECLARATIONS[column.valueType])
|
|
48
|
+
names.add(column.valueType);
|
|
49
|
+
}
|
|
50
|
+
return [...names].sort();
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* @internal
|
|
54
|
+
*
|
|
55
|
+
* The names that types/db.ts declares, imports or uses from JavaScript for
|
|
56
|
+
* the given tables, which no enum or table interface may take.
|
|
57
|
+
*/
|
|
58
|
+
export function dbTypesReservedNames(tables) {
|
|
59
|
+
const valueTypes = new Set(tables.flatMap(table => table.columns.map(column => column.valueType)));
|
|
60
|
+
return [
|
|
61
|
+
'CalendarDate',
|
|
62
|
+
'ClockTime',
|
|
63
|
+
'ClockTimeTz',
|
|
64
|
+
'ColumnType',
|
|
65
|
+
'DB',
|
|
66
|
+
'DBClass',
|
|
67
|
+
'DateTime',
|
|
68
|
+
...dbTypesHelperNames(tables),
|
|
69
|
+
...(valueTypes.has('Date') ? ['Date'] : []),
|
|
70
|
+
...(valueTypes.has('Buffer') ? ['Buffer'] : []),
|
|
71
|
+
...(valueTypes.has('Interval') ? ['IPostgresInterval'] : []),
|
|
72
|
+
];
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* @internal
|
|
76
|
+
*
|
|
77
|
+
* The TypeScript name types/db.ts gives a table or enum: its name, with a
|
|
78
|
+
* schema's `.` as `_`, pascalized, and prefixed with `_` when it would start
|
|
79
|
+
* with a digit. A number is added when the name is in `takenNames`, which
|
|
80
|
+
* the chosen name joins.
|
|
81
|
+
*/
|
|
82
|
+
export function dbTypesName(name, takenNames) {
|
|
83
|
+
const pascalized = pascalize(name.replace(/\./g, '_'));
|
|
84
|
+
const baseName = /^\d/.test(pascalized) ? `_${pascalized}` : pascalized;
|
|
85
|
+
let typeName = baseName;
|
|
86
|
+
for (let suffix = 2; takenNames.has(typeName); suffix++)
|
|
87
|
+
typeName = `${baseName}${suffix}`;
|
|
88
|
+
takenNames.add(typeName);
|
|
89
|
+
return typeName;
|
|
90
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { matchesGlob } from 'node:path';
|
|
2
|
+
/**
|
|
3
|
+
* @internal
|
|
4
|
+
*
|
|
5
|
+
* Whether a table matches a `tableIncludePattern` or `tableExcludePattern`:
|
|
6
|
+
* a glob in Node's `path.matchesGlob` syntax (e.g. `chalupas*`, `public.*`
|
|
7
|
+
* or `public.+(users|posts)`), compared without regard to case. A pattern
|
|
8
|
+
* that contains a `.` is matched against `<schema>.<name>`, and any other
|
|
9
|
+
* against the table's name alone. As with micromatch, a leading `!` (one that
|
|
10
|
+
* does not open an extglob `!(…)`) negates the pattern, and a backslash
|
|
11
|
+
* before a glob character such as `*` or `?` matches that character itself.
|
|
12
|
+
*/
|
|
13
|
+
export default function tableMatchesPattern(table, pattern) {
|
|
14
|
+
if (/^!(?!\()/.test(pattern))
|
|
15
|
+
return !tableMatchesPattern(table, pattern.slice(1));
|
|
16
|
+
const subject = pattern.includes('.') ? `${table.schema ?? '*'}.${table.name}` : table.name;
|
|
17
|
+
// matchesGlob does not read a backslash as an escape, so an escaped
|
|
18
|
+
// character is matched through a class of that one character
|
|
19
|
+
const glob = pattern.replace(/\\(.)/g, '[$1]');
|
|
20
|
+
return matchesGlob(subject.toLowerCase(), glob.toLowerCase());
|
|
21
|
+
}
|
package/dist/esm/src/Dream.js
CHANGED
|
@@ -3019,7 +3019,9 @@ export default class Dream {
|
|
|
3019
3019
|
* Writes the value into the current attributes as given, with none of
|
|
3020
3020
|
* setAttribute's checks. Only for values Dream already trusts: a row read
|
|
3021
3021
|
* from the database, and the ciphertext the @Encrypted property setter
|
|
3022
|
-
*
|
|
3022
|
+
* writes (freshly encrypted, or the ciphertext as loaded or last saved,
|
|
3023
|
+
* which it keeps when that already holds the assigned plaintext). Every
|
|
3024
|
+
* caller-supplied value goes through setAttribute.
|
|
3023
3025
|
*/
|
|
3024
3026
|
setAttributeUnchecked(column, val) {
|
|
3025
3027
|
this.currentAttributes[column] = val;
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
export default function dataTypes() {
|
|
2
|
-
// In the future, when we support multiple db drivers,
|
|
3
|
-
// this will need to be updated
|
|
4
|
-
return postgresDatatypes;
|
|
5
|
-
}
|
|
6
|
-
export function isPrimitiveDataType(type) {
|
|
7
|
-
return dataTypes().includes(type.replace(/\[\]$/, ''));
|
|
8
|
-
}
|
|
9
1
|
export const postgresDatatypes = [
|
|
10
2
|
'bigint',
|
|
11
3
|
'bigserial',
|