LLM DOCS:VIEW
Models & Database
Lockness uses Drizzle ORM for type-safe database operations with PostgreSQL.
Creating Models
Generate a model with all related files:
bash
deno task cli make:model Post -aThe -a flag creates:
app/model/post.ts- Drizzle schema + Zod validationapp/repository/post_repository.ts- Data access layerapp/controller/post_controller.ts- REST API controllerapp/seeder/post_seeder.ts- Database seeder
Defining Models
Create a Drizzle table schema:
typescript
// app/model/post.ts
import { boolean, pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core'
import { createInsertSchema, createSelectSchema } from 'drizzle-zod'
import { z } from 'zod'
export const posts = pgTable('posts', {
id: serial('id').primaryKey(),
title: text('title').notNull(),
content: text('content').notNull(),
published: boolean('published').default(false),
createdAt: timestamp('created_at').defaultNow(),
updatedAt: timestamp('updated_at').defaultNow(),
})
// Validation schemas
export const insertPostSchema = createInsertSchema(posts, {
title: z.string().min(5).max(200),
content: z.string().min(10),
})
export const selectPostSchema = createSelectSchema(posts)
// TypeScript types
export type Post = typeof posts.$inferSelect
export type NewPost = typeof posts.$inferInsertRepositories
Repositories provide a clean data access layer:
typescript
// app/repository/post_repository.ts
import { Inject, Service } from '@lockness/core'
import { Database } from '@lockness/drizzle'
import { type NewPost, type Post, posts } from '../model/post.ts'
import { eq } from 'drizzle-orm'
@Service()
export class PostRepository {
@Inject(Database)
accessor db!: Database
async findAll(): Promise<Post[]> {
return await this.db.instance.select().from(posts)
}
async findById(id: number): Promise<Post | undefined> {
const result = await this.db.instance
.select()
.from(posts)
.where(eq(posts.id, id))
return result[0]
}
async create(data: NewPost): Promise<Post> {
const result = await this.db.instance
.insert(posts)
.values(data)
.returning()
return result[0]
}
async update(id: number, data: Partial<NewPost>): Promise<Post> {
const result = await this.db.instance
.update(posts)
.set(data)
.where(eq(posts.id, id))
.returning()
return result[0]
}
async delete(id: number): Promise<void> {
await this.db.instance.delete(posts).where(eq(posts.id, id))
}
}Migrations
Generate migrations from your schema:
bash
deno task cli db:generateThis creates migration files in migrations/:
sql
-- migrations/0001_create_posts.sql
CREATE TABLE "posts" (
"id" serial PRIMARY KEY,
"title" text NOT NULL,
"content" text NOT NULL,
"published" boolean DEFAULT false,
"created_at" timestamp DEFAULT now(),
"updated_at" timestamp DEFAULT now()
);Apply migrations:
bash
deno task cli db:migrateSeeders
Create seed data for testing:
typescript
// app/seeder/post_seeder.ts
import { Database } from '@lockness/drizzle'
import { posts } from '../model/post.ts'
export class PostSeeder {
async run(db: Database) {
await db.instance.insert(posts).values([
{
title: 'First Post',
content: 'This is the content of the first post',
published: true,
},
{
title: 'Second Post',
content: 'This is the content of the second post',
published: false,
},
])
}
}Run seeders:
bash
deno task cli db:seedRelationships
Define relationships between models:
typescript
import { integer, pgTable, serial, text } from 'drizzle-orm/pg-core'
import { relations } from 'drizzle-orm'
export const users = pgTable('users', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
})
export const posts = pgTable('posts', {
id: serial('id').primaryKey(),
title: text('title').notNull(),
authorId: integer('author_id').references(() => users.id),
})
// Define relations
export const usersRelations = relations(users, ({ many }) => ({
posts: many(posts),
}))
export const postsRelations = relations(posts, ({ one }) => ({
author: one(users, {
fields: [posts.authorId],
references: [users.id],
}),
}))Query with relations:
typescript
const postsWithAuthors = await db.instance.query.posts.findMany({
with: {
author: true,
},
})Query Building
Use Drizzle's query builder for complex queries:
typescript
import { and, desc, eq, like } from 'drizzle-orm'
// Find published posts by author
const publishedPosts = await db.instance
.select()
.from(posts)
.where(and(
eq(posts.published, true),
eq(posts.authorId, userId),
))
.orderBy(desc(posts.createdAt))
// Search posts by title
const searchResults = await db.instance
.select()
.from(posts)
.where(like(posts.title, `%${query}%`))Drizzle Studio
Launch the visual database browser:
bash
dx drizzle-kit studioThis opens Drizzle Studio at https://local.drizzle.studio where you can:
- Browse tables and data
- Run queries
- Edit records
- View relationships
- Manage your database visually