import { Database, type Changes } from "bun:sqlite"; import _ from "lodash"; import { Ok, Err, Result, None, Some, Option } from "ts-results-es"; import { z } from "zod"; const db = new Database("lab.sqlite", { strict: true }) initDB(db); const boardSchema = z.object({ id: z.number().nonnegative(), name: z.string(), room: z.string(), ipv4: z.string().ip({ version: "v4" }), ipv6: z.string().ip({ version: "v6" }), port: z.number().nonnegative().lte(65535), cmdID: z.number().nonnegative() }).partial({ ipv6: true, cmdID: true }) export type Board = z.infer export function isBoard(obj: any): obj is Board { return boardSchema.safeParse(obj).success } const userSchema = z.object({ id: z.number().nonnegative(), name: z.string(), password: z.string(), boardID: z.number(), }).partial({ boardID: true, }) export type User = z.infer export function isUser(obj: any): obj is User { return userSchema.safeParse(obj).success } function initDB(db: Database) { const tables = allTables() if (!tables.includes("Users")) { db.query(` CREATE TABLE Users( id INT PRIMARY KEY NOT NULL, name TEXT NOT NULL, password TEXT NOT NULL ); `).run(); } if (!tables.includes("Boards")) db.query(` CREATE TABLE Boards( id INT PRIMARY KEY NOT NULL, name TEXT NOT NULL, room TEXT NOT NULL, ipv4 CHAR(16) NOT NULL, ipv6 CHAR(46) , port INT NOT NULL ) `).run(); } export function allTables(): Array { const query = db.query(`SELECT name FROM sqlite_master WHERE type='table'`) var tables = new Array() // Flaten array for (const item of query.values()) { tables.push(item[0]) } query.finalize() return tables } export function tableColumnName(table: string): Array { const query = db.query(`PRAGMA table_info(${table})`) var columnName = new Array() for (const column of query.values()) { columnName.push(column[1]) } return columnName } export namespace BoardTable { export function add(board: Board): Result { if (!isBoard(board)) { return new Err("Wrong type") } if (board.id == 0) { const cnt = count() board.id = cnt + 1 } else if (includes(board.id)) { return new Err("ID conflict") } const query = db.query(` INSERT INTO Boards VALUES (${board.id}, '${board.name}, '${board.room}', '${board.ipv4}', '${typeof board.ipv6 === "undefined" ? "NULL" : board.ipv6}', ${board.port}); `) return Ok(query.run()) } export function addFromArray(array: Array): Result { for (const item of array) { const ret = add(item) if (ret.isErr()) { return new Err("Wrong type") } } return new Ok() } export function count(): number { const query = db.query(`SELECT COUNT(*) FROM Boards`) return query.values()[0][0] as number } export function remove(name?: string): Result export function remove(id?: number): Result export function remove(board?: Board): Result export function remove(arg: any): Result { let retBoard let condition: string if (isBoard(arg)) { retBoard = _.cloneDeep(arg) condition = `id=${arg.id}` } else if (_.isNumber(arg)) { retBoard = find(arg) if (retBoard.isOk() && retBoard.value.isSome()) { retBoard = _.cloneDeep(retBoard.value.value) condition = `id=${arg}` } else { return new Err("No such Board") } } else if (_.isString(arg)) { retBoard = find(arg) if (retBoard.isOk() && retBoard.value.isSome()) { retBoard = _.cloneDeep(retBoard.value.value) condition = `name=${arg}` } else { return new Err("No such Board") } } else { return new Err("Wrong Type") } const query = db.query(`DELETE FROM Boards WHERE ${condition}`) query.run() return new Ok(retBoard) } export function all() { const query = db.query(`SELECT * FROM Boards`) const boards = query.all() query.finalize() return boards } export function find(name: string, room: string): Result, "Wrong type"> export function find(id: number): Result, "Wrong type"> export function find(arg1: any, arg2: any): Result, "Wrong type"> { let condition: string if (_.isNumber(arg1)) { condition = `id=${arg1}` } else if (_.isString(arg1)) { condition = `name='${arg1}'` } else { return new Err("Wrong type") } const query = db.query(`SELECT * FROM Boards WHERE ${condition}`) const spRet = boardSchema.safeParse(query.get()) if (spRet.success) { return new Ok(Some(spRet.data)) } else { return new Ok(None) } } export function includes(name?: string): Result export function includes(id?: number): Result export function includes(arg: any): Result { let condition: string if (_.isNumber(arg)) { condition = `id=${arg}` } else if (_.isString(arg)) { condition = `name='${arg}'` } else { return new Err("Wrong type") } const query = db.query(`SELECT * FROM Boards WHERE ${condition}`) const spRet = boardSchema.safeParse(query.get()) if (spRet.success) { return new Ok(true) } else { return new Ok(false) } } } export namespace UserTable { export function count(): number { const query = db.query(`SELECT COUNT(*) FROM Users`) return query.values()[0][0] as number } export function find(id: number): Result, "Wrong Type"> export function find(name: string): Result, "Wrong Type"> export function find(arg: any): Result, "Wrong Type"> { let condition: string if (_.isNumber(arg)) { condition = `id=${arg}` } else if (_.isString(arg)) { condition = `name=${arg}` } else { return new Err("Wrong Type") } const query = db.query(`SELECT * FROM Users WHERE name='${arg}'`) const spRet = userSchema.safeParse(query.get()) if (spRet.success) { return new Ok(Some(spRet.data)) } else { return new Ok(None) } } }