-
Notifications
You must be signed in to change notification settings - Fork 1
RFC: High-level database API + Auto Schema Sync #58
Copy link
Copy link
Open
Description
Summary
This issue proposes a new architecture for @deessejs/collections that provides a higher-level API similar to PayloadCMS but simpler, with automatic schema synchronization in development.
Current State
Currently, @deessejs/collections:
- Uses
defineConfig()to create collections - Exposes raw Drizzle instance:
db.select().from(posts).where(...) - Requires manual CLI commands:
db:push,db:generate,db:migrate
Proposed Architecture
1. High-Level API
const { collections, db } = defineConfig({
database: adapter,
collections: [Users, Posts]
})
// Instead of: db.select().from(posts).where(...)
// We get:
await db.posts.find({ where: { status: 'published' } })
await db.posts.findById(1)
await db.posts.create({ data: { title: 'Hello' } })
await db.posts.update({ where: { id: 1 }, data: { title: 'Updated' } })
await db.posts.delete({ where: { id: 1 } })
await db.posts.count({ where: { status: 'draft' } })2. No Generated Types File Needed
Unlike PayloadCMS which needs payload-types.ts because config is runtime, our approach preserves TypeScript types through inference:
// Types are automatically inferred
db.posts.find() // TypeScript knows the return type
collections.users.slug // Typed as 'users'3. Simplified CLI
Only db:push is needed since schema is implicit (no migration files):
collections db:push # Sync schema to database
collections db:push --dry-run # Preview changes4. Default Config Path
Default location for collections config:
lib/collections.ts
Can be overridden:
withCollections({
collectionsPath: './config/my-collections.ts'
}, nextConfig)5. Auto Schema Push in Development
withCollections includes a worker that automatically watches for config changes and pushes the schema:
// Development mode (automatic)
// - Worker watches lib/collections.ts
// - Detects changes to collections
// - Auto db:push in background
// Production mode
// - No worker
// - User runs db:push once manuallyAPI Design (Detailed)
Query Methods
db.posts.find({
where: { status: 'published', authorId: 1 },
select: { id: true, title: true },
orderBy: { createdAt: 'desc' },
limit: 10,
offset: 0
})
db.posts.findById(id, { select: { id: true, title: true } })
db.posts.count({ where: { status: 'draft' } })Mutation Methods
db.posts.create({
data: { title: 'Hello', content: '...' },
returning: true // default
})
db.posts.update({
where: { id: 1 },
data: { title: 'Updated' },
returning: true
})
db.posts.delete({
where: { id: 1 },
returning: false
})Hooks Support
const posts = collection({
slug: 'posts',
fields: { ... },
hooks: {
beforeCreate: [validateData],
afterCreate: [logCreation]
}
})Hooks are automatically executed by the high-level API.
Open Questions
- Where syntax: Simple equality vs operators (e.g.,
{ title: 'hello' }vs{ title: { $contains: 'hello' } }) - Pagination: Cursor-based vs offset-based
- Transactions: How to handle multi-collection transactions
- Return format: Just data vs data + metadata (total, page, etc.)
Implementation Plan
- Create high-level
DbWrapperwith collection methods - Update
defineConfigto returndbwith collection operations - Implement CRUD operations with hooks
- Simplify CLI (keep only
db:push) - Add default config path detection
- Implement schema watcher for auto-push in dev
References
- PayloadCMS architecture analysis: RFC: Auto-schema push in development mode (like PayloadCMS) #57
- Drizzle ORM: https://drizzle-orm.com
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels