Skip to content

feat: Drizzle 1.0 type safety fixes#234

Draft
austinm911 wants to merge 21 commits intorocicorp:0xcadams/drizzle-betafrom
austinm911:drizzle-1.0
Draft

feat: Drizzle 1.0 type safety fixes#234
austinm911 wants to merge 21 commits intorocicorp:0xcadams/drizzle-betafrom
austinm911:drizzle-1.0

Conversation

@austinm911
Copy link
Contributor

@austinm911 austinm911 commented Jan 19, 2026

Drizzle 1.0 Support

Human Summary

This is entirely claude generated so buyer beware, however I am migrating a project to Drizzle 1.0 beta and this seems to mostly work, except for some missing types in a JSON field.

I figured I'd keep this up in draft form in case you'd like to reference anything or take over to clean up.

⚠️ Draft PR

Summary

This PR adds support for Drizzle ORM 1.0 (currently ^1.0.0-beta.10), which introduced significant internal changes to column type representation.

Status: All 633 tests passing, 0 type errors. Working in my production app with Drizzle 1.0 beta, generating correct Zero schemas with proper types.

What Changed in Drizzle 1.0

Drizzle 1.0 changed how column types are represented internally:

Aspect Drizzle 0.x Drizzle 1.0
dataType Simple: 'string', 'number' Compound: 'string uuid', 'object date'
columnType In column._ object Direct property on column
$type<T>() Sets _.$type Sets _.data directly
Relations relations() helper defineRelations() API

Changes Made

Core Type System (src/)

  • New type predicates: IsTimestampDataType, IsBigIntDataType, IsStringNumericDataType to detect Drizzle 1.0's compound dataTypes
  • IsExactType helper: Distinguishes default types (Date, string, bigint) from explicit $type<T>() overrides
  • Runtime utilities: extractBaseType() and mapDrizzle1DataTypeToZero() for parsing compound dataTypes
  • Updated CustomType/ZeroMappedCustomType: Handle new column structure while preserving backwards compatibility

Type Resolution (src/cli/)

  • Fixed ReadonlyJSONValue being incorrectly expanded (now uses UseAliasDefinedOutsideCurrentScope flag first)

Previously Unsupported Types

These types now work in Drizzle 1.0 (they have valid compound dataTypes):

  • interval, cidr, macaddr, inetstring
  • point, line, geometryjson

Type Mapping Logic

Drizzle 1.0 dataType    →  Zero Type
─────────────────────────────────────
'string'                →  string
'string uuid'           →  string
'string timestamp'      →  number (!)
'string date'           →  number (!)
'string numeric'        →  number (!)
'number'                →  number
'number int32'          →  number
'bigint int64'          →  number
'object date'           →  number
'object json'           →  json
'array point'           →  json
'boolean'               →  boolean
'custom'                →  (fallback to getSQLType())

Key insight: $type<T>() overrides are preserved. If you use timestamp().$type<ISODateString>(), the custom type is kept rather than being converted to number.

Testing

pnpm test  # 633 tests passing, 0 type errors

New tests added:

  • tests/drizzle-1.0.test.ts - Compound dataType utility tests
  • Type-level tests in tests/types.test.ts for timestamp/bigint/numeric mapping

Questions for Maintainer

  1. Backwards compatibility: The changes attempt to support both Drizzle 0.x and 1.0 column structures. Is this the right approach, or should we drop 0.x support?

  2. defineRelations() vs relations(): Both APIs are supported. The old relations() still works but defineRelations() is the new recommended approach.

  3. Type coercion: Timestamps/dates/bigints all map to number in Zero. This matches how Zero stores these values. Is this correct?

  4. Custom type preservation: When $type<T>() is used, we preserve the custom type instead of converting. This seemed like the right UX but want to confirm.

How I Tested

  • Running in a production app with Drizzle 1.0 beta
  • Schema generation produces correct types
  • Zero client works with generated schemas
  • All existing tests pass

Happy to address any feedback or concerns. This is based on the earlier 0xcadams/drizzle-beta branch with additional fixes for type safety issues discovered during testing.

selfire1 and others added 20 commits January 7, 2026 15:46
* fix: remove warn logs for defaults

* Revert "fix: remove warn logs for defaults"

This reverts commit 901b09f.

* chore: implement suppress warnings tests

* feat: implement `suppressDefaultsWarning` flag
- Add imports for RelationV2, OneV2, ManyV2 from drizzle-orm/relations
- Add isTablesRelationalConfig() detection for new API output
- Add getRelationInfo() helper to normalize old/new API differences
- Update drizzleZeroConfig to process TablesRelationalConfig
- Update findRelationSourceAndDestFields for V2 relations
- Maintain backwards compatibility with old relations() API
* fix: undeprecate row types

