Lab 07: Type-Safe ORM
Overview
Step 1: Drizzle ORM Schema Definition
import { sqliteTable, text, integer, real, index, primaryKey } from 'drizzle-orm/sqlite-core';
import { relations } from 'drizzle-orm';
import { createId } from '@paralleldrive/cuid2';
// Schema definition is the source of truth for TypeScript types
export const users = sqliteTable('users', {
id: text('id').primaryKey().$defaultFn(() => createId()),
name: text('name').notNull(),
email: text('email').notNull().unique(),
role: text('role', { enum: ['admin', 'user', 'guest'] }).notNull().default('user'),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().$defaultFn(() => new Date()),
updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull().$defaultFn(() => new Date()),
}, (t) => ({
emailIdx: index('users_email_idx').on(t.email),
roleIdx: index('users_role_idx').on(t.role),
}));
export const posts = sqliteTable('posts', {
id: text('id').primaryKey().$defaultFn(() => createId()),
title: text('title').notNull(),
body: text('body').notNull(),
authorId: text('author_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
published: integer('published', { mode: 'boolean' }).notNull().default(false),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().$defaultFn(() => new Date()),
});
// Relations — enable join queries
export const usersRelations = relations(users, ({ many }) => ({
posts: many(posts),
}));
export const postsRelations = relations(posts, ({ one }) => ({
author: one(users, { fields: [posts.authorId], references: [users.id] }),
}));
// Inferred types — free from schema
export type User = typeof users.$inferSelect; // SELECT result
export type NewUser = typeof users.$inferInsert; // INSERT shape
export type UserRole = typeof users.role.enumValues[number]; // 'admin' | 'user' | 'guest'Step 2: Drizzle Queries — Type-Inferred Results
Step 3: Drizzle — CTEs and Window Functions
Step 4: Kysely — Fully Typed SQL Builder
Step 5: Branded Types for SQL Safety
Step 6: Type-Safe Migrations
Step 7: Repository Pattern with Type Safety
Step 8: Capstone — Drizzle + better-sqlite3 Verification
Summary
Feature
Drizzle
Kysely
Last updated
