diff --git a/database/postgres/pg.js b/database/postgres/pg.js new file mode 100644 index 00000000..31ed4c92 --- /dev/null +++ b/database/postgres/pg.js @@ -0,0 +1,45 @@ +const { Client } = require('pg') +require('dotenv').config() + +const pgModule = {} +let client + +pgModule.startPGDB = ()=>{ + client = new Client({ + host: process.env.HOS, + port: process.env.PORT, + user: process.env.USERNAME, + password: process.env.PASSWORD, + database: process.env.DATABASE + }) + return client.connect() +} + +pgModule.closePGDB = ()=>{ + return client.end() +} + +pgModule.createPgAccount = async (username, password)=>{ + if(!username || !password) return + try{ + await client.query(`CREATE DATABASE IF NOT EXISTS ${username}`) + await client.query(`CREATE USER IF NOT EXISTS ${username} WITH ENCRYPTED password '${password}'`) + await client.query(`GRANT ALL PRIVILEGES ON DATABASE ${username} TO ${username}`) + }catch(err){ + console.log('failed to createPgAccount', err) + throw new Error(`failed to createPgAccount for user: ${username}`) + } +} + +pgModule.deletePgAccount = async (username)=>{ + if(!username) return + try{ + await client.query(`DROP DATABASE IF EXISTS ${username}`) + await client.query(`DROP USER IF EXISTS ${username}`) + }catch(err){ + console.log('failed to deletePgAccount', err) + throw new Error(`failed to deletePgAccount for database and user: ${username}`) + } +} + +module.exports = pgModule diff --git a/database/postgres/pg.test.js b/database/postgres/pg.test.js new file mode 100644 index 00000000..71d4a62b --- /dev/null +++ b/database/postgres/pg.test.js @@ -0,0 +1,81 @@ +jest.mock('pg') +const {Client} = require('pg') +const {startPGDB, closePGDB, createPgAccount, deletePgAccount} = require('./pg') + +describe('Test PG DB', ()=>{ + beforeEach(()=>{ + jest.clearAllMocks() + }) + let mockClient = { + query: jest.fn().mockReturnValue(Promise.resolve()), + connect: jest.fn().mockReturnValue(Promise.resolve()), + end: jest.fn().mockReturnValue(Promise.resolve()) + } + Client.mockImplementation(function(){ + return mockClient + }) + describe('Test startPGDB && closePGDB', ()=>{ + it('it should call connect when starting PGDB', async ()=>{ + await startPGDB() + expect(mockClient.connect).toHaveBeenCalledTimes(1) + }) + it('it should call end when closing PGDB', async ()=>{ + await closePGDB() + expect(mockClient.end).toHaveBeenCalledTimes(1) + }) + }) + describe('Test create and delete pgAccount', ()=>{ + beforeEach(async ()=>{ + await startPGDB() + }) + afterEach(async ()=>{ + await closePGDB() + }) + describe('Test createPgAccount', ()=>{ + it('it should execute all queries if required arguments are passed into createPgAccount', async ()=>{ + await createPgAccount('username', 'password') + expect(mockClient.query).toHaveBeenCalledTimes(3) + expect(mockClient.query).toHaveBeenNthCalledWith(1, `CREATE DATABASE IF NOT EXISTS username`) + expect(mockClient.query).toHaveBeenNthCalledWith(2, `CREATE USER IF NOT EXISTS username WITH ENCRYPTED password 'password'`) + expect(mockClient.query).toHaveBeenNthCalledWith(3, `GRANT ALL PRIVILEGES ON DATABASE username TO username`) + }) + it('it should not execute any queries in createPgAccount if required arguments are not passed in', async ()=>{ + await createPgAccount() + expect(mockClient.query).toHaveBeenCalledTimes(0) + }) + it('it should check if console.log is called at throw of createPgAccount', async ()=>{ + try{ + console.log = jest.fn() + await mockClient.query.mockReturnValue(Promise.reject()) + const resCreatePgAccount = await createPgAccount('username', 'password') + expect(resCreatePgAccount).rejects.toThrow() + }catch(err){ + expect(console.log).toHaveBeenCalledTimes(1) + } + }) + }) + describe('Test deletePgAccount', ()=>{ + it('it should execute all queries if required arguments are passed into deletePgAccount', async ()=>{ + mockClient.query.mockReturnValue(Promise.resolve()) + await deletePgAccount('username') + expect(mockClient.query).toHaveBeenCalledTimes(2) + expect(mockClient.query).toHaveBeenNthCalledWith(1, `DROP DATABASE IF EXISTS username`) + expect(mockClient.query).toHaveBeenNthCalledWith(2, `DROP USER IF EXISTS username`) + }) + it('it should not execute any queries in deletePgAccount if required arguments are not passed in', async ()=>{ + await deletePgAccount() + expect(mockClient.query).toHaveBeenCalledTimes(0) + }) + it('it should check if console.log is called at throw of deletePgAccount', async ()=>{ + try{ + console.log = jest.fn() + await mockClient.query.mockReturnValue(Promise.reject()) + const resDeletePgAccount = await deletePgAccount('username', 'password') + expect(resDeletePgAccount).rejects.toThrow() + }catch(err){ + expect(console.log).toHaveBeenCalledTimes(1) + } + }) + }) + }) +}) diff --git a/package.json b/package.json new file mode 100644 index 00000000..2619c997 --- /dev/null +++ b/package.json @@ -0,0 +1,27 @@ +{ + "name": "databases", + "version": "1.0.0", + "description": "Create databases in postgres, mongoDB and neo4J", + "main": "index.js", + "scripts": { + "test": "jest --coverage" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/garageScript/databases.git" + }, + "author": "garageScript", + "license": "ISC", + "bugs": { + "url": "https://github.com/gargeScript/databases/issues" + }, + "homepage": "https://github.com/garageScript/databases#readme", + "devDependencies": { + "dotenv": "^8.2.0", + "jest": "^25.2.4", + "pm2": "^4.2.3" + }, + "dependencies": { + "pg": "^8.0.0" + } +}