feat(04-01): add tags schema with case-insensitive unique index
- Add tags table with nanoid PK and case-insensitive unique index on name - Add entry_tags junction table with composite PK and cascade deletes - Export lower() helper function for case-insensitive queries - Export Tag, NewTag, EntryTag types for TypeScript inference
This commit is contained in:
@@ -1,4 +1,11 @@
|
||||
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
|
||||
import { sqliteTable, text, integer, uniqueIndex, primaryKey } from 'drizzle-orm/sqlite-core';
|
||||
import { sql, type SQL } from 'drizzle-orm';
|
||||
import type { AnySQLiteColumn } from 'drizzle-orm/sqlite-core';
|
||||
|
||||
// Helper function for case-insensitive indexing
|
||||
export function lower(column: AnySQLiteColumn): SQL {
|
||||
return sql`lower(${column})`;
|
||||
}
|
||||
|
||||
// Entry types: 'task' (actionable) or 'thought' (reference)
|
||||
export const entries = sqliteTable('entries', {
|
||||
@@ -36,3 +43,35 @@ export const images = sqliteTable('images', {
|
||||
|
||||
export type Image = typeof images.$inferSelect;
|
||||
export type NewImage = typeof images.$inferInsert;
|
||||
|
||||
// Tags table: reusable tags for organizing entries
|
||||
export const tags = sqliteTable(
|
||||
'tags',
|
||||
{
|
||||
id: text('id').primaryKey(), // nanoid
|
||||
name: text('name').notNull(),
|
||||
createdAt: text('created_at')
|
||||
.notNull()
|
||||
.$defaultFn(() => new Date().toISOString())
|
||||
},
|
||||
(table) => [uniqueIndex('tagNameUniqueIndex').on(lower(table.name))]
|
||||
);
|
||||
|
||||
export type Tag = typeof tags.$inferSelect;
|
||||
export type NewTag = typeof tags.$inferInsert;
|
||||
|
||||
// Junction table for many-to-many entry-tag relationship
|
||||
export const entryTags = sqliteTable(
|
||||
'entry_tags',
|
||||
{
|
||||
entryId: text('entry_id')
|
||||
.notNull()
|
||||
.references(() => entries.id, { onDelete: 'cascade' }),
|
||||
tagId: text('tag_id')
|
||||
.notNull()
|
||||
.references(() => tags.id, { onDelete: 'cascade' })
|
||||
},
|
||||
(t) => [primaryKey({ columns: [t.entryId, t.tagId] })]
|
||||
);
|
||||
|
||||
export type EntryTag = typeof entryTags.$inferSelect;
|
||||
|
||||
Reference in New Issue
Block a user