import pgPkg from 'pg'; const { Pool } = pgPkg; const pool = new Pool(); const parseVoter = (voter) => ({ id: parseInt(voter.id), login: voter.login, password: voter.password, full_name: voter.full_name, vgroup_id: parseInt(voter.vgroup_id), is_admin: JSON.parse(voter.is_admin), registration_date: voter.registration_date, }); const parseVgroup = (vgroup) => ({ id: parseInt(vgroup.id), name: vgroup.name, description: vgroup.description, }); const parseVote = (vote) => ({ id: parseInt(vote.id), health: parseInt(vote.health), love: parseInt(vote.love), sex: parseInt(vote.sex), rest: parseInt(vote.rest), finances: parseInt(vote.finances), meaning_of_life: parseInt(vote.meaning_of_life), serenity: parseInt(vote.serenity), relations: parseInt(vote.relations), pers_growth: parseInt(vote.pers_growth), work: parseInt(vote.work), vote_date: vote.vote_date, voter_id: parseInt(vote.voter_id), }); // TODO: implement const parseVoteResult = (voteResult) => ({ }); export class DBAccess { static async tableExists(table) { const res = await pool.query("SELECT 1 FROM pg_database WHERE datname = $1", [table]); return res.rows.length > 0; } static async scaffold() { await pool.query(`CREATE TABLE IF NOT EXISTS vgroup ( id SERIAL PRIMARY KEY, name VARCHAR(50) NOT NULL, description VARCHAR(255) NOT NULL DEFAULT '' )`); await pool.query(`CREATE TABLE IF NOT EXISTS voter ( id SERIAL PRIMARY KEY, login VARCHAR(255) UNIQUE NOT NULL, password VARCHAR(255) NOT NULL, vgroup_id INT, full_name VARCHAR(255) NOT NULL DEFAULT '', is_admin BOOLEAN NOT NULL DEFAULT false, registration_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_vgroup FOREIGN KEY(vgroup_id) REFERENCES vgroup(id) )`); await pool.query(`CREATE TABLE IF NOT EXISTS vote ( id SERIAL PRIMARY KEY, health INT NOT NULL, love INT NOT NULL, sex INT NOT NULL, rest INT NOT NULL, finances INT NOT NULL, meaning_of_life INT NOT NULL, serenity INT NOT NULL, relations INT NOT NULL, pers_growth INT NOT NULL, work INT NOT NULL, vote_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP, voter_id INT NOT NULL, CONSTRAINT voter FOREIGN KEY(voter_id) REFERENCES voter(id) )`); } static async dropAll() { await pool.query("DROP TABLE IF EXISTS vote"); await pool.query("DROP TABLE IF EXISTS voter"); await pool.query("DROP TABLE IF EXISTS vgroup"); } static query(text, params, callback) { return pool.query(text, params, callback); } static async queryAsync(text, params) { return pool.query(text, params); } static async countVoters() { const res = await pool.query("SELECT COUNT(*) FROM voter"); return parseInt(res.rows[0].count); } static async findVoterByLogin(login) { const res = await pool.query("SELECT * FROM voter WHERE login = $1", [login]); if (res.rows.length != 0) { return parseVoter(res.rows[0]); } return null; } static async validateVoter(login, password) { const res = await pool.query("SELECT * FROM voter WHERE login = $1 AND password = $2", [login, password]); if (res.rows.length != 0) { return parseVoter(res.rows[0]); } return null; } static async createVoter(login, password, full_name, is_admin) { let res = await pool.query( "INSERT INTO voter(login, password, full_name, is_admin) VALUES ($1, $2, $3, $4) RETURNING *", [login, password, full_name, is_admin] ); if (res.rows.length != 0) { if (is_admin) { let adminGroup = await pool.query("SELECT * FROM vgroup WHERE name = $1", ["admin"]); if (adminGroup.rows.length === 0) { adminGroup = await pool.query("INSERT INTO vgroup(name, description) VALUES ($1, $2) RETURNING *", ["admin", "Администраторы"]); } res = await pool.query("UPDATE voter SET vgroup_id = $1 WHERE login = $2 RETURNING *", [adminGroup.rows[0].id, login]); } if (res.rows.length != 0) { return parseVoter(res.rows[0]); } } return null; } static async getVoters() { const res = await pool.query("SELECT * FROM voter ORDER BY registration_date"); return res.rows.map(parseVoter); } static async getVoterById(id) { const res = await pool.query("SELECT * FROM voter WHERE id = $1", [id]); if (res.rows.length != 0) { return parseVoter(res.rows[0]); } return null; } static async deleteVoterVotes(id) { await pool.query("DELETE FROM vote WHERE voter_id = $1", [id]); } static async deleteVoter(id) { await this.deleteVoterVotes(id); await pool.query("DELETE FROM voter WHERE id = $1", [id]); } static async promoteVoter(id, vgroup_id, setAdmin) { const user = await this.getVoterById(id); const admCount = (await this.getVoters()).reduce((acc, item) => acc + (item.is_admin ? 1 : 0), 0); if (user) { if (user.is_admin && admCount === 1) { throw new Error("Нельзя удалить последнего администратора"); } if (setAdmin) { await pool.query("UPDATE voter SET vgroup_id = $1, is_admin = true WHERE id = $2", [vgroup_id, id]); } else { await pool.query("UPDATE voter SET vgroup_id = $1, is_admin = false WHERE id = $2", [vgroup_id, id]); } } else { throw new Error("Такого пользователя нет"); } } static async getVgroups() { const res = await pool.query("SELECT * FROM vgroup"); return res.rows.map(parseVgroup); } static async createVgroup(name, description) { const res = await pool.query("INSERT INTO vgroup(name, description) VALUES ($1, $2) RETURNING *", [name, description]); if (res.rows.length != 0) { return parseVgroup(res.rows[0]); } return null; } static async deleteVgroup(id) { await pool.query("DELETE FROM vgroup WHERE id = $1", [id]); } static async createVote(vote) { const res = await pool.query(`INSERT INTO vote( health, love, sex, rest, relations, pers_growth, work, finances, meaning_of_life, serenity, voter_id ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) RETURNING *`, [ vote.health, vote.love, vote.sex, vote.rest, vote.relations, vote.pers_growth, vote.work, vote.finances, vote.meaning_of_life, vote.serenity, vote.voter_id ]); if (res.rows.length != 0) { return parseVote(res.rows[0]); } return null; } static async getVotes() { const res = await pool.query("SELECT * FROM vote ORDER BY vote.vote_date desc"); return res.rows.map(parseVote); } static async getVotesByVoterId(voter_id) { const res = await pool.query("SELECT * FROM vote WHERE voter_id = $1", [voter_id]); return res.rows.map(parseVote); } static async deleteVote(id) { await pool.query("DELETE FROM vote WHERE id = $1", [id]); } static async getGrouppedVotes() { const res = await pool.query(` select array_agg(v.health) as health, array_agg(v.love) as love, array_agg(v.sex) as sex, array_agg(v.rest) as rest, array_agg(v.finances) as finances, array_agg(v.meaning_of_life) as meaning_of_life, array_agg(v.serenity) as serenity, array_agg(v.relations) as relations, array_agg(v.pers_growth) as pers_growth, array_agg(v.work) as work, v1.vgroup_id, to_char(v.vote_date, 'mm.yyyy') as vote_date from vote as v inner join voter v1 on v1.id = v.voter_id group by v1.vgroup_id, to_char(v.vote_date, 'mm.yyyy') order by to_char(v.vote_date, 'mm.yyyy') asc`.trim()); return res.rows;//.map(parseVote); } static async didUserBotedThisMonth(voter_id) { const res = await pool.query("SELECT * FROM vote WHERE voter_id = $1 AND vote_date >= date_trunc('month', now())", [voter_id]); return res.rows.length != 0; } static async shutdown() { return await pool.end(); } }