128 lines
3.6 KiB
TypeScript
128 lines
3.6 KiB
TypeScript
import type { Database } from "bun:sqlite";
|
|
|
|
function tableExists(sqlite: Database, tableName: string) {
|
|
return Boolean(sqlite.query("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?").get(tableName));
|
|
}
|
|
|
|
function columnExists(sqlite: Database, tableName: string, columnName: string) {
|
|
if (!tableExists(sqlite, tableName)) {
|
|
return false;
|
|
}
|
|
|
|
return sqlite
|
|
.query(`PRAGMA table_info(${tableName})`)
|
|
.all()
|
|
.some((column) => typeof column === "object" && column !== null && "name" in column && column.name === columnName);
|
|
}
|
|
|
|
function resetLegacySchema(sqlite: Database) {
|
|
sqlite.exec(`
|
|
PRAGMA foreign_keys = OFF;
|
|
DROP TABLE IF EXISTS sessions;
|
|
DROP TABLE IF EXISTS audit_events;
|
|
DROP TABLE IF EXISTS refunds;
|
|
DROP TABLE IF EXISTS order_items;
|
|
DROP TABLE IF EXISTS orders;
|
|
DROP TABLE IF EXISTS inventory;
|
|
DROP TABLE IF EXISTS products;
|
|
DROP TABLE IF EXISTS addresses;
|
|
DROP TABLE IF EXISTS users;
|
|
DROP TABLE IF EXISTS customers;
|
|
DROP TABLE IF EXISTS employees;
|
|
PRAGMA foreign_keys = ON;
|
|
`);
|
|
}
|
|
|
|
function needsLegacyReset(sqlite: Database) {
|
|
return tableExists(sqlite, "customers") || tableExists(sqlite, "employees") || columnExists(sqlite, "audit_events", "employee_id");
|
|
}
|
|
|
|
export function initializeDatabase(sqlite: Database) {
|
|
if (needsLegacyReset(sqlite)) {
|
|
resetLegacySchema(sqlite);
|
|
}
|
|
|
|
sqlite.exec(`
|
|
PRAGMA foreign_keys = ON;
|
|
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id TEXT PRIMARY KEY,
|
|
username TEXT NOT NULL UNIQUE,
|
|
name TEXT NOT NULL,
|
|
email TEXT NOT NULL UNIQUE,
|
|
role TEXT NOT NULL,
|
|
created_at TEXT NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
id TEXT PRIMARY KEY,
|
|
user_id TEXT NOT NULL REFERENCES users(id),
|
|
created_at TEXT NOT NULL,
|
|
expires_at TEXT NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS addresses (
|
|
id TEXT PRIMARY KEY,
|
|
full_name TEXT NOT NULL,
|
|
line_1 TEXT NOT NULL,
|
|
line_2 TEXT,
|
|
city TEXT NOT NULL,
|
|
state TEXT NOT NULL,
|
|
postal_code TEXT NOT NULL,
|
|
country TEXT NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS products (
|
|
id TEXT PRIMARY KEY,
|
|
sku TEXT NOT NULL UNIQUE,
|
|
name TEXT NOT NULL,
|
|
price_cents INTEGER NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS inventory (
|
|
product_id TEXT PRIMARY KEY REFERENCES products(id),
|
|
available_quantity INTEGER NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS orders (
|
|
id TEXT PRIMARY KEY,
|
|
order_number TEXT NOT NULL UNIQUE,
|
|
customer_id TEXT NOT NULL REFERENCES users(id),
|
|
shipping_address_id TEXT NOT NULL REFERENCES addresses(id),
|
|
status TEXT NOT NULL,
|
|
notes TEXT,
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS order_items (
|
|
id TEXT PRIMARY KEY,
|
|
order_id TEXT NOT NULL REFERENCES orders(id),
|
|
product_id TEXT NOT NULL REFERENCES products(id),
|
|
quantity INTEGER NOT NULL,
|
|
unit_price_cents INTEGER NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS refunds (
|
|
id TEXT PRIMARY KEY,
|
|
order_id TEXT NOT NULL REFERENCES orders(id),
|
|
amount_cents INTEGER NOT NULL,
|
|
reason TEXT NOT NULL,
|
|
created_at TEXT NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS audit_events (
|
|
id TEXT PRIMARY KEY,
|
|
order_id TEXT NOT NULL REFERENCES orders(id),
|
|
actor TEXT NOT NULL,
|
|
type TEXT NOT NULL,
|
|
message TEXT NOT NULL,
|
|
created_at TEXT NOT NULL
|
|
);
|
|
`);
|
|
|
|
if (!columnExists(sqlite, "orders", "notes")) {
|
|
sqlite.exec("ALTER TABLE orders ADD COLUMN notes TEXT");
|
|
}
|
|
}
|