update test

This commit is contained in:
maix0 2025-07-17 16:34:43 +02:00 committed by Maieul BOYER
parent 0b3ea4b406
commit 3f5cb97501
5 changed files with 133 additions and 19 deletions

View file

@ -11,7 +11,9 @@
"dependencies": { "dependencies": {
"better-sqlite3": "^11.10.0", "better-sqlite3": "^11.10.0",
"fastify": "^5.0.0", "fastify": "^5.0.0",
"fastify-plugin": "^5.0.1" "fastify-plugin": "^5.0.1",
"typescript-result": "3.1.1",
"uuidv7": "^1.0.2"
}, },
"devDependencies": { "devDependencies": {
"@types/better-sqlite3": "^7.6.13", "@types/better-sqlite3": "^7.6.13",
@ -2122,6 +2124,15 @@
"node": ">=14.17" "node": ">=14.17"
} }
}, },
"node_modules/typescript-result": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/typescript-result/-/typescript-result-3.1.1.tgz",
"integrity": "sha512-KQ7SdBa1UcZCu+qI7pgZ1FdzBIlGiyoHTaQQDshtsKCKiPdzLlkU6OWkJuhjzo+xl+y+dOVO+2HyyEpODNDHyw==",
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/undici-types": { "node_modules/undici-types": {
"version": "6.21.0", "version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
@ -2135,6 +2146,15 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/uuidv7": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/uuidv7/-/uuidv7-1.0.2.tgz",
"integrity": "sha512-8JQkH4ooXnm1JCIhqTMbtmdnYEn6oKukBxHn1Ic9878jMkL7daTI7anTExfY18VRCX7tcdn5quzvCb6EWrR8PA==",
"license": "Apache-2.0",
"bin": {
"uuidv7": "cli.js"
}
},
"node_modules/v8-compile-cache-lib": { "node_modules/v8-compile-cache-lib": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",

View file

@ -19,7 +19,9 @@
"dependencies": { "dependencies": {
"better-sqlite3": "^11.10.0", "better-sqlite3": "^11.10.0",
"fastify": "^5.0.0", "fastify": "^5.0.0",
"fastify-plugin": "^5.0.1" "fastify-plugin": "^5.0.1",
"typescript-result": "3.1.1",
"uuidv7": "^1.0.2"
}, },
"devDependencies": { "devDependencies": {
"@types/better-sqlite3": "^7.6.13", "@types/better-sqlite3": "^7.6.13",

View file

@ -6,45 +6,97 @@
// By: maiboyer <maiboyer@student.42.fr> +#+ +:+ +#+ // // By: maiboyer <maiboyer@student.42.fr> +#+ +:+ +#+ //
// +#+#+#+#+#+ +#+ // // +#+#+#+#+#+ +#+ //
// Created: 2025/06/17 17:06:31 by maiboyer #+# #+# // // Created: 2025/06/17 17:06:31 by maiboyer #+# #+# //
// Updated: 2025/06/20 00:11:43 by maiboyer ### ########.fr // // Updated: 2025/07/17 16:28:48 by maiboyer ### ########.fr //
// // // //
// ************************************************************************** // // ************************************************************************** //
import fp from 'fastify-plugin' import fp from 'fastify-plugin'
import { FastifyInstance } from 'fastify' import { FastifyInstance } from 'fastify'
import sqlite from 'better-sqlite3' import sqlite from 'better-sqlite3'
import { Result } from 'typescript-result'
import initSql from "./init.sql.js" import initSql from "./init.sql.js"
import { newUUIDv7, UUIDv7 } from './uuid.js'
export class DBUserExists extends Error {
public readonly type = 'db-user-exists';
}
// Only way to use the database. Everything must be done through this.
// Prefer to use prepared statement `using this.db.prepare`
export class Database { export class Database {
private db: sqlite.Database; private db: sqlite.Database;
private st: Map<string, sqlite.Statement> = new Map();
constructor(db_path: string) { /**
this.db = sqlite(db_path, {}); * Create a new instance of the database, and init it to a known state
this.db.pragma('journal_mode = WAL'); * the file ./init.sql will be ran onto the database, creating any table that might be missing
this.db.exec(initSql); */
} constructor(db_path: string) {
this.db = sqlite(db_path, {});
this.db.pragma('journal_mode = WAL');
this.db.transaction(() => this.db.exec(initSql))();
}
destroy(): void { /**
this.db?.close(); * close the database
} */
destroy(): void {
// remove any statement from the cache
this.st.clear();
// close the database
this.db?.close();
}
/**
* use this to create queries. This will create statements (kinda expensive) and cache them
* since they will be cached, this means that they are only created once,
* otherwise they'll be just spat out from the cache
* the statements are cached by the {query} argument,
* meaning that if you try to make two identiqual statement, but with different {query} they won't be cached
*
* @example this.prepare('SELECT * FROM users WHERE id = ?')
* @example this.prepare('SELECT * FROM users LIMIT 100 OFFSET ?')
*/
private prepare(query: string): sqlite.Statement {
let st = this.st.get(query);
if (st !== undefined) return st;
st = this.db.prepare(query);
this.st.set(query, st);
return st;
}
public createUser(user: string): Result<UUIDv7, DBUserExists> {
const st = this.prepare('INSERT INTO users VALUES (?, ?) RETURNING id');
try {
st.get(newUUIDv7(), user)
}
catch (e: any) {
console.log(e)
console.log(typeof e)
}
return Result.ok(newUUIDv7());
}
} }
// When using .decorate you have to specify added properties for Typescript // When using .decorate you have to specify added properties for Typescript
declare module 'fastify' { declare module 'fastify' {
export interface FastifyInstance { export interface FastifyInstance {
db: Database; db: Database;
} }
} }
export type DatabaseOption = { export type DatabaseOption = {
path: string; path: string;
}; };
export const uDatabase = fp<DatabaseOption>(async function( export const uDatabase = fp<DatabaseOption>(async function(
_fastify: FastifyInstance, _fastify: FastifyInstance,
_options: DatabaseOption) { _options: DatabaseOption) {
}); });

View file

@ -1,4 +1,9 @@
-- this file will make sure that the database is always up to date with the correct schema -- this file will make sure that the database is always up to date with the correct schema
-- when editing this file, make sure to always include stuff like `IF NOT EXISTS` such as to not throw error -- when editing this file, make sure to always include stuff like `IF NOT EXISTS` such as to not throw error
-- NEVER DROP ANYTHING IN THIS FILE -- NEVER DROP ANYTHING IN THIS FILE
CREATE TABLE IF NOT EXISTS users (name STRING); CREATE TABLE IF NOT EXISTS users (
id STRING UNIQUE PRIMARY KEY, -- UUIDv7 as a string
name STRING UNIQUE, -- name of the user
token STRING UNIQUE, -- the token of the user (aka the cookie)
);

35
src/utils/src/uuid.ts Normal file
View file

@ -0,0 +1,35 @@
// ************************************************************************** //
// //
// ::: :::::::: //
// uuid.ts :+: :+: :+: //
// +:+ +:+ +:+ //
// By: maiboyer <maiboyer@student.42.fr> +#+ +:+ +#+ //
// +#+#+#+#+#+ +#+ //
// Created: 2025/06/20 17:41:01 by maiboyer #+# #+# //
// Updated: 2025/06/20 17:44:29 by maiboyer ### ########.fr //
// //
// ************************************************************************** //
import { Result } from "typescript-result";
import { uuidv7 } from "uuidv7";
export class InvalidUUID extends Error {
public readonly type = 'invalid-uuid';
};
export type UUIDv7 = string & { readonly __brand: unique symbol };
const uuidv7Regex = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
export function isUUIDv7(value: string): value is UUIDv7 {
return uuidv7Regex.test(value);
}
export function toUUIDv7(value: string): Result<UUIDv7, InvalidUUID> {
if (!isUUIDv7(value)) return Result.error(new InvalidUUID());
return Result.ok(value as UUIDv7);
}
export function newUUIDv7(): UUIDv7 {
return uuidv7() as UUIDv7;
}