Switching to use SQLite instead of MySQL
This commit is contained in:
parent
dd46f61ecc
commit
0c6c9df93f
9 changed files with 1031 additions and 295 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -7,3 +7,6 @@ dist/
|
||||||
|
|
||||||
# vscode
|
# vscode
|
||||||
.vscode/settings.json
|
.vscode/settings.json
|
||||||
|
|
||||||
|
# sqlite
|
||||||
|
autobaan_db
|
||||||
|
|
@ -1,16 +1,4 @@
|
||||||
services:
|
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:
|
http:
|
||||||
build:
|
build:
|
||||||
context: ..
|
context: ..
|
||||||
|
|
@ -19,6 +7,5 @@ services:
|
||||||
env_file: ./server/.env
|
env_file: ./server/.env
|
||||||
ports:
|
ports:
|
||||||
- 3000:3000
|
- 3000:3000
|
||||||
depends_on:
|
# volumes:
|
||||||
database:
|
# - ./autobaan_db:/app/autobaan_db
|
||||||
condition: service_healthy
|
|
||||||
1129
package-lock.json
generated
1129
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -29,14 +29,13 @@
|
||||||
"argon2": "^0.30.3",
|
"argon2": "^0.30.3",
|
||||||
"axios": "^1.2.0",
|
"axios": "^1.2.0",
|
||||||
"dayjs": "^1.11.6",
|
"dayjs": "^1.11.6",
|
||||||
"mysql": "^2.18.1",
|
|
||||||
"node-cron": "^3.0.2",
|
"node-cron": "^3.0.2",
|
||||||
"puppeteer": "^19.5.2",
|
"puppeteer": "^19.5.2",
|
||||||
|
"sqlite3": "^5.1.4",
|
||||||
"uuid": "^9.0.0"
|
"uuid": "^9.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^29.2.3",
|
"@types/jest": "^29.2.3",
|
||||||
"@types/mysql": "^2.15.21",
|
|
||||||
"@types/node": "^18.11.9",
|
"@types/node": "^18.11.9",
|
||||||
"@types/node-cron": "^3.0.6",
|
"@types/node-cron": "^3.0.6",
|
||||||
"@types/puppeteer": "^7.0.4",
|
"@types/puppeteer": "^7.0.4",
|
||||||
|
|
|
||||||
|
|
@ -1,81 +1,34 @@
|
||||||
import mysql, { Connection, ConnectionConfig, FieldInfo } from 'mysql'
|
import { resolve } from 'path'
|
||||||
import { TABLE_reservations } from './sql'
|
import sqlite from 'sqlite3'
|
||||||
|
import { CREATE_TABLE_reservations } from './sql'
|
||||||
|
|
||||||
const createConnectionConfig = async (): Promise<ConnectionConfig> => {
|
export const run = async (sql: string, params?: unknown) => {
|
||||||
const host = process.env.MYSQL_HOST
|
const db = new sqlite.Database(resolve('autobaan_db'))
|
||||||
const user = process.env.MYSQL_USER
|
await new Promise<void>((res, rej) => {
|
||||||
const password = process.env.MYSQL_PASSWORD
|
db.run(sql, params, (err) => {
|
||||||
const database = process.env.MYSQL_DATABASE
|
if (err) rej(err)
|
||||||
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()
|
res()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
)
|
db.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
export const disconnect = async () => {
|
export const all = async <T>(sql: string, params?: unknown) => {
|
||||||
return new Promise<void>((res, rej) =>
|
const db = new sqlite.Database(resolve('autobaan_db'))
|
||||||
getConnection().then((cn) => {
|
const rows = await new Promise<T[]>((res, rej) =>
|
||||||
cn.end((err) => {
|
db.all(sql, params, (err, rows) => {
|
||||||
if (err) {
|
if (err) rej(err)
|
||||||
rej(err)
|
res(rows)
|
||||||
}
|
|
||||||
res()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
db.close()
|
||||||
|
return rows
|
||||||
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 init = async () => {
|
export const init = async () => {
|
||||||
try {
|
try {
|
||||||
await connect()
|
await run(CREATE_TABLE_reservations)
|
||||||
await query(TABLE_reservations)
|
} catch (err: unknown) {
|
||||||
} catch (err: any) {
|
|
||||||
console.error(err)
|
console.error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
export const TABLE_reservations = `
|
export const CREATE_TABLE_reservations = `
|
||||||
CREATE TABLE IF NOT EXISTS reservations (
|
CREATE TABLE IF NOT EXISTS reservations (
|
||||||
id VARCHAR(36) NOT NULL PRIMARY KEY,
|
id VARCHAR(36) NOT NULL PRIMARY KEY,
|
||||||
username VARCHAR(64) NOT NULL UNIQUE,
|
username VARCHAR(64) NOT NULL UNIQUE,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Dayjs } from 'dayjs'
|
import { Dayjs } from 'dayjs'
|
||||||
import { v4 } from 'uuid'
|
import { v4 } from 'uuid'
|
||||||
import dayjs from './dayjs'
|
import dayjs from './dayjs'
|
||||||
import { query } from './database'
|
import { all, run } from './database'
|
||||||
|
|
||||||
const RESERVATION_AVAILABLE_WITHIN_DAYS = 7
|
const RESERVATION_AVAILABLE_WITHIN_DAYS = 7
|
||||||
|
|
||||||
|
|
@ -127,7 +127,7 @@ export class Reservation {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async save(res: Reservation) {
|
public static async save(res: Reservation) {
|
||||||
await query(
|
await run(
|
||||||
`
|
`
|
||||||
INSERT INTO reservations
|
INSERT INTO reservations
|
||||||
(
|
(
|
||||||
|
|
@ -163,19 +163,17 @@ export class Reservation {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async delete(res: Reservation) {
|
public static async delete(res: Reservation) {
|
||||||
await query(
|
await run(
|
||||||
`
|
`
|
||||||
DELETE FROM reservations
|
DELETE FROM reservations
|
||||||
WHERE id = $
|
WHERE id = $
|
||||||
`,
|
`,
|
||||||
[
|
[res.id]
|
||||||
res.id,
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async fetchById(id: string): Promise<Reservation | null> {
|
public static async fetchById(id: string): Promise<Reservation | null> {
|
||||||
const response = await query<SqlReservation>(
|
const response = await all<SqlReservation>(
|
||||||
`
|
`
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM reservations
|
FROM reservations
|
||||||
|
|
@ -184,8 +182,8 @@ export class Reservation {
|
||||||
[id]
|
[id]
|
||||||
)
|
)
|
||||||
|
|
||||||
if (response.results.length === 1) {
|
if (response.length === 1) {
|
||||||
const sqlReservation = response.results[0]
|
const sqlReservation = response[0]
|
||||||
const res = new Reservation(
|
const res = new Reservation(
|
||||||
{
|
{
|
||||||
username: sqlReservation.username,
|
username: sqlReservation.username,
|
||||||
|
|
@ -197,7 +195,7 @@ export class Reservation {
|
||||||
},
|
},
|
||||||
{ id: sqlReservation.opponent_id, name: sqlReservation.opponent_name },
|
{ id: sqlReservation.opponent_id, name: sqlReservation.opponent_name },
|
||||||
undefined,
|
undefined,
|
||||||
sqlReservation.id,
|
sqlReservation.id
|
||||||
)
|
)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
@ -206,7 +204,7 @@ export class Reservation {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async fetchFirst(): Promise<Reservation | null> {
|
public static async fetchFirst(): Promise<Reservation | null> {
|
||||||
const response = await query<SqlReservation>(
|
const response = await all<SqlReservation>(
|
||||||
`
|
`
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM reservations
|
FROM reservations
|
||||||
|
|
@ -215,8 +213,8 @@ export class Reservation {
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
if (response.results.length === 1) {
|
if (response.length === 1) {
|
||||||
const sqlReservation = response.results[0]
|
const sqlReservation = response[0]
|
||||||
const res = new Reservation(
|
const res = new Reservation(
|
||||||
{
|
{
|
||||||
username: sqlReservation.username,
|
username: sqlReservation.username,
|
||||||
|
|
@ -228,7 +226,7 @@ export class Reservation {
|
||||||
},
|
},
|
||||||
{ id: sqlReservation.opponent_id, name: sqlReservation.opponent_name },
|
{ id: sqlReservation.opponent_id, name: sqlReservation.opponent_name },
|
||||||
undefined,
|
undefined,
|
||||||
sqlReservation.id,
|
sqlReservation.id
|
||||||
)
|
)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
@ -236,8 +234,11 @@ export class Reservation {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async fetchByDate(date: Dayjs, limit = 20): Promise<Reservation[]> {
|
public static async fetchByDate(
|
||||||
const response = await query<SqlReservation>(
|
date: Dayjs,
|
||||||
|
limit = 20
|
||||||
|
): Promise<Reservation[]> {
|
||||||
|
const response = await all<SqlReservation>(
|
||||||
`
|
`
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM reservations
|
FROM reservations
|
||||||
|
|
@ -245,14 +246,13 @@ export class Reservation {
|
||||||
ORDER BY date_range_start DESC
|
ORDER BY date_range_start DESC
|
||||||
LIMIT ?;
|
LIMIT ?;
|
||||||
`,
|
`,
|
||||||
[
|
[date.format('YYYY-MM-DD'), limit]
|
||||||
date.format('YYYY-MM-DD'),
|
|
||||||
limit,
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (response.results.length > 0) {
|
if (response.length > 0) {
|
||||||
return response.results.map((sqlReservation) => new Reservation(
|
return response.map(
|
||||||
|
(sqlReservation) =>
|
||||||
|
new Reservation(
|
||||||
{
|
{
|
||||||
username: sqlReservation.username,
|
username: sqlReservation.username,
|
||||||
password: sqlReservation.password,
|
password: sqlReservation.password,
|
||||||
|
|
@ -261,10 +261,14 @@ export class Reservation {
|
||||||
start: dayjs(sqlReservation.date_range_start),
|
start: dayjs(sqlReservation.date_range_start),
|
||||||
end: dayjs(sqlReservation.date_range_end),
|
end: dayjs(sqlReservation.date_range_end),
|
||||||
},
|
},
|
||||||
{ id: sqlReservation.opponent_id, name: sqlReservation.opponent_name },
|
{
|
||||||
|
id: sqlReservation.opponent_id,
|
||||||
|
name: sqlReservation.opponent_name,
|
||||||
|
},
|
||||||
undefined,
|
undefined,
|
||||||
sqlReservation.id,
|
sqlReservation.id
|
||||||
))
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return []
|
return []
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { disconnect, init } from '../common/database'
|
import { init } from '../common/database'
|
||||||
import { Logger, LogLevel } from '../common/logger'
|
import { Logger, LogLevel } from '../common/logger'
|
||||||
import server from './http'
|
import server from './http'
|
||||||
import { startTasks, stopTasks } from './cron'
|
import { startTasks, stopTasks } from './cron'
|
||||||
|
|
@ -14,7 +14,6 @@ process.on('uncaughtException', (error, origin) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
process.on('beforeExit', async () => {
|
process.on('beforeExit', async () => {
|
||||||
await disconnect()
|
|
||||||
stopTasks()
|
stopTasks()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ describe('scheduler', () => {
|
||||||
{ start, end },
|
{ start, end },
|
||||||
{ id: '123', name: 'collin' },
|
{ id: '123', name: 'collin' },
|
||||||
undefined,
|
undefined,
|
||||||
'1234',
|
'1234'
|
||||||
),
|
),
|
||||||
scheduledFor: start
|
scheduledFor: start
|
||||||
.subtract(7, 'days')
|
.subtract(7, 'days')
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue