From e201b49b9f4f6c9c5fb4a90ce608f4fe33e4c143 Mon Sep 17 00:00:00 2001 From: Josh Calder Date: Thu, 12 Jan 2023 15:42:30 +1100 Subject: [PATCH] add field config --- .../custom-prisma-multischema/schema.graphql | 41 ++++++++++++++----- .../custom-prisma-multischema/schema.prisma | 16 ++++---- examples/custom-prisma-multischema/schema.ts | 37 +++++++++++++++-- .../core/src/fields/types/bigInt/index.ts | 2 + .../src/fields/types/calendarDay/index.ts | 2 + .../core/src/fields/types/checkbox/index.ts | 6 ++- .../core/src/fields/types/decimal/index.ts | 7 +++- packages/core/src/fields/types/file/index.ts | 4 ++ packages/core/src/fields/types/float/index.ts | 2 + packages/core/src/fields/types/image/index.ts | 4 ++ .../core/src/fields/types/integer/index.ts | 2 + packages/core/src/fields/types/json/index.ts | 3 +- .../src/fields/types/multiselect/index.ts | 2 + .../core/src/fields/types/password/index.ts | 2 + .../src/fields/types/relationship/index.ts | 4 ++ .../core/src/fields/types/select/index.ts | 2 + packages/core/src/fields/types/text/index.ts | 2 +- .../core/src/fields/types/timestamp/index.ts | 2 + .../src/lib/core/resolve-relationships.ts | 10 +++++ .../json-field-type-polyfill-for-sqlite.ts | 3 ++ packages/fields-document/src/index.ts | 3 +- 21 files changed, 128 insertions(+), 28 deletions(-) diff --git a/examples/custom-prisma-multischema/schema.graphql b/examples/custom-prisma-multischema/schema.graphql index 8d4db4656a1..038d01f5e1d 100644 --- a/examples/custom-prisma-multischema/schema.graphql +++ b/examples/custom-prisma-multischema/schema.graphql @@ -159,7 +159,8 @@ input PostRelateToManyForCreateInput { type PhoneNumber { id: ID! label: String - user: User + user(where: UserWhereInput! = {}, orderBy: [UserOrderByInput!]! = [], take: Int, skip: Int! = 0): [User!] + userCount(where: UserWhereInput! = {}): Int type: String value: String } @@ -173,11 +174,17 @@ input PhoneNumberWhereInput { OR: [PhoneNumberWhereInput!] NOT: [PhoneNumberWhereInput!] id: IDFilter - user: UserWhereInput + user: UserManyRelationFilter type: StringNullableFilter value: StringFilter } +input UserManyRelationFilter { + every: UserWhereInput + some: UserWhereInput + none: UserWhereInput +} + input StringNullableFilter { equals: String in: [String!] @@ -214,15 +221,16 @@ input PhoneNumberOrderByInput { } input PhoneNumberUpdateInput { - user: UserRelateToOneForUpdateInput + user: UserRelateToManyForUpdateInput type: String value: String } -input UserRelateToOneForUpdateInput { - create: UserCreateInput - connect: UserWhereUniqueInput - disconnect: Boolean +input UserRelateToManyForUpdateInput { + disconnect: [UserWhereUniqueInput!] + set: [UserWhereUniqueInput!] + create: [UserCreateInput!] + connect: [UserWhereUniqueInput!] } input PhoneNumberUpdateArgs { @@ -231,14 +239,14 @@ input PhoneNumberUpdateArgs { } input PhoneNumberCreateInput { - user: UserRelateToOneForCreateInput + user: UserRelateToManyForCreateInput type: String value: String } -input UserRelateToOneForCreateInput { - create: UserCreateInput - connect: UserWhereUniqueInput +input UserRelateToManyForCreateInput { + create: [UserCreateInput!] + connect: [UserWhereUniqueInput!] } type Post { @@ -297,6 +305,12 @@ input PostUpdateInput { author: UserRelateToOneForUpdateInput } +input UserRelateToOneForUpdateInput { + create: UserCreateInput + connect: UserWhereUniqueInput + disconnect: Boolean +} + input PostUpdateArgs { where: PostWhereUniqueInput! data: PostUpdateInput! @@ -310,6 +324,11 @@ input PostCreateInput { author: UserRelateToOneForCreateInput } +input UserRelateToOneForCreateInput { + create: UserCreateInput + connect: UserWhereUniqueInput +} + """ The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). """ diff --git a/examples/custom-prisma-multischema/schema.prisma b/examples/custom-prisma-multischema/schema.prisma index df2bfa1a27b..a69edbfd342 100644 --- a/examples/custom-prisma-multischema/schema.prisma +++ b/examples/custom-prisma-multischema/schema.prisma @@ -18,7 +18,7 @@ model User { id String @id @default(cuid()) name String @default("") @map("RealName") email String @unique @default("") - password String? + password String? @map("Password") roles String @default("") phoneNumbers PhoneNumber[] @relation("PhoneNumber_user") posts Post[] @relation("Post_author") @@ -27,13 +27,11 @@ model User { } model PhoneNumber { - id String @id @default(cuid()) - user User? @relation("PhoneNumber_user", fields: [userId], references: [id]) - userId String? @map("user") - type String? - value String @default("") + id String @id @default(cuid()) + user User[] @relation("PhoneNumber_user") + type String? @map("Type") + value String @default("") - @@index([userId]) @@schema("Content") } @@ -41,9 +39,9 @@ model Post { id String @id @default(cuid()) title String @default("") status String @default("draft") - content Json @default("[{\"type\":\"paragraph\",\"children\":[{\"text\":\"\"}]}]") + content Json @default("[{\"type\":\"paragraph\",\"children\":[{\"text\":\"\"}]}]") @map("Content") publishDate DateTime? - author User? @relation("Post_author", fields: [authorId], references: [id]) + author User? @relation("Post_author", fields: [authorId], references: [id], onUpdate: Cascade, onDelete: Cascade) authorId String? @map("author") @@index([authorId]) diff --git a/examples/custom-prisma-multischema/schema.ts b/examples/custom-prisma-multischema/schema.ts index 7b6966432a7..34a67f08150 100644 --- a/examples/custom-prisma-multischema/schema.ts +++ b/examples/custom-prisma-multischema/schema.ts @@ -25,10 +25,16 @@ const User: Lists.User = list({ isIndexed: 'unique', validation: { isRequired: true }, }), - password: password(), + password: password({ db: { extendPrismaField: list => list + ' @map("Password")' } }), roles: text({}), phoneNumbers: relationship({ ref: 'PhoneNumber.user', + db: { + extendPrismaField: field => { + console.log('Phone Number - User: ', field); + return field; + }, + }, many: true, ui: { displayMode: 'cards', @@ -38,7 +44,10 @@ const User: Lists.User = list({ linkToItem: true, }, }), - posts: relationship({ ref: 'Post.author', many: true }), + posts: relationship({ + ref: 'Post.author', + many: true, + }), randomNumber: virtual({ field: graphql.field({ type: graphql.Float, @@ -78,7 +87,16 @@ export const lists: Lists = { }, }, }), - user: relationship({ ref: 'User.phoneNumbers' }), + user: relationship({ + ref: 'User.phoneNumbers', + many: true, + db: { + extendPrismaField: field => { + console.log('Phone Number: ', field); + return field; + }, + }, + }), type: select({ options: [ { label: 'Home', value: 'home' }, @@ -88,6 +106,9 @@ export const lists: Lists = { ui: { displayMode: 'segmented-control', }, + db: { + extendPrismaField: list => list + ' @map("Type")', + }, }), value: text({}), }, @@ -129,9 +150,19 @@ export const lists: Lists = { ], links: true, dividers: true, + db: { + extendPrismaField: list => list + ' @map("Content")', + }, }), publishDate: timestamp(), author: relationship({ + db: { + extendPrismaField: () => + `\nauthor User? @relation("Post_author", fields: [authorId], references: [id], onUpdate: Cascade, onDelete: Cascade) + authorId String? @map("author") + + @@index([authorId])`, + }, ref: 'User.posts', ui: { displayMode: 'cards', diff --git a/packages/core/src/fields/types/bigInt/index.ts b/packages/core/src/fields/types/bigInt/index.ts index 4220e719bee..2c768b0da8a 100644 --- a/packages/core/src/fields/types/bigInt/index.ts +++ b/packages/core/src/fields/types/bigInt/index.ts @@ -34,6 +34,7 @@ export type BigIntFieldConfig = db?: { isNullable?: boolean; map?: string; + extendPrismaField?: (field: string) => string; }; }; @@ -111,6 +112,7 @@ export const bigInt = ? { kind: 'autoincrement' } : undefined, map: config.db?.map, + extendPrismaField: config.db?.extendPrismaField, })({ ...config, hooks: { diff --git a/packages/core/src/fields/types/calendarDay/index.ts b/packages/core/src/fields/types/calendarDay/index.ts index 44078668c82..1f48250a8d5 100644 --- a/packages/core/src/fields/types/calendarDay/index.ts +++ b/packages/core/src/fields/types/calendarDay/index.ts @@ -28,6 +28,7 @@ export type CalendarDayFieldConfig = }; db?: { isNullable?: boolean; + extendPrismaField?: (field: string) => string; map?: string; }; }; @@ -84,6 +85,7 @@ export const calendarDay = } : undefined, map: config.db?.map, + extendPrismaField: config.db?.extendPrismaField, nativeType: usesNativeDateType ? 'Date' : undefined, })({ ...config, diff --git a/packages/core/src/fields/types/checkbox/index.ts b/packages/core/src/fields/types/checkbox/index.ts index 1859b0739d6..07cb5642d23 100644 --- a/packages/core/src/fields/types/checkbox/index.ts +++ b/packages/core/src/fields/types/checkbox/index.ts @@ -17,7 +17,10 @@ export type CheckboxFieldConfig = read?: { isNonNull?: boolean }; create?: { isNonNull?: boolean }; }; - db?: { map?: string }; + db?: { + map?: string; + extendPrismaField?: (field: string) => string; + }; }; export const checkbox = @@ -39,6 +42,7 @@ export const checkbox = scalar: 'Boolean', default: { kind: 'literal', value: defaultValue }, map: config.db?.map, + extendPrismaField: config.db?.extendPrismaField, })({ ...config, input: { diff --git a/packages/core/src/fields/types/decimal/index.ts b/packages/core/src/fields/types/decimal/index.ts index 10766d32ffe..f32f5f52551 100644 --- a/packages/core/src/fields/types/decimal/index.ts +++ b/packages/core/src/fields/types/decimal/index.ts @@ -28,7 +28,11 @@ export type DecimalFieldConfig = defaultValue?: string; isIndexed?: boolean | 'unique'; graphql?: { create?: { isNonNull?: boolean }; read?: { isNonNull?: boolean } }; - db?: { isNullable?: boolean; map?: string }; + db?: { + isNullable?: boolean; + map?: string; + extendPrismaField?: (field: string) => string; + }; }; function parseDecimalValueOption(meta: FieldData, value: string, name: string) { @@ -121,6 +125,7 @@ export const decimal = default: defaultValue === undefined ? undefined : { kind: 'literal' as const, value: defaultValue }, map: config.db?.map, + extendPrismaField: config.db?.extendPrismaField, } as const; return fieldType(dbField)({ ...config, diff --git a/packages/core/src/fields/types/file/index.ts b/packages/core/src/fields/types/file/index.ts index edee4676365..79f74d3c59e 100644 --- a/packages/core/src/fields/types/file/index.ts +++ b/packages/core/src/fields/types/file/index.ts @@ -10,6 +10,9 @@ import { graphql } from '../../..'; export type FileFieldConfig = { storage: string; + db?: { + extendPrismaField?: (field: string) => string; + }; } & CommonFieldConfig; const FileFieldInput = graphql.inputObject({ @@ -70,6 +73,7 @@ export const file = filesize: { kind: 'scalar', scalar: 'Int', mode: 'optional' }, filename: { kind: 'scalar', scalar: 'String', mode: 'optional' }, }, + extendPrismaField: config.db?.extendPrismaField, })({ ...config, hooks: storage.preserve diff --git a/packages/core/src/fields/types/float/index.ts b/packages/core/src/fields/types/float/index.ts index d45a5498c93..2319d66240f 100644 --- a/packages/core/src/fields/types/float/index.ts +++ b/packages/core/src/fields/types/float/index.ts @@ -35,6 +35,7 @@ export type FloatFieldConfig = db?: { isNullable?: boolean; map?: string; + extendPrismaField?: (field: string) => string; }; }; @@ -101,6 +102,7 @@ export const float = default: typeof defaultValue === 'number' ? { kind: 'literal', value: defaultValue } : undefined, map: config.db?.map, + extendPrismaField: config.db?.extendPrismaField, })({ ...config, hooks: { diff --git a/packages/core/src/fields/types/image/index.ts b/packages/core/src/fields/types/image/index.ts index 1ae6c6a8577..dce33327e00 100644 --- a/packages/core/src/fields/types/image/index.ts +++ b/packages/core/src/fields/types/image/index.ts @@ -12,6 +12,9 @@ import { SUPPORTED_IMAGE_EXTENSIONS } from './utils'; export type ImageFieldConfig = { storage: string; + db?: { + extendPrismaField?: (field: string) => string; + }; } & CommonFieldConfig; const ImageExtensionEnum = graphql.enum({ @@ -82,6 +85,7 @@ export const image = return fieldType({ kind: 'multi', + extendPrismaField: config.db?.extendPrismaField, fields: { filesize: { kind: 'scalar', scalar: 'Int', mode: 'optional' }, extension: { kind: 'scalar', scalar: 'String', mode: 'optional' }, diff --git a/packages/core/src/fields/types/integer/index.ts b/packages/core/src/fields/types/integer/index.ts index b8630cf7c80..12c03532f63 100644 --- a/packages/core/src/fields/types/integer/index.ts +++ b/packages/core/src/fields/types/integer/index.ts @@ -34,6 +34,7 @@ export type IntegerFieldConfig = db?: { isNullable?: boolean; map?: string; + extendPrismaField?: (field: string) => string; }; }; @@ -125,6 +126,7 @@ export const integer = ? { kind: 'autoincrement' } : undefined, map: config.db?.map, + extendPrismaField: config.db?.extendPrismaField, })({ ...config, hooks: { diff --git a/packages/core/src/fields/types/json/index.ts b/packages/core/src/fields/types/json/index.ts index 29a3526ec04..ab6352c8922 100644 --- a/packages/core/src/fields/types/json/index.ts +++ b/packages/core/src/fields/types/json/index.ts @@ -10,7 +10,7 @@ import { graphql } from '../../..'; export type JsonFieldConfig = CommonFieldConfig & { defaultValue?: JSONValue; - db?: { map?: string }; + db?: { map?: string; extendPrismaField?: (field: string) => string }; }; export const json = @@ -47,6 +47,7 @@ export const json = ? undefined : { kind: 'literal', value: JSON.stringify(defaultValue) }, map: config.db?.map, + extendPrismaField: config.db?.extendPrismaField, } ); }; diff --git a/packages/core/src/fields/types/multiselect/index.ts b/packages/core/src/fields/types/multiselect/index.ts index b51d6de7df5..e3b89261086 100644 --- a/packages/core/src/fields/types/multiselect/index.ts +++ b/packages/core/src/fields/types/multiselect/index.ts @@ -42,6 +42,7 @@ export type MultiselectFieldConfig = }; db?: { map?: string; + extendPrismaField?: (field: string) => string; }; }; @@ -150,6 +151,7 @@ export const multiselect = { mode: 'required', map: config?.db?.map, + extendPrismaField: config.db?.extendPrismaField, default: { kind: 'literal', value: JSON.stringify(defaultValue) }, } ); diff --git a/packages/core/src/fields/types/password/index.ts b/packages/core/src/fields/types/password/index.ts index 41c91f0d2a0..12c1063a17f 100644 --- a/packages/core/src/fields/types/password/index.ts +++ b/packages/core/src/fields/types/password/index.ts @@ -27,6 +27,7 @@ export type PasswordFieldConfig = db?: { isNullable?: boolean; map?: string; + extendPrismaField?: (field: string) => string; }; bcrypt?: Pick; }; @@ -113,6 +114,7 @@ export const password = scalar: 'String', mode: isNullable === false ? 'required' : 'optional', map: config.db?.map, + extendPrismaField: config.db?.extendPrismaField, })({ ...config, hooks: { diff --git a/packages/core/src/fields/types/relationship/index.ts b/packages/core/src/fields/types/relationship/index.ts index 14fa3c55649..85ef185d065 100644 --- a/packages/core/src/fields/types/relationship/index.ts +++ b/packages/core/src/fields/types/relationship/index.ts @@ -55,6 +55,7 @@ type CountDisplayConfig = { type OneDbConfig = { many?: false; db?: { + extendPrismaField?: (field: string) => string; foreignKey?: | true | { @@ -67,6 +68,7 @@ type ManyDbConfig = { many: true; db?: { relationName?: string; + extendPrismaField?: (field: string) => string; }; }; @@ -246,6 +248,7 @@ export const relationship = list: foreignListKey, field: foreignFieldKey, relationName: config.db?.relationName, + extendPrismaField: config.db?.extendPrismaField, })({ ...commonConfig, input: { @@ -300,6 +303,7 @@ export const relationship = list: foreignListKey, field: foreignFieldKey, foreignKey: config.db?.foreignKey, + extendPrismaField: config.db?.extendPrismaField, })({ ...commonConfig, input: { diff --git a/packages/core/src/fields/types/select/index.ts b/packages/core/src/fields/types/select/index.ts index 0378fb553a8..25889fd4210 100644 --- a/packages/core/src/fields/types/select/index.ts +++ b/packages/core/src/fields/types/select/index.ts @@ -58,6 +58,7 @@ export type SelectFieldConfig = db?: { isNullable?: boolean; map?: string; + extendPrismaField?: (field: string) => string; }; }; @@ -131,6 +132,7 @@ export const select = ? undefined : { kind: 'literal' as const, value: defaultValue as any }, map: config.db?.map, + extendPrismaField: config.db?.extendPrismaField, } as const; const resolveCreate = (val: T | null | undefined): T | null => { diff --git a/packages/core/src/fields/types/text/index.ts b/packages/core/src/fields/types/text/index.ts index 2000e9a9fd3..4b07f6106b5 100644 --- a/packages/core/src/fields/types/text/index.ts +++ b/packages/core/src/fields/types/text/index.ts @@ -28,8 +28,8 @@ export type TextFieldConfig = graphql?: { create?: { isNonNull?: boolean }; read?: { isNonNull?: boolean } }; db?: { isNullable?: boolean; - extendPrismaField?: (field: string) => string; map?: string; + extendPrismaField?: (field: string) => string; /** * The underlying database type. * Only some of the types are supported on PostgreSQL and MySQL. diff --git a/packages/core/src/fields/types/timestamp/index.ts b/packages/core/src/fields/types/timestamp/index.ts index fd40ffa4f12..cc7c55ac2a8 100644 --- a/packages/core/src/fields/types/timestamp/index.ts +++ b/packages/core/src/fields/types/timestamp/index.ts @@ -30,6 +30,7 @@ export type TimestampFieldConfig = updatedAt?: boolean; isNullable?: boolean; map?: string; + extendPrismaField?: (field: string) => string; }; }; @@ -83,6 +84,7 @@ export const timestamp = : { kind: 'now' }, updatedAt: config.db?.updatedAt, map: config.db?.map, + extendPrismaField: config.db?.extendPrismaField, })({ ...config, hooks: { diff --git a/packages/core/src/lib/core/resolve-relationships.ts b/packages/core/src/lib/core/resolve-relationships.ts index 3a0aff7cc06..303cf6b4684 100644 --- a/packages/core/src/lib/core/resolve-relationships.ts +++ b/packages/core/src/lib/core/resolve-relationships.ts @@ -170,6 +170,7 @@ export function resolveRelationships( mode: 'one', field: rightRel.fieldPath, list: rightRel.listKey, + extendPrismaField: leftRel.field.extendPrismaField, foreignIdField: { kind: 'owned-unique', map: @@ -184,6 +185,7 @@ export function resolveRelationships( mode: 'one', field: leftRel.fieldPath, list: leftRel.listKey, + extendPrismaField: rightRel.field.extendPrismaField, foreignIdField: { kind: 'none' }, relationName, }; @@ -195,6 +197,7 @@ export function resolveRelationships( resolvedLists[leftRel.listKey][leftRel.fieldPath] = { kind: 'relation', mode: 'many', + extendPrismaField: leftRel.field.extendPrismaField, field: rightRel.fieldPath, list: rightRel.listKey, relationName, @@ -202,6 +205,7 @@ export function resolveRelationships( resolvedLists[rightRel.listKey][rightRel.fieldPath] = { kind: 'relation', mode: 'many', + extendPrismaField: rightRel.field.extendPrismaField, field: leftRel.fieldPath, list: leftRel.listKey, relationName, @@ -213,6 +217,7 @@ export function resolveRelationships( kind: 'relation', mode: 'one', field: rightRel.fieldPath, + extendPrismaField: leftRel.field.extendPrismaField, list: rightRel.listKey, foreignIdField: { kind: 'owned', @@ -226,6 +231,7 @@ export function resolveRelationships( resolvedLists[rightRel.listKey][rightRel.fieldPath] = { kind: 'relation', mode: 'many', + extendPrismaField: rightRel.field.extendPrismaField, field: leftRel.fieldPath, list: leftRel.listKey, relationName, @@ -244,6 +250,7 @@ export function resolveRelationships( resolvedLists[field.list][foreignFieldPath] = { kind: 'relation', mode: 'many', + extendPrismaField: field.extendPrismaField, list: listKey, field: fieldPath, relationName, @@ -251,6 +258,7 @@ export function resolveRelationships( resolvedList[fieldPath] = { kind: 'relation', mode: 'many', + extendPrismaField: field.extendPrismaField, list: field.list, field: foreignFieldPath, relationName, @@ -260,6 +268,7 @@ export function resolveRelationships( resolvedLists[field.list][foreignFieldPath] = { kind: 'relation', mode: 'many', + extendPrismaField: field.extendPrismaField, list: listKey, field: fieldPath, relationName, @@ -267,6 +276,7 @@ export function resolveRelationships( resolvedList[fieldPath] = { kind: 'relation', list: field.list, + extendPrismaField: field.extendPrismaField, field: foreignFieldPath, foreignIdField: { kind: 'owned', diff --git a/packages/core/src/types/json-field-type-polyfill-for-sqlite.ts b/packages/core/src/types/json-field-type-polyfill-for-sqlite.ts index a19927a9222..187fde6d469 100644 --- a/packages/core/src/types/json-field-type-polyfill-for-sqlite.ts +++ b/packages/core/src/types/json-field-type-polyfill-for-sqlite.ts @@ -110,6 +110,7 @@ export function jsonFieldTypePolyfilledForSQLite< map?: string; mode?: 'required' | 'optional'; default?: ScalarDBField<'Json', 'optional'>['default']; + extendPrismaField?: (field: string) => string; } ) { if (provider === 'sqlite') { @@ -119,6 +120,7 @@ export function jsonFieldTypePolyfilledForSQLite< scalar: 'String', default: dbFieldConfig?.default, map: dbFieldConfig?.map, + extendPrismaField: dbFieldConfig?.extendPrismaField, })({ ...config, input: { @@ -140,5 +142,6 @@ export function jsonFieldTypePolyfilledForSQLite< scalar: 'Json', default: dbFieldConfig?.default, map: dbFieldConfig?.map, + extendPrismaField: dbFieldConfig?.extendPrismaField, })(config); } diff --git a/packages/fields-document/src/index.ts b/packages/fields-document/src/index.ts index b3956d8d2c4..0f0cecc28a5 100644 --- a/packages/fields-document/src/index.ts +++ b/packages/fields-document/src/index.ts @@ -68,7 +68,7 @@ export type DocumentFieldConfig = links?: true; dividers?: true; layouts?: readonly (readonly [number, ...number[]])[]; - db?: { map?: string }; + db?: { map?: string; extendPrismaField?: (field: string) => string }; }; export const document = @@ -174,6 +174,7 @@ export const document = value: JSON.stringify([{ type: 'paragraph', children: [{ text: '' }] }]), }, map: config.db?.map, + extendPrismaField: config.db?.extendPrismaField, } ); };