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(),
|
2026-06-29 00:27:51 -05:00
|
|
|
display_name: varchar({ length: 63 }).unique().notNull(),
|
2026-05-23 17:35:08 -05:00
|
|
|
|
2026-06-29 00:27:51 -05:00
|
|
|
username: varchar({ length: 63 }).unique().notNull(),
|
2026-05-23 17:35:08 -05:00
|
|
|
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
|
|
|
}));
|