53 lines
2.2 KiB
SQL
53 lines
2.2 KiB
SQL
CREATE TABLE IF NOT EXISTS users (
|
|
id SERIAL PRIMARY KEY,
|
|
username TEXT NOT NULL,
|
|
password_hash TEXT NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
CREATE UNIQUE INDEX IF NOT EXISTS users_username_lower_key ON users (lower(username));
|
|
|
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
token_hash BYTEA PRIMARY KEY,
|
|
user_id INT NOT NULL REFERENCES users ON DELETE CASCADE,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
expires_at TIMESTAMPTZ NOT NULL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS sessions_user_id_idx ON sessions (user_id);
|
|
|
|
CREATE TABLE IF NOT EXISTS genres (
|
|
id SMALLSERIAL PRIMARY KEY,
|
|
name TEXT NOT NULL UNIQUE
|
|
);
|
|
|
|
-- WHERE NOT EXISTS instead of ON CONFLICT: ON CONFLICT consumes a sequence value per row
|
|
-- on every startup, which would eventually overflow SMALLSERIAL.
|
|
INSERT INTO genres (name)
|
|
SELECT seed.name
|
|
FROM (VALUES ('Fiction'), ('Non-Fiction'), ('Mystery'), ('Thriller'), ('Science Fiction'),
|
|
('Fantasy'), ('Romance'), ('Horror'), ('Historical Fiction'), ('Biography'),
|
|
('Memoir'), ('Self-Help'), ('Science'), ('History'), ('Poetry'), ('Other')) AS seed(name)
|
|
WHERE NOT EXISTS (SELECT 1 FROM genres WHERE genres.name = seed.name);
|
|
|
|
CREATE TABLE IF NOT EXISTS books (
|
|
id SERIAL PRIMARY KEY,
|
|
user_id INT NOT NULL REFERENCES users ON DELETE CASCADE,
|
|
title TEXT NOT NULL CHECK (btrim(title) <> ''),
|
|
author TEXT NOT NULL CHECK (btrim(author) <> ''),
|
|
genre_id SMALLINT NOT NULL REFERENCES genres,
|
|
total_pages INT NOT NULL CHECK (total_pages > 0),
|
|
current_page INT NOT NULL DEFAULT 0,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
CONSTRAINT books_current_page_range CHECK (current_page BETWEEN 0 AND total_pages)
|
|
);
|
|
CREATE INDEX IF NOT EXISTS books_user_id_idx ON books (user_id);
|
|
|
|
CREATE TABLE IF NOT EXISTS notes (
|
|
id SERIAL PRIMARY KEY,
|
|
book_id INT NOT NULL REFERENCES books ON DELETE CASCADE,
|
|
body TEXT NOT NULL CHECK (btrim(body) <> ''),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
CREATE INDEX IF NOT EXISTS notes_book_id_idx ON notes (book_id);
|