import { Table } from 'drizzle-orm'; import { ReadonlyJSONValue, ColumnBuilder, ValueType, TableBuilderWithColumns } from '@rocicorp/zero'; export { ColumnBuilder, ReadonlyJSONValue, TableBuilderWithColumns } from '@rocicorp/zero'; /** * Maps Drizzle data types to their corresponding Zero schema types. * This is a constant mapping that ensures type safety when converting between the two systems. */ declare const drizzleDataTypeToZeroType: { readonly number: "number"; readonly bigint: "number"; readonly boolean: "boolean"; readonly date: "number"; }; /** * Type representation of the Drizzle to Zero type mapping. * Extracts the type information from the drizzleDataTypeToZeroType constant. */ type DrizzleDataTypeToZeroType = typeof drizzleDataTypeToZeroType; /** * Maps Postgres-specific Drizzle column types to their corresponding Zero schema types. * Handles special cases where Postgres types need specific Zero type representations. */ declare const drizzleColumnTypeToZeroType: { readonly PgText: "string"; readonly PgChar: "string"; readonly PgVarchar: "string"; readonly PgUUID: "string"; readonly PgEnumColumn: "string"; readonly PgJsonb: "json"; readonly PgJson: "json"; readonly PgNumeric: "number"; readonly PgDateString: "number"; readonly PgTime: "number"; readonly PgTimestampString: "number"; readonly PgArray: "json"; }; /** * Type representation of the Postgres-specific Drizzle to Zero type mapping. * Extracts the type information from the drizzleColumnTypeToZeroType constant. */ type DrizzleColumnTypeToZeroType = typeof drizzleColumnTypeToZeroType; /** * Maps Zero schema types to their corresponding TypeScript types. */ type ZeroTypeToTypescriptType = { number: number; boolean: boolean; date: string; string: string; json: ReadonlyJSONValue; }; /** * Gets the keys of columns that can be used as indexes. * @template TTable - The table to get index keys from */ type ColumnIndexKeys = { [K in keyof Columns]: K; }[keyof Columns]; /** * Configuration type for specifying which tables and columns to include in the Zero schema. * @template TDrizzleSchema - The complete Drizzle schema */ type TableColumnsConfig> = Partial ? K : never]: TDrizzleSchema[K] extends Table ? ColumnsConfig : never; }>>; /** * A default config type which includes all tables in the Drizzle schema. * @template TDrizzleSchema - The complete Drizzle schema */ type DefaultTableColumnsConfig> = Flatten<{ readonly [K in keyof TDrizzleSchema as TDrizzleSchema[K] extends Table ? K : never]: TDrizzleSchema[K] extends Table ? DefaultColumnsConfig : never; }>; /** * A default config type which includes all columns in a Drizzle table. * @template TTable - The Drizzle table type */ type DefaultColumnsConfig = { readonly [K in ColumnNames]: true; }; /** * Gets all columns from a Drizzle table type. * @template TTable The Drizzle table type */ type Columns = TTable['_']['columns']; /** * Gets all column names from a Drizzle table type. * @template TTable The Drizzle table type */ type ColumnNames = keyof Columns; /** * Helper type that extracts primary key columns from a table. * @template T The Drizzle table type */ type PrimaryKeyColumns = { [K in keyof Columns]: Columns[K]['_']['isPrimaryKey'] extends true ? K extends string ? K : never : never; }[keyof Columns]; /** * Finds the primary key(s) from a table. * @template T The Drizzle table type */ type FindPrimaryKeyFromTable = [ PrimaryKeyColumns ] extends [never] ? [never] : [PrimaryKeyColumns]; /** * Type guard that checks if a type is a Table with a specific name. * @template T The type to check * @template Name The name to check for */ type IsTableWithName = T extends { _: { name: Name; }; } ? T extends Table ? true : false : false; /** * Finds a table in the schema by its name. * @template TDrizzleSchema The complete Drizzle schema * @template Name The name of the table to find */ type FindTableByName, Name extends string> = Extract<{ [P in keyof TDrizzleSchema]: IsTableWithName extends true ? TDrizzleSchema[P] : never; }[keyof TDrizzleSchema], Table>; /** * Utility type that flattens an object type by removing any intermediate interfaces. * @template T The type to flatten */ type Flatten = { [K in keyof T]: T[K]; } & {}; /** * Represents a column definition from a Drizzle table, filtered by column name. * @template TTable The Drizzle table type * @template K The column name to filter by */ type ColumnDefinition> = { [C in keyof Columns]: C extends K ? Columns[C] : never; }[keyof Columns]; /** * The type override for a column. * Used to customize how a Drizzle column is mapped to a Zero schema. * @template TCustomType The TypeScript type that corresponds to the Zero type */ type TypeOverride = { readonly type: 'string' | 'number' | 'boolean' | 'json'; readonly optional: boolean; readonly customType: TCustomType; readonly kind?: 'enum'; }; /** * Configuration for specifying which columns to include in the Zero schema and how to map them. * @template TTable The Drizzle table type */ type ColumnsConfig = boolean | Partial<{ /** * The columns to include in the Zero schema. * Set to true to use default mapping, or provide a TypeOverride for custom mapping. */ readonly [KColumn in ColumnNames]: boolean | ColumnBuilder[KColumn]['dataType']]]>>; }>; /** * Maps a Drizzle column type to its corresponding Zero type. */ type ZeroMappedColumnType, CD extends ColumnDefinition['_'] = ColumnDefinition['_']> = CD extends { columnType: keyof DrizzleColumnTypeToZeroType; } ? DrizzleColumnTypeToZeroType[CD['columnType']] : DrizzleDataTypeToZeroType[CD['dataType']]; /** * Maps a Drizzle column to its corresponding TypeScript type in Zero. * Handles special cases like enums and custom types. */ type ZeroMappedCustomType, CD extends ColumnDefinition['_'] = ColumnDefinition['_']> = CD extends { columnType: 'PgCustomColumn'; } ? CD['data'] : CD extends { columnType: 'PgEnumColumn'; } ? CD['data'] : CD extends { columnType: 'PgText'; data: string; } ? CD['data'] : CD extends { columnType: 'PgArray'; data: infer TArrayData; } ? TArrayData : CD extends { $type: any; } ? CD['$type'] : ZeroTypeToTypescriptType[ZeroMappedColumnType]; /** * Defines the structure of a column in the Zero schema. */ type ZeroColumnDefinition> = Flatten<{ optional: boolean; type: ValueType; customType: ZeroMappedCustomType; serverName?: string; }>; type PrimaryKeyColumnNames = Extract[number], ColumnNames>; type IncludedColumnKeys | undefined> = [TColumnConfig] extends [boolean | undefined] ? ColumnNames : [PrimaryKeyColumnNames] extends [never] ? ColumnNames : Extract | { [KColumn in keyof TColumnConfig & ColumnNames]: [ TColumnConfig[KColumn] ] extends [false | undefined] ? never : KColumn; }[keyof TColumnConfig & ColumnNames], ColumnNames>; /** * Maps the columns configuration to their Zero schema definitions. */ type ZeroColumns | undefined> = Flatten<{ [KColumn in IncludedColumnKeys]: TColumnConfig extends object ? KColumn extends keyof TColumnConfig ? TColumnConfig[KColumn] extends ColumnBuilder ? TColumnConfig[KColumn]['schema'] : ZeroColumnDefinition : ZeroColumnDefinition : ZeroColumnDefinition; }>; /** * Represents the underlying schema for a Zero table. */ type ZeroTableBuilderSchema | undefined> = Flatten<{ name: TTableName; primaryKey: FindPrimaryKeyFromTable extends [never] ? readonly [string, ...string[]] : readonly [string, ...string[]] & FindPrimaryKeyFromTable; columns: Flatten>; }>; /** * Represents the complete Zero schema for a Drizzle table. */ type ZeroTableBuilder | undefined> = TableBuilderWithColumns>>; /** * Casing for the Zero table builder. */ type ZeroTableCasing = 'snake_case' | 'camelCase' | undefined; /** * Creates a Zero schema from a Drizzle table definition. * * @returns A Zero schema definition for the table * @throws {Error} If primary key configuration is invalid or column types are unsupported */ declare const createZeroTableBuilder: | undefined = undefined, TCasing extends ZeroTableCasing = ZeroTableCasing>( /** * The mapped name of the table */ tableName: TTableName, /** * The Drizzle table instance */ table: TTable, /** * Configuration specifying which columns to include and how to map them */ columns?: TColumnConfig, /** * Whether to enable debug mode. */ debug?: boolean, /** * The casing to use for the table name. */ casing?: TCasing, /** * Whether to hide warnings for columns with default values. */ suppressDefaultsWarning?: boolean) => ZeroTableBuilder; /** * Get the key of a column in the schema from the column name. * @param columnName - The name of the column to get the key for * @param table - The table to get the column key from * @returns The key of the column in the schema */ declare const getDrizzleColumnKeyFromColumnName: ({ columnName, table, }: { columnName: string; table: Table; }) => string; type IsAny = 0 extends 1 & T ? true : false; type SchemaIsAnyError = { __error__: 'The schema passed in to `ZeroCustomType` is `any`. Please make sure to pass in a proper schema type, or check your imports to make sure that Typescript can resolve your schema definition.'; }; /** * Maps a column definition to its Zero type (string, number, boolean, json). */ type DirectZeroType = CD extends { columnType: keyof DrizzleColumnTypeToZeroType; } ? DrizzleColumnTypeToZeroType[CD['columnType']] : CD extends { dataType: keyof DrizzleDataTypeToZeroType; } ? DrizzleDataTypeToZeroType[CD['dataType']] : never; /** * Maps column types to their default TypeScript types when no custom type is specified. */ type DefaultColumnType = DirectZeroType extends keyof ZeroTypeToTypescriptType ? ZeroTypeToTypescriptType[DirectZeroType] : unknown; /** * Direct extraction of the custom type from Drizzle schema. This falls back * to the default TypeScript type if no custom type is specified. * * @template DrizzleSchema - The Drizzle schema object (typeof drizzleSchema) * @template TableKey - The key of the table in the schema * @template ColumnKey - The key of the column in the table */ type CustomType = TableKey extends keyof DrizzleSchema ? DrizzleSchema[TableKey] extends Table ? ColumnKey extends keyof DrizzleSchema[TableKey] ? DrizzleSchema[TableKey][ColumnKey] extends { _: infer CD; } ? CD extends { columnType: 'PgCustomColumn'; data: infer TData; } ? TData : CD extends { columnType: 'PgEnumColumn'; data: infer TData; } ? TData : CD extends { columnType: 'PgText'; data: infer TData; } ? TData extends string ? TData : string : CD extends { columnType: 'PgArray'; data: infer TArrayData; } ? TArrayData : CD extends { $type: infer TType; } ? TType : DefaultColumnType : unknown : unknown : unknown : unknown; /** * Type utility to get the Drizzle custom type for a table and column. * * @template ZeroSchema - The complete Zero schema * @template TableName - The name of the table * @template ColumnName - The name of the column */ type ZeroCustomType = IsAny extends true ? SchemaIsAnyError : ZeroSchema extends { tables: Record; }>; } ? T : unknown; /** * Configuration type for many-to-many relationships for a specific table. * @template TDrizzleSchema - The complete Drizzle schema * @template TSourceTableName - The name of the source table */ type ManyTableConfig, TSourceTableName extends keyof TDrizzleSchema & string> = { readonly [TRelationName: string]: readonly [keyof TDrizzleSchema, keyof TDrizzleSchema] | { [K in keyof TDrizzleSchema]: { [L in keyof TDrizzleSchema]: readonly [ { readonly destTable: K; readonly sourceField: ColumnIndexKeys>[]; readonly destField: ColumnIndexKeys>[]; }, { readonly destTable: L; readonly sourceField: ColumnIndexKeys>[]; readonly destField: ColumnIndexKeys>[]; } ]; }[keyof TDrizzleSchema]; }[keyof TDrizzleSchema]; }; /** * Configuration for many-to-many relationships across all tables. * Organized by source table, with each relationship specifying a tuple of [junction table name, destination table name]. * The junction table and destination table must be different from the source table and each other. */ type ManyConfig> = { readonly [TSourceTableName in keyof TDrizzleSchema & string]?: ManyTableConfig; }; /** * The mapped Zero schema from a Drizzle schema with version and tables. */ type DrizzleToZeroSchema = DefaultTableColumnsConfig> = { readonly tables: { readonly [K in Extract<{ [TTableName in keyof TDrizzleSchema & keyof TColumnConfig]: TDrizzleSchema[TTableName] extends Table ? [TColumnConfig[TTableName]] extends [false | undefined] ? never : TTableName : never; }[keyof TDrizzleSchema & keyof TColumnConfig], keyof TDrizzleSchema & string>]: TDrizzleSchema[K] extends Table ? ZeroTableBuilderSchema : never; }; readonly relationships: any; readonly enableLegacyMutators?: boolean; readonly enableLegacyQueries?: boolean; }; /** * Configuration for the Zero schema generator. This defines how your Drizzle ORM schema * is transformed into a Zero schema format, handling both direct relationships and many-to-many relationships. * * This allows you to: * - Select which tables to include in the Zero schema * - Configure column types and transformations * - Define many-to-many relationships through junction tables * * @param schema - The Drizzle schema to create a Zero schema from. This should be your complete Drizzle schema object * containing all your table definitions and relationships. * @param config - Configuration object for the Zero schema generation * @param config.tables - Specify which tables and columns to include in sync * @param config.manyToMany - Optional configuration for many-to-many relationships through junction tables * @param config.casing - The casing to use for the table name. * @param config.debug - Whether to enable debug mode. * * @returns A configuration object for the Zero schema CLI. * * @example * ```typescript * import { integer, pgTable, serial, text, varchar } from 'drizzle-orm/pg-core'; * import { relations } from 'drizzle-orm'; * import { drizzleZeroConfig } from 'drizzle-zero'; * * // Define Drizzle schema * const users = pgTable('users', { * id: serial('id').primaryKey(), * name: text('name'), * }); * * const posts = pgTable('posts', { * id: serial('id').primaryKey(), * title: varchar('title'), * authorId: integer('author_id').references(() => users.id), * }); * * const usersRelations = relations(users, ({ one }) => ({ * posts: one(posts, { * fields: [users.id], * references: [posts.authorId], * }), * })); * * // Export the configuration for the Zero schema CLI * export default drizzleZeroConfig( * { users, posts, usersRelations }, * { * tables: { * users: { * id: true, * name: true, * }, * posts: { * id: true, * title: true, * authorId: true, * }, * }, * } * ); * ``` */ declare const drizzleZeroConfig: = DefaultTableColumnsConfig, const TManyConfig extends ManyConfig | undefined = undefined, const TCasing extends ZeroTableCasing = undefined>( /** * The Drizzle schema to create a Zero schema from. */ schema: TDrizzleSchema, /** * The configuration for the Zero schema. * * @param config.tables - The tables to include in the Zero schema. * @param config.many - Configuration for many-to-many relationships. */ config?: { /** * Specify the tables to include in the Zero schema. * This can include type overrides for columns, using `column.json()` for example. * * @example * ```ts * { * user: { * id: true, * name: true, * }, * profile_info: { * id: true, * user_id: true, * metadata: column.json(), * }, * } * ``` */ readonly tables?: TColumnConfig; /** * Configuration for many-to-many relationships. * Organized by source table, with each relationship specifying a tuple of [junction table name, destination table name]. * * @example * ```ts * { * user: { * comments: ['message', 'comment'] * } * } * ``` */ readonly manyToMany?: TManyConfig; /** * The casing to use for the table name. * * @example * ```ts * { casing: 'snake_case' } * ``` */ readonly casing?: TCasing; /** * Whether to enable debug mode. * * @example * ```ts * { debug: true } * ``` */ readonly debug?: boolean; /** * Whether to hide warnings for columns with default values. * * @example * ```ts * { suppressDefaultsWarning: true } * ``` * @see https://bugs.rocicorp.dev/p/zero/issue/3465 */ readonly suppressDefaultsWarning?: boolean; }) => Flatten>; export { type ColumnsConfig, type CustomType, type DrizzleToZeroSchema, type ZeroColumns, type ZeroCustomType, type ZeroTableBuilder, type ZeroTableBuilderSchema, type ZeroTableCasing, createZeroTableBuilder, drizzleZeroConfig, getDrizzleColumnKeyFromColumnName };