Files
blog-service/backend/src/db/schema.ts
T

103 lines
2.8 KiB
TypeScript
Raw Normal View History

2025-12-26 21:30:38 -06:00
import {
timestamp,
uuid,
pgTable,
pgEnum,
jsonb,
varchar,
integer,
bigint,
2026-06-28 20:06:01 -05:00
unique,
2026-05-23 17:35:08 -05:00
boolean,
smallint,
check
2025-12-26 21:30:38 -06:00
} from "drizzle-orm/pg-core";
2026-06-28 00:18:49 -05:00
import { sql, defineRelations } from "drizzle-orm";
2025-12-26 21:30:38 -06:00
export const blockTypeEnum = pgEnum("post_block_type", [
"title",
"paragraph",
"heading",
"image",
"code",
"quote",
"ordered_list",
"unordered_list"
]);
export const articleStatusEnum = pgEnum("post_status", [
"draft",
"published"
]);
2025-11-14 17:47:23 -06:00
2025-11-23 23:35:41 -06:00
export const articles = pgTable("articles", {
id: uuid().notNull().primaryKey().defaultRandom(),
2025-12-26 21:30:38 -06:00
2025-11-14 17:47:23 -06:00
name: varchar({ length: 255 }).notNull(),
2026-06-28 20:06:01 -05:00
article_status: articleStatusEnum().notNull().default("draft"),
author_id: uuid().notNull().references(() => users.id, { onDelete: "cascade" }),
2026-05-23 17:35:08 -05:00
slug: varchar({ length: 511 }).unique().notNull(),
2025-12-26 21:30:38 -06:00
summary: varchar({ length: 255 }).notNull(),
date_created: timestamp({ mode: "date", withTimezone: true }).defaultNow().notNull(),
last_edit: timestamp({ mode: "date", withTimezone: true }).defaultNow().notNull(),
date_published: timestamp({ mode: "date", withTimezone: true }),
2026-06-28 20:06:01 -05:00
},
(table) => [{
slugIdx: unique("no_repeat_slugs_per_author")
.on(table.author_id, table.slug)
}]);
2025-11-14 17:47:23 -06:00
2025-12-26 21:30:38 -06:00
export const articleBlocks = pgTable("article_blocks", {
id: uuid().notNull().primaryKey().defaultRandom(),
article_id: uuid().notNull().references(() => articles.id, { onDelete: "cascade" }),
position: integer().notNull(),
type: blockTypeEnum().notNull(),
content: jsonb().$type<Record<string, unknown>>().notNull(),
},
(table) => [{
2026-06-28 20:06:01 -05:00
postPositionIdx: unique("no_repeat_block_position_per_article")
.on(table.article_id, table.position)
2025-12-26 21:30:38 -06:00
}]);
export const images = pgTable("images", {
2026-06-28 20:06:01 -05:00
id: uuid().notNull().primaryKey().defaultRandom(), // Linked in 'content' of articleBlock with type 'image'
2025-12-26 21:30:38 -06:00
bucket: varchar({ length: 63 }).notNull(),
key: varchar({ length: 255 }).notNull(),
mime_type: varchar({ length: 63 }).notNull(),
height: integer().notNull(),
width: integer().notNull(),
bytes: bigint({ mode: "number" }).notNull(),
});
2026-05-23 17:35:08 -05:00
export const users = pgTable("users", {
id: uuid().notNull().primaryKey().defaultRandom(),
display_name: varchar({ length: 63 }).notNull(),
username: varchar({ length: 63 }).notNull(),
hashed_password: varchar({ length: 255 }).notNull(),
logged_in: boolean().notNull().default(false),
token: varchar({ length: 511 }),
permissions: smallint().notNull().default(44),
},
2026-06-28 20:06:01 -05:00
(_) => [
2026-05-23 17:35:08 -05:00
check("permissions lower bound", sql`users.permissions >= 0`),
check("permissions upper bound", sql`users.permissions <= 77`),
]
);
2025-12-26 21:30:38 -06:00
2026-06-28 20:06:01 -05:00
export const relations = defineRelations({ articles, articleBlocks, users }, (r) => ({
2026-06-28 00:18:49 -05:00
articles: {
blocks: r.many.articleBlocks()
},
articleBlocks: {
article: r.one.articles({
from: r.articleBlocks.article_id,
to: r.articles.id
})
}
2025-12-26 21:30:38 -06:00
}));