From 8fa594159f5126ad85f1a41fcac715bc3711039c Mon Sep 17 00:00:00 2001 From: SikongJueluo Date: Mon, 24 Mar 2025 15:07:06 +0800 Subject: [PATCH] add basic test for database --- server/common.ts | 19 +++--- server/database.test.ts | 37 ++++++++--- server/database.ts | 134 ++++++++++++++++++++++++---------------- 3 files changed, 121 insertions(+), 69 deletions(-) diff --git a/server/common.ts b/server/common.ts index ecbd261..3426ab6 100644 --- a/server/common.ts +++ b/server/common.ts @@ -9,17 +9,20 @@ export const int8 = z.number().lt(Math.pow(2, 7)).gte(-Math.pow(2, 8)) export const int16 = z.number().lt(Math.pow(2, 15)).gte(-Math.pow(2, 16)) export const int32 = z.number().lt(Math.pow(2, 31)).gte(-Math.pow(2, 32)) -export function numberToBytes(num: number, bytesLength: number): Uint8Array { - var array = new Uint8Array(bytesLength) +export namespace fun { + export function numberToBytes(num: number, bytesLength: number): Uint8Array { + var array = new Uint8Array(bytesLength) - for (let i = 0; i < bytesLength; i++) { - array[i] = num & (0xFF << (i << 3)) + for (let i = 0; i < bytesLength; i++) { + array[i] = num & (0xFF << (i << 3)) + } + + return array } - return array + export function randomFromArray(array: Array) { + return array[_.random(0, array.length - 1, false)] + } } -export function randomFromArray(array: Array) { - return array[_.random(0, array.length - 1, false)] -} diff --git a/server/database.test.ts b/server/database.test.ts index 47dec42..183e57c 100644 --- a/server/database.test.ts +++ b/server/database.test.ts @@ -1,39 +1,58 @@ import { test, expect } from "bun:test" import * as db from "./database.ts" import _ from "lodash" -import { randomFromArray } from "./common.ts" -import { None, Ok } from "ts-results-es" +import { None, Ok, Option, Some } from "ts-results-es" test("DataBase", () => { const allTables = db.allTables() expect(allTables).toBeArray() expect(allTables).toEqual(["Users", "Boards"]) - expect(db.BoardTable.count()).toBe(0) - expect(db.UserTable.count()).toBe(0) + expect(db.BoardTable.countAll()).toBe(0) + expect(db.UserTable.countAll()).toBe(0) }) test("Board Table", () => { const boardsNumber = 10 - const rooms = ["A1", "A2"] + const rooms = ["A1", "A1", "A1", "A1", "A1", "A2", "A2", "A2", "A2", "A2"] // Try to find something empty const findEmptyByID = db.BoardTable.find(_.random(0, boardsNumber)) expect(findEmptyByID).toEqual(Ok(None)) - const findEmptyByName = db.BoardTable.find("Hello") + const findEmptyByName = db.BoardTable.find("Hello", "World") expect(findEmptyByName).toEqual(Ok(None)) const boardsArray: Array = [] for (let i = 0; i < boardsNumber; i++) { boardsArray.push({ - id: _.random(0, 100), + id: i, name: `Board ${i}`, - room: randomFromArray(rooms), + room: rooms[i], ipv4: `192.168.172.${i}`, - port: _.random(0, 665535), + port: i, }) } + db.BoardTable.addFromArray(boardsArray) + // Test Find + expect(db.BoardTable.find(1)).toEqual(Ok(Some({ + id: 1, + name: `Board ${1}`, + room: rooms[1], + ipv4: `192.168.172.${1}`, + port: 1, + } as db.Board))) + expect(db.BoardTable.find("Board 3", "A1")).toEqual(Ok(Some({ + id: 3, + name: `Board ${3}`, + room: rooms[3], + ipv4: `192.168.172.${3}`, + port: 3, + } as db.Board))) + + // Test Count + expect(db.BoardTable.countByName("Board 1")).toBe(1) + expect(db.BoardTable.countByRoom("A1")).toBe(5) }) diff --git a/server/database.ts b/server/database.ts index a3c89cc..e3f022f 100644 --- a/server/database.ts +++ b/server/database.ts @@ -93,18 +93,35 @@ export function tableColumnName(table: string): Array { export namespace BoardTable { - export function add(board: Board): Result { + export function add(board: Board): Result { if (!isBoard(board)) { return new Err("Wrong type") } + // Ensure no id conflict if (board.id == 0) { - const cnt = count() + const cnt = countAll() board.id = cnt + 1 - } else if (includes(board.id)) { - return new Err("ID conflict") + } else { + const retID = includes(board.id) + if (retID.isOk()) { + if (retID.value) return new Err("ID conflict") + } else { + return new Err("Wrong type") + } } + // Ensure no name conflict in the same room + { + const retName = includes(board.name, board.room) + if (retName.isOk()) { + if (retName.value) { + return new Err("Name conflict in one room") + } + } else { + return new Err("Wrong type") + } + } const query = db.query(` INSERT INTO Boards VALUES @@ -112,53 +129,74 @@ export namespace BoardTable { '${board.name}, '${board.room}', '${board.ipv4}', - '${typeof board.ipv6 === "undefined" ? "NULL" : board.ipv6}', + '${_.isUndefined(board.ipv6) ? "NULL" : board.ipv6}', ${board.port}); `) return Ok(query.run()) } - export function addFromArray(array: Array): Result { + export function addFromArray(array: Array): Result, "Wrong type"> { + let arrayChanges: Array = [] for (const item of array) { const ret = add(item) if (ret.isErr()) { return new Err("Wrong type") + } else { + arrayChanges.push(ret.value) } } - return new Ok() + return new Ok(arrayChanges) } - export function count(): number { + export function all() { + const query = db.query(`SELECT * FROM Boards`) + const boards = query.all() + + query.finalize() + return boards + } + + export function countAll(): 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 { + export function countByName(name: string): number { + const query = db.query(`SELECT * FROM Boards WHERE name=${name}`) + return query.values()[0][0] as number + } + + export function countByRoom(room: string): number { + const query = db.query(`SELECT * FROM Boards WHERE room=${room}`) + return query.values()[0][0] as number + } + + export function remove(name: string, room: string): Result + export function remove(id: number): Result + export function remove(board: Board): Result + export function remove(arg1: any, arg2?: any): Result { let retBoard let condition: string - if (isBoard(arg)) { - retBoard = _.cloneDeep(arg) - condition = `id=${arg.id}` + if (isBoard(arg1)) { + retBoard = _.cloneDeep(arg1) + condition = `id=${arg1.id}` - } else if (_.isNumber(arg)) { - retBoard = find(arg) + } else if (_.isNumber(arg1)) { + retBoard = find(arg1) if (retBoard.isOk() && retBoard.value.isSome()) { retBoard = _.cloneDeep(retBoard.value.value) - condition = `id=${arg}` + condition = `id=${arg1}` } else { return new Err("No such Board") } - } else if (_.isString(arg)) { - retBoard = find(arg) + } else if (_.isString(arg1) && _.isString(arg2)) { + retBoard = find(arg1, arg2) if (retBoard.isOk() && retBoard.value.isSome()) { retBoard = _.cloneDeep(retBoard.value.value) - condition = `name=${arg}` + condition = `name=${arg1}` } else { return new Err("No such Board") } @@ -173,28 +211,18 @@ export namespace BoardTable { 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"> { + 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 if (_.isString(arg1) && _.isString(arg2)) { + condition = `name='${arg1}' AND room='${arg2}'` } else { return new Err("Wrong type") - } const query = db.query(`SELECT * FROM Boards WHERE ${condition}`) @@ -208,37 +236,39 @@ export namespace BoardTable { } } - export function includes(name?: string): Result - export function includes(id?: number): Result - export function includes(arg: any): Result { + export function includes(name: string, room?: string): Result + export function includes(id: number): Result + export function includes(arg1: any, arg2?: any): Result { let condition: string - if (_.isNumber(arg)) { - condition = `id=${arg}` + if (_.isUndefined(arg2)) { + if (_.isNumber(arg1)) { + condition = `id=${arg1}` - } else if (_.isString(arg)) { - condition = `name='${arg}'` + } else if (_.isString(arg1)) { + condition = `name='${arg1}'` + } else { + return new Err("Wrong type") + } } else { - return new Err("Wrong type") - + if (_.isString(arg1) && _.isString(arg2)) { + condition = `name='${arg1} AND room=${arg2}'` + } else { + return new Err("Wrong type") + } } - const query = db.query(`SELECT * FROM Boards WHERE ${condition}`) + const query = db.query(`SELECT COUNT(*) FROM Boards WHERE ${condition}`) + const num = query.values()[0][0] as number - const spRet = boardSchema.safeParse(query.get()) - - if (spRet.success) { - return new Ok(true) - } else { - return new Ok(false) - } + return new Ok(num > 0 ? true : false) } } export namespace UserTable { - export function count(): number { + export function countAll(): number { const query = db.query(`SELECT COUNT(*) FROM Users`) return query.values()[0][0] as number }