@rvoh/dream 2.1.2 → 2.1.4-alpha.1
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/README.md +4 -4
- package/dist/cjs/src/Dream.js +35 -0
- package/dist/cjs/src/bin/index.js +1 -1
- package/dist/cjs/src/cli/index.js +5 -1
- package/dist/cjs/src/cli/logger/loggable/DreamCliLoggableText.js +1 -0
- package/dist/cjs/src/dream/DreamClassTransactionBuilder.js +30 -0
- package/dist/cjs/src/dream/Query.js +30 -0
- package/dist/cjs/src/dream/QueryDriver/Base.js +32 -0
- package/dist/cjs/src/dream/QueryDriver/Kysely.js +52 -6
- package/dist/cjs/src/dream/QueryDriver/helpers/kysely/foreignKeyTypeFromPrimaryKey.js +3 -0
- package/dist/cjs/src/dream/constants.js +1 -1
- package/dist/cjs/src/dream/internal/printSerializerHierarchyLevel.js +2 -0
- package/dist/cjs/src/dream-app/helpers/DreamImporter.js +3 -1
- package/dist/cjs/src/dream-app/index.js +2 -1
- package/dist/cjs/src/helpers/Env.js +2 -0
- package/dist/cjs/src/helpers/cli/ASTConnectionBuilder.js +1 -1
- package/dist/cjs/src/helpers/cli/DBClassDeprecation.js +2 -0
- package/dist/cjs/src/helpers/cli/generateDream.js +2 -1
- package/dist/cjs/src/helpers/cli/generateFactory.js +2 -1
- package/dist/cjs/src/helpers/cli/generateFactoryContent.js +13 -3
- package/dist/cjs/src/helpers/cli/generateMigration.js +2 -1
- package/dist/cjs/src/helpers/cli/generateMigrationContent.js +18 -4
- package/dist/cjs/src/helpers/cli/generateSerializer.js +2 -1
- package/dist/cjs/src/helpers/cli/generateUnitSpec.js +2 -1
- package/dist/cjs/src/helpers/getFiles.js +3 -1
- package/dist/cjs/src/helpers/sspawn.js +2 -0
- package/dist/cjs/src/package-exports/system.js +1 -0
- package/dist/esm/src/Dream.js +35 -0
- package/dist/esm/src/bin/index.js +1 -1
- package/dist/esm/src/cli/index.js +5 -1
- package/dist/esm/src/cli/logger/loggable/DreamCliLoggableText.js +1 -0
- package/dist/esm/src/dream/DreamClassTransactionBuilder.js +30 -0
- package/dist/esm/src/dream/Query.js +30 -0
- package/dist/esm/src/dream/QueryDriver/Base.js +32 -0
- package/dist/esm/src/dream/QueryDriver/Kysely.js +52 -6
- package/dist/esm/src/dream/QueryDriver/helpers/kysely/foreignKeyTypeFromPrimaryKey.js +3 -0
- package/dist/esm/src/dream/constants.js +1 -1
- package/dist/esm/src/dream/internal/printSerializerHierarchyLevel.js +2 -0
- package/dist/esm/src/dream-app/helpers/DreamImporter.js +3 -1
- package/dist/esm/src/dream-app/index.js +2 -1
- package/dist/esm/src/helpers/Env.js +2 -0
- package/dist/esm/src/helpers/cli/ASTConnectionBuilder.js +1 -1
- package/dist/esm/src/helpers/cli/DBClassDeprecation.js +2 -0
- package/dist/esm/src/helpers/cli/generateDream.js +2 -1
- package/dist/esm/src/helpers/cli/generateFactory.js +2 -1
- package/dist/esm/src/helpers/cli/generateFactoryContent.js +13 -3
- package/dist/esm/src/helpers/cli/generateMigration.js +2 -1
- package/dist/esm/src/helpers/cli/generateMigrationContent.js +18 -4
- package/dist/esm/src/helpers/cli/generateSerializer.js +2 -1
- package/dist/esm/src/helpers/cli/generateUnitSpec.js +2 -1
- package/dist/esm/src/helpers/getFiles.js +3 -1
- package/dist/esm/src/helpers/sspawn.js +2 -0
- package/dist/esm/src/package-exports/system.js +1 -0
- package/dist/types/src/Dream.d.ts +42 -0
- package/dist/types/src/dream/DreamClassTransactionBuilder.d.ts +26 -0
- package/dist/types/src/dream/Query.d.ts +26 -0
- package/dist/types/src/dream/QueryDriver/Base.d.ts +29 -3
- package/dist/types/src/dream/QueryDriver/Kysely.d.ts +30 -4
- package/dist/types/src/dream/QueryDriver/helpers/kysely/foreignKeyTypeFromPrimaryKey.d.ts +2 -2
- package/dist/types/src/dream/constants.d.ts +1 -1
- package/dist/types/src/dream-app/helpers/PackageManager.d.ts +1 -1
- package/dist/types/src/dream-app/index.d.ts +6 -7
- package/dist/types/src/helpers/cli/generateMigrationContent.d.ts +1 -1
- package/dist/types/src/helpers/cli/generateStiMigrationContent.d.ts +1 -1
- package/dist/types/src/package-exports/system.d.ts +1 -0
- package/dist/types/src/package-exports/types.d.ts +1 -1
- package/dist/types/src/types/associations/belongsTo.d.ts +1 -1
- package/dist/types/src/types/associations/belongsTo.ts +1 -1
- package/dist/types/src/types/db.d.ts +2 -0
- package/dist/types/src/types/db.ts +2 -0
- package/dist/types/src/types/dream.d.ts +1 -2
- package/dist/types/src/types/dream.ts +1 -3
- package/dist/types/src/types/serializer.ts +2 -2
- package/docs/assets/navigation.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/classes/db.DreamMigrationHelpers.html +9 -9
- package/docs/classes/db.KyselyQueryDriver.html +47 -31
- package/docs/classes/db.PostgresQueryDriver.html +48 -32
- package/docs/classes/db.QueryDriverBase.html +46 -30
- package/docs/classes/errors.CheckConstraintViolation.html +4 -4
- package/docs/classes/errors.ColumnOverflow.html +4 -4
- package/docs/classes/errors.CreateOrFindByFailedToCreateAndFind.html +4 -4
- package/docs/classes/errors.DataIncompatibleWithDatabaseField.html +4 -4
- package/docs/classes/errors.DataTypeColumnTypeMismatch.html +4 -4
- package/docs/classes/errors.GlobalNameNotSet.html +4 -4
- package/docs/classes/errors.InvalidCalendarDate.html +4 -4
- package/docs/classes/errors.MissingSerializersDefinition.html +4 -4
- package/docs/classes/errors.NonLoadedAssociation.html +4 -4
- package/docs/classes/errors.NotNullViolation.html +4 -4
- package/docs/classes/errors.RecordNotFound.html +4 -4
- package/docs/classes/errors.ValidationError.html +4 -4
- package/docs/classes/index.CalendarDate.html +2 -2
- package/docs/classes/index.Decorators.html +19 -19
- package/docs/classes/index.Dream.html +227 -201
- package/docs/classes/index.DreamApp.html +5 -5
- package/docs/classes/index.DreamTransaction.html +2 -2
- package/docs/classes/index.Env.html +2 -2
- package/docs/classes/index.Query.html +91 -75
- 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/index.html +4 -4
- 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 +2 -1
- package/docs/modules/types.html +4 -3
- 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.PrimaryKeyType.html +1 -0
- 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/system.primaryKeyTypes.html +1 -0
- package/docs/variables/types.TRIGRAM_OPERATORS.html +1 -1
- package/package.json +17 -17
- package/CHANGELOG.md +0 -332
- package/docs/variables/types.primaryKeyTypes.html +0 -1
package/README.md
CHANGED
|
@@ -158,7 +158,7 @@ this test app is used to run all of our assertions, and is meant to be replaced
|
|
|
158
158
|
to get into the console, type:
|
|
159
159
|
|
|
160
160
|
```bash
|
|
161
|
-
|
|
161
|
+
pnpm console
|
|
162
162
|
```
|
|
163
163
|
|
|
164
164
|
Once inside the repl, you are able to access all the models within the test app. All the classes are automagically imported.
|
|
@@ -174,7 +174,7 @@ await user.save()
|
|
|
174
174
|
Running specs is very easy, not much to explain here.
|
|
175
175
|
|
|
176
176
|
```
|
|
177
|
-
|
|
177
|
+
pnpm spec
|
|
178
178
|
```
|
|
179
179
|
|
|
180
180
|
We are using jest under the hood, and have a plugin enabled called `jest-plugin-context`, which allows us to branch specs out using the `context` function in place of `describe`, like so:
|
|
@@ -210,7 +210,7 @@ describe('Dream#pluck', () => {
|
|
|
210
210
|
Dream provides a similarity searching library out of the box which allows you to implement fuzzy-searching in your app. To use it, first write a migration.
|
|
211
211
|
|
|
212
212
|
```bash
|
|
213
|
-
|
|
213
|
+
pnpm psy g:migration add_fuzzy_search_to_users
|
|
214
214
|
```
|
|
215
215
|
|
|
216
216
|
Open the generated migration, create the pg_trgm extension and create a gin index for a field on your model
|
|
@@ -236,7 +236,7 @@ export async function down(db: Kysely<any>): Promise<void> {
|
|
|
236
236
|
Once done, run migrations
|
|
237
237
|
|
|
238
238
|
```bash
|
|
239
|
-
NODE_ENV=development
|
|
239
|
+
NODE_ENV=development pnpm psy db:migrate
|
|
240
240
|
```
|
|
241
241
|
|
|
242
242
|
Now you can take full advantage of pg_trgm using the dream adapters!
|
package/dist/cjs/src/Dream.js
CHANGED
|
@@ -556,7 +556,9 @@ export default class Dream {
|
|
|
556
556
|
const serializer = inferSerializersFromDreamClassOrViewModelClass(this, key)[0] ?? null;
|
|
557
557
|
if (!serializer)
|
|
558
558
|
throw new Error(`unable to find serializer with key: ${key}`);
|
|
559
|
+
// eslint-disable-next-line no-console
|
|
559
560
|
console.log(yoctocolors.cyan(this.sanitizedName));
|
|
561
|
+
// eslint-disable-next-line no-console
|
|
560
562
|
console.log(yoctocolors.gray(serializer.globalName));
|
|
561
563
|
return this.recursiveSerializationMap(serializer, {
|
|
562
564
|
forDisplay: true,
|
|
@@ -1014,6 +1016,38 @@ export default class Dream {
|
|
|
1014
1016
|
static async min(columnName) {
|
|
1015
1017
|
return await this.query().min(columnName);
|
|
1016
1018
|
}
|
|
1019
|
+
/**
|
|
1020
|
+
* Retrieves the sum for all values of the specified column
|
|
1021
|
+
* for this model's records.
|
|
1022
|
+
*
|
|
1023
|
+
*
|
|
1024
|
+
* ```ts
|
|
1025
|
+
* await Game.sum('score')
|
|
1026
|
+
* // 100
|
|
1027
|
+
* ```
|
|
1028
|
+
*
|
|
1029
|
+
* @param columnName - a column name on the model
|
|
1030
|
+
* @returns the sum for all values of the specified column for this model's records
|
|
1031
|
+
*/
|
|
1032
|
+
static async sum(columnName) {
|
|
1033
|
+
return await this.query().sum(columnName);
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* Retrieves the average for all values of the specified column
|
|
1037
|
+
* for this model's records.
|
|
1038
|
+
*
|
|
1039
|
+
*
|
|
1040
|
+
* ```ts
|
|
1041
|
+
* await Game.avg('score')
|
|
1042
|
+
* // 100
|
|
1043
|
+
* ```
|
|
1044
|
+
*
|
|
1045
|
+
* @param columnName - a column name on the model
|
|
1046
|
+
* @returns the average for all values of the specified column for this model's records
|
|
1047
|
+
*/
|
|
1048
|
+
static async avg(columnName) {
|
|
1049
|
+
return await this.query().avg(columnName);
|
|
1050
|
+
}
|
|
1017
1051
|
/**
|
|
1018
1052
|
* Persists a new record, setting the provided attributes.
|
|
1019
1053
|
* Automatically sets createdAt and updatedAt timestamps.
|
|
@@ -3356,6 +3390,7 @@ export default class Dream {
|
|
|
3356
3390
|
*/
|
|
3357
3391
|
loaded(associationName) {
|
|
3358
3392
|
try {
|
|
3393
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
3359
3394
|
;
|
|
3360
3395
|
this[associationName];
|
|
3361
3396
|
return true;
|
|
@@ -65,7 +65,7 @@ export default class DreamBin {
|
|
|
65
65
|
// to use it to generate docs for their apps.
|
|
66
66
|
static async buildDocs() {
|
|
67
67
|
DreamCLI.logger.logStartProgress('generating docs...');
|
|
68
|
-
await sspawn('
|
|
68
|
+
await sspawn('pnpm typedoc src/package-exports/*.ts --tsconfig ./tsconfig.esm.build.json --out docs');
|
|
69
69
|
DreamCLI.logger.logEndProgress();
|
|
70
70
|
}
|
|
71
71
|
}
|
|
@@ -14,6 +14,10 @@ ${INDENT}all properties default to not nullable; null can be allowed by appendin
|
|
|
14
14
|
${INDENT} subtitle:string:optional
|
|
15
15
|
${INDENT}
|
|
16
16
|
${INDENT}supported types:
|
|
17
|
+
${INDENT} - uuid:
|
|
18
|
+
${INDENT} - uuid[]:
|
|
19
|
+
${INDENT} a column optimized for storing UUIDs
|
|
20
|
+
${INDENT}
|
|
17
21
|
${INDENT} - citext:
|
|
18
22
|
${INDENT} - citext[]:
|
|
19
23
|
${INDENT} case insensitive text (indexes and queries are automatically case insensitive)
|
|
@@ -213,7 +217,7 @@ ${INDENT} to extend the Coach model in src/app/models/Health/Coach: Health/Co
|
|
|
213
217
|
.description('Seeds the database using the file located in db/seed.ts.')
|
|
214
218
|
.action(async () => {
|
|
215
219
|
if (process.env.NODE_ENV === 'test' && process.env.DREAM_SEED_DB_IN_TEST !== '1') {
|
|
216
|
-
|
|
220
|
+
DreamApp.log('skipping db seed for test env. To really seed for test, add DREAM_SEED_DB_IN_TEST=1');
|
|
217
221
|
return;
|
|
218
222
|
}
|
|
219
223
|
await initializeDreamApp();
|
|
@@ -13,6 +13,7 @@ export default class DreamCliLoggableText extends DreamCliLoggable {
|
|
|
13
13
|
this.logPrefixBgColor = logPrefixBgColor;
|
|
14
14
|
}
|
|
15
15
|
render() {
|
|
16
|
+
// eslint-disable-next-line no-console
|
|
16
17
|
console.log(`${this.colorizedLogPrefix} ${colorize(this.text, { color: this.color, bgColor: this.bgColor })}`);
|
|
17
18
|
}
|
|
18
19
|
}
|
|
@@ -124,6 +124,36 @@ export default class DreamClassTransactionBuilder {
|
|
|
124
124
|
async min(columnName) {
|
|
125
125
|
return this.queryInstance().min(columnName);
|
|
126
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* Retrieves the sum value of the specified column
|
|
129
|
+
* for this Query
|
|
130
|
+
*
|
|
131
|
+
* ```ts
|
|
132
|
+
* await Game.txn(txn).sum('score')
|
|
133
|
+
* // 1
|
|
134
|
+
* ```
|
|
135
|
+
*
|
|
136
|
+
* @param columnName - a column name on the model
|
|
137
|
+
* @returns the sum of the values of the specified column for this Query
|
|
138
|
+
*/
|
|
139
|
+
async sum(columnName) {
|
|
140
|
+
return this.queryInstance().sum(columnName);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Retrieves the average value of the specified column
|
|
144
|
+
* for this Query
|
|
145
|
+
*
|
|
146
|
+
* ```ts
|
|
147
|
+
* await Game.txn(txn).avg('score')
|
|
148
|
+
* // 1
|
|
149
|
+
* ```
|
|
150
|
+
*
|
|
151
|
+
* @param columnName - a column name on the model
|
|
152
|
+
* @returns the average of the values of the specified column for this Query
|
|
153
|
+
*/
|
|
154
|
+
async avg(columnName) {
|
|
155
|
+
return this.queryInstance().avg(columnName);
|
|
156
|
+
}
|
|
127
157
|
/**
|
|
128
158
|
* Persists a new record, setting the provided attributes.
|
|
129
159
|
* Automatically sets createdAt and updatedAt timestamps.
|
|
@@ -1043,6 +1043,36 @@ export default class Query {
|
|
|
1043
1043
|
async min(columnName) {
|
|
1044
1044
|
return await this.dbDriverInstance().min(columnName);
|
|
1045
1045
|
}
|
|
1046
|
+
/**
|
|
1047
|
+
* Retrieves the sum value of the specified column
|
|
1048
|
+
* for this Query
|
|
1049
|
+
*
|
|
1050
|
+
* ```ts
|
|
1051
|
+
* await Game.query().sum('score')
|
|
1052
|
+
* // 1
|
|
1053
|
+
* ```
|
|
1054
|
+
*
|
|
1055
|
+
* @param columnName - a column name on the model
|
|
1056
|
+
* @returns the sum of the values of the specified column for this Query
|
|
1057
|
+
*/
|
|
1058
|
+
async sum(columnName) {
|
|
1059
|
+
return await this.dbDriverInstance().sum(columnName);
|
|
1060
|
+
}
|
|
1061
|
+
/**
|
|
1062
|
+
* Retrieves the average value of the specified column
|
|
1063
|
+
* for this Query
|
|
1064
|
+
*
|
|
1065
|
+
* ```ts
|
|
1066
|
+
* await Game.query().avg('score')
|
|
1067
|
+
* // 1
|
|
1068
|
+
* ```
|
|
1069
|
+
*
|
|
1070
|
+
* @param columnName - a column name on the model
|
|
1071
|
+
* @returns the average of the values of the specified column for this Query
|
|
1072
|
+
*/
|
|
1073
|
+
async avg(columnName) {
|
|
1074
|
+
return await this.dbDriverInstance().avg(columnName);
|
|
1075
|
+
}
|
|
1046
1076
|
/**
|
|
1047
1077
|
* Plucks the provided fields from the given dream class table
|
|
1048
1078
|
*
|
|
@@ -273,6 +273,38 @@ export default class QueryDriverBase {
|
|
|
273
273
|
async min(columnName) {
|
|
274
274
|
throw new Error('implement min in child class');
|
|
275
275
|
}
|
|
276
|
+
/**
|
|
277
|
+
* Retrieves the sum value of the specified column
|
|
278
|
+
* for this Query
|
|
279
|
+
*
|
|
280
|
+
* ```ts
|
|
281
|
+
* await Game.query().sum('score')
|
|
282
|
+
* // 1
|
|
283
|
+
* ```
|
|
284
|
+
*
|
|
285
|
+
* @param columnName - a column name on the model
|
|
286
|
+
* @returns the sum of the values of the specified column for this Query
|
|
287
|
+
*/
|
|
288
|
+
// eslint-disable-next-line @typescript-eslint/require-await, @typescript-eslint/no-unused-vars
|
|
289
|
+
async sum(columnName) {
|
|
290
|
+
throw new Error('implement sum in child class');
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Retrieves the average value of the specified column
|
|
294
|
+
* for this Query
|
|
295
|
+
*
|
|
296
|
+
* ```ts
|
|
297
|
+
* await Game.query().avg('score')
|
|
298
|
+
* // 1
|
|
299
|
+
* ```
|
|
300
|
+
*
|
|
301
|
+
* @param columnName - a column name on the model
|
|
302
|
+
* @returns the average of the values of the specified column for this Query
|
|
303
|
+
*/
|
|
304
|
+
// eslint-disable-next-line @typescript-eslint/require-await, @typescript-eslint/no-unused-vars
|
|
305
|
+
async avg(columnName) {
|
|
306
|
+
throw new Error('implement avg in child class');
|
|
307
|
+
}
|
|
276
308
|
/**
|
|
277
309
|
* Retrieves the number of records in the database
|
|
278
310
|
*
|
|
@@ -67,6 +67,7 @@ import sqlResultToDreamInstance from '../internal/sqlResultToDreamInstance.js';
|
|
|
67
67
|
import Query from '../Query.js';
|
|
68
68
|
import QueryDriverBase from './Base.js';
|
|
69
69
|
import checkForNeedToBeRunMigrations from './helpers/kysely/checkForNeedToBeRunMigrations.js';
|
|
70
|
+
import foreignKeyTypeFromPrimaryKey from './helpers/kysely/foreignKeyTypeFromPrimaryKey.js';
|
|
70
71
|
import runMigration from './helpers/kysely/runMigration.js';
|
|
71
72
|
export default class KyselyQueryDriver extends QueryDriverBase {
|
|
72
73
|
// ATTENTION FRED
|
|
@@ -194,6 +195,7 @@ export default class KyselyQueryDriver extends QueryDriverBase {
|
|
|
194
195
|
}
|
|
195
196
|
}
|
|
196
197
|
catch (error) {
|
|
198
|
+
// eslint-disable-next-line no-console
|
|
197
199
|
console.error(error);
|
|
198
200
|
await DreamCLI.logger.logProgress('[dream] sync failed, reverting file contents...', async () => {
|
|
199
201
|
await CliFileWriter.revert();
|
|
@@ -210,12 +212,7 @@ export default class KyselyQueryDriver extends QueryDriverBase {
|
|
|
210
212
|
* gives the driver the opportunity to switch i.e. bigserial to bigint.
|
|
211
213
|
*/
|
|
212
214
|
static foreignKeyTypeFromPrimaryKey(primaryKey) {
|
|
213
|
-
|
|
214
|
-
case 'bigserial':
|
|
215
|
-
return 'bigint';
|
|
216
|
-
default:
|
|
217
|
-
return primaryKey;
|
|
218
|
-
}
|
|
215
|
+
return foreignKeyTypeFromPrimaryKey(primaryKey);
|
|
219
216
|
}
|
|
220
217
|
/**
|
|
221
218
|
* @internal
|
|
@@ -228,6 +225,8 @@ export default class KyselyQueryDriver extends QueryDriverBase {
|
|
|
228
225
|
switch (dreamconf.primaryKeyType) {
|
|
229
226
|
case 'bigint':
|
|
230
227
|
case 'bigserial':
|
|
228
|
+
case 'uuid7':
|
|
229
|
+
case 'uuid4':
|
|
231
230
|
case 'uuid':
|
|
232
231
|
case 'integer':
|
|
233
232
|
return dreamconf.primaryKeyType;
|
|
@@ -452,6 +451,52 @@ export default class KyselyQueryDriver extends QueryDriverBase {
|
|
|
452
451
|
const data = await executeDatabaseQuery(kyselyQuery, 'executeTakeFirstOrThrow');
|
|
453
452
|
return data.min;
|
|
454
453
|
}
|
|
454
|
+
/**
|
|
455
|
+
* Retrieves the sum value of the specified column
|
|
456
|
+
* for this Query
|
|
457
|
+
*
|
|
458
|
+
* ```ts
|
|
459
|
+
* await Game.query().sum('score')
|
|
460
|
+
* // 1
|
|
461
|
+
* ```
|
|
462
|
+
*
|
|
463
|
+
* @param columnName - a column name on the model
|
|
464
|
+
* @returns the sum of the values of the specified column for this Query
|
|
465
|
+
*/
|
|
466
|
+
async sum(columnName) {
|
|
467
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
468
|
+
const { sum } = this.dbFor('select').fn;
|
|
469
|
+
let kyselyQuery = new this.constructor(this.query).buildSelect({
|
|
470
|
+
bypassSelectAll: true,
|
|
471
|
+
bypassOrder: true,
|
|
472
|
+
});
|
|
473
|
+
kyselyQuery = kyselyQuery.select(sum(columnName));
|
|
474
|
+
const data = await executeDatabaseQuery(kyselyQuery, 'executeTakeFirstOrThrow');
|
|
475
|
+
return data.sum === null ? null : parseFloat(data.sum);
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Retrieves the average value of the specified column
|
|
479
|
+
* for this Query
|
|
480
|
+
*
|
|
481
|
+
* ```ts
|
|
482
|
+
* await Game.query().avg('score')
|
|
483
|
+
* // 1
|
|
484
|
+
* ```
|
|
485
|
+
*
|
|
486
|
+
* @param columnName - a column name on the model
|
|
487
|
+
* @returns the average of the values of the specified column for this Query
|
|
488
|
+
*/
|
|
489
|
+
async avg(columnName) {
|
|
490
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
491
|
+
const { avg } = this.dbFor('select').fn;
|
|
492
|
+
let kyselyQuery = new this.constructor(this.query).buildSelect({
|
|
493
|
+
bypassSelectAll: true,
|
|
494
|
+
bypassOrder: true,
|
|
495
|
+
});
|
|
496
|
+
kyselyQuery = kyselyQuery.select(avg(columnName));
|
|
497
|
+
const data = await executeDatabaseQuery(kyselyQuery, 'executeTakeFirstOrThrow');
|
|
498
|
+
return data.avg;
|
|
499
|
+
}
|
|
455
500
|
/**
|
|
456
501
|
* Retrieves the number of records in the database
|
|
457
502
|
*
|
|
@@ -893,6 +938,7 @@ export default class KyselyQueryDriver extends QueryDriverBase {
|
|
|
893
938
|
const hasMany = association.type === 'HasMany';
|
|
894
939
|
// initialize by trying to access the association, which throws an exception if not yet initialized
|
|
895
940
|
try {
|
|
941
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
896
942
|
;
|
|
897
943
|
dream[association.as];
|
|
898
944
|
}
|
|
@@ -7,7 +7,9 @@ export default function printSerializerHierarchyLevel({ serializerAssociationTyp
|
|
|
7
7
|
});
|
|
8
8
|
const prefix = `${hierarchyLine} `;
|
|
9
9
|
const nestedAssociationDisplay = indentation + `${prefix}${serializerAssociationType} ${yoctocolors.cyan(serializerAssociationName)}`;
|
|
10
|
+
// eslint-disable-next-line no-console
|
|
10
11
|
console.log(nestedAssociationDisplay);
|
|
12
|
+
// eslint-disable-next-line no-console
|
|
11
13
|
console.log(yoctocolors.gray(indentation +
|
|
12
14
|
indent(prefix.length, { tabWidth: 1 }) +
|
|
13
15
|
associationSerializer.globalName));
|
|
@@ -4,7 +4,9 @@ export default class DreamImporter {
|
|
|
4
4
|
static async ls(dir) {
|
|
5
5
|
try {
|
|
6
6
|
const dirents = await fs.readdir(dir, { withFileTypes: true });
|
|
7
|
-
const files = await Promise.all(
|
|
7
|
+
const files = await Promise.all(
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/await-thenable
|
|
9
|
+
dirents
|
|
8
10
|
.map(dirent => {
|
|
9
11
|
const res = path.resolve(dir, dirent.name);
|
|
10
12
|
return dirent.isDirectory()
|
|
@@ -137,6 +137,7 @@ export default class DreamApp {
|
|
|
137
137
|
}
|
|
138
138
|
static checkKey(encryptionIdentifier, key, algorithm) {
|
|
139
139
|
if (!Encrypt.validateKey(key, algorithm))
|
|
140
|
+
// eslint-disable-next-line no-console
|
|
140
141
|
console.warn(`
|
|
141
142
|
Your current key value for ${encryptionIdentifier} encryption is invalid.
|
|
142
143
|
Try setting it to something valid, like:
|
|
@@ -410,7 +411,7 @@ function argToString(arg) {
|
|
|
410
411
|
return arg.toISO();
|
|
411
412
|
return util.inspect(arg, { depth: 3 });
|
|
412
413
|
}
|
|
413
|
-
export const DreamAppAllowedPackageManagersEnumValues = ['
|
|
414
|
+
export const DreamAppAllowedPackageManagersEnumValues = ['pnpm', 'yarn', 'npm'];
|
|
414
415
|
// GeneratorImportStyles are used by CLI generators to determine how
|
|
415
416
|
// to style import suffixes. When integrating with other apps, this
|
|
416
417
|
// suffix style can change, and may need to be configured.
|
|
@@ -38,12 +38,14 @@ export default class Env {
|
|
|
38
38
|
return this.optional(env) === '1';
|
|
39
39
|
}
|
|
40
40
|
setString(env, val) {
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
41
42
|
val === undefined ? delete process.env[env] : (process.env[env] = val);
|
|
42
43
|
}
|
|
43
44
|
unsetString(env) {
|
|
44
45
|
delete process.env[env];
|
|
45
46
|
}
|
|
46
47
|
setInteger(env, val) {
|
|
48
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
47
49
|
val === undefined ? delete process.env[env] : (process.env[env] = Math.floor(val).toString());
|
|
48
50
|
}
|
|
49
51
|
unsetInteger(env) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as fs from 'node:fs/promises';
|
|
2
|
+
import DreamCLI from '../../cli/index.js';
|
|
2
3
|
import dreamFileAndDirPaths from '../path/dreamFileAndDirPaths.js';
|
|
3
4
|
import dreamPath from '../path/dreamPath.js';
|
|
4
5
|
import standardizeFullyQualifiedModelName from '../standardizeFullyQualifiedModelName.js';
|
|
@@ -11,7 +12,7 @@ export default async function generateDream({ fullyQualifiedModelName, columnsWi
|
|
|
11
12
|
fullyQualifiedModelName = standardizeFullyQualifiedModelName(fullyQualifiedModelName);
|
|
12
13
|
const { relFilePath, absDirPath, absFilePath } = dreamFileAndDirPaths(dreamPath('models'), `${fullyQualifiedModelName}.ts`);
|
|
13
14
|
try {
|
|
14
|
-
|
|
15
|
+
DreamCLI.logger.log(`[dream] generating dream: ${relFilePath}`);
|
|
15
16
|
await fs.mkdir(absDirPath, { recursive: true });
|
|
16
17
|
await fs.writeFile(absFilePath, generateDreamContent({
|
|
17
18
|
fullyQualifiedModelName,
|
|
@@ -3,11 +3,12 @@ import dreamFileAndDirPaths from '../path/dreamFileAndDirPaths.js';
|
|
|
3
3
|
import dreamPath from '../path/dreamPath.js';
|
|
4
4
|
import standardizeFullyQualifiedModelName from '../standardizeFullyQualifiedModelName.js';
|
|
5
5
|
import generateFactoryContent from './generateFactoryContent.js';
|
|
6
|
+
import DreamCLI from '../../cli/index.js';
|
|
6
7
|
export default async function generateFactory({ fullyQualifiedModelName, columnsWithTypes, }) {
|
|
7
8
|
fullyQualifiedModelName = standardizeFullyQualifiedModelName(fullyQualifiedModelName);
|
|
8
9
|
const { relFilePath, absDirPath, absFilePath } = dreamFileAndDirPaths(dreamPath('factories'), `${fullyQualifiedModelName}Factory.ts`);
|
|
9
10
|
try {
|
|
10
|
-
|
|
11
|
+
DreamCLI.logger.log(`[dream] generating factory: ${relFilePath}`);
|
|
11
12
|
await fs.mkdir(absDirPath, { recursive: true });
|
|
12
13
|
await fs.writeFile(absFilePath, generateFactoryContent({ fullyQualifiedModelName, columnsWithTypes }));
|
|
13
14
|
}
|
|
@@ -9,16 +9,17 @@ export default function generateFactoryContent({ fullyQualifiedModelName, column
|
|
|
9
9
|
const dreamTypeImports = ['UpdateableProperties'];
|
|
10
10
|
const dreamImports = [];
|
|
11
11
|
const additionalImports = [];
|
|
12
|
+
const nodeImports = [];
|
|
12
13
|
const belongsToNames = [];
|
|
13
14
|
const belongsToTypedNames = [];
|
|
14
15
|
const associationCreationStatements = [];
|
|
15
16
|
const attributeDefaults = [];
|
|
16
17
|
let counterVariableIncremented = false;
|
|
17
18
|
for (const attribute of columnsWithTypes) {
|
|
18
|
-
const [attributeName,
|
|
19
|
+
const [attributeName, _attributeType, ...descriptors] = attribute.split(':');
|
|
19
20
|
if (attributeName === undefined)
|
|
20
21
|
continue;
|
|
21
|
-
if (
|
|
22
|
+
if (_attributeType === undefined)
|
|
22
23
|
continue;
|
|
23
24
|
const optional = optionalFromDescriptors(descriptors);
|
|
24
25
|
if (optional)
|
|
@@ -28,6 +29,7 @@ export default function generateFactoryContent({ fullyQualifiedModelName, column
|
|
|
28
29
|
continue;
|
|
29
30
|
if (/(_type|_id)$/.test(attributeName))
|
|
30
31
|
continue;
|
|
32
|
+
const attributeType = /uuid$/.test(attributeName) ? 'uuid' : _attributeType;
|
|
31
33
|
if (!attributeType)
|
|
32
34
|
throw new Error(`Must pass a column type for ${attributeName} (i.e. ${attributeName}:string)`);
|
|
33
35
|
const safeAttributeType = camelize(attributeType)?.toLowerCase();
|
|
@@ -95,6 +97,14 @@ export default function generateFactoryContent({ fullyQualifiedModelName, column
|
|
|
95
97
|
dreamImports.push('DateTime');
|
|
96
98
|
attributeDefaults.push(`${attributeVariable}: [DateTime.now()],`);
|
|
97
99
|
break;
|
|
100
|
+
case 'uuid':
|
|
101
|
+
nodeImports.push('randomUUID');
|
|
102
|
+
attributeDefaults.push(`${attributeVariable}: randomUUID(),`);
|
|
103
|
+
break;
|
|
104
|
+
case 'uuid[]':
|
|
105
|
+
nodeImports.push('randomUUID');
|
|
106
|
+
attributeDefaults.push(`${attributeVariable}: [randomUUID()],`);
|
|
107
|
+
break;
|
|
98
108
|
default:
|
|
99
109
|
if (/\[\]$/.test(attributeType)) {
|
|
100
110
|
attributeDefaults.push(`${attributeVariable}: [],`);
|
|
@@ -105,7 +115,7 @@ export default function generateFactoryContent({ fullyQualifiedModelName, column
|
|
|
105
115
|
const relativePath = absoluteDreamPath('models', fullyQualifiedModelName);
|
|
106
116
|
const modelClassName = globalClassNameFromFullyQualifiedModelName(fullyQualifiedModelName);
|
|
107
117
|
return `\
|
|
108
|
-
${dreamImports.length ? `import { ${uniq(dreamImports).join(', ')} } from '@rvoh/dream'\n` : ''}import { ${uniq(dreamTypeImports).join(', ')} } from '@rvoh/dream/types'
|
|
118
|
+
${nodeImports.length ? `import { ${uniq(nodeImports).join(', ')} } from 'node:crypto'\n` : ''}${dreamImports.length ? `import { ${uniq(dreamImports).join(', ')} } from '@rvoh/dream'\n` : ''}import { ${uniq(dreamTypeImports).join(', ')} } from '@rvoh/dream/types'
|
|
109
119
|
import ${modelClassName} from '${relativePath}'${additionalImports.length ? '\n' + uniq(additionalImports).join('\n') : ''}
|
|
110
120
|
${counterVariableIncremented ? '\nlet counter = 0\n' : ''}
|
|
111
121
|
export default async function create${modelClassName}(attrs: UpdateableProperties<${modelClassName}> = {}) {
|
|
@@ -10,6 +10,7 @@ import dreamFileAndDirPaths from '../path/dreamFileAndDirPaths.js';
|
|
|
10
10
|
import dreamPath from '../path/dreamPath.js';
|
|
11
11
|
import snakeify from '../snakeify.js';
|
|
12
12
|
import generateStiMigrationContent from './generateStiMigrationContent.js';
|
|
13
|
+
import DreamCLI from '../../cli/index.js';
|
|
13
14
|
export default async function generateMigration({ migrationName, columnsWithTypes, connectionName, fullyQualifiedModelName, fullyQualifiedParentName, }) {
|
|
14
15
|
const { relFilePath, absFilePath } = connectionName === 'default'
|
|
15
16
|
? dreamFileAndDirPaths(path.join(dreamPath('db'), 'migrations'), `${migrationVersion()}-${hyphenize(migrationName).replace(/\//g, '-')}.ts`)
|
|
@@ -41,7 +42,7 @@ export default async function generateMigration({ migrationName, columnsWithType
|
|
|
41
42
|
});
|
|
42
43
|
}
|
|
43
44
|
try {
|
|
44
|
-
|
|
45
|
+
DreamCLI.logger.log(`[dream] generating migration: ${relFilePath}`);
|
|
45
46
|
await fs.writeFile(absFilePath, finalContent);
|
|
46
47
|
}
|
|
47
48
|
catch (error) {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import pluralize from 'pluralize-esm';
|
|
2
2
|
import Query from '../../dream/Query.js';
|
|
3
3
|
import InvalidDecimalFieldPassedToGenerator from '../../errors/InvalidDecimalFieldPassedToGenerator.js';
|
|
4
|
+
import camelize from '../camelize.js';
|
|
4
5
|
import compact from '../compact.js';
|
|
5
6
|
import snakeify from '../snakeify.js';
|
|
6
|
-
import camelize from '../camelize.js';
|
|
7
7
|
const STI_TYPE_COLUMN_NAME = 'type';
|
|
8
8
|
const COLUMNS_TO_INDEX = [STI_TYPE_COLUMN_NAME];
|
|
9
9
|
export default function generateMigrationContent({ connectionName = 'default', table, columnsWithTypes = [], primaryKeyType = 'bigserial', createOrAlter = 'create', stiChildClassName, } = {}) {
|
|
@@ -13,11 +13,17 @@ export default function generateMigrationContent({ connectionName = 'default', t
|
|
|
13
13
|
const { columnDefs, columnDrops, indexDefs, indexDrops } = columnsWithTypes.reduce((acc, attributeDeclaration) => {
|
|
14
14
|
const { columnDefs, columnDrops, indexDefs, indexDrops } = acc;
|
|
15
15
|
const [nonStandardAttributeName, _attributeType, ...descriptors] = attributeDeclaration.split(':');
|
|
16
|
+
if (!nonStandardAttributeName)
|
|
17
|
+
return acc;
|
|
16
18
|
/**
|
|
17
19
|
* Automatically set email columns to citext since different casings of
|
|
18
20
|
* email address are the same email address
|
|
19
21
|
*/
|
|
20
|
-
const attributeType = nonStandardAttributeName
|
|
22
|
+
const attributeType = /email$/.test(nonStandardAttributeName)
|
|
23
|
+
? 'citext'
|
|
24
|
+
: /uuid$/.test(nonStandardAttributeName)
|
|
25
|
+
? 'uuid'
|
|
26
|
+
: _attributeType;
|
|
21
27
|
const processedAttrType = camelize(attributeType)?.toLowerCase();
|
|
22
28
|
const userWantsThisOptional = optionalFromDescriptors(descriptors);
|
|
23
29
|
// when creating a migration for an STI child, we don't want to include notNull;
|
|
@@ -232,7 +238,7 @@ function generateColumnStr(attributeName, attributeType, descriptors, { omitInli
|
|
|
232
238
|
const providedDefaultArg = descriptors.find(d => /^default\(/.test(d));
|
|
233
239
|
const providedDefault = providedDefaultArg?.replace(/^default\(/, '')?.replace(/\)$/, '');
|
|
234
240
|
const notNull = !optional;
|
|
235
|
-
const isUnique =
|
|
241
|
+
const isUnique = /(email|token|uuid)$/.test(attributeName);
|
|
236
242
|
const hasExtraValues = providedDefault || notNull || isUnique;
|
|
237
243
|
const isArray = /\[\]$/.test(attributeType);
|
|
238
244
|
if (hasExtraValues)
|
|
@@ -249,7 +255,7 @@ function generateColumnStr(attributeName, attributeType, descriptors, { omitInli
|
|
|
249
255
|
if (attributeName === STI_TYPE_COLUMN_NAME)
|
|
250
256
|
returnStr = `// CONSIDER: when using type for STI, always use an enum
|
|
251
257
|
// Try using the enum syntax in your generator, e.g.:
|
|
252
|
-
//
|
|
258
|
+
// pnpm psy g:model Balloon type:enum:balloon_type:latex,mylar
|
|
253
259
|
${returnStr}`;
|
|
254
260
|
return returnStr;
|
|
255
261
|
}
|
|
@@ -281,6 +287,14 @@ function generateBelongsToStr(connectionName, associationName, { primaryKeyType,
|
|
|
281
287
|
}
|
|
282
288
|
function generateIdStr({ primaryKeyType }) {
|
|
283
289
|
switch (primaryKeyType) {
|
|
290
|
+
case 'uuid7':
|
|
291
|
+
return `\
|
|
292
|
+
.addColumn('id', 'uuid', col =>
|
|
293
|
+
col
|
|
294
|
+
.primaryKey()
|
|
295
|
+
.defaultTo(sql\`uuid_generate_v7()\`),
|
|
296
|
+
)`;
|
|
297
|
+
case 'uuid4':
|
|
284
298
|
case 'uuid':
|
|
285
299
|
return `\
|
|
286
300
|
.addColumn('id', 'uuid', col =>
|
|
@@ -3,11 +3,12 @@ import dreamFileAndDirPaths from '../path/dreamFileAndDirPaths.js';
|
|
|
3
3
|
import dreamPath from '../path/dreamPath.js';
|
|
4
4
|
import standardizeFullyQualifiedModelName from '../standardizeFullyQualifiedModelName.js';
|
|
5
5
|
import generateSerializerContent from './generateSerializerContent.js';
|
|
6
|
+
import DreamCLI from '../../cli/index.js';
|
|
6
7
|
export default async function generateSerializer({ fullyQualifiedModelName, columnsWithTypes, fullyQualifiedParentName, stiBaseSerializer, includeAdminSerializers, }) {
|
|
7
8
|
fullyQualifiedModelName = standardizeFullyQualifiedModelName(fullyQualifiedModelName);
|
|
8
9
|
const { relFilePath, absDirPath, absFilePath } = dreamFileAndDirPaths(dreamPath('serializers'), `${fullyQualifiedModelName}Serializer.ts`);
|
|
9
10
|
try {
|
|
10
|
-
|
|
11
|
+
DreamCLI.logger.log(`[dream] generating serializer: ${relFilePath}`);
|
|
11
12
|
await fs.mkdir(absDirPath, { recursive: true });
|
|
12
13
|
await fs.writeFile(absFilePath, generateSerializerContent({
|
|
13
14
|
fullyQualifiedModelName,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as fs from 'node:fs/promises';
|
|
2
|
+
import DreamCLI from '../../cli/index.js';
|
|
2
3
|
import dreamFileAndDirPaths from '../path/dreamFileAndDirPaths.js';
|
|
3
4
|
import dreamPath from '../path/dreamPath.js';
|
|
4
5
|
import standardizeFullyQualifiedModelName from '../standardizeFullyQualifiedModelName.js';
|
|
@@ -7,7 +8,7 @@ export default async function generateUnitSpec({ fullyQualifiedModelName, }) {
|
|
|
7
8
|
fullyQualifiedModelName = standardizeFullyQualifiedModelName(fullyQualifiedModelName);
|
|
8
9
|
const { relFilePath, absDirPath, absFilePath } = dreamFileAndDirPaths(dreamPath('modelSpecs'), `${fullyQualifiedModelName}.spec.ts`);
|
|
9
10
|
try {
|
|
10
|
-
|
|
11
|
+
DreamCLI.logger.log(`[dream] generating spec: ${relFilePath}`);
|
|
11
12
|
await fs.mkdir(absDirPath, { recursive: true });
|
|
12
13
|
await fs.writeFile(absFilePath, generateUnitSpecContent({ fullyQualifiedModelName }));
|
|
13
14
|
}
|
|
@@ -3,7 +3,9 @@ import * as path from 'node:path';
|
|
|
3
3
|
export default async function getFiles(dir) {
|
|
4
4
|
try {
|
|
5
5
|
const dirents = await fs.readdir(dir, { withFileTypes: true });
|
|
6
|
-
const files = await Promise.all(
|
|
6
|
+
const files = await Promise.all(
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/await-thenable
|
|
8
|
+
dirents.map(dirent => {
|
|
7
9
|
const res = path.resolve(dir, dirent.name);
|
|
8
10
|
return dirent.isDirectory() ? getFiles(res) : res.replace(/\.ts$/, '.js');
|
|
9
11
|
}));
|