272 lines
7.9 KiB
TypeScript
272 lines
7.9 KiB
TypeScript
import { Pool, PoolClient } from 'pg';
|
|
import { loadConfig } from './configLoader';
|
|
const config = loadConfig();
|
|
|
|
class SqlSystem {
|
|
|
|
private static pool: Pool = new Pool({
|
|
database: process.env.DATABASE,
|
|
host: process.env.DB_HOST,
|
|
user: process.env.DB_USER,
|
|
password: process.env.DB_PASSWORD,
|
|
max: config.data.worker_count ?? 10
|
|
})
|
|
|
|
|
|
public static async InitDB() {
|
|
let conn: PoolClient | undefined;
|
|
try {
|
|
conn = await this.pool.connect();
|
|
//Setup tables for auctions and lifetimes
|
|
await conn.query(`
|
|
CREATE TABLE if NOT EXISTS auctions (
|
|
id UUID PRIMARY KEY,
|
|
auctionid VARCHAR(255) NOT NULL,
|
|
lbin DECIMAL(65,5),
|
|
UNIQUE (auctionid)
|
|
);
|
|
CREATE TABLE if NOT EXISTS lifetimes (id UUID PRIMARY KEY, insertedon TIMESTAMP(2));
|
|
`);
|
|
//Setup lifetime Trigger
|
|
await conn.query(`
|
|
-- Insert trigger function
|
|
CREATE OR REPLACE FUNCTION public.fn_insert_lifetime()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
INSERT INTO lifetimes (id, insertedon)
|
|
VALUES (NEW.id, NOW());
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- Update trigger function
|
|
CREATE OR REPLACE FUNCTION public.fn_update_lifetime()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
UPDATE lifetimes
|
|
SET insertedon = NOW()
|
|
WHERE id = NEW.id;
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- Remove trigger function
|
|
CREATE OR REPLACE FUNCTION public.fn_remove_lifetime()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
DELETE FROM lifetimes
|
|
WHERE id = OLD.id;
|
|
RETURN OLD;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
`);
|
|
await conn.query(`
|
|
-- Insert trigger
|
|
DROP TRIGGER IF EXISTS insert_lifetime ON auctions;
|
|
CREATE TRIGGER insert_lifetime
|
|
AFTER INSERT ON auctions
|
|
FOR EACH ROW
|
|
EXECUTE PROCEDURE public.fn_insert_lifetime();
|
|
|
|
-- Update trigger
|
|
DROP TRIGGER IF EXISTS update_lifetime ON auctions;
|
|
CREATE TRIGGER update_lifetime
|
|
AFTER UPDATE ON auctions
|
|
FOR EACH ROW
|
|
EXECUTE PROCEDURE public.fn_update_lifetime();
|
|
|
|
-- Remove trigger
|
|
DROP TRIGGER IF EXISTS remove_lifetime ON auctions;
|
|
CREATE TRIGGER remove_lifetime
|
|
BEFORE DELETE ON auctions
|
|
FOR EACH ROW
|
|
EXECUTE PROCEDURE public.fn_remove_lifetime();
|
|
`);
|
|
//Setup Table sanitation
|
|
await conn.query(`
|
|
CREATE OR REPLACE FUNCTION public.cleanup_old_entries()
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $$
|
|
DECLARE
|
|
temp_id INT;
|
|
BEGIN
|
|
FOR temp_id IN
|
|
SELECT id
|
|
FROM lifetimes
|
|
WHERE EXTRACT(EPOCH FROM (NOW() - insertedon))/3600 >= 6 -- 6 hours
|
|
LOOP
|
|
-- Removes matching entries from auctions
|
|
DELETE FROM auctions
|
|
WHERE auctions.id = temp_id;
|
|
END LOOP;
|
|
|
|
RETURN;
|
|
END;
|
|
$$;
|
|
`);
|
|
}
|
|
catch (error) {
|
|
console.error("InitDB Error: ", error);
|
|
throw error;
|
|
}
|
|
finally {
|
|
if (conn) conn.release();
|
|
}
|
|
}
|
|
//INSERT ELEMENT IN AUCTIONS TABLE OR UPDATE IF IT ALREADY EXISTS
|
|
public static async Upsert(auctionid: string|string[], lbin: number|number[]) {
|
|
let conn: PoolClient | undefined;
|
|
try {
|
|
conn = await this.pool.connect();
|
|
await conn.query('BEGIN');
|
|
if(Array.isArray(auctionid) && Array.isArray(lbin))
|
|
if(auctionid.length === lbin.length) {
|
|
await conn.query(`
|
|
INSERT INTO auctions (auctionid, LBin)
|
|
VALUES (?,?)
|
|
ON DUPLICATE KEY UPDATE
|
|
LBin = VALUES(LBin);
|
|
`,[await this.UnifiedArray(auctionid,lbin)]);
|
|
}
|
|
else if(Array.isArray(auctionid) || Array.isArray(lbin))
|
|
throw Error(`Upsert SQL Function error - cannot unify collection ${Array.isArray(auctionid) ? auctionid : lbin} to singlet ${!Array.isArray(auctionid) ? auctionid : lbin}`);
|
|
else {
|
|
await conn.query(`
|
|
INSERT INTO auctions (auctionid, LBin)
|
|
VALUES (?,?)
|
|
ON DUPLICATE KEY UPDATE
|
|
LBin = VALUES(LBin);
|
|
`, [auctionid, lbin]);
|
|
}
|
|
await conn.query('COMMIT');
|
|
}
|
|
catch(error)
|
|
{
|
|
console.error("message_before_error: ", error);
|
|
if (conn) await conn.query('ROLLBACK');
|
|
throw error;
|
|
}
|
|
finally
|
|
{
|
|
if (conn) conn.release();
|
|
}
|
|
}
|
|
//REMOVE ELEMENT IN AUCTIONS TABLE
|
|
public static async Remove(auctionid: string|string[]) {
|
|
let conn: PoolClient | undefined;
|
|
try {
|
|
conn = await this.pool.connect();
|
|
await conn.query('BEGIN');
|
|
await conn.query(`
|
|
DELETE FROM auctions WHERE auctionid = ?
|
|
`,[auctionid]);
|
|
await conn.query('COMMIT');
|
|
}
|
|
catch (error) {
|
|
console.error("InitDB Error: ", error);
|
|
if (conn) await conn.query('ROLLBACK');
|
|
throw error;
|
|
}
|
|
finally {
|
|
if (conn) conn.release();
|
|
}
|
|
}
|
|
|
|
public static async Query(query:string,use_transaction:boolean = true) {
|
|
let conn: PoolClient | undefined;
|
|
try{
|
|
conn = await this.pool.connect()
|
|
if (use_transaction) await conn.query('BEGIN');
|
|
await conn.query(query);
|
|
if (use_transaction) await conn.query('COMMIT');
|
|
}
|
|
catch(error) {
|
|
console.error("InitDB Error: ", error);
|
|
if (use_transaction && conn) await conn.query('ROLLBACK');
|
|
throw error;
|
|
}
|
|
finally
|
|
{
|
|
if(conn) conn.release();
|
|
}
|
|
}
|
|
//MATCH PROVIDED ELEMENTS IN AUCTIONS TABLE - returns true/false
|
|
public static async Match(auctionid:string|string[],lbin:number|number[]): Promise<boolean|any> {
|
|
let conn: PoolClient | undefined;
|
|
let result;
|
|
try{
|
|
conn = await this.pool.connect();
|
|
if(Array.isArray(auctionid) && Array.isArray(lbin))
|
|
if(auctionid.length === lbin.length) {
|
|
result = await conn.query(`
|
|
CREATE TEMPORARY TABLE IF NOT EXISTS TEMP (
|
|
auctionID VARCHAR(255) PRIMARY KEY,
|
|
lbin DECIMAL(65,5)
|
|
);
|
|
INSERT INTO TEMP (auctionID, lbin) VALUES ?
|
|
SELECT tmp.*
|
|
FROM TEMP AS tmp
|
|
WHERE NOT EXISTS (
|
|
SELECT 1
|
|
FROM auctions AS auc
|
|
WHERE auc.auctionID = tmp.auctionID
|
|
AND auc.lbin = tmp.lbin);
|
|
`,[await this.UnifiedArray(auctionid,lbin)]);
|
|
return result;
|
|
}
|
|
else if(Array.isArray(auctionid) || Array.isArray(lbin))
|
|
throw Error(`Match SQL Function error - cannot unify collection ${Array.isArray(auctionid) ? auctionid : lbin} to singlet ${!Array.isArray(auctionid) ? auctionid : lbin}`);
|
|
else {
|
|
result = await conn.query(`
|
|
SELECT CASE
|
|
WHEN COUNT(*) > 0
|
|
THEN true
|
|
ELSE false
|
|
END AS user_exists
|
|
FROM auctions WHERE auctionID = ?;
|
|
`,[auctionid]);
|
|
return Boolean(result.rows.length);
|
|
}
|
|
}
|
|
catch(error)
|
|
{
|
|
console.error("message_before_error: ", error);
|
|
throw error;
|
|
}
|
|
finally
|
|
{
|
|
if (conn) conn.release();
|
|
}
|
|
}
|
|
|
|
//EXAMPLE BLOCK OF CODE FOR ADDING DATABASE FUNCTIONS
|
|
/*
|
|
public static async example_name() {
|
|
let conn:PoolClient|undefined;
|
|
try{
|
|
conn = await this.pool.connect();
|
|
await conn.query('BEGIN');
|
|
|
|
//CODE HERE//
|
|
|
|
await conn.query('COMMIT');
|
|
}
|
|
catch(error)
|
|
{
|
|
console.error("message_before_error: ", error);
|
|
if(conn) await conn.query('ROLLBACK');
|
|
throw error;
|
|
}
|
|
finally
|
|
{
|
|
if(conn) conn.release();
|
|
}
|
|
*/
|
|
private static async UnifiedArray<T1, T2>(auctionid: string[], lbin: number[]): Promise<{ x: string[], y: number[] }> {
|
|
return { x: [...auctionid], y: [...lbin] };
|
|
}
|
|
}
|
|
export {
|
|
SqlSystem
|
|
}
|