valtyr / prisma-kysely

🪄 Generate Kysely types directly from your Prisma schema!
https://www.npmjs.com/package/prisma-kysely
MIT License
915 stars 35 forks source link

Unable to assign values to fields marked as Generated in TypeScript. #64

Closed noccio-nocci closed 4 months ago

noccio-nocci commented 1 year ago

Fields with @default directives in the Prisma schema are converted to type Generated in the generated type.ts.

While this makes sense for fields where the database is responsible for generating the value (like auto-incremented IDs or timestamps), it becomes problematic for fields where I need to assign a value during insert or update operations. TypeScript throws a type error when I try to assign a value to these Generated fields.

Here's an example of a generated type:

import type { ColumnType } from 'kysely';
export type Generated<T> = T extends ColumnType<infer S, infer I, infer U>
  ? ColumnType<S, I | undefined, U>
  : ColumnType<T, T | undefined, T>;
export type Timestamp = ColumnType<Date, Date | string, Date | string>;

export type User = {
  userId: string;
  userName: string;
  lastName: string | null;
  firstName: string | null;
  email: string;
  emailVerified: Generated<boolean>; // @default(true) in schema.prisma
  phoneNumber: string | null;
  birthdate: string | null;
  enabled: Generated<boolean>;
  createdAt: Generated<Timestamp>;
  updatedAt: Timestamp;
};

Is there a recommended way to handle this situation? Or would you consider adding an option that would allow us to distinguish between fields that are always generated by the database and fields that can be assigned manually?

valtyr commented 1 year ago

Key @noccio-nocci, here's a passage from the Kysely docs:

Columns that are generated by the database should be marked using the Generated type. This way they are automatically made optional in inserts and updates.

Here the key word is optional. Kysely allows the user to optionally provide values for generated fields. There's another type called GeneratedAlways that exhibits the behavior you're describing. To my best knowledge this would be a bug with Kysely itself, if true. It would be cool if you could provide a reproducible example of this error so I can investigate. In the meantime if you're still grappling with this issue you can use per field type overrides.

mateusm09 commented 11 months ago

I did a little type helper that removes the Generated type from the field. So you can use the exported type in other objects.

It scans the provided type looking for the ColumnType (which Generated uses underneath), and infers the first generic type.

import { ColumnType } from 'kysely';
export type Clean<T> = { [K in keyof T]-?: T[K] extends ColumnType<infer S> ? S : T[K] };

type User = {
  id: Generated<string>
  name: string
  age: number
};

type CleanedUser = Clean<User>;

/* result - {
  id: string;
  name: string;
  age: number
} */
valtyr commented 4 months ago

@mateusm09 The move here would probably be to use the Selectable, Insertable, Updateable etc. type helpers from Kysely. The types generated from prisma-kysely aren't really meant to be used directly in business logic unless you're wrapping the query client itself.

Check out the examples at the bottom of the code block here: https://kysely.dev/docs/getting-started#types