drizzle-zero

repository·main·Indexed 43 days ago

https://github.com/rocicorp/drizzle-zero

A utility to generate Zero schemas from existing Drizzle ORM schemas, enabling type-safe, synchronized data access between Drizzle and Zero. Version 0.20.0 provides a CLI for schema conversion, support for many-to-many relationships via junction tables, and a configuration system via drizzle-zero.config.ts to selectively include tables and columns.

Tokens
7.8K
Snippets
26
Records
30
Agent score
54%

What's inside drizzle-zero

  1. Configure Many-to-Many relationships

    main

    Drizzle-zero supports many-to-many relationships via junction tables. You can configure them using either a Simple or Extended format in your drizzle-zero.config.ts.

    Simple Configuration

    Use this when you have a standard junction table. The format is [junction_table, target_table].

    Extended Configuration

    Use this for complex scenarios like self-referential relationships. You must explicitly map the sourceField, destTable, and destField.

    Example of Extended Configuration (Self-referential):

    export default drizzleZeroConfig(drizzleSchema, {
      tables: {
        user: { id: true, name: true },
        friendship: { requestingId: true, acceptingId: true },
      },
      manyToMany: {
        user: {
          friends: [
            {
              sourceField: ['id'],
              destTable: 'friendship',
              destField: ['requestingId'],
            },
            {
              sourceField: ['acceptingId'],
              destTable: 'user',
              destField: ['id'],
            },
          ],
        },
      },
    });
    // Simple format example
    export default drizzleZeroConfig(drizzleSchema, {
      tables: {
        user: { id: true, name: true },
        usersToGroup: { userId: true, groupId: true },
        group: { id: true, name: true },
      },
      manyToMany: {
        user: {
          groups: ['usersToGroup', 'group'],
        },
      },
    });
  2. Generate Zero schemas from Drizzle schemas

    main

    Use the drizzle-zero generate CLI command to convert your Drizzle ORM schema into a Zero schema.

    Requirements:

    • You must have an existing Drizzle schema.
    • The Drizzle schema must be included in your tsconfig for type resolution to work, otherwise you will encounter a Failed to find type definitions error.
    • By default, the CLI looks for a Drizzle Kit config at drizzle.config.ts in the current directory. This must be a single TS file (not a folder/glob).

    Common CLI Flags:

    • -s, --schema <input-file>: Path to your Drizzle schema file.
    • -k, --drizzle-kit-config <input-file>: Path to your drizzle.config.ts file.
    • -o, --output <output-file>: Custom path for the generated schema (default is zero-schema.gen.ts).
    • -f, --format: Use Prettier to format the generated output.
    • -t, --tsconfig <tsconfig-file>: Specify a custom tsconfig file.
    • -j, --js-file-extension: Manually override .js extension behavior for imports.
    • -c, --config <input-file>: Path to a custom drizzle-zero.config.ts file.

    Output Control Flags:

    • --skip-types: Skip generating table Row[] type exports.
    • --skip-builder: Skip generating the query createBuilder export.
    • --skip-declare: Skip generating the module augmentation for default types in Zero.
    • --enable-legacy-mutators: Enable legacy CRUD mutators.
    • --enable-legacy-queries: Enable legacy CRUD queries.
    • --suppress-defaults-warning: Hide warnings for columns using database defaults (.default() or .defaultFn()).
    {
      "scripts": {
        "generate": "drizzle-zero generate --format",
        "postinstall": "npm generate"
      }
    }
  3. Install drizzle-zero

    main

    Install drizzle-zero using your preferred package manager to begin generating Zero schemas from your Drizzle ORM schemas.

    npm install drizzle-zero
    # or
    bun add drizzle-zero
    # or
    yarn add drizzle-zero
    # or
    pnpm add drizzle-zero
  4. Configure table and column syncing with `drizzle-zero.config.ts`

    main

    Create a drizzle-zero.config.ts file to selectively include specific tables and columns in your Zero schema. This is useful for the "expand/migrate/contract" pattern.

    Important Notes:

    • The config file must be included in your tsconfig for type resolution to work.
    • All tables/columns must be defined in the config, but you can set them to false to exclude them.
    • For column names, use the JavaScript field name (e.g., authorId), not the database column name (e.g., author_id).
    • For large schemas, the config file may struggle with types; in those cases, use the default CLI behavior without a config file.

    Configuration Options:

    • tables: An object mapping table names to their included columns or false to exclude the table.
    • casing: Specify a casing style (e.g., "snake_case") to match your Drizzle configuration.
    import {drizzleZeroConfig} from 'drizzle-zero';
    import * as drizzleSchema from './drizzle-schema';
    
    export default drizzleZeroConfig(drizzleSchema, {
      tables: {
        users: {
          id: true,
          name: true,
          email: true,
        },
        posts: {
          id: true,
          content: true,
          authorId: true,
        },
      },
      // casing: "snake_case",
    });
  5. Resolve Drizzle schema files via Drizzle Kit configuration

    main

    When setting up drizzle-zero, you can automatically locate your Drizzle schema files by pointing to your drizzle-kit configuration file. This allows drizzle-zero to inherit settings like casing directly from your existing Drizzle Kit setup.

    drizzle-zero supports two ways to find your schema:

    1. Direct Path: Provide a specific path to your Drizzle schema file using drizzleSchemaPath.
    2. Drizzle Kit Config: Provide a path to your drizzle-kit.config.ts (or similar) using drizzleKitConfigPath. The utility will then parse the config to find the schema and casing properties.

    Important Constraints:

    • The schema property in your Drizzle Kit config must be a single string path, not an array. drizzle-zero requires a single file to ensure imports work correctly.
    • If you encounter errors loading the config, ensure your package.json includes "type": "module" if you are using ESM.
  6. Configure drizzle-zero with a configuration file

    main

    drizzle-zero looks for a configuration file named drizzle-zero.config.ts in your project root by default. This file is used to define your schema and other project settings.

    To ensure the CLI can correctly import your configuration, you must export either a default export or a named export called schema containing your Drizzle schema.

    If you encounter import errors, ensure your package.json includes "type": "module" to support ESM imports.

    // drizzle-zero.config.ts
    import { someSchema } from './my-schema';
    
    export default someSchema;
    
    // OR
    
    export const schema = someSchema;
  7. Configure Drizzle Kit for drizzle-zero

    main

    The drizzle.config.ts file is used to configure drizzle-kit for managing your database schema and migrations. When using drizzle-zero, ensure you specify the path to your schema file, the output directory for migrations, and the database dialect.

    Key configuration properties:

    • schema: The path to your Drizzle schema definition file.
    • out: The directory where migrations will be generated.
    • dialect: The database dialect being used (e.g., 'postgresql').
    import type {Config} from 'drizzle-kit';
    
    export default {
      schema: './drizzle/schema.ts',
      out: './drizzle',
      dialect: 'postgresql',
    } satisfies Config;
  8. Configure columns in `createZeroTableBuilder`

    main

    The columns parameter in createZeroTableBuilder allows you to control which Drizzle columns are exposed to the Zero client and how they are typed.

    Configuration Options:

    • boolean:
      • true: Includes the column using default mapping.
      • false: Excludes the column from the Zero schema.
    • ColumnBuilder: Provides a custom mapping for the column. This is used to override the type, optionality, or provide a custom schema.
    • undefined (default): If columns is not provided, all primary keys and columns explicitly marked as true (or columns with server defaults/not-null constraints depending on internal logic) are processed. Note that if columns is an object, any column not explicitly listed as true or a ColumnBuilder will be excluded (unless it is a primary key).

    Example: Partial Column Inclusion

    const zeroTable = createZeroTableBuilder('users', usersTable, {
      id: true, // Include as is
      email: true, // Include as is
      bio: zeroString().optional(), // Custom mapping
      password_hash: false, // Explicitly exclude
    });
    export type ColumnsConfig<TTable extends Table> =
      | boolean
      | Partial<{
          readonly [KColumn in ColumnNames<TTable>]:
            | boolean
            | ColumnBuilder<...>;
        }>;
  9. Configure drizzle-zero with drizzleZeroConfig

    main

    To set up drizzle-zero, use the drizzleZeroConfig function. This function takes your existing Drizzle schema and a configuration object to define which tables are exposed and how complex relationships like many-to-many are handled.

    Common configuration keys include:

    • tables: An object mapping table names to boolean values. Setting a table to true enables it for drizzle-zero. Setting allTypes: true can be used to include all types.
    • manyToMany: An object used to define custom many-to-many relationship logic for specific tables.
    • testSerialPk, testUuidPk, etc.: Boolean flags used for testing various primary key types.
    import {drizzleZeroConfig} from 'drizzle-zero';
    import * as drizzleSchema from '../db/drizzle/schema';
    
    export const schema = drizzleZeroConfig(drizzleSchema, {
      tables: {
        user: true,
        project: true,
        // ... other tables
      },
      manyToMany: {
        // custom relationship definitions
      },
    });
  10. Error: Drizzle Kit config schema is an array

    main

    If your drizzle-kit.config.ts defines the schema property as an array of files (e.g., schema: ['./src/schema/a.ts', './src/schema/b.ts']), drizzle-zero will fail with the following error:

    ❌ drizzle-zero: Drizzle Kit config schema is an array. Please specify a single schema file for imports to be able to work correctly.

    Resolution: Update your Drizzle Kit configuration to point to a single entry point file that exports all your schema definitions.

  11. Create a Zero schema from a Drizzle table with `createZeroTableBuilder`

    main

    Use createZeroTableBuilder to transform a Drizzle ORM table definition into a Zero schema definition. This function handles mapping Drizzle column types to Zero types, identifying primary keys, and managing column inclusion/exclusion.

    Key Features:

    • Automatic Type Mapping: Automatically maps Drizzle types (string, number, boolean, json, etc.) to their Zero equivalents.
    • Primary Key Detection: Automatically identifies primary keys from the Drizzle table. If no primary key is found, it throws an error.
    • Column Filtering: You can specify which columns to include in the Zero schema using the columns configuration.
    • Casing Support: Supports camelCase or snake_case for the Zero schema table name via the casing option.
    • Server Default Warnings: Warns you if a column uses a database default, as the Zero client cannot use these defaults directly (you should use mutators instead).

    Parameters:

    • tableName: The name of the table in the Zero schema.
    • table: The Drizzle table instance.
    • columns (optional): Configuration for column inclusion and custom mapping.
    • debug (optional): Enables debug logging.
    • casing (optional): 'camelCase' | 'snake_case'.
    • suppressDefaultsWarning (optional): If true, hides warnings about database-side default values.
    import { createZeroTableBuilder } from 'drizzle-zero';
    import { myDrizzleTable } from './schema';
    
    const zeroTable = createZeroTableBuilder(
      'my_table',
      myDrizzleTable,
      {
        // Only include specific columns
        id: true,
        name: true,
        // Customize a column with a ColumnBuilder
        description: zeroString().optional(),
      }
    );