From 30c3085f3ae49d2b00aec0f0d6f423d230af81ef Mon Sep 17 00:00:00 2001 From: Morgan Zolob Date: Fri, 17 Nov 2023 16:23:20 -0800 Subject: [PATCH] Fix type compatibility issues Fixes issues where the types were not compatible with the corresponding types from the Prisma client. Also adds additional options for bytes types. BufferObject matches the default JSON.stringify output for a Buffer object. --- generator.ts | 69 ++++++++++------- prisma/example.prisma | 15 +++- test.ts | 72 +++++++++++++----- tests/base.mongo.prisma | 45 +++++++++++ tests/{base.prisma => base.postgres.prisma} | 10 +++ .../buffer-array-type/expected/interfaces.ts | 65 ++++++++++++++++ tests/buffer-array-type/schema.prisma | 6 ++ .../buffer-object-type/expected/interfaces.ts | 67 +++++++++++++++++ tests/buffer-object-type/schema.prisma | 6 ++ tests/custom-output/expected/generated.ts | 29 ++++---- tests/custom-output/schema.prisma | 2 +- .../expected/interfaces.ts | 74 +++++++++++++++++++ .../schema.prisma | 4 +- .../expected/interfaces.ts | 36 ++++++--- tests/{union-enums => enums}/schema.prisma | 4 +- tests/mongo-types/expected/interfaces.ts | 16 +--- tests/mongo-types/schema.prisma | 45 +---------- tests/no-custom-types/schema.prisma | 2 +- tests/no-options/expected/interfaces.ts | 29 ++++---- tests/no-options/schema.prisma | 2 +- tests/prefix-suffix/expected/interfaces.ts | 67 ++++------------- tests/prefix-suffix/schema.prisma | 4 +- tests/prettier/expected/interfaces.ts | 29 ++++---- tests/prettier/schema.prisma | 2 +- .../expected/interfaces.ts | 11 ++- tests/required-relations/schema.prisma | 6 ++ .../expected/interfaces.ts | 25 ++++--- .../schema.prisma | 2 +- tests/validation-errors/expected-error.txt | 1 - tests/validation-errors/schema.prisma | 2 +- 30 files changed, 507 insertions(+), 240 deletions(-) create mode 100644 tests/base.mongo.prisma rename tests/{base.prisma => base.postgres.prisma} (91%) create mode 100644 tests/buffer-array-type/expected/interfaces.ts create mode 100644 tests/buffer-array-type/schema.prisma create mode 100644 tests/buffer-object-type/expected/interfaces.ts create mode 100644 tests/buffer-object-type/schema.prisma create mode 100644 tests/enums-prefix-suffix/expected/interfaces.ts rename tests/{union-enums-prefix-suffix => enums-prefix-suffix}/schema.prisma (68%) rename tests/{union-enums-prefix-suffix => enums}/expected/interfaces.ts (66%) rename tests/{union-enums => enums}/schema.prisma (57%) rename tests/{union-enums => required-relations}/expected/interfaces.ts (81%) create mode 100644 tests/required-relations/schema.prisma rename tests/{changed-types => string-types}/expected/interfaces.ts (72%) rename tests/{changed-types => string-types}/schema.prisma (84%) diff --git a/generator.ts b/generator.ts index e22037d..503d362 100644 --- a/generator.ts +++ b/generator.ts @@ -4,15 +4,18 @@ import { dirname } from "node:path"; interface Config { enumType: "stringUnion" | "enum"; - enumSuffix: string; enumPrefix: string; - modelSuffix: string; + enumSuffix: string; modelPrefix: string; + modelSuffix: string; + typePrefix: string; + typeSuffix: string; dateType: "string" | "Date"; bigIntType: "string" | "bigint"; decimalType: "string" | "Decimal"; - bytesType: "Buffer" | "string"; - prettier: "true" | "false"; + bytesType: "string" | "Buffer" | "BufferObject" | "number[]"; + optionalRelations: boolean; + prettier: boolean; } // Map of Prisma scalar types to Typescript type getters @@ -31,9 +34,10 @@ const SCALAR_TYPE_GETTERS: Record string> = { // Since we want the output to have zero dependencies, define custom types which are compatible // with the actual Prisma types. If users need the real Prisma types, they can cast to them. const CUSTOM_TYPES: Record = { + BufferObject: 'type BufferObject = { type: "Buffer"; data: number[] };', + Decimal: "type Decimal = { valueOf(): string };", JsonValue: - "type JsonValue = string | number | boolean | { [key in string]: JsonValue } | Array | null;", - Decimal: "interface Decimal {\n valueOf(): string;\n}", + "type JsonValue = string | number | boolean | { [key in string]?: JsonValue } | Array | null;", }; function validateConfig(config: Config) { @@ -50,12 +54,9 @@ function validateConfig(config: Config) { if (!["string", "Decimal"].includes(config.decimalType)) { errors.push(`Invalid decimalType: ${config.decimalType}`); } - if (!["Buffer", "string"].includes(config.bytesType)) { + if (!["string", "Buffer", "BufferObject", "number[]"].includes(config.bytesType)) { errors.push(`Invalid bytesType: ${config.bytesType}`); } - if (!["true", "false"].includes(config.prettier)) { - errors.push(`Invalid prettier: ${config.prettier}`); - } if (errors.length > 0) { throw new Error(errors.join("\n")); } @@ -87,12 +88,15 @@ function getModelTs( modelData: DMMF.Model, modelNameMap: Map, enumNameMap: Map, + typeNameMap: Map, usedCustomTypes: Set, ): string { const fields = modelData.fields .map(({ name, kind, type, isRequired, isList }) => { - const getDefinition = (resolvedType: string) => - ` ${name}: ${resolvedType}${isList ? "[]" : ""}${!isRequired ? " | null" : ""};`; + const getDefinition = (resolvedType: string, optional = false) => + ` ${name}${optional ? "?" : ""}: ${resolvedType}${isList ? "[]" : ""}${ + !isRequired ? " | null" : "" + };`; switch (kind) { case "scalar": { @@ -108,10 +112,14 @@ function getModelTs( } case "object": { const modelName = modelNameMap.get(type); - if (!modelName) { + const typeName = typeNameMap.get(type); + if (!modelName && !typeName) { throw new Error(`Unknown model name: ${type}`); } - return getDefinition(modelName); + return getDefinition( + (modelName ?? typeName) as string, + config.optionalRelations && !typeName, // Type relations are never optional + ); } case "enum": { const enumName = enumNameMap.get(type); @@ -128,7 +136,8 @@ function getModelTs( }) .join("\n"); - return `export interface ${modelNameMap.get(modelData.name)} {\n${fields}\n}`; + const name = modelNameMap.get(modelData.name) ?? typeNameMap.get(modelData.name); + return `export interface ${name} {\n${fields}\n}`; } generatorHandler({ @@ -139,27 +148,31 @@ generatorHandler({ }; }, async onGenerate(options) { + const baseConfig = options.generator.config; const config: Config = { - enumType: "enum", - enumSuffix: "", + enumType: "stringUnion", enumPrefix: "", - modelSuffix: "", + enumSuffix: "", modelPrefix: "", + modelSuffix: "", + typePrefix: "", + typeSuffix: "", dateType: "Date", bigIntType: "bigint", decimalType: "Decimal", bytesType: "Buffer", - prettier: "false", - ...options.generator.config, + ...baseConfig, + // Booleans go here since in the base config they are strings + optionalRelations: baseConfig.optionalRelations !== "false", // Default true + prettier: baseConfig.prettier === "true", // Default false }; validateConfig(config); const datamodel = options.dmmf.datamodel; + const models = datamodel.models; const enums = datamodel.enums; - - // For the purposes of this generator, models and types are equivalent - const models = [...datamodel.models, ...datamodel.types]; + const types = datamodel.types; const usedCustomTypes = new Set(); @@ -169,16 +182,20 @@ generatorHandler({ const modelNameMap = new Map( models.map((m) => [m.name, `${config.modelPrefix}${m.name}${config.modelSuffix}`]), ); + const typeNameMap = new Map( + types.map((t) => [t.name, `${config.typePrefix}${t.name}${config.typeSuffix}`]), + ); const enumsTs = enums.map((e) => getEnumTs(config, e, enumNameMap)); - const modelsTs = models.map((m) => - getModelTs(config, m, modelNameMap, enumNameMap, usedCustomTypes), + // Types and Models are essentially the same thing, so we can run both through getModelTs + const modelsTs = [...models, ...types].map((m) => + getModelTs(config, m, modelNameMap, enumNameMap, typeNameMap, usedCustomTypes), ); const customTypesTs = Array.from(usedCustomTypes).map((t) => CUSTOM_TYPES[t]); let ts = [...enumsTs, ...modelsTs, ...customTypesTs].join("\n\n") + "\n"; - if (config.prettier === "true") { + if (config.prettier) { // Prettier is imported inside this if so that it's not a required dependency let prettier: typeof import("prettier"); try { diff --git a/prisma/example.prisma b/prisma/example.prisma index eec3f64..88e8d26 100644 --- a/prisma/example.prisma +++ b/prisma/example.prisma @@ -3,7 +3,7 @@ datasource db { provider = "postgresql" - url = "" + url = "postgresql://postgres:password@localhost:5432/testing?schema=public" } generator client { @@ -16,6 +16,17 @@ generator typescriptInterfaces { prettier = true } +generator typescriptInterfacesJson { + provider = "node --loader ts-node/esm generator.ts" + output = "exampleJson.ts" + modelSuffix = "Json" + dateType = "string" + bigIntType = "string" + decimalType = "string" + bytesType = "BufferObject" + prettier = true +} + enum Gender { Male Female @@ -30,8 +41,8 @@ model Person { gender Gender addressId Int address Address @relation(fields: [addressId], references: [id]) - friends Person[] @relation("Friends") friendsOf Person[] @relation("Friends") + friends Person[] @relation("Friends") data Data? } diff --git a/test.ts b/test.ts index ba054cd..a6d1c47 100644 --- a/test.ts +++ b/test.ts @@ -5,7 +5,10 @@ * "expected-error.txt" file in the relevant test folder. * * You can run specific tests by passing the one(s) you want to run as arguments to this script: - * npm run test custom-output no-options prettier + * npm run test -- custom-output no-options prettier + * + * If you want to run all tests even if some fail, pass the --continue or -c flag: + * npm run test -- -c */ import { exec } from "node:child_process"; @@ -15,7 +18,7 @@ import fs from "node:fs/promises"; import path from "node:path"; const TEMP_TEST_DIRNAME = "__TEST_TMP__"; -const BASE_REPLACE_STRING = "// TEST_INSERT_BASE_HERE"; +const BASE_REPLACE_REGEX = /^\/\/ ?#INSERT base\.([a-z]+)\.prisma$/gm; const RED = "\x1b[1m\x1b[41m\x1b[97m"; const GREEN = "\x1b[1m\x1b[42m\x1b[97m"; const RESET = "\x1b[0m"; @@ -29,29 +32,50 @@ const trimMultiLine = (s: string) => .map((l) => l.trim()) .join("\n"); -const testFilters = process.argv.slice(2); +let testFilters = process.argv.slice(2); + +// Continue on errors if --continue or -c is passed +let continueOnError = false; +let hasErrors = false; +if (testFilters.some((f) => f === "--continue" || f === "-c")) { + continueOnError = true; + testFilters = testFilters.filter((f) => f !== "--continue" && f !== "-c"); +} -const tests = (await fs.readdir("tests", { withFileTypes: true })) - .filter( - (dirent) => dirent.isDirectory() && (!testFilters.length || testFilters.includes(dirent.name)), - ) - .map((t) => path.join(t.path, t.name)); +const testsEntries = await fs.readdir("tests", { withFileTypes: true }); +const tests = testsEntries + .filter((d) => d.isDirectory() && (!testFilters.length || testFilters.includes(d.name))) + .map((d) => path.join(d.path, d.name)); + +// Common schemas used by multiple tests +const baseSchemas = new Map( + await Promise.all( + testsEntries + .filter((f) => f.isFile() && /^base\.[a-z]+\.prisma$/.test(f.name)) + .map>((f) => + readFile(path.join(f.path, f.name)).then((c) => [f.name, c]), + ), + ), +); // Get the length of the longest test name, so we can pad the output const longestName = Math.max(...tests.map((t) => t.length)); -// Common schema text used by many of the tests -const baseSchema = await readFile(path.join("tests", "base.prisma")); - console.log("Running tests..."); -try { - for (const test of tests) { +for (const test of tests) { + try { process.stdout.write(` ${test}${" ".repeat(longestName - test.length + 2)}`); - const schema = (await readFile(path.join(test, "schema.prisma"))).replace( - BASE_REPLACE_STRING, - baseSchema, + const schema = (await readFile(path.join(test, "schema.prisma"))).replaceAll( + BASE_REPLACE_REGEX, + (_, baseName) => { + const baseSchema = baseSchemas.get(`base.${baseName}.prisma`); + if (!baseSchema) { + throw new Error(`Unknown base schema: ${baseName}`); + } + return baseSchema; + }, ); let expectedError: string | null; // Text of expected stderr after a non-zero exit code @@ -119,11 +143,19 @@ try { process.stdout.write(GREEN + " PASS " + RESET + "\n"); await rimraf(testDir); + } catch (e) { + process.stdout.write(RED + " FAIL " + RESET + "\n\n"); + console.error((e as Error).message, "\n"); + hasErrors = true; + if (!continueOnError) { + process.exit(1); + } } +} - console.log("\n\nAll tests passed!"); -} catch (e) { - process.stdout.write(RED + " FAIL " + RESET + "\n\n"); - console.error((e as Error).message); +if (hasErrors) { + console.error("\nSome tests failed!"); process.exit(1); +} else { + console.log("\nAll tests passed!"); } diff --git a/tests/base.mongo.prisma b/tests/base.mongo.prisma new file mode 100644 index 0000000..9d39f40 --- /dev/null +++ b/tests/base.mongo.prisma @@ -0,0 +1,45 @@ +// We need to use mongo to test composite types +datasource db { + provider = "mongodb" + url = "" +} + +enum Gender { + Male + Female + Other +} + +enum PhotoType { + Selfie + Profile + Tagged +} + +model Person { + id Int @id @map("_id") + name String + gender Gender + addressId Int + address Address @relation(fields: [addressId], references: [id]) + photos Photo[] + tags Tag? +} + +model Address { + id Int @id @map("_id") + addresText String + people Person[] +} + +type Photo { + height Int + Width Int + url String + type PhotoType +} + +type Tag { + id Int + name String +} diff --git a/tests/base.prisma b/tests/base.postgres.prisma similarity index 91% rename from tests/base.prisma rename to tests/base.postgres.prisma index fae81ef..c480d79 100644 --- a/tests/base.prisma +++ b/tests/base.postgres.prisma @@ -10,6 +10,13 @@ enum Gender { Other } +enum DataTest { + Apple + Banana + Orange + Pear +} + model Person { id Int @id @default(autoincrement()) name String @@ -43,6 +50,7 @@ model Data { dateField DateTime jsonField Json bytesField Bytes + enumField DataTest optionalStringField String? optionalBooleanField Boolean? @@ -53,6 +61,7 @@ model Data { optionalDateField DateTime? optionalJsonField Json? optionalBytesField Bytes? + optionalEnumField DataTest? stringArrayField String[] booleanArrayField Boolean[] @@ -63,6 +72,7 @@ model Data { dateArrayField DateTime[] jsonArrayField Json[] bytesArrayField Bytes[] + enumArrayField DataTest[] personId Int @unique person Person @relation(fields: [personId], references: [id]) diff --git a/tests/buffer-array-type/expected/interfaces.ts b/tests/buffer-array-type/expected/interfaces.ts new file mode 100644 index 0000000..977085a --- /dev/null +++ b/tests/buffer-array-type/expected/interfaces.ts @@ -0,0 +1,65 @@ +export type Gender = "Male" | "Female" | "Other"; + +export type DataTest = "Apple" | "Banana" | "Orange" | "Pear"; + +export interface Person { + id: number; + name: string; + age: number; + email: string | null; + gender: Gender; + addressId: number; + address?: Address; + friends?: Person[]; + friendsOf?: Person[]; + data?: Data | null; +} + +export interface Address { + id: number; + streetNumber: number; + streetName: string; + city: string; + isBilling: boolean; + people?: Person[]; +} + +export interface Data { + id: string; + stringField: string; + booleanField: boolean; + intField: number; + bigIntField: bigint; + floatField: number; + decimalField: Decimal; + dateField: Date; + jsonField: JsonValue; + bytesField: number[]; + enumField: DataTest; + optionalStringField: string | null; + optionalBooleanField: boolean | null; + optionalIntField: number | null; + optionalBigIntField: bigint | null; + optionalFloatField: number | null; + optionalDecimalField: Decimal | null; + optionalDateField: Date | null; + optionalJsonField: JsonValue | null; + optionalBytesField: number[] | null; + optionalEnumField: DataTest | null; + stringArrayField: string[]; + booleanArrayField: boolean[]; + intArrayField: number[]; + bigIntArrayField: bigint[]; + floatArrayField: number[]; + decimalArrayField: Decimal[]; + dateArrayField: Date[]; + jsonArrayField: JsonValue[]; + bytesArrayField: number[][]; + enumArrayField: DataTest[]; + personId: number; + person?: Person; +} + +type Decimal = { valueOf(): string }; + +type JsonValue = string | number | boolean | { [key in string]?: JsonValue } | Array | null; diff --git a/tests/buffer-array-type/schema.prisma b/tests/buffer-array-type/schema.prisma new file mode 100644 index 0000000..80b7cc2 --- /dev/null +++ b/tests/buffer-array-type/schema.prisma @@ -0,0 +1,6 @@ +generator typescriptInterfaces { + provider = "node generator.js" + bytesType = "number[]" +} + +// #INSERT base.postgres.prisma diff --git a/tests/buffer-object-type/expected/interfaces.ts b/tests/buffer-object-type/expected/interfaces.ts new file mode 100644 index 0000000..53c1ff4 --- /dev/null +++ b/tests/buffer-object-type/expected/interfaces.ts @@ -0,0 +1,67 @@ +export type Gender = "Male" | "Female" | "Other"; + +export type DataTest = "Apple" | "Banana" | "Orange" | "Pear"; + +export interface Person { + id: number; + name: string; + age: number; + email: string | null; + gender: Gender; + addressId: number; + address?: Address; + friends?: Person[]; + friendsOf?: Person[]; + data?: Data | null; +} + +export interface Address { + id: number; + streetNumber: number; + streetName: string; + city: string; + isBilling: boolean; + people?: Person[]; +} + +export interface Data { + id: string; + stringField: string; + booleanField: boolean; + intField: number; + bigIntField: bigint; + floatField: number; + decimalField: Decimal; + dateField: Date; + jsonField: JsonValue; + bytesField: BufferObject; + enumField: DataTest; + optionalStringField: string | null; + optionalBooleanField: boolean | null; + optionalIntField: number | null; + optionalBigIntField: bigint | null; + optionalFloatField: number | null; + optionalDecimalField: Decimal | null; + optionalDateField: Date | null; + optionalJsonField: JsonValue | null; + optionalBytesField: BufferObject | null; + optionalEnumField: DataTest | null; + stringArrayField: string[]; + booleanArrayField: boolean[]; + intArrayField: number[]; + bigIntArrayField: bigint[]; + floatArrayField: number[]; + decimalArrayField: Decimal[]; + dateArrayField: Date[]; + jsonArrayField: JsonValue[]; + bytesArrayField: BufferObject[]; + enumArrayField: DataTest[]; + personId: number; + person?: Person; +} + +type Decimal = { valueOf(): string }; + +type JsonValue = string | number | boolean | { [key in string]?: JsonValue } | Array | null; + +type BufferObject = { type: "Buffer"; data: number[] }; diff --git a/tests/buffer-object-type/schema.prisma b/tests/buffer-object-type/schema.prisma new file mode 100644 index 0000000..cec0bc0 --- /dev/null +++ b/tests/buffer-object-type/schema.prisma @@ -0,0 +1,6 @@ +generator typescriptInterfaces { + provider = "node generator.js" + bytesType = "BufferObject" +} + +// #INSERT base.postgres.prisma diff --git a/tests/custom-output/expected/generated.ts b/tests/custom-output/expected/generated.ts index 2003333..4ce581e 100644 --- a/tests/custom-output/expected/generated.ts +++ b/tests/custom-output/expected/generated.ts @@ -1,8 +1,6 @@ -export enum Gender { - Male = "Male", - Female = "Female", - Other = "Other" -} +export type Gender = "Male" | "Female" | "Other"; + +export type DataTest = "Apple" | "Banana" | "Orange" | "Pear"; export interface Person { id: number; @@ -11,10 +9,10 @@ export interface Person { email: string | null; gender: Gender; addressId: number; - address: Address; - friends: Person[]; - friendsOf: Person[]; - data: Data | null; + address?: Address; + friends?: Person[]; + friendsOf?: Person[]; + data?: Data | null; } export interface Address { @@ -23,7 +21,7 @@ export interface Address { streetName: string; city: string; isBilling: boolean; - people: Person[]; + people?: Person[]; } export interface Data { @@ -37,6 +35,7 @@ export interface Data { dateField: Date; jsonField: JsonValue; bytesField: Buffer; + enumField: DataTest; optionalStringField: string | null; optionalBooleanField: boolean | null; optionalIntField: number | null; @@ -46,6 +45,7 @@ export interface Data { optionalDateField: Date | null; optionalJsonField: JsonValue | null; optionalBytesField: Buffer | null; + optionalEnumField: DataTest | null; stringArrayField: string[]; booleanArrayField: boolean[]; intArrayField: number[]; @@ -55,12 +55,11 @@ export interface Data { dateArrayField: Date[]; jsonArrayField: JsonValue[]; bytesArrayField: Buffer[]; + enumArrayField: DataTest[]; personId: number; - person: Person; + person?: Person; } -interface Decimal { - valueOf(): string; -} +type Decimal = { valueOf(): string }; -type JsonValue = string | number | boolean | { [key in string]: JsonValue } | Array | null; +type JsonValue = string | number | boolean | { [key in string]?: JsonValue } | Array | null; diff --git a/tests/custom-output/schema.prisma b/tests/custom-output/schema.prisma index 73abbb0..7b63736 100644 --- a/tests/custom-output/schema.prisma +++ b/tests/custom-output/schema.prisma @@ -3,4 +3,4 @@ generator typescriptInterfaces { output = "generated.ts" } -// TEST_INSERT_BASE_HERE +// #INSERT base.postgres.prisma diff --git a/tests/enums-prefix-suffix/expected/interfaces.ts b/tests/enums-prefix-suffix/expected/interfaces.ts new file mode 100644 index 0000000..7b031b1 --- /dev/null +++ b/tests/enums-prefix-suffix/expected/interfaces.ts @@ -0,0 +1,74 @@ +export enum EnumGenderUnion { + Male = "Male", + Female = "Female", + Other = "Other" +} + +export enum EnumDataTestUnion { + Apple = "Apple", + Banana = "Banana", + Orange = "Orange", + Pear = "Pear" +} + +export interface Person { + id: number; + name: string; + age: number; + email: string | null; + gender: EnumGenderUnion; + addressId: number; + address?: Address; + friends?: Person[]; + friendsOf?: Person[]; + data?: Data | null; +} + +export interface Address { + id: number; + streetNumber: number; + streetName: string; + city: string; + isBilling: boolean; + people?: Person[]; +} + +export interface Data { + id: string; + stringField: string; + booleanField: boolean; + intField: number; + bigIntField: bigint; + floatField: number; + decimalField: Decimal; + dateField: Date; + jsonField: JsonValue; + bytesField: Buffer; + enumField: EnumDataTestUnion; + optionalStringField: string | null; + optionalBooleanField: boolean | null; + optionalIntField: number | null; + optionalBigIntField: bigint | null; + optionalFloatField: number | null; + optionalDecimalField: Decimal | null; + optionalDateField: Date | null; + optionalJsonField: JsonValue | null; + optionalBytesField: Buffer | null; + optionalEnumField: EnumDataTestUnion | null; + stringArrayField: string[]; + booleanArrayField: boolean[]; + intArrayField: number[]; + bigIntArrayField: bigint[]; + floatArrayField: number[]; + decimalArrayField: Decimal[]; + dateArrayField: Date[]; + jsonArrayField: JsonValue[]; + bytesArrayField: Buffer[]; + enumArrayField: EnumDataTestUnion[]; + personId: number; + person?: Person; +} + +type Decimal = { valueOf(): string }; + +type JsonValue = string | number | boolean | { [key in string]?: JsonValue } | Array | null; diff --git a/tests/union-enums-prefix-suffix/schema.prisma b/tests/enums-prefix-suffix/schema.prisma similarity index 68% rename from tests/union-enums-prefix-suffix/schema.prisma rename to tests/enums-prefix-suffix/schema.prisma index 9cbf14e..d1b5eb5 100644 --- a/tests/union-enums-prefix-suffix/schema.prisma +++ b/tests/enums-prefix-suffix/schema.prisma @@ -1,8 +1,8 @@ generator typescriptInterfaces { provider = "node generator.js" - enumType = "stringUnion" + enumType = "enum" enumPrefix = "Enum" enumSuffix = "Union" } -// TEST_INSERT_BASE_HERE +// #INSERT base.postgres.prisma diff --git a/tests/union-enums-prefix-suffix/expected/interfaces.ts b/tests/enums/expected/interfaces.ts similarity index 66% rename from tests/union-enums-prefix-suffix/expected/interfaces.ts rename to tests/enums/expected/interfaces.ts index e86c098..1f86d2d 100644 --- a/tests/union-enums-prefix-suffix/expected/interfaces.ts +++ b/tests/enums/expected/interfaces.ts @@ -1,16 +1,27 @@ -export type EnumGenderUnion = "Male" | "Female" | "Other"; +export enum Gender { + Male = "Male", + Female = "Female", + Other = "Other" +} + +export enum DataTest { + Apple = "Apple", + Banana = "Banana", + Orange = "Orange", + Pear = "Pear" +} export interface Person { id: number; name: string; age: number; email: string | null; - gender: EnumGenderUnion; + gender: Gender; addressId: number; - address: Address; - friends: Person[]; - friendsOf: Person[]; - data: Data | null; + address?: Address; + friends?: Person[]; + friendsOf?: Person[]; + data?: Data | null; } export interface Address { @@ -19,7 +30,7 @@ export interface Address { streetName: string; city: string; isBilling: boolean; - people: Person[]; + people?: Person[]; } export interface Data { @@ -33,6 +44,7 @@ export interface Data { dateField: Date; jsonField: JsonValue; bytesField: Buffer; + enumField: DataTest; optionalStringField: string | null; optionalBooleanField: boolean | null; optionalIntField: number | null; @@ -42,6 +54,7 @@ export interface Data { optionalDateField: Date | null; optionalJsonField: JsonValue | null; optionalBytesField: Buffer | null; + optionalEnumField: DataTest | null; stringArrayField: string[]; booleanArrayField: boolean[]; intArrayField: number[]; @@ -51,12 +64,11 @@ export interface Data { dateArrayField: Date[]; jsonArrayField: JsonValue[]; bytesArrayField: Buffer[]; + enumArrayField: DataTest[]; personId: number; - person: Person; + person?: Person; } -interface Decimal { - valueOf(): string; -} +type Decimal = { valueOf(): string }; -type JsonValue = string | number | boolean | { [key in string]: JsonValue } | Array | null; +type JsonValue = string | number | boolean | { [key in string]?: JsonValue } | Array | null; diff --git a/tests/union-enums/schema.prisma b/tests/enums/schema.prisma similarity index 57% rename from tests/union-enums/schema.prisma rename to tests/enums/schema.prisma index cd42fdd..395a805 100644 --- a/tests/union-enums/schema.prisma +++ b/tests/enums/schema.prisma @@ -1,6 +1,6 @@ generator typescriptInterfaces { provider = "node generator.js" - enumType = "stringUnion" + enumType = "enum" } -// TEST_INSERT_BASE_HERE +// #INSERT base.postgres.prisma diff --git a/tests/mongo-types/expected/interfaces.ts b/tests/mongo-types/expected/interfaces.ts index a1d6b57..ed19d41 100644 --- a/tests/mongo-types/expected/interfaces.ts +++ b/tests/mongo-types/expected/interfaces.ts @@ -1,21 +1,13 @@ -export enum Gender { - Male = "Male", - Female = "Female", - Other = "Other" -} +export type Gender = "Male" | "Female" | "Other"; -export enum PhotoType { - Selfie = "Selfie", - Profile = "Profile", - Tagged = "Tagged" -} +export type PhotoType = "Selfie" | "Profile" | "Tagged"; export interface Person { id: number; name: string; gender: Gender; addressId: number; - address: Address; + address?: Address; photos: Photo[]; tags: Tag | null; } @@ -23,7 +15,7 @@ export interface Person { export interface Address { id: number; addresText: string; - people: Person[]; + people?: Person[]; } export interface Photo { diff --git a/tests/mongo-types/schema.prisma b/tests/mongo-types/schema.prisma index d44c79a..53df48a 100644 --- a/tests/mongo-types/schema.prisma +++ b/tests/mongo-types/schema.prisma @@ -1,48 +1,5 @@ -datasource db { - provider = "mongodb" - url = "" -} - generator typescriptInterfaces { provider = "node generator.js" } -enum Gender { - Male - Female - Other -} - -enum PhotoType { - Selfie - Profile - Tagged -} - -model Person { - id Int @id @map("_id") - name String - gender Gender - addressId Int - address Address @relation(fields: [addressId], references: [id]) - photos Photo[] - tags Tag? -} - -model Address { - id Int @id @map("_id") - addresText String - people Person[] -} - -type Photo { - height Int - Width Int - url String - type PhotoType -} - -type Tag { - id Int - name String -} +// #INSERT base.mongo.prisma diff --git a/tests/no-custom-types/schema.prisma b/tests/no-custom-types/schema.prisma index c367a18..e5c1014 100644 --- a/tests/no-custom-types/schema.prisma +++ b/tests/no-custom-types/schema.prisma @@ -7,7 +7,7 @@ datasource db { url = "" } -// Basic model which does not use Json or Decimal +// Basic model which does not use custom types such as Json or Decimal model User { id String @id @default(cuid()) name String diff --git a/tests/no-options/expected/interfaces.ts b/tests/no-options/expected/interfaces.ts index 2003333..4ce581e 100644 --- a/tests/no-options/expected/interfaces.ts +++ b/tests/no-options/expected/interfaces.ts @@ -1,8 +1,6 @@ -export enum Gender { - Male = "Male", - Female = "Female", - Other = "Other" -} +export type Gender = "Male" | "Female" | "Other"; + +export type DataTest = "Apple" | "Banana" | "Orange" | "Pear"; export interface Person { id: number; @@ -11,10 +9,10 @@ export interface Person { email: string | null; gender: Gender; addressId: number; - address: Address; - friends: Person[]; - friendsOf: Person[]; - data: Data | null; + address?: Address; + friends?: Person[]; + friendsOf?: Person[]; + data?: Data | null; } export interface Address { @@ -23,7 +21,7 @@ export interface Address { streetName: string; city: string; isBilling: boolean; - people: Person[]; + people?: Person[]; } export interface Data { @@ -37,6 +35,7 @@ export interface Data { dateField: Date; jsonField: JsonValue; bytesField: Buffer; + enumField: DataTest; optionalStringField: string | null; optionalBooleanField: boolean | null; optionalIntField: number | null; @@ -46,6 +45,7 @@ export interface Data { optionalDateField: Date | null; optionalJsonField: JsonValue | null; optionalBytesField: Buffer | null; + optionalEnumField: DataTest | null; stringArrayField: string[]; booleanArrayField: boolean[]; intArrayField: number[]; @@ -55,12 +55,11 @@ export interface Data { dateArrayField: Date[]; jsonArrayField: JsonValue[]; bytesArrayField: Buffer[]; + enumArrayField: DataTest[]; personId: number; - person: Person; + person?: Person; } -interface Decimal { - valueOf(): string; -} +type Decimal = { valueOf(): string }; -type JsonValue = string | number | boolean | { [key in string]: JsonValue } | Array | null; +type JsonValue = string | number | boolean | { [key in string]?: JsonValue } | Array | null; diff --git a/tests/no-options/schema.prisma b/tests/no-options/schema.prisma index 63cd7b8..fc8316b 100644 --- a/tests/no-options/schema.prisma +++ b/tests/no-options/schema.prisma @@ -2,4 +2,4 @@ generator typescriptInterfaces { provider = "node generator.js" } -// TEST_INSERT_BASE_HERE +// #INSERT base.postgres.prisma diff --git a/tests/prefix-suffix/expected/interfaces.ts b/tests/prefix-suffix/expected/interfaces.ts index 065536d..24cc369 100644 --- a/tests/prefix-suffix/expected/interfaces.ts +++ b/tests/prefix-suffix/expected/interfaces.ts @@ -1,66 +1,31 @@ -export enum enumGenderEnum { - Male = "Male", - Female = "Female", - Other = "Other" -} +export type enumGenderEnum = "Male" | "Female" | "Other"; + +export type enumPhotoTypeEnum = "Selfie" | "Profile" | "Tagged"; export interface modelPersonModel { id: number; name: string; - age: number; - email: string | null; gender: enumGenderEnum; addressId: number; - address: modelAddressModel; - friends: modelPersonModel[]; - friendsOf: modelPersonModel[]; - data: modelDataModel | null; + address?: modelAddressModel; + photos: typePhotoType[]; + tags: typeTagType | null; } export interface modelAddressModel { id: number; - streetNumber: number; - streetName: string; - city: string; - isBilling: boolean; - people: modelPersonModel[]; + addresText: string; + people?: modelPersonModel[]; } -export interface modelDataModel { - id: string; - stringField: string; - booleanField: boolean; - intField: number; - bigIntField: bigint; - floatField: number; - decimalField: Decimal; - dateField: Date; - jsonField: JsonValue; - bytesField: Buffer; - optionalStringField: string | null; - optionalBooleanField: boolean | null; - optionalIntField: number | null; - optionalBigIntField: bigint | null; - optionalFloatField: number | null; - optionalDecimalField: Decimal | null; - optionalDateField: Date | null; - optionalJsonField: JsonValue | null; - optionalBytesField: Buffer | null; - stringArrayField: string[]; - booleanArrayField: boolean[]; - intArrayField: number[]; - bigIntArrayField: bigint[]; - floatArrayField: number[]; - decimalArrayField: Decimal[]; - dateArrayField: Date[]; - jsonArrayField: JsonValue[]; - bytesArrayField: Buffer[]; - personId: number; - person: modelPersonModel; +export interface typePhotoType { + height: number; + Width: number; + url: string; + type: enumPhotoTypeEnum; } -interface Decimal { - valueOf(): string; +export interface typeTagType { + id: number; + name: string; } - -type JsonValue = string | number | boolean | { [key in string]: JsonValue } | Array | null; diff --git a/tests/prefix-suffix/schema.prisma b/tests/prefix-suffix/schema.prisma index 1c1fd14..b251a3e 100644 --- a/tests/prefix-suffix/schema.prisma +++ b/tests/prefix-suffix/schema.prisma @@ -4,6 +4,8 @@ generator typescriptInterfaces { enumSuffix = "Enum" modelPrefix = "model" modelSuffix = "Model" + typePrefix = "type" + typeSuffix = "Type" } -// TEST_INSERT_BASE_HERE +// #INSERT base.mongo.prisma diff --git a/tests/prettier/expected/interfaces.ts b/tests/prettier/expected/interfaces.ts index 7b9bcbc..eee3254 100644 --- a/tests/prettier/expected/interfaces.ts +++ b/tests/prettier/expected/interfaces.ts @@ -1,8 +1,6 @@ -export enum Gender { - Male = "Male", - Female = "Female", - Other = "Other", -} +export type Gender = "Male" | "Female" | "Other"; + +export type DataTest = "Apple" | "Banana" | "Orange" | "Pear"; export interface Person { id: number; @@ -11,10 +9,10 @@ export interface Person { email: string | null; gender: Gender; addressId: number; - address: Address; - friends: Person[]; - friendsOf: Person[]; - data: Data | null; + address?: Address; + friends?: Person[]; + friendsOf?: Person[]; + data?: Data | null; } export interface Address { @@ -23,7 +21,7 @@ export interface Address { streetName: string; city: string; isBilling: boolean; - people: Person[]; + people?: Person[]; } export interface Data { @@ -37,6 +35,7 @@ export interface Data { dateField: Date; jsonField: JsonValue; bytesField: Buffer; + enumField: DataTest; optionalStringField: string | null; optionalBooleanField: boolean | null; optionalIntField: number | null; @@ -46,6 +45,7 @@ export interface Data { optionalDateField: Date | null; optionalJsonField: JsonValue | null; optionalBytesField: Buffer | null; + optionalEnumField: DataTest | null; stringArrayField: string[]; booleanArrayField: boolean[]; intArrayField: number[]; @@ -55,18 +55,17 @@ export interface Data { dateArrayField: Date[]; jsonArrayField: JsonValue[]; bytesArrayField: Buffer[]; + enumArrayField: DataTest[]; personId: number; - person: Person; + person?: Person; } -interface Decimal { - valueOf(): string; -} +type Decimal = { valueOf(): string }; type JsonValue = | string | number | boolean - | { [key in string]: JsonValue } + | { [key in string]?: JsonValue } | Array | null; diff --git a/tests/prettier/schema.prisma b/tests/prettier/schema.prisma index a9428ba..f990b4d 100644 --- a/tests/prettier/schema.prisma +++ b/tests/prettier/schema.prisma @@ -3,4 +3,4 @@ generator typescriptInterfaces { prettier = true } -// TEST_INSERT_BASE_HERE +// #INSERT base.postgres.prisma diff --git a/tests/union-enums/expected/interfaces.ts b/tests/required-relations/expected/interfaces.ts similarity index 81% rename from tests/union-enums/expected/interfaces.ts rename to tests/required-relations/expected/interfaces.ts index beeb8de..8b800af 100644 --- a/tests/union-enums/expected/interfaces.ts +++ b/tests/required-relations/expected/interfaces.ts @@ -1,5 +1,7 @@ export type Gender = "Male" | "Female" | "Other"; +export type DataTest = "Apple" | "Banana" | "Orange" | "Pear"; + export interface Person { id: number; name: string; @@ -33,6 +35,7 @@ export interface Data { dateField: Date; jsonField: JsonValue; bytesField: Buffer; + enumField: DataTest; optionalStringField: string | null; optionalBooleanField: boolean | null; optionalIntField: number | null; @@ -42,6 +45,7 @@ export interface Data { optionalDateField: Date | null; optionalJsonField: JsonValue | null; optionalBytesField: Buffer | null; + optionalEnumField: DataTest | null; stringArrayField: string[]; booleanArrayField: boolean[]; intArrayField: number[]; @@ -51,12 +55,11 @@ export interface Data { dateArrayField: Date[]; jsonArrayField: JsonValue[]; bytesArrayField: Buffer[]; + enumArrayField: DataTest[]; personId: number; person: Person; } -interface Decimal { - valueOf(): string; -} +type Decimal = { valueOf(): string }; -type JsonValue = string | number | boolean | { [key in string]: JsonValue } | Array | null; +type JsonValue = string | number | boolean | { [key in string]?: JsonValue } | Array | null; diff --git a/tests/required-relations/schema.prisma b/tests/required-relations/schema.prisma new file mode 100644 index 0000000..e06ebd4 --- /dev/null +++ b/tests/required-relations/schema.prisma @@ -0,0 +1,6 @@ +generator typescriptInterfaces { + provider = "node generator.js" + optionalRelations = false +} + +// #INSERT base.postgres.prisma diff --git a/tests/changed-types/expected/interfaces.ts b/tests/string-types/expected/interfaces.ts similarity index 72% rename from tests/changed-types/expected/interfaces.ts rename to tests/string-types/expected/interfaces.ts index edcb05b..55b42b8 100644 --- a/tests/changed-types/expected/interfaces.ts +++ b/tests/string-types/expected/interfaces.ts @@ -1,8 +1,6 @@ -export enum Gender { - Male = "Male", - Female = "Female", - Other = "Other" -} +export type Gender = "Male" | "Female" | "Other"; + +export type DataTest = "Apple" | "Banana" | "Orange" | "Pear"; export interface Person { id: number; @@ -11,10 +9,10 @@ export interface Person { email: string | null; gender: Gender; addressId: number; - address: Address; - friends: Person[]; - friendsOf: Person[]; - data: Data | null; + address?: Address; + friends?: Person[]; + friendsOf?: Person[]; + data?: Data | null; } export interface Address { @@ -23,7 +21,7 @@ export interface Address { streetName: string; city: string; isBilling: boolean; - people: Person[]; + people?: Person[]; } export interface Data { @@ -37,6 +35,7 @@ export interface Data { dateField: string; jsonField: JsonValue; bytesField: string; + enumField: DataTest; optionalStringField: string | null; optionalBooleanField: boolean | null; optionalIntField: number | null; @@ -46,6 +45,7 @@ export interface Data { optionalDateField: string | null; optionalJsonField: JsonValue | null; optionalBytesField: string | null; + optionalEnumField: DataTest | null; stringArrayField: string[]; booleanArrayField: boolean[]; intArrayField: number[]; @@ -55,8 +55,9 @@ export interface Data { dateArrayField: string[]; jsonArrayField: JsonValue[]; bytesArrayField: string[]; + enumArrayField: DataTest[]; personId: number; - person: Person; + person?: Person; } -type JsonValue = string | number | boolean | { [key in string]: JsonValue } | Array | null; +type JsonValue = string | number | boolean | { [key in string]?: JsonValue } | Array | null; diff --git a/tests/changed-types/schema.prisma b/tests/string-types/schema.prisma similarity index 84% rename from tests/changed-types/schema.prisma rename to tests/string-types/schema.prisma index dd4fb51..73dd734 100644 --- a/tests/changed-types/schema.prisma +++ b/tests/string-types/schema.prisma @@ -6,4 +6,4 @@ generator typescriptInterfaces { bytesType = "string" } -// TEST_INSERT_BASE_HERE +// #INSERT base.postgres.prisma diff --git a/tests/validation-errors/expected-error.txt b/tests/validation-errors/expected-error.txt index f1039d9..cd1ceeb 100644 --- a/tests/validation-errors/expected-error.txt +++ b/tests/validation-errors/expected-error.txt @@ -4,4 +4,3 @@ Invalid dateType: wrong Invalid bigIntType: values Invalid decimalType: go Invalid bytesType: here -Invalid prettier: bad diff --git a/tests/validation-errors/schema.prisma b/tests/validation-errors/schema.prisma index 82edd22..d3cd542 100644 --- a/tests/validation-errors/schema.prisma +++ b/tests/validation-errors/schema.prisma @@ -8,4 +8,4 @@ generator typescriptInterfaces { prettier = "bad" } -// TEST_INSERT_BASE_HERE +// #INSERT base.postgres.prisma