From 9f49c7d2eb8c3d86e35ded6134f96e195d6ebd58 Mon Sep 17 00:00:00 2001 From: Morgan Zolob Date: Wed, 13 Dec 2023 14:16:17 -0800 Subject: [PATCH] Add omitRelations option Adds an option which will fully omit relations from the generated model definitions. --- README.md | 37 +++++------ generator.ts | 13 ++-- package-lock.json | 4 +- package.json | 2 +- .../expected/mongoOmitRelations.ts | 31 ++++++++++ tests/mongo-types/schema.prisma | 8 +++ .../expected/omitRelations.ts | 61 +++++++++++++++++++ tests/options-behavior/schema.prisma | 7 +++ 8 files changed, 137 insertions(+), 26 deletions(-) create mode 100644 tests/mongo-types/expected/mongoOmitRelations.ts create mode 100644 tests/options-behavior/expected/omitRelations.ts diff --git a/README.md b/README.md index 4852d97..aed8566 100644 --- a/README.md +++ b/README.md @@ -46,24 +46,25 @@ Note that `bigint` types don't have a default `toJSON` method, so the above assu ## Options -| **Option** | **Type** | **Default** | **Description** | -| ----------------- | :----------------------------------------------------: | :------------------------------------------------------------------------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| output | `string` | `"interfaces.ts"` | The output location for the generated Typescript interfaces. | -| enumPrefix | `string` | `""` | Prefix to add to enum types. | -| enumSuffix | `string` | `""` | Suffix to add to enum types. | -| modelPrefix | `string` | `""` | Prefix to add to model types. | -| modelSuffix | `string` | `""` | Suffix to add to model types. | -| typePrefix | `string` | `""` | Prefix to add to [type](https://www.prisma.io/docs/concepts/components/prisma-schema/data-model#defining-composite-types) types (mongodb only). | -| typeSuffix | `string` | `""` | Suffix to add to [type](https://www.prisma.io/docs/concepts/components/prisma-schema/data-model#defining-composite-types) types (mongodb only). | -| headerComment | `string` | `"This file was auto-generated by prisma-generator-typescript-interfaces"` | Sets the header comment added to the top of the generated file. Set this to an empty string to disable the header comment. Supports multiple lines with `"\n"`. | -| modelType | `"interface" \| "type"` | `"interface"` | Controls how model definitions are generated. `"interface"` will create Typescript interfaces, `"type"` will create Typescript types. If using mongodb, this also affects `type` definitions. | -| enumType | `"stringUnion" \| "enum"` | `"stringUnion"` | Controls how enums are generated. `"enum"` will create Typescript enums, `"stringUnion"` will create union types with all the enum values. | -| dateType | `"Date" \| "string" \| "number"` | `"Date"` | The type to use for DateTime model fields. | -| bigIntType | `"bigint" \| "string" \| "number"` | `"bigint"` | The type to use for BigInt model fields. | -| decimalType | `"Decimal" \| "string" \| "number"` | `"Decimal"` | The type to use for Decimal model fields. Note that the `Decimal` type here is just an interface with a `getValue()` function. You will need to cast to an actual Decimal type if you want to use other methods. | -| bytesType | `"Buffer" \| "BufferObject" \| "string" \| "number[]"` | `"Buffer"` | The type to use for Bytes model fields. `BufferObject` is a type definition which matches the output of `Buffer.toJSON()`, which is called when running `JSON.stringify()` on a Buffer. | -| optionalRelations | `boolean` | `true` | Controls whether model relation fields are optional or not. If `true`, all model relation fields will use `?:` in the field definition. | -| prettier | `boolean` | `false` | Formats the output using Prettier. Setting this to `true` requires that the `prettier` package is available. [Prettier settings files](https://prettier.io/docs/en/configuration.html) will be respected. | +| **Option** | **Type** | **Default** | **Description** | +| ----------------- | :----------------------------------------------------: | :------------------------------------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| output | `string` | `"interfaces.ts"` | The output location for the generated Typescript interfaces. | +| enumPrefix | `string` | `""` | Prefix to add to enum types. | +| enumSuffix | `string` | `""` | Suffix to add to enum types. | +| modelPrefix | `string` | `""` | Prefix to add to model types. | +| modelSuffix | `string` | `""` | Suffix to add to model types. | +| typePrefix | `string` | `""` | Prefix to add to [type](https://www.prisma.io/docs/concepts/components/prisma-schema/data-model#defining-composite-types) types (mongodb only). | +| typeSuffix | `string` | `""` | Suffix to add to [type](https://www.prisma.io/docs/concepts/components/prisma-schema/data-model#defining-composite-types) types (mongodb only). | +| headerComment | `string` | `"This file was auto-generated by prisma-generator-typescript-interfaces"` | Sets the header comment added to the top of the generated file. Set this to an empty string to disable the header comment. Supports multiple lines with `"\n"`. | +| modelType | `"interface" \| "type"` | `"interface"` | Controls how model definitions are generated. `"interface"` will create Typescript interfaces, `"type"` will create Typescript types. If using mongodb, this also affects `type` definitions. | +| enumType | `"stringUnion" \| "enum"` | `"stringUnion"` | Controls how enums are generated. `"enum"` will create Typescript enums, `"stringUnion"` will create union types with all the enum values. | +| dateType | `"Date" \| "string" \| "number"` | `"Date"` | The type to use for DateTime model fields. | +| bigIntType | `"bigint" \| "string" \| "number"` | `"bigint"` | The type to use for BigInt model fields. | +| decimalType | `"Decimal" \| "string" \| "number"` | `"Decimal"` | The type to use for Decimal model fields. The `Decimal` type here is just an interface with a `getValue()` function. You will need to cast to an actual Decimal type if you want to use other methods. | +| bytesType | `"Buffer" \| "BufferObject" \| "string" \| "number[]"` | `"Buffer"` | The type to use for Bytes model fields. `BufferObject` is a type definition which matches the output of `Buffer.toJSON()`, which is called when running `JSON.stringify()` on a Buffer. | +| optionalRelations | `boolean` | `true` | Controls whether model relation fields are optional. If `true`, all model relation fields will use `?:` in the field definition. | +| omitRelations | `boolean` | `false` | Controls whether model relation fields are omitted. If `true`, model definitions will not include their relations. | +| prettier | `boolean` | `false` | Formats the output using Prettier. Setting this to `true` requires that the `prettier` package is available. | ## Example diff --git a/generator.ts b/generator.ts index 5799b17..02e4505 100644 --- a/generator.ts +++ b/generator.ts @@ -22,6 +22,7 @@ interface Config { decimalType: "Decimal" | "string" | "number"; bytesType: "Buffer" | "BufferObject" | "string" | "number[]"; optionalRelations: boolean; + omitRelations: boolean; prettier: boolean; } @@ -123,13 +124,13 @@ function getModelTs( case "object": { const modelName = modelNameMap.get(type); const typeName = typeNameMap.get(type); - if (!modelName && !typeName) { + if (typeName) { + return getDefinition(typeName); // Type relations are never optional or omitted + } else if (modelName) { + return config.omitRelations ? null : getDefinition(modelName, config.optionalRelations); + } else { throw new Error(`Unknown model name: ${type}`); } - return getDefinition( - (modelName ?? typeName) as string, - config.optionalRelations && !typeName, // Type relations are never optional - ); } case "enum": { const enumName = enumNameMap.get(type); @@ -144,6 +145,7 @@ function getModelTs( throw new Error(`Unknown field kind: ${kind}`); } }) + .filter((f) => f !== null) .join("\n"); const name = modelNameMap.get(modelData.name) ?? typeNameMap.get(modelData.name); @@ -184,6 +186,7 @@ generatorHandler({ ...baseConfig, // Booleans go here since in the base config they are strings optionalRelations: baseConfig.optionalRelations !== "false", // Default true + omitRelations: baseConfig.omitRelations === "true", // Default false prettier: baseConfig.prettier === "true", // Default false }; diff --git a/package-lock.json b/package-lock.json index a423def..f1e9fcc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "prisma-generator-typescript-interfaces", - "version": "1.3.0", + "version": "1.4.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "prisma-generator-typescript-interfaces", - "version": "1.3.0", + "version": "1.4.0", "license": "MIT", "dependencies": { "@prisma/generator-helper": "^5.7.0" diff --git a/package.json b/package.json index fc63623..3098fbe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prisma-generator-typescript-interfaces", - "version": "1.3.0", + "version": "1.4.0", "description": "Generate zero-dependency Typescript interfaces from Prisma schema", "author": "Morgan Zolob", "license": "MIT", diff --git a/tests/mongo-types/expected/mongoOmitRelations.ts b/tests/mongo-types/expected/mongoOmitRelations.ts new file mode 100644 index 0000000..b2fa5c6 --- /dev/null +++ b/tests/mongo-types/expected/mongoOmitRelations.ts @@ -0,0 +1,31 @@ +// This file was auto-generated by prisma-generator-typescript-interfaces + +export type Gender = "Male" | "Female" | "Other"; + +export type PhotoType = "Selfie" | "Profile" | "Tagged"; + +export interface Person { + id: number; + name: string; + gender: Gender; + addressId: number; + photos: Photo[]; + tags: Tag | null; +} + +export interface Address { + id: number; + addressText: string; +} + +export interface Photo { + height: number; + Width: number; + url: string; + type: PhotoType; +} + +export interface Tag { + id: number; + name: string; +} diff --git a/tests/mongo-types/schema.prisma b/tests/mongo-types/schema.prisma index 20ea2b9..95541ac 100644 --- a/tests/mongo-types/schema.prisma +++ b/tests/mongo-types/schema.prisma @@ -10,12 +10,20 @@ generator mongoTypes { output = "mongoTypes.ts" } +// Ensure modelType = "type" also applies to `type` definitions generator mongoModelType { provider = "node --loader ts-node/esm generator.ts" output = "mongoModelType.ts" modelType = "type" } +// Ensure omitRelations does not apply to `type` definitions (since they always exist on the object) +generator mongoOmitRelations { + provider = "node --loader ts-node/esm generator.ts" + output = "mongoOmitRelations.ts" + omitRelations = true +} + generator prefixSuffix { provider = "node --loader ts-node/esm generator.ts" output = "prefixSuffix.ts" diff --git a/tests/options-behavior/expected/omitRelations.ts b/tests/options-behavior/expected/omitRelations.ts new file mode 100644 index 0000000..0d4811f --- /dev/null +++ b/tests/options-behavior/expected/omitRelations.ts @@ -0,0 +1,61 @@ +// This file was auto-generated by prisma-generator-typescript-interfaces + +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; +} + +export interface Address { + id: number; + streetNumber: number; + streetName: string; + city: string; + isBilling: boolean; +} + +export interface Data { + id: string; + stringField: string; + booleanField: boolean; + intField: number; + bigIntField: bigint; + floatField: number; + decimalField: Decimal; + dateField: Date; + jsonField: JsonValue; + bytesField: Buffer; + 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: Buffer | null; + optionalEnumField: DataTest | null; + stringArrayField: string[]; + booleanArrayField: boolean[]; + intArrayField: number[]; + bigIntArrayField: bigint[]; + floatArrayField: number[]; + decimalArrayField: Decimal[]; + dateArrayField: Date[]; + jsonArrayField: JsonValue[]; + bytesArrayField: Buffer[]; + enumArrayField: DataTest[]; + personId: number; +} + +type Decimal = { valueOf(): string }; + +type JsonValue = string | number | boolean | { [key in string]?: JsonValue } | Array | null; diff --git a/tests/options-behavior/schema.prisma b/tests/options-behavior/schema.prisma index 699acdd..3468d1b 100644 --- a/tests/options-behavior/schema.prisma +++ b/tests/options-behavior/schema.prisma @@ -4,6 +4,7 @@ // Generator Tests // ======================== +// Unlike other tests, this one should output to the default "interfaces.ts" generator noOptions { provider = "node --loader ts-node/esm generator.ts" } @@ -43,6 +44,12 @@ generator requiredRelations { optionalRelations = false } +generator omitRelations { + provider = "node --loader ts-node/esm generator.ts" + output = "omitRelations.ts" + omitRelations = true +} + generator prefixSuffix { provider = "node --loader ts-node/esm generator.ts" output = "prefixSuffix.ts"