* test: update

* chore: format
- Updated drizzle-* deps to 1.0.0-beta series
- Took tooling updates (oxlint, prettier)
- Kept drizzle-1.0 branch structure for db/package.json
- Add IsTimestampDataType, IsBigIntDataType, IsStringNumericDataType predicates
- Add IsExactType helper to distinguish default types from $type<T>() overrides
- Add extractBaseType and mapDrizzle1DataTypeToZero runtime utilities
- Update CustomType and ZeroMappedCustomType for Drizzle 1.0 column structure
- Remove 'custom' from base type mapping (falls through to getSQLType)

Drizzle 1.0 uses compound dataTypes like 'string uuid', 'object date', etc.
These changes ensure proper mapping to Zero types while preserving custom
type overrides.
- Use UseAliasDefinedOutsideCurrentScope flag first to preserve type aliases
- Fall back to InTypeAlias for expanding custom interface types
- Fixes jsonb columns incorrectly expanding ReadonlyJSONValue to union

The InTypeAlias flag was expanding ReadonlyJSONValue to its full union
definition with import() paths, which failed isSafeResolvedType checks.
- Update interval/cidr/macaddr/inet/point/line/geometry tests
  (now supported in Drizzle 1.0, no longer emit warnings)
- Add drizzle-1.0.test.ts for compound dataType utility tests
- Add type-level tests for timestamp/bigint/numeric → number mapping
- Add type-level tests for $type<T>() preservation
- Update snapshots for ReadonlyJSONValue preservation
- Move backtick string literal to safe types (valid literal)
- Add relations to drizzle() config (required in Drizzle 1.0)
- Update where clause syntax to use object filters
  (before: where: (t, {eq}) => eq(t.id, x), after: where: {id: x})
Comprehensive documentation of:
- All changes made for Drizzle 1.0 compatibility
- Drizzle 1.0 internal changes (compound dataTypes, column structure)
- Type mapping logic and decision tree
- Commands for testing and development
The blocklist approach broke CLI tests that expect ZeroCustomType<...>
helper in generated output. User-defined $type<T>() still works via
the ZeroCustomType helper which resolves at compile time.

Also documents beta.11 TypeScript type issues (staying on beta.10).
Runtime changes (src/tables.ts):
- Detect array columns via 'dimensions' property (Drizzle 1.0 style)
- Map array columns to 'json' type in Zero
- Prevent enum arrays from being treated as enums

Test corrections (tests/tables.test.ts):
- Fix $type<T>() usage on array columns to use element type, not array type
  Drizzle's .array() already wraps the type automatically
- Document Drizzle 1.0 limitation: nested .array().array() only tracks
  single dimension at type level (runtime still receives correct 2D data)

All 633 tests now pass.
- Add RESERVED_TYPE_NAMES set with built-in types (Record, Array, etc.)
  and utility types (Partial, Readonly, etc.)
- Tables like 'records' now generate 'RecordRow' instead of 'Record'
  to avoid shadowing TypeScript's built-in Record<K,V> utility type
- Remove ReadonlyJSONObject from isSafeResolvedType special case
  since it's not auto-imported (falls back to ZeroCustomType)
- Add test to verify reserved type name handling

Fixes circular reference error when generated schema uses Record<...>
for JSON column types while also exporting 'type Record = ...'.
- Add knownSafeTypeAliases set for ReadonlyJSONValue and ReadonlyJSONObject
- Allow 'readonly' modifier in object type index signatures
- Track and import both ReadonlyJSONValue and ReadonlyJSONObject from @rocicorp/zero
- Add comprehensive tests for complex $type<> structures:
  - Nested objects (UserProfile with nested address)
  - Discriminated unions (NotificationEvent)
  - Arrays of complex objects (FormFieldConfig[])
  - Objects with ReadonlyJSONValue (WorkflowStep)
  - Type alias chains (RecordData -> JsonObject -> ReadonlyJSONObject)
- Verify RecordRow type name doesn't conflict with built-in Record<K,V>

Fixes issue where type alias chain to ReadonlyJSONObject resolved to {}.
@0xcadams
Copy link
Member

I am sorry but this is such a massive PR, it’s going to be very hard for me to review this and merge. I will use it as a reference but 4k lines changing won’t be something I can review meaningfully.

@austinm911
Copy link
Contributor Author

Absolutely no worries! I did not mean to overwhelm or expect you to review much. I just figured that if it's helpful in any way as a reference, then great. Thanks for your work !

- Update devDependencies to use 'beta' dist-tag (resolves to 1.0.0-beta.14)
- Update peerDependency to >=1.0.0-beta.2
- Fix test-utils type issue with large table insert overload
- Reformat with oxfmt
- All 647 tests pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants