Drizzle ORM
Drizzle ORM is a TypeScript ORM with type-safe schema definitions. gqlkit integrates seamlessly with Drizzle by using InferSelectModel and InferInsertModel to derive GraphQL types from your table definitions.
Installation
npm install drizzle-orm postgrespnpm add drizzle-orm postgresyarn add drizzle-orm postgresDefining Tables
Define your database tables with Drizzle:
// src/db/schema.ts
import { pgEnum, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
export const userStatusEnum = pgEnum("user_status", [
"active",
"inactive",
"suspended",
]);
export const users = pgTable("users", {
id: uuid().primaryKey().defaultRandom(),
name: text().notNull(),
email: text().notNull().unique(),
status: userStatusEnum().notNull().default("active"),
createdAt: timestamp().notNull().defaultNow(),
});
export const posts = pgTable("posts", {
id: uuid().primaryKey().defaultRandom(),
title: text().notNull(),
content: text(),
priority: text({ enum: ["low", "medium", "high"] }).notNull().default("medium"),
authorId: uuid()
.notNull()
.references(() => users.id),
createdAt: timestamp().notNull().defaultNow(),
});Both pgEnum() and text({ enum: [...] }) are supported for defining enum columns. gqlkit automatically generates corresponding GraphQL enum types from these definitions.
Defining Custom Scalars
Define custom scalar types using GqlScalar for fields like timestamps:
// src/gqlkit/schema/scalars.ts
import type { GqlScalar } from "@gqlkit-ts/runtime";
export type DateTime = GqlScalar<"DateTime", Date>;Exporting GraphQL Types
Use Drizzle’s type inference utilities to export GraphQL types from your table definitions:
// src/gqlkit/schema/user.ts
import type { InferSelectModel } from "drizzle-orm";
import { users as usersTable } from "../../db/schema.js";
// Export as GraphQL object type
export type User = InferSelectModel<typeof usersTable>;This generates the following GraphQL schema:
enum UserStatus {
ACTIVE
INACTIVE
SUSPENDED
}
type User {
id: String!
name: String!
email: String!
status: UserStatus!
createdAt: DateTime!
}Defining Resolvers
Define resolvers that use the derived types:
// src/gqlkit/schema/user.ts
import type { NoArgs } from "@gqlkit-ts/runtime";
import type { InferInsertModel, InferSelectModel } from "drizzle-orm";
import { eq } from "drizzle-orm";
import { posts as postsTable, users as usersTable } from "../../db/schema.js";
import { defineField, defineMutation, defineQuery } from "../gqlkit.js";
import type { Post } from "./post.js";
export type User = InferSelectModel<typeof usersTable>;
export const allUsers = defineQuery<NoArgs, User[]>(
async (_root, _args, ctx) => {
return ctx.db.select().from(usersTable);
},
);
export const user = defineQuery<{ id: string }, User | null>(
async (_root, args, ctx) => {
const result = await ctx.db
.select()
.from(usersTable)
.where(eq(usersTable.id, args.id));
return result[0] ?? null;
},
);
export const createUser = defineMutation<
{ input: Omit<InferInsertModel<typeof usersTable>, "id" | "createdAt"> },
User
>(async (_root, args, ctx) => {
const result = await ctx.db.insert(usersTable).values(args.input).returning();
return result[0]!;
});
export const posts = defineField<User, NoArgs, Post[]>(
async (parent, _args, ctx) => {
return ctx.db
.select()
.from(postsTable)
.where(eq(postsTable.authorId, parent.id));
},
);Context with Database
Set up the context type to include your database instance. For basic setup, see Set Up Context and Resolver Factories.
// src/db/db.ts
import { drizzle } from "drizzle-orm/postgres-js";
import postgres from "postgres";
import * as schema from "./schema.js";
const client = postgres(process.env.DATABASE_URL!);
export const db = drizzle(client, { schema, casing: "snake_case" });
export type Database = typeof db;// src/gqlkit/context.ts
import type { Database } from "../db/db.js";
export type Context = {
db: Database;
};Complete Example
See the examples/with-drizzle directory for a complete working example with:
- PostgreSQL tables with DateTime scalar
- Enum types using both
pgEnum()andtext({ enum: [...] }) - User and Post types with relationships
- Query, Mutation, and Field resolvers