Repository: Quramy/prisma-fabbrica
Pull request #52 (2022-11-28 15:04:29)

fix: Json scalar field generation


Patch:
diff --git a/packages/prisma-fabbrica/src/scalar/types.ts b/packages/prisma-fabbrica/src/scalar/types.ts
index 65668f0..ce8b1e3 100644
--- a/packages/prisma-fabbrica/src/scalar/types.ts
+++ b/packages/prisma-fabbrica/src/scalar/types.ts
@@ -12,7 +12,7 @@ export interface ScalarFieldValueGenerator {
   Int: (options: ScalarFieldGenerateOptions) => number;
   Float: (options: ScalarFieldGenerateOptions) => number;
   BigInt: (options: ScalarFieldGenerateOptions) => bigint;
-  Decimal: (options: ScalarFieldGenerateOptions) => unknown;
+  Decimal: (options: ScalarFieldGenerateOptions) => any;
   DateTime: (options: ScalarFieldGenerateOptions) => Date;
   Bytes: (options: ScalarFieldGenerateOptions) => Buffer;
   Json: (options: ScalarFieldGenerateOptions) => any;
diff --git a/packages/prisma-fabbrica/src/templates/index.ts b/packages/prisma-fabbrica/src/templates/index.ts
index 5766e21..e699c46 100644
--- a/packages/prisma-fabbrica/src/templates/index.ts
+++ b/packages/prisma-fabbrica/src/templates/index.ts
@@ -20,10 +20,7 @@ function filterRequiredFields(inputType: DMMF.InputType) {
 }
 
 function isScalarOrEnumField(field: DMMF.SchemaArg) {
-  return (
-    field.inputTypes.length === 1 &&
-    field.inputTypes.every(cit => cit.location === "enumTypes" || cit.location === "scalar")
-  );
+  return field.inputTypes.every(cit => cit.location === "enumTypes" || cit.location === "scalar");
 }
 
 function isInputObjectTypeField(field: DMMF.SchemaArg) {
@@ -106,17 +103,15 @@ export const scalarFieldType = (
     case "Float":
       return ast.keywordTypeNode(ts.SyntaxKind.NumberKeyword);
     case "BigInt":
-      return ast.keywordTypeNode(ts.SyntaxKind.BigIntKeyword);
+      return template.typeNode`bigint | number`();
     case "Decimal":
-      return template.typeNode`Prisma.Decimal`();
+      return template.typeNode`Prisma.Decimal | Prisma.DecimalJsLike | string`();
     case "DateTime":
       return template.typeNode`Date`();
     case "Bytes":
       return template.typeNode`Buffer`();
     case "Json":
-      // FIXME Is the folloing type right?
-      // return template.typeNode`Prisma.Json`();
-      return ast.keywordTypeNode(ts.SyntaxKind.AnyKeyword);
+      return template.typeNode`Prisma.InputJsonValue`();
     default:
       throw new Error(`Unknown scalar type "${inputType.type}" for ${model.name}.${fieldName} .`);
   }
@@ -127,7 +122,9 @@ export const argInputType = (model: DMMF.Model, fieldName: string, inputType: DM
     if (inputType.location === "scalar") {
       return scalarFieldType(model, fieldName, inputType);
     } else if (inputType.location === "enumTypes") {
-      return ast.typeReferenceNode(ast.identifier(inputType.type as string));
+      return inputType.namespace === "model"
+        ? ast.typeReferenceNode(ast.identifier(inputType.type as string))
+        : template.typeNode`Prisma.${() => ast.identifier(inputType.type as string)}`();
     } else if (inputType.location === "outputObjectTypes" || inputType.location === "inputObjectTypes") {
       return ast.typeReferenceNode(
         template.expression<ts.Identifier>`Prisma.${() => ast.identifier(inputType.type as string)}`(),
@@ -230,11 +227,12 @@ export const autoGenerateModelScalarsOrEnumsFieldArgs = (
   field: DMMF.SchemaArg,
   enums: DMMF.SchemaEnum[],
 ) =>
-  field.inputTypes[0].location === "scalar"
+  // Note: In Json sclar filed, inputTypes[0].location is not scalar but enumType
+  field.inputTypes[field.inputTypes.length - 1].location === "scalar"
     ? template.expression`
         scalarFieldValueGenerator.SCALAR_TYPE({ modelName: MODEL_NAME, fieldName: FIELD_NAME, isId: IS_ID, isUnique: IS_UNIQUE, seq })
       `({
-        SCALAR_TYPE: ast.identifier(field.inputTypes[0].type as string),
+        SCALAR_TYPE: ast.identifier(field.inputTypes[field.inputTypes.length - 1].type as string),
         MODEL_NAME: ast.stringLiteral(model.name),
         FIELD_NAME: ast.stringLiteral(field.name),
         IS_ID:
@@ -384,18 +382,22 @@ export function getSourceFile({
   document: DMMF.Document;
   prismaClientModuleSpecifier?: string;
 }) {
-  const enums = [
+  const modelEnums = [
     ...new Set(
       document.schema.inputObjectTypes.prisma
         .filter(iOT => iOT.name.endsWith("CreateInput"))
         .flatMap(filterEnumFields)
-        .map(field => field.inputTypes[0].type as string),
+        .flatMap(field =>
+          field.inputTypes
+            .filter(inputType => inputType.namespace === "model")
+            .map(inputType => inputType.type as string),
+        ),
     ),
   ];
   const modelNames = document.datamodel.models.map(m => m.name);
   const statements = [
     ...modelNames.map(modelName => importStatement(modelName, prismaClientModuleSpecifier)),
-    ...enums.map(enumName => importStatement(enumName, prismaClientModuleSpecifier)),
+    ...modelEnums.map(enumName => importStatement(enumName, prismaClientModuleSpecifier)),
     ...header(prismaClientModuleSpecifier).statements,
     modelFieldDefinitions(document.datamodel.models),
     ...document.datamodel.models


Test patch:
diff --git a/packages/prisma-fabbrica/src/templates/modelScalarOrEnumFields.test.ts b/packages/prisma-fabbrica/src/templates/modelScalarOrEnumFields.test.ts
index 85b3b88..be18312 100644
--- a/packages/prisma-fabbrica/src/templates/modelScalarOrEnumFields.test.ts
+++ b/packages/prisma-fabbrica/src/templates/modelScalarOrEnumFields.test.ts
@@ -24,7 +24,7 @@ describe(modelScalarOrEnumFields, () => {
           boolField: boolean;
           strField: string;
           floatField: number;
-          bigIntField: bigint;
+          bigIntField: (bigint | number);
           bytesField: Buffer;
           dateTimeField: Date;
         }
diff --git a/packages/ts-compile-testing/fixtures/field-variation/__generated__/fabbrica/index.ts b/packages/ts-compile-testing/fixtures/field-variation/__generated__/fabbrica/index.ts
index 3873aa6..ed2da5a 100644
--- a/packages/ts-compile-testing/fixtures/field-variation/__generated__/fabbrica/index.ts
+++ b/packages/ts-compile-testing/fixtures/field-variation/__generated__/fabbrica/index.ts
@@ -1,5 +1,6 @@
 import { User } from "./../client";
 import { ComplexIdModel } from "./../client";
+import { FieldTypePatternModel } from "./../client";
 import { Role } from "./../client";
 import { Prisma } from "./../client";
 import type { PrismaClient } from "./../client";
@@ -8,7 +9,6 @@ import { ModelWithFields, createScreener } from "@quramy/prisma-fabbrica/lib/rel
 import scalarFieldValueGenerator from "@quramy/prisma-fabbrica/lib/scalar/gen";
 import { Resolver, normalizeResolver, getSequenceCounter } from "@quramy/prisma-fabbrica/lib/helpers";
 export { initialize, resetSequence } from "@quramy/prisma-fabbrica";
-
 type BuildDataOptions = {
     readonly seq: number;
 };
@@ -18,6 +18,9 @@ const modelFieldDefinitions: ModelWithFields[] = [{
     }, {
         name: "ComplexIdModel",
         fields: []
+    }, {
+        name: "FieldTypePatternModel",
+        fields: []
     }];
 type UserScalarOrEnumFields = {
     id: string;
@@ -25,7 +28,6 @@ type UserScalarOrEnumFields = {
 };
 type UserFactoryDefineInput = {
     id?: string;
-    nullableStr?: string | null;
     role?: Role;
     roleDefault?: Role;
     roles?: Prisma.UserCreaterolesInput | Prisma.Enumerable<Role>;
@@ -147,3 +149,94 @@ function defineComplexIdModelFactoryInternal({ defaultData: defaultDataResolver
 export function defineComplexIdModelFactory(args: ComplexIdModelFactoryDefineOptions = {}) {
     return defineComplexIdModelFactoryInternal(args);
 }
+type FieldTypePatternModelScalarOrEnumFields = {
+    id: number;
+    requiredInt: number;
+    requiredStr: string;
+    requiredBool: boolean;
+    requiredFlaot: number;
+    requiredDecimal: (Prisma.Decimal | Prisma.DecimalJsLike | string);
+    requiredJson: Prisma.JsonNullValueInput | Prisma.InputJsonValue;
+    requriedBytes: Buffer;
+    requiredBigInt: (bigint | number);
+};
+type FieldTypePatternModelFactoryDefineInput = {
+    id?: number;
+    requiredInt?: number;
+    nullableInt?: number | null;
+    requiredStr?: string;
+    nullableStr?: string | null;
+    requiredBool?: boolean;
+    nullableBool?: boolean | null;
+    requiredFlaot?: number;
+    nullableFloat?: number | null;
+    requiredDecimal?: (Prisma.Decimal | Prisma.DecimalJsLike | string);
+    nullableDecimal?: (Prisma.Decimal | Prisma.DecimalJsLike | string) | null;
+    requiredJson?: Prisma.JsonNullValueInput | Prisma.InputJsonValue;
+    nullableJson?: Prisma.NullableJsonNullValueInput | Prisma.InputJsonValue;
+    requriedBytes?: Buffer;
+    nullableBytes?: Buffer | null;
+    requiredBigInt?: (bigint | number);
+    nullableBigInt?: (bigint | number) | null;
+};
+type FieldTypePatternModelFactoryDefineOptions = {
+    defaultData?: Resolver<FieldTypePatternModelFactoryDefineInput, BuildDataOptions>;
+};
+function autoGenerateFieldTypePatternModelScalarsOrEnums({ seq }: {
+    readonly seq: number;
+}): FieldTypePatternModelScalarOrEnumFields {
+    return {
+        id: scalarFieldValueGenerator.Int({ modelName: "FieldTypePatternModel", fieldName: "id", isId: true, isUnique: false, seq }),
+        requiredInt: scalarFieldValueGenerator.Int({ modelName: "FieldTypePatternModel", fieldName: "requiredInt", isId: false, isUnique: false, seq }),
+        requiredStr: scalarFieldValueGenerator.String({ modelName: "FieldTypePatternModel", fieldName: "requiredStr", isId: false, isUnique: false, seq }),
+        requiredBool: scalarFieldValueGenerator.Boolean({ modelName: "FieldTypePatternModel", fieldName: "requiredBool", isId: false, isUnique: false, seq }),
+        requiredFlaot: scalarFieldValueGenerator.Float({ modelName: "FieldTypePatternModel", fieldName: "requiredFlaot", isId: false, isUnique: false, seq }),
+        requiredDecimal: scalarFieldValueGenerator.Decimal({ modelName: "FieldTypePatternModel", fieldName: "requiredDecimal", isId: false, isUnique: false, seq }),
+        requiredJson: scalarFieldValueGenerator.Json({ modelName: "FieldTypePatternModel", fieldName: "requiredJson", isId: false, isUnique: false, seq }),
+        requriedBytes: scalarFieldValueGenerator.Bytes({ modelName: "FieldTypePatternModel", fieldName: "requriedBytes", isId: false, isUnique: false, seq }),
+        requiredBigInt: scalarFieldValueGenerator.BigInt({ modelName: "FieldTypePatternModel", fieldName: "requiredBigInt", isId: false, isUnique: false, seq })
+    };
+}
+function defineFieldTypePatternModelFactoryInternal({ defaultData: defaultDataResolver }: FieldTypePatternModelFactoryDefineOptions) {
+    const seqKey = {};
+    const getSeq = () => getSequenceCounter(seqKey);
+    const screen = createScreener("FieldTypePatternModel", modelFieldDefinitions);
+    const build = async (inputData: Partial<Prisma.FieldTypePatternModelCreateInput> = {}) => {
+        const seq = getSeq();
+        const requiredScalarData = autoGenerateFieldTypePatternModelScalarsOrEnums({ seq });
+        const resolveValue = normalizeResolver<FieldTypePatternModelFactoryDefineInput, BuildDataOptions>(defaultDataResolver ?? {});
+        const defaultData = await resolveValue({ seq });
+        const defaultAssociations = {};
+        const data: Prisma.FieldTypePatternModelCreateInput = { ...requiredScalarData, ...defaultData, ...defaultAssociations, ...inputData };
+        return data;
+    };
+    const buildList = (inputData: number | Partial<Prisma.FieldTypePatternModelCreateInput>[]) => {
+        const list = typeof inputData === "number" ? [...new Array(inputData).keys()].map(() => ({})) : inputData;
+        return Promise.all(list.map(data => build(data)));
+    };
+    const pickForConnect = (inputData: FieldTypePatternModel) => ({
+        id: inputData.id
+    });
+    const create = async (inputData: Partial<Prisma.FieldTypePatternModelCreateInput> = {}) => {
+        const data = await build(inputData).then(screen);
+        return await getClient<PrismaClient>().fieldTypePatternModel.create({ data });
+    };
+    const createList = (inputData: number | Partial<Prisma.FieldTypePatternModelCreateInput>[]) => {
+        const list = typeof inputData === "number" ? [...new Array(inputData).keys()].map(() => ({})) : inputData;
+        return Promise.all(list.map(data => create(data)));
+    };
+    const createForConnect = (inputData: Partial<Prisma.FieldTypePatternModelCreateInput> = {}) => create(inputData).then(pickForConnect);
+    return {
+        _factoryFor: "FieldTypePatternModel" as const,
+        build,
+        buildList,
+        buildCreateInput: build,
+        pickForConnect,
+        create,
+        createList,
+        createForConnect,
+    };
+}
+export function defineFieldTypePatternModelFactory(args: FieldTypePatternModelFactoryDefineOptions = {}) {
+    return defineFieldTypePatternModelFactoryInternal(args);
+}
diff --git a/packages/ts-compile-testing/fixtures/field-variation/schema.prisma b/packages/ts-compile-testing/fixtures/field-variation/schema.prisma
index 43ed9c7..ed96db1 100644
--- a/packages/ts-compile-testing/fixtures/field-variation/schema.prisma
+++ b/packages/ts-compile-testing/fixtures/field-variation/schema.prisma
@@ -16,7 +16,6 @@ datasource db {
 
 model User {
   id           String @id
-  nullableStr  String?
   role         Role
   roleDefault  Role @default(USER)
   roles        Role[]
@@ -32,3 +31,23 @@ model ComplexIdModel {
   lastName  String
   @@id([firstName, lastName])
 }
+
+model FieldTypePatternModel {
+  id              Int @id
+  requiredInt     Int
+  nullableInt     Int?
+  requiredStr     String
+  nullableStr     String?
+  requiredBool    Boolean
+  nullableBool    Boolean?
+  requiredFlaot   Float
+  nullableFloat   Float?
+  requiredDecimal Decimal
+  nullableDecimal Decimal?
+  requiredJson    Json
+  nullableJson    Json?
+  requriedBytes   Bytes
+  nullableBytes   Bytes?
+  requiredBigInt  BigInt
+  nullableBigInt  BigInt?
+}