first commit

This commit is contained in:
Craig Osterhout
2023-07-17 10:17:25 -07:00
commit 9bbd95c7dd
40 changed files with 31133 additions and 0 deletions

2
src/persistence/index.js Normal file
View File

@ -0,0 +1,2 @@
if (process.env.MYSQL_HOST) module.exports = require('./mysql');
else module.exports = require('./sqlite');

135
src/persistence/mysql.js Normal file
View File

@ -0,0 +1,135 @@
const waitPort = require('wait-port');
const fs = require('fs');
const mysql = require('mysql2');
const {
MYSQL_HOST: HOST,
MYSQL_HOST_FILE: HOST_FILE,
MYSQL_USER: USER,
MYSQL_USER_FILE: USER_FILE,
MYSQL_PASSWORD: PASSWORD,
MYSQL_PASSWORD_FILE: PASSWORD_FILE,
MYSQL_DB: DB,
MYSQL_DB_FILE: DB_FILE,
} = process.env;
let pool;
async function init() {
const host = HOST_FILE ? fs.readFileSync(HOST_FILE) : HOST;
const user = USER_FILE ? fs.readFileSync(USER_FILE) : USER;
const password = PASSWORD_FILE ? fs.readFileSync(PASSWORD_FILE) : PASSWORD;
const database = DB_FILE ? fs.readFileSync(DB_FILE) : DB;
await waitPort({
host,
port: 3306,
timeout: 10000,
waitForDns: true,
});
pool = mysql.createPool({
connectionLimit: 5,
host,
user,
password,
database,
charset: 'utf8mb4',
});
return new Promise((acc, rej) => {
pool.query(
'CREATE TABLE IF NOT EXISTS todo_items (id varchar(36), name varchar(255), completed boolean) DEFAULT CHARSET utf8mb4',
err => {
if (err) return rej(err);
console.log(`Connected to mysql db at host ${HOST}`);
acc();
},
);
});
}
async function teardown() {
return new Promise((acc, rej) => {
pool.end(err => {
if (err) rej(err);
else acc();
});
});
}
async function getItems() {
return new Promise((acc, rej) => {
pool.query('SELECT * FROM todo_items', (err, rows) => {
if (err) return rej(err);
acc(
rows.map(item =>
Object.assign({}, item, {
completed: item.completed === 1,
}),
),
);
});
});
}
async function getItem(id) {
return new Promise((acc, rej) => {
pool.query('SELECT * FROM todo_items WHERE id=?', [id], (err, rows) => {
if (err) return rej(err);
acc(
rows.map(item =>
Object.assign({}, item, {
completed: item.completed === 1,
}),
)[0],
);
});
});
}
async function storeItem(item) {
return new Promise((acc, rej) => {
pool.query(
'INSERT INTO todo_items (id, name, completed) VALUES (?, ?, ?)',
[item.id, item.name, item.completed ? 1 : 0],
err => {
if (err) return rej(err);
acc();
},
);
});
}
async function updateItem(id, item) {
return new Promise((acc, rej) => {
pool.query(
'UPDATE todo_items SET name=?, completed=? WHERE id=?',
[item.name, item.completed ? 1 : 0, id],
err => {
if (err) return rej(err);
acc();
},
);
});
}
async function removeItem(id) {
return new Promise((acc, rej) => {
pool.query('DELETE FROM todo_items WHERE id = ?', [id], err => {
if (err) return rej(err);
acc();
});
});
}
module.exports = {
init,
teardown,
getItems,
getItem,
storeItem,
updateItem,
removeItem,
};

113
src/persistence/sqlite.js Normal file
View File

@ -0,0 +1,113 @@
const sqlite3 = require('sqlite3').verbose();
const fs = require('fs');
const location = process.env.SQLITE_DB_LOCATION || '/etc/todos/todo.db';
let db, dbAll, dbRun;
function init() {
const dirName = require('path').dirname(location);
if (!fs.existsSync(dirName)) {
fs.mkdirSync(dirName, { recursive: true });
}
return new Promise((acc, rej) => {
db = new sqlite3.Database(location, err => {
if (err) return rej(err);
if (process.env.NODE_ENV !== 'test')
console.log(`Using sqlite database at ${location}`);
db.run(
'CREATE TABLE IF NOT EXISTS todo_items (id varchar(36), name varchar(255), completed boolean)',
(err, result) => {
if (err) return rej(err);
acc();
},
);
});
});
}
async function teardown() {
return new Promise((acc, rej) => {
db.close(err => {
if (err) rej(err);
else acc();
});
});
}
async function getItems() {
return new Promise((acc, rej) => {
db.all('SELECT * FROM todo_items', (err, rows) => {
if (err) return rej(err);
acc(
rows.map(item =>
Object.assign({}, item, {
completed: item.completed === 1,
}),
),
);
});
});
}
async function getItem(id) {
return new Promise((acc, rej) => {
db.all('SELECT * FROM todo_items WHERE id=?', [id], (err, rows) => {
if (err) return rej(err);
acc(
rows.map(item =>
Object.assign({}, item, {
completed: item.completed === 1,
}),
)[0],
);
});
});
}
async function storeItem(item) {
return new Promise((acc, rej) => {
db.run(
'INSERT INTO todo_items (id, name, completed) VALUES (?, ?, ?)',
[item.id, item.name, item.completed ? 1 : 0],
err => {
if (err) return rej(err);
acc();
},
);
});
}
async function updateItem(id, item) {
return new Promise((acc, rej) => {
db.run(
'UPDATE todo_items SET name=?, completed=? WHERE id = ?',
[item.name, item.completed ? 1 : 0, id],
err => {
if (err) return rej(err);
acc();
},
);
});
}
async function removeItem(id) {
return new Promise((acc, rej) => {
db.run('DELETE FROM todo_items WHERE id = ?', [id], err => {
if (err) return rej(err);
acc();
});
});
}
module.exports = {
init,
teardown,
getItems,
getItem,
storeItem,
updateItem,
removeItem,
};