TypeScript Helpers for Drizzle

April 22, 2024

TypeScript Helpers for Drizzle

Table of Contents

Models

InferInsertModel

This is a custom type is similar to the built-in InferInsertModel type, but allows columns with default values to be omitted.

  • ColumnConfigs - a utility type that extracts a filtered list of column configurations from a table schema.
  • RequiredColumns - extracts the columns that are required and do not have a default value.
  • OptionalColumns - extracts the columns that are optional and may have a default value.
  • Prettify - a simple type that combines the properties of two object types.
ts
import type { AnyColumn, AnyTable, ColumnBaseConfig, ColumnDataType, GetColumnData } from "drizzle-orm";

type ColumnConfigs<Table extends AnyTable<{}>, Filter extends Partial<ColumnBaseConfig<ColumnDataType, string>> = {}> = {
	[K in keyof Table["_"]["columns"] as Table["_"]["columns"][K] extends AnyColumn<Filter> ? K : never]: GetColumnData<
		Table["_"]["columns"][K]
	>;
};

type RequiredColumns<Table extends AnyTable<{}>> = ColumnConfigs<Table, { notNull: true; hasDefault: false }>;
type OptionalColumns<Table extends AnyTable<{}>, Defaults extends boolean = true> = Defaults extends true
	? Partial<ColumnConfigs<Table, { notNull: false } | { hasDefault: true }>>
	: Partial<ColumnConfigs<Table, { notNull: false; hasDefault: false }>>;

type InferInsertModel<Table extends AnyTable<{}>, Defaults extends boolean = true> = Prettify<
	RequiredColumns<Table> & OptionalColumns<Table, Defaults>
>;

Example

InferQueryModel

This custom type takes two arguments. The table name from the schema, and a query builder configuration object. It returns the type of the query result.

ts
import * as schema from "$server/db/schema";
import type { BuildQueryResult, DBQueryConfig, ExtractTablesWithRelations } from "drizzle-orm";

type TSchema = ExtractTablesWithRelations<typeof schema>;
export type QueryConfig<TableName extends keyof TSchema> = DBQueryConfig<"one" | "many", boolean, TSchema, TSchema[TableName]>;
export type InferQueryModel<
	TableName extends keyof TSchema,
	QBConfig extends QueryConfig<TableName> = {}
> = BuildQueryResult<TSchema, TSchema[TableName], QBConfig>;

Example

ts
export const logIncludes = {
	dm: true,
	magicItemsGained: true,
	magicItemsLost: true,
	storyAwardsGained: true,
	storyAwardsLost: true
} as const satisfies QueryConfig<"logs">["with"];

export type LogData = InferQueryModel<"logs", { with: typeof logIncludes }>;

const log = await q.logs.findFirst({
  with: logIncludes,
  where: (logs, { eq }) => eq(logs.id, logId)
});