2fd71fd406
- drafts stay unnumbered, the number is handed out when an entry goes live - DELETE /api/v1/media/:id and a delete control in the media library - cover_media_id in the draft read, coverMediaId and coverUrl in the archive read
75 lines
3.6 KiB
TypeScript
75 lines
3.6 KiB
TypeScript
import { sql } from 'drizzle-orm'
|
|
import { index, integer, jsonb, pgEnum, pgTable, primaryKey, text, timestamp, unique, uuid } from 'drizzle-orm/pg-core'
|
|
import { projects } from './brands'
|
|
import { media } from './media'
|
|
import { postTypes } from './post-types'
|
|
|
|
export const postAudience = pgEnum('post_audience', ['internal', 'customer', 'public'])
|
|
export const postStatus = pgEnum('post_status', ['draft', 'review', 'scheduled', 'published', 'archived'])
|
|
export const postLocale = pgEnum('post_locale', ['de', 'en'])
|
|
export const issueStatus = pgEnum('issue_status', ['draft', 'scheduled', 'published'])
|
|
|
|
export const issues = pgTable('issue', {
|
|
id: uuid('id').primaryKey().defaultRandom(),
|
|
projectId: uuid('project_id').notNull().references(() => projects.id, { onDelete: 'cascade' }),
|
|
title: text('title').notNull(),
|
|
periodFrom: timestamp('period_from', { withTimezone: true }),
|
|
periodTo: timestamp('period_to', { withTimezone: true }),
|
|
status: issueStatus('status').notNull().default('draft'),
|
|
publishAt: timestamp('publish_at', { withTimezone: true }),
|
|
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
|
})
|
|
|
|
export const posts = pgTable('post', {
|
|
id: uuid('id').primaryKey().defaultRandom(),
|
|
projectId: uuid('project_id').notNull().references(() => projects.id, { onDelete: 'cascade' }),
|
|
issueId: uuid('issue_id').references(() => issues.id, { onDelete: 'set null' }),
|
|
number: integer('number'),
|
|
slug: text('slug').notNull(),
|
|
title: text('title').notNull(),
|
|
teaser: text('teaser'),
|
|
typeId: uuid('type_id')
|
|
.notNull()
|
|
.default(sql`post_type_default()`)
|
|
.references(() => postTypes.id, { onDelete: 'restrict' }),
|
|
audience: postAudience('audience').notNull().default('internal'),
|
|
status: postStatus('status').notNull().default('draft'),
|
|
locale: postLocale('locale').notNull().default('de'),
|
|
translationGroup: uuid('translation_group'),
|
|
publishAt: timestamp('publish_at', { withTimezone: true }),
|
|
authorName: text('author_name'),
|
|
coverMediaId: uuid('cover_media_id').references(() => media.id, { onDelete: 'set null' }),
|
|
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
|
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
|
|
}, table => [
|
|
unique('post_project_slug').on(table.projectId, table.slug),
|
|
unique('post_project_number').on(table.projectId, table.number),
|
|
index('post_publish_at').on(table.publishAt),
|
|
index('post_project_status').on(table.projectId, table.status),
|
|
])
|
|
|
|
export const blocks = pgTable('block', {
|
|
id: uuid('id').primaryKey().defaultRandom(),
|
|
postId: uuid('post_id').notNull().references(() => posts.id, { onDelete: 'cascade' }),
|
|
sort: integer('sort').notNull().default(0),
|
|
type: text('type').notNull(),
|
|
data: jsonb('data').$type<Record<string, unknown>>().notNull().default({}),
|
|
}, table => [index('block_post_sort').on(table.postId, table.sort)])
|
|
|
|
export const tags = pgTable('tag', {
|
|
id: uuid('id').primaryKey().defaultRandom(),
|
|
projectId: uuid('project_id').notNull().references(() => projects.id, { onDelete: 'cascade' }),
|
|
slug: text('slug').notNull(),
|
|
label: text('label').notNull(),
|
|
}, table => [unique('tag_project_slug').on(table.projectId, table.slug)])
|
|
|
|
export const postTags = pgTable('post_tag', {
|
|
postId: uuid('post_id').notNull().references(() => posts.id, { onDelete: 'cascade' }),
|
|
tagId: uuid('tag_id').notNull().references(() => tags.id, { onDelete: 'cascade' }),
|
|
}, table => [primaryKey({ columns: [table.postId, table.tagId] })])
|
|
|
|
export type Issue = typeof issues.$inferSelect
|
|
export type Post = typeof posts.$inferSelect
|
|
export type Block = typeof blocks.$inferSelect
|
|
export type Tag = typeof tags.$inferSelect
|