170 lines
4.9 KiB
JavaScript

import { mkdirSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { DatabaseSync } from "node:sqlite";
import { catalogProducts } from "./catalog.js";
const __dirname = dirname(fileURLToPath(import.meta.url));
export const dbPath = join(__dirname, "../data/shop.sqlite");
mkdirSync(dirname(dbPath), { recursive: true });
export const db = new DatabaseSync(dbPath);
db.exec(`
PRAGMA foreign_keys = ON;
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT NOT NULL UNIQUE,
password_hash TEXT NOT NULL,
password_salt TEXT NOT NULL,
name TEXT,
first_name TEXT NOT NULL,
surname TEXT NOT NULL,
address TEXT,
street_name TEXT,
house_number TEXT,
zip_code TEXT,
city TEXT,
birthdate TEXT,
created_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS sessions (
token TEXT PRIMARY KEY,
user_id INTEGER NOT NULL,
created_at TEXT NOT NULL,
expires_at TEXT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS products (
id TEXT PRIMARY KEY,
slug TEXT NOT NULL,
name TEXT NOT NULL,
kind TEXT NOT NULL,
size_label TEXT NOT NULL,
price_cents INTEGER NOT NULL,
discovery_credit_cents INTEGER NOT NULL DEFAULT 0
);
CREATE TABLE IF NOT EXISTS cart_items (
user_id INTEGER NOT NULL,
product_id TEXT NOT NULL,
quantity INTEGER NOT NULL,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
PRIMARY KEY (user_id, product_id),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (product_id) REFERENCES products(id)
);
CREATE TABLE IF NOT EXISTS orders (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
subtotal_cents INTEGER NOT NULL,
discount_cents INTEGER NOT NULL,
total_cents INTEGER NOT NULL,
shipping_address TEXT NOT NULL,
payment_method TEXT NOT NULL,
created_at TEXT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS order_items (
id INTEGER PRIMARY KEY AUTOINCREMENT,
order_id INTEGER NOT NULL,
product_id TEXT NOT NULL,
quantity INTEGER NOT NULL,
unit_price_cents INTEGER NOT NULL,
line_total_cents INTEGER NOT NULL,
FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE,
FOREIGN KEY (product_id) REFERENCES products(id)
);
CREATE TABLE IF NOT EXISTS discovery_credits (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
order_id INTEGER NOT NULL,
amount_cents INTEGER NOT NULL,
redeemed_order_id INTEGER,
created_at TEXT NOT NULL,
redeemed_at TEXT,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE,
FOREIGN KEY (redeemed_order_id) REFERENCES orders(id)
);
CREATE TABLE IF NOT EXISTS sample_credits (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
slug TEXT NOT NULL,
order_id INTEGER NOT NULL,
amount_cents INTEGER NOT NULL,
redeemed_order_id INTEGER,
created_at TEXT NOT NULL,
redeemed_at TEXT,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE,
FOREIGN KEY (redeemed_order_id) REFERENCES orders(id)
);
CREATE TABLE IF NOT EXISTS notification_preferences (
user_id INTEGER PRIMARY KEY,
drops_enabled INTEGER NOT NULL DEFAULT 0,
restocks_enabled INTEGER NOT NULL DEFAULT 0,
small_batch_enabled INTEGER NOT NULL DEFAULT 0,
discovery_enabled INTEGER NOT NULL DEFAULT 0,
updated_at TEXT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS product_subscriptions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
product_id TEXT NOT NULL,
type TEXT NOT NULL,
created_at TEXT NOT NULL,
UNIQUE (user_id, product_id, type),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (product_id) REFERENCES products(id)
);
`);
const seedProduct = db.prepare(`
INSERT INTO products (
id, slug, name, kind, size_label, price_cents, discovery_credit_cents
) VALUES (?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(id) DO UPDATE SET
slug = excluded.slug,
name = excluded.name,
kind = excluded.kind,
size_label = excluded.size_label,
price_cents = excluded.price_cents,
discovery_credit_cents = excluded.discovery_credit_cents
`);
for (const product of catalogProducts) {
seedProduct.run(
product.id,
product.slug,
product.name,
product.kind,
product.size_label,
product.price_cents,
product.discovery_credit_cents
);
}
db.exec(`
DELETE FROM discovery_credits
WHERE id NOT IN (
SELECT MIN(id)
FROM discovery_credits
GROUP BY user_id
);
`);
console.log(`SQLite shop database ready at ${dbPath}`);