drizzle-team / drizzle-team/drizzle-orm
[FEATURE]: Allow for different typing for select and insert in custom types
- Dominant language
- TypeScript
- Stars
- 35.8k
- Forks
- 1.6k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 4
Description
### Feature hasn't been suggested before.
- [x] I have verified this feature I'm about to request hasn't been suggested before.
### Describe the enhancement you want to request
Currently, customType has 1 typing for the desired data type outside of the DB. I would like to suggest an option that would split that into 2 types. Something like this:
```ts
customType<{
data: unknown; // represents select data
mutationData: object; // represents mutations (insert, update) data. This can default to data.
}>({
dataType(config) {
},
// The type for data here should be mutationData
toDriver(data) {
}
// The type for data here should be data
fromDriver(data) {
}
});
```
This is useful for types where valid and invalid data represents 2 different types. For example, the [Luxon](https://moment.github.io/luxon/) date library has a type of `DateTime` by default, where the boolean represents if it's valid. A validated value's type then becomes `DateTime`, which changes the output type of a few methods (eg the `toString()` method changes from `string | null` to `string`).
With the above change, I can then add validation within the customType itself and have it output the proper type.
```ts
const ts = customType<{
data: DateTime;
mutationData: DateTime;
driverData: string;
config: { withTimezone?: boolean; precision?: number };
}>({
dataType(config) {
const { precision: precisionOpt, withTimezone = true } = config ?? {};
const precision =
typeof precisionOpt !== "undefined" ? ` (${precisionOpt})` : "";
return `timestamp${precision}${withTimezone ? " with time zone" : ""}`;
},
// this is automatically typed as DateTime;
toDriver(data) {
if (!assertValidDateTime(data)) {
throw new Error(
"[drizzle][customTimestamp] Invalid DateTime. Reason: " +
(data as DateTime).invalidReason
);
}
return data.setZone("utc").toISO();
},
// this will error out if the type isn't DateTime, i.e. not validated yet;
fromDriver(data) {
const res = DateTime.fromSQL(data);
if (!assertValidDateTime(res)) {
throw new Error(
"[drizzle][customTimestamp] Invalid DateTime. Reason: " +
(res as DateTime).invalidReason
);
}
return res;
},
});
const table = pgTable("test", {
createdAt: ts("created_at")
});
await db.insert(table).values({
createdAt: DateTime.fromISO("2025-01-01T00:00:00Z") // this will not error out, since it is a DateTime type
});
const createdAt = (await db.select().from(table))[0]; // this will automatically be DateTime, since validation is already done.
```
Contributor guide
Assessment
This issue has not been assessed yet.