Switching to use SQLite instead of MySQL

This commit is contained in:
Collin Duncan 2023-01-28 10:51:46 +01:00
parent dd46f61ecc
commit 0c6c9df93f
No known key found for this signature in database
9 changed files with 1031 additions and 295 deletions

3
.gitignore vendored
View file

@ -7,3 +7,6 @@ dist/
# vscode
.vscode/settings.json
# sqlite
autobaan_db

View file

@ -1,16 +1,4 @@
services:
database:
image: mysql:latest
restart: always
env_file: ./database/.env
command: --default-authentication-plugin=mysql_native_password
ports:
- 3306:3306
healthcheck:
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
timeout: 5s
retries: 10
http:
build:
context: ..
@ -19,6 +7,5 @@ services:
env_file: ./server/.env
ports:
- 3000:3000
depends_on:
database:
condition: service_healthy
# volumes:
# - ./autobaan_db:/app/autobaan_db

1129
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -29,14 +29,13 @@
"argon2": "^0.30.3",
"axios": "^1.2.0",
"dayjs": "^1.11.6",
"mysql": "^2.18.1",
"node-cron": "^3.0.2",
"puppeteer": "^19.5.2",
"sqlite3": "^5.1.4",
"uuid": "^9.0.0"
},
"devDependencies": {
"@types/jest": "^29.2.3",
"@types/mysql": "^2.15.21",
"@types/node": "^18.11.9",
"@types/node-cron": "^3.0.6",
"@types/puppeteer": "^7.0.4",

View file

@ -1,81 +1,34 @@
import mysql, { Connection, ConnectionConfig, FieldInfo } from 'mysql'
import { TABLE_reservations } from './sql'
import { resolve } from 'path'
import sqlite from 'sqlite3'
import { CREATE_TABLE_reservations } from './sql'
const createConnectionConfig = async (): Promise<ConnectionConfig> => {
const host = process.env.MYSQL_HOST
const user = process.env.MYSQL_USER
const password = process.env.MYSQL_PASSWORD
const database = process.env.MYSQL_DATABASE
if (!user || !password || !database) {
throw new DatabaseEnvironmentError(
'Required environment variables are missing'
)
}
return {
host,
user,
password,
database,
}
}
let connection: Connection
export const getConnection = async (): Promise<Connection> => {
if (!connection) {
const config = await createConnectionConfig()
connection = mysql.createConnection(config)
}
return connection
}
export type ResultSet<T> = T[]
export const connect = async () => {
return new Promise<void>((res, rej) =>
getConnection().then((cn) => {
cn.connect((err) => {
if (err) {
rej(err)
}
res()
})
})
)
}
export const disconnect = async () => {
return new Promise<void>((res, rej) =>
getConnection().then((cn) => {
cn.end((err) => {
if (err) {
rej(err)
}
res()
})
})
)
}
export const query = async <T = unknown, V = unknown>(
sql: string,
values?: V
): Promise<{ results: ResultSet<T>; fields?: FieldInfo[] }> => {
return new Promise((res, rej) => {
connection.query({ sql, values }, (err, results, fields) => {
if (err) {
rej(err)
}
res({ results, fields })
export const run = async (sql: string, params?: unknown) => {
const db = new sqlite.Database(resolve('autobaan_db'))
await new Promise<void>((res, rej) => {
db.run(sql, params, (err) => {
if (err) rej(err)
res()
})
})
db.close()
}
export const all = async <T>(sql: string, params?: unknown) => {
const db = new sqlite.Database(resolve('autobaan_db'))
const rows = await new Promise<T[]>((res, rej) =>
db.all(sql, params, (err, rows) => {
if (err) rej(err)
res(rows)
})
)
db.close()
return rows
}
export const init = async () => {
try {
await connect()
await query(TABLE_reservations)
} catch (err: any) {
await run(CREATE_TABLE_reservations)
} catch (err: unknown) {
console.error(err)
}
}

View file

@ -1,4 +1,4 @@
export const TABLE_reservations = `
export const CREATE_TABLE_reservations = `
CREATE TABLE IF NOT EXISTS reservations (
id VARCHAR(36) NOT NULL PRIMARY KEY,
username VARCHAR(64) NOT NULL UNIQUE,

View file

@ -1,7 +1,7 @@
import { Dayjs } from 'dayjs'
import { v4 } from 'uuid'
import dayjs from './dayjs'
import { query } from './database'
import { all, run } from './database'
const RESERVATION_AVAILABLE_WITHIN_DAYS = 7
@ -127,7 +127,7 @@ export class Reservation {
}
public static async save(res: Reservation) {
await query(
await run(
`
INSERT INTO reservations
(
@ -163,19 +163,17 @@ export class Reservation {
}
public static async delete(res: Reservation) {
await query(
await run(
`
DELETE FROM reservations
WHERE id = $
`,
[
res.id,
]
[res.id]
)
}
public static async fetchById(id: string): Promise<Reservation | null> {
const response = await query<SqlReservation>(
const response = await all<SqlReservation>(
`
SELECT *
FROM reservations
@ -184,8 +182,8 @@ export class Reservation {
[id]
)
if (response.results.length === 1) {
const sqlReservation = response.results[0]
if (response.length === 1) {
const sqlReservation = response[0]
const res = new Reservation(
{
username: sqlReservation.username,
@ -197,7 +195,7 @@ export class Reservation {
},
{ id: sqlReservation.opponent_id, name: sqlReservation.opponent_name },
undefined,
sqlReservation.id,
sqlReservation.id
)
return res
}
@ -206,7 +204,7 @@ export class Reservation {
}
public static async fetchFirst(): Promise<Reservation | null> {
const response = await query<SqlReservation>(
const response = await all<SqlReservation>(
`
SELECT *
FROM reservations
@ -215,8 +213,8 @@ export class Reservation {
`
)
if (response.results.length === 1) {
const sqlReservation = response.results[0]
if (response.length === 1) {
const sqlReservation = response[0]
const res = new Reservation(
{
username: sqlReservation.username,
@ -228,7 +226,7 @@ export class Reservation {
},
{ id: sqlReservation.opponent_id, name: sqlReservation.opponent_name },
undefined,
sqlReservation.id,
sqlReservation.id
)
return res
}
@ -236,8 +234,11 @@ export class Reservation {
return null
}
public static async fetchByDate(date: Dayjs, limit = 20): Promise<Reservation[]> {
const response = await query<SqlReservation>(
public static async fetchByDate(
date: Dayjs,
limit = 20
): Promise<Reservation[]> {
const response = await all<SqlReservation>(
`
SELECT *
FROM reservations
@ -245,26 +246,29 @@ export class Reservation {
ORDER BY date_range_start DESC
LIMIT ?;
`,
[
date.format('YYYY-MM-DD'),
limit,
]
[date.format('YYYY-MM-DD'), limit]
)
if (response.results.length > 0) {
return response.results.map((sqlReservation) => new Reservation(
{
username: sqlReservation.username,
password: sqlReservation.password,
},
{
start: dayjs(sqlReservation.date_range_start),
end: dayjs(sqlReservation.date_range_end),
},
{ id: sqlReservation.opponent_id, name: sqlReservation.opponent_name },
undefined,
sqlReservation.id,
))
if (response.length > 0) {
return response.map(
(sqlReservation) =>
new Reservation(
{
username: sqlReservation.username,
password: sqlReservation.password,
},
{
start: dayjs(sqlReservation.date_range_start),
end: dayjs(sqlReservation.date_range_end),
},
{
id: sqlReservation.opponent_id,
name: sqlReservation.opponent_name,
},
undefined,
sqlReservation.id
)
)
}
return []

View file

@ -1,4 +1,4 @@
import { disconnect, init } from '../common/database'
import { init } from '../common/database'
import { Logger, LogLevel } from '../common/logger'
import server from './http'
import { startTasks, stopTasks } from './cron'
@ -14,7 +14,6 @@ process.on('uncaughtException', (error, origin) => {
})
process.on('beforeExit', async () => {
await disconnect()
stopTasks()
})

View file

@ -56,7 +56,7 @@ describe('scheduler', () => {
{ start, end },
{ id: '123', name: 'collin' },
undefined,
'1234',
'1234'
),
scheduledFor: start
.subtract(7, 'days')