drizzle-team / drizzle-team/drizzle-orm

[BUG]:createInsertSchema with refinements doesn't handle type inference properly with optional columns (drizzle-typebox)

Open
#4,896 2 comments 1 reaction 0 assignees View on GitHub
bug drizzle/typebox
Dominant language
TypeScript
Stars
35.8k
Forks
1.6k
Avg merge
2d 7h
Merged PRs (30d)
4

Description

### Report hasn't been filed before.

- [x] I have verified that the bug I'm about to report hasn't been filed before.

### What version of `drizzle-orm` are you using?

0.44.4

### What version of `drizzle-kit` are you using?

0.31.4

### Other packages

drizzle-typebox@0.3.3

### Describe the Bug

### What is the undesired behavior?

When using `createInsertSchema` with refinements, all fields in the generated schema are inferred as **required**, even if they should remain optional or nullable.

Specifically:
- `Id` and `UpdatedTime` (auto-increment / default-now) should be optional.
- `Content` (nullable) should be optional.
- Only `RequiredContent` should remain required.

Instead, the refinement step seems to remove optionality and forces all fields to required.

---

### Steps to reproduce

```js
//@ts-check
import { describe, test, expect } from "vitest";
import { createInsertSchema } from "drizzle-typebox";
import * as c from "drizzle-orm/mysql-core";
import { TypeGuard as G } from "@sinclair/typebox";

const simpleTable = c.mysqlTable("simple_table", {
Id: c.int("id").autoincrement().primaryKey(),
Content: c.varchar({ length: 120 }),
RequiredContent: c.varchar({ length: 120 }).notNull(),
UpdatedTime: c.timestamp("UpdatedTime", { mode: 'string' })
.defaultNow()
.onUpdateNow()
.notNull(),
});

test("refinements should not affect optionality", () => {
const schema = createInsertSchema(simpleTable, {
// dummy refinements
Content: (s) => s,
Id: (s) => s,
RequiredContent: (s) => s,
UpdatedTime: (s) => s,
});

const { Content, Id, RequiredContent, UpdatedTime } = schema.properties;

// These pass at runtime but fail in inferred types
expect(G.IsOptional(Id)).toEqual(true);
expect(G.IsOptional(UpdatedTime)).toEqual(true);
expect(G.IsOptional(Content)).toEqual(true);
expect(G.IsOptional(RequiredContent)).toEqual(false);
});
```

The resulting inference resolved to ...
```ts
TObject<{
Id: TInteger;
Content: TUnion<[TString, TNull]>;
RequiredContent: TString;
UpdatedTime: TString;
}>
```

### Desired result
expected Refinements to preserve existing optionality/nullability of columns.
The generated schema should look like:
```ts
TObject<{
Id: TOptional;
Content: TOptional>;
RequiredContent: TString; // required
UpdatedTime: TOptional;
}>
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.