From 5c4ad704017ba0d09d454d74239c4382ee4add13 Mon Sep 17 00:00:00 2001 From: Chidi Orji Date: Mon, 16 Mar 2020 12:10:14 +0100 Subject: [PATCH 01/12] chore: pretty and lint --- test/index.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/index.test.js b/test/index.test.js index cd11fb8..0c51bd9 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -1,4 +1,3 @@ - import { expect, server, BASE_URL } from './setup'; describe('Index page test', () => { From ac91ec6995c427e7e6d6efeb2e458f084764a817 Mon Sep 17 00:00:00 2001 From: Chidi Orji Date: Mon, 16 Mar 2020 13:07:06 +0100 Subject: [PATCH 02/12] deps: install node-postgres --- package.json | 6 ++- yarn.lock | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 106 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index ea05c25..de7f884 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "pretty": "prettier --write '**/*.{js,json}' '!node_modules/**'", "postpretty": "yarn lint --fix", "test": "nyc --reporter=html --reporter=text --reporter=lcov mocha -r @babel/register", - "coverage": "nyc report --reporter=text-lcov | coveralls" + "coverage": "nyc report --reporter=text-lcov | coveralls", + "runQuery": "babel-node ./src/utils/runQuery" }, "dependencies": { "cookie-parser": "~1.4.4", @@ -18,7 +19,8 @@ "dotenv": "^8.2.0", "express": "~4.16.1", "http-errors": "~1.6.3", - "morgan": "~1.9.1" + "morgan": "~1.9.1", + "pg": "^7.18.2" }, "devDependencies": { "@babel/cli": "^7.8.4", diff --git a/yarn.lock b/yarn.lock index 4e28d62..26b32da 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1178,6 +1178,11 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== +buffer-writer@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04" + integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw== + bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" @@ -3702,6 +3707,11 @@ package-json@^4.0.0: registry-url "^3.0.3" semver "^5.1.0" +packet-reader@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" + integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -3800,6 +3810,58 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= +pg-connection-string@0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-0.1.3.tgz#da1847b20940e42ee1492beaf65d49d91b245df7" + integrity sha1-2hhHsglA5C7hSSvq9l1J2RskXfc= + +pg-int8@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" + integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== + +pg-packet-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pg-packet-stream/-/pg-packet-stream-1.1.0.tgz#e45c3ae678b901a2873af1e17b92d787962ef914" + integrity sha512-kRBH0tDIW/8lfnnOyTwKD23ygJ/kexQVXZs7gEyBljw4FYqimZFxnMMx50ndZ8In77QgfGuItS5LLclC2TtjYg== + +pg-pool@^2.0.10: + version "2.0.10" + resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-2.0.10.tgz#842ee23b04e86824ce9d786430f8365082d81c4a" + integrity sha512-qdwzY92bHf3nwzIUcj+zJ0Qo5lpG/YxchahxIN8+ZVmXqkahKXsnl2aiJPHLYN9o5mB/leG+Xh6XKxtP7e0sjg== + +pg-types@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" + integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== + dependencies: + pg-int8 "1.0.1" + postgres-array "~2.0.0" + postgres-bytea "~1.0.0" + postgres-date "~1.0.4" + postgres-interval "^1.1.0" + +pg@^7.18.2: + version "7.18.2" + resolved "https://registry.yarnpkg.com/pg/-/pg-7.18.2.tgz#4e219f05a00aff4db6aab1ba02f28ffa4513b0bb" + integrity sha512-Mvt0dGYMwvEADNKy5PMQGlzPudKcKKzJds/VbOeZJpb6f/pI3mmoXX0JksPgI3l3JPP/2Apq7F36O63J7mgveA== + dependencies: + buffer-writer "2.0.0" + packet-reader "1.0.0" + pg-connection-string "0.1.3" + pg-packet-stream "^1.1.0" + pg-pool "^2.0.10" + pg-types "^2.1.0" + pgpass "1.x" + semver "4.3.2" + +pgpass@1.x: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.2.tgz#2a7bb41b6065b67907e91da1b07c1847c877b306" + integrity sha1-Knu0G2BltnkH6R2hsHwYR8h3swY= + dependencies: + split "^1.0.0" + picomatch@^2.0.4, picomatch@^2.0.7: version "2.2.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a" @@ -3853,6 +3915,28 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= +postgres-array@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" + integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== + +postgres-bytea@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" + integrity sha1-AntTPAqokOJtFy1Hz5zOzFIazTU= + +postgres-date@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.4.tgz#1c2728d62ef1bff49abdd35c1f86d4bdf118a728" + integrity sha512-bESRvKVuTrjoBluEcpv2346+6kgB7UlnqWZsnbnCccTNq/pqfj1j6oBaN5+b/NrDXepYUT/HKadqv3iS9lJuVA== + +postgres-interval@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" + integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== + dependencies: + xtend "^4.0.0" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -4238,6 +4322,11 @@ semver-diff@^2.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== +semver@4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.2.tgz#c7a07158a80bedd052355b770d82d6640f803be7" + integrity sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c= + semver@7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" @@ -4467,6 +4556,13 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" +split@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" + integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== + dependencies: + through "2" + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -4676,7 +4772,7 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= -through@^2.3.6: +through@2, through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= @@ -5050,6 +5146,11 @@ xdg-basedir@^3.0.0: resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ= +xtend@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + y18n@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" From ba5b9f7f2535774f67eece7f7457a91e096ad1bf Mon Sep 17 00:00:00 2001 From: Chidi Orji Date: Mon, 16 Mar 2020 14:56:10 +0100 Subject: [PATCH 03/12] chore: add model to communicate with db --- src/models/model.js | 19 +++++++++++++++++++ src/models/pool.js | 6 ++++++ 2 files changed, 25 insertions(+) create mode 100644 src/models/model.js create mode 100644 src/models/pool.js diff --git a/src/models/model.js b/src/models/model.js new file mode 100644 index 0000000..f457529 --- /dev/null +++ b/src/models/model.js @@ -0,0 +1,19 @@ +import { pool } from './pool'; + +class Model { + constructor(table) { + this.pool = pool; + this.table = table; + this.pool.on( + 'error', + (err, client) => `Error, ${err}, on idle client${client}` + ); + } + + async select(columns, clause) { + let query = `SELECT ${columns} FROM ${this.table}`; + if (clause) query += clause; + return this.pool.query(query); + } +} +export default Model; diff --git a/src/models/pool.js b/src/models/pool.js new file mode 100644 index 0000000..013986b --- /dev/null +++ b/src/models/pool.js @@ -0,0 +1,6 @@ +import { Pool } from 'pg'; +import dotenv from 'dotenv'; +import { connectionString } from '../settings'; + +dotenv.config(); +export const pool = new Pool({ connectionString }); From 94d3a4f4c64a887cb53343ce8277d57f9b28cfa4 Mon Sep 17 00:00:00 2001 From: Chidi Orji Date: Mon, 16 Mar 2020 14:56:29 +0100 Subject: [PATCH 04/12] chore: add db utility functions --- src/utils/queries.js | 16 ++++++++++++++++ src/utils/queryFunctions.js | 18 ++++++++++++++++++ src/utils/runQuery.js | 6 ++++++ 3 files changed, 40 insertions(+) create mode 100644 src/utils/queries.js create mode 100644 src/utils/queryFunctions.js create mode 100644 src/utils/runQuery.js diff --git a/src/utils/queries.js b/src/utils/queries.js new file mode 100644 index 0000000..0e3a0c9 --- /dev/null +++ b/src/utils/queries.js @@ -0,0 +1,16 @@ +export const createMessageTable = ` +DROP TABLE IF EXISTS messages; +CREATE TABLE IF NOT EXISTS messages ( + id SERIAL PRIMARY KEY, + name VARCHAR DEFAULT '', + message VARCHAR NOT NULL + ) + `; + +export const insertMessages = ` +INSERT INTO messages(name, message) +VALUES ('chidimo', 'first message'), + ('orji', 'second message') +`; + +export const dropMessagesTable = 'DROP TABLE messages'; diff --git a/src/utils/queryFunctions.js b/src/utils/queryFunctions.js new file mode 100644 index 0000000..31c627b --- /dev/null +++ b/src/utils/queryFunctions.js @@ -0,0 +1,18 @@ +import { pool } from '../models/pool'; +import { + insertMessages, + dropMessagesTable, + createMessageTable, +} from './queries'; + +export const executeQueryArray = async arr => new Promise(resolve => { + const stop = arr.length; + arr.forEach(async (q, index) => { + await pool.query(q); + if (index + 1 === stop) resolve(); + }); +}); + +export const dropTables = () => executeQueryArray([ dropMessagesTable ]); +export const createTables = () => executeQueryArray([ createMessageTable ]); +export const insertIntoTables = () => executeQueryArray([ insertMessages ]); diff --git a/src/utils/runQuery.js b/src/utils/runQuery.js new file mode 100644 index 0000000..bdada9e --- /dev/null +++ b/src/utils/runQuery.js @@ -0,0 +1,6 @@ +import { createTables, insertIntoTables } from './queryFunctions'; + +(async () => { + await createTables(); + await insertIntoTables(); +})(); From 012770167e97a601ebf5fbb79e8cf0b0c30bb45f Mon Sep 17 00:00:00 2001 From: Chidi Orji Date: Mon, 16 Mar 2020 14:56:50 +0100 Subject: [PATCH 05/12] feat: add messages route and controller --- src/controllers/index.js | 1 + src/controllers/messages.js | 12 ++++++++++++ src/routes/index.js | 3 ++- src/settings.js | 1 + 4 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 src/controllers/messages.js diff --git a/src/controllers/index.js b/src/controllers/index.js index e20557b..686a7a0 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -1 +1,2 @@ export * from './home'; +export * from './messages'; diff --git a/src/controllers/messages.js b/src/controllers/messages.js new file mode 100644 index 0000000..6037e13 --- /dev/null +++ b/src/controllers/messages.js @@ -0,0 +1,12 @@ +import Model from '../models/model'; + +const messagesModel = new Model('messages'); + +export const messagesPage = async (req, res) => { + try { + const data = await messagesModel.select('name, message'); + res.status(200).json({ messages: data.rows }); + } catch (err) { + res.status(200).json({ messages: err.stack }); + } +}; diff --git a/src/routes/index.js b/src/routes/index.js index 442bf61..d33b704 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -1,7 +1,8 @@ import express from 'express'; -import { indexPage } from '../controllers'; +import { indexPage, messagesPage } from '../controllers'; const indexRouter = express.Router(); indexRouter.get('/', indexPage); +indexRouter.get('/messages', messagesPage); export default indexRouter; diff --git a/src/settings.js b/src/settings.js index 6c21089..53454aa 100644 --- a/src/settings.js +++ b/src/settings.js @@ -2,3 +2,4 @@ import dotenv from 'dotenv'; dotenv.config(); export const testEnvironmentVariable = process.env.TEST_ENV_VARIABLE; +export const connectionString = process.env.CONNECTION_STRING; From 2c8ca33ffb1b1b4e09064e2fb3b2610f7e410e60 Mon Sep 17 00:00:00 2001 From: Chidi Orji Date: Mon, 16 Mar 2020 15:13:28 +0100 Subject: [PATCH 06/12] test: update test and ci-cd --- .appveyor.yml | 7 +++++++ .travis.yml | 13 +++++++++++++ test/hooks.js | 14 ++++++++++++++ test/messages.test.js | 18 ++++++++++++++++++ 4 files changed, 52 insertions(+) create mode 100644 test/hooks.js create mode 100644 test/messages.test.js diff --git a/.appveyor.yml b/.appveyor.yml index 778117e..bc69466 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -7,3 +7,10 @@ install: test_script: - yarn test build: off +before_test: + - SET PGUSER=postgres + - SET PGPASSWORD=Password12! + - PATH=C:\Program Files\PostgreSQL\10\bin\;%PATH% + - createdb testdb +services: + - postgresql101 diff --git a/.travis.yml b/.travis.yml index 769ec13..2551927 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ install: yarn after_success: yarn coverage before_script: + - psql -c 'create database testdb;' -U postgres - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter - chmod +x ./cc-test-reporter - ./cc-test-reporter before-build @@ -19,3 +20,15 @@ script: - yarn test after_script: - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT + +services: + - postgresql +addons: + postgresql: "10" + apt: + packages: + - postgresql-10 + - postgresql-client-10 +before_install: + - sudo cp /etc/postgresql/{9.6,10}/main/pg_hba.conf + - sudo /etc/init.d/postgresql restart diff --git a/test/hooks.js b/test/hooks.js new file mode 100644 index 0000000..d28c0f8 --- /dev/null +++ b/test/hooks.js @@ -0,0 +1,14 @@ +import { + dropTables, + createTables, + insertIntoTables, +} from '../src/utils/queryFunctions'; + +before(async () => { + await createTables(); + await insertIntoTables(); +}); + +after(async () => { + await dropTables(); +}); diff --git a/test/messages.test.js b/test/messages.test.js new file mode 100644 index 0000000..5afca48 --- /dev/null +++ b/test/messages.test.js @@ -0,0 +1,18 @@ +import { expect, server, BASE_URL } from './setup'; + +describe('Messages', () => { + it('get messages page', done => { + server + .get(`${BASE_URL}/messages`) + .expect(200) + .end((err, res) => { + expect(res.status).to.equal(200); + expect(res.body.messages).to.be.instanceOf(Array); + res.body.messages.forEach(m => { + expect(m).to.have.property('name'); + expect(m).to.have.property('message'); + }); + done(); + }); + }); +}); From 1dd4561a0e5c638cc11182be2afc6802ca2a086e Mon Sep 17 00:00:00 2001 From: Chidi Orji Date: Mon, 16 Mar 2020 12:10:14 +0100 Subject: [PATCH 07/12] chore: pretty and lint --- test/index.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/index.test.js b/test/index.test.js index cd11fb8..0c51bd9 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -1,4 +1,3 @@ - import { expect, server, BASE_URL } from './setup'; describe('Index page test', () => { From 965cae72b67e99a34f65f34f503f97d00cb09db6 Mon Sep 17 00:00:00 2001 From: Chidi Orji Date: Mon, 16 Mar 2020 13:07:06 +0100 Subject: [PATCH 08/12] deps: install node-postgres --- package.json | 6 ++- yarn.lock | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 106 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index ea05c25..de7f884 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "pretty": "prettier --write '**/*.{js,json}' '!node_modules/**'", "postpretty": "yarn lint --fix", "test": "nyc --reporter=html --reporter=text --reporter=lcov mocha -r @babel/register", - "coverage": "nyc report --reporter=text-lcov | coveralls" + "coverage": "nyc report --reporter=text-lcov | coveralls", + "runQuery": "babel-node ./src/utils/runQuery" }, "dependencies": { "cookie-parser": "~1.4.4", @@ -18,7 +19,8 @@ "dotenv": "^8.2.0", "express": "~4.16.1", "http-errors": "~1.6.3", - "morgan": "~1.9.1" + "morgan": "~1.9.1", + "pg": "^7.18.2" }, "devDependencies": { "@babel/cli": "^7.8.4", diff --git a/yarn.lock b/yarn.lock index 4e28d62..26b32da 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1178,6 +1178,11 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== +buffer-writer@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04" + integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw== + bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" @@ -3702,6 +3707,11 @@ package-json@^4.0.0: registry-url "^3.0.3" semver "^5.1.0" +packet-reader@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" + integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -3800,6 +3810,58 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= +pg-connection-string@0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-0.1.3.tgz#da1847b20940e42ee1492beaf65d49d91b245df7" + integrity sha1-2hhHsglA5C7hSSvq9l1J2RskXfc= + +pg-int8@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" + integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== + +pg-packet-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pg-packet-stream/-/pg-packet-stream-1.1.0.tgz#e45c3ae678b901a2873af1e17b92d787962ef914" + integrity sha512-kRBH0tDIW/8lfnnOyTwKD23ygJ/kexQVXZs7gEyBljw4FYqimZFxnMMx50ndZ8In77QgfGuItS5LLclC2TtjYg== + +pg-pool@^2.0.10: + version "2.0.10" + resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-2.0.10.tgz#842ee23b04e86824ce9d786430f8365082d81c4a" + integrity sha512-qdwzY92bHf3nwzIUcj+zJ0Qo5lpG/YxchahxIN8+ZVmXqkahKXsnl2aiJPHLYN9o5mB/leG+Xh6XKxtP7e0sjg== + +pg-types@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" + integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== + dependencies: + pg-int8 "1.0.1" + postgres-array "~2.0.0" + postgres-bytea "~1.0.0" + postgres-date "~1.0.4" + postgres-interval "^1.1.0" + +pg@^7.18.2: + version "7.18.2" + resolved "https://registry.yarnpkg.com/pg/-/pg-7.18.2.tgz#4e219f05a00aff4db6aab1ba02f28ffa4513b0bb" + integrity sha512-Mvt0dGYMwvEADNKy5PMQGlzPudKcKKzJds/VbOeZJpb6f/pI3mmoXX0JksPgI3l3JPP/2Apq7F36O63J7mgveA== + dependencies: + buffer-writer "2.0.0" + packet-reader "1.0.0" + pg-connection-string "0.1.3" + pg-packet-stream "^1.1.0" + pg-pool "^2.0.10" + pg-types "^2.1.0" + pgpass "1.x" + semver "4.3.2" + +pgpass@1.x: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.2.tgz#2a7bb41b6065b67907e91da1b07c1847c877b306" + integrity sha1-Knu0G2BltnkH6R2hsHwYR8h3swY= + dependencies: + split "^1.0.0" + picomatch@^2.0.4, picomatch@^2.0.7: version "2.2.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a" @@ -3853,6 +3915,28 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= +postgres-array@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" + integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== + +postgres-bytea@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" + integrity sha1-AntTPAqokOJtFy1Hz5zOzFIazTU= + +postgres-date@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.4.tgz#1c2728d62ef1bff49abdd35c1f86d4bdf118a728" + integrity sha512-bESRvKVuTrjoBluEcpv2346+6kgB7UlnqWZsnbnCccTNq/pqfj1j6oBaN5+b/NrDXepYUT/HKadqv3iS9lJuVA== + +postgres-interval@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" + integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== + dependencies: + xtend "^4.0.0" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -4238,6 +4322,11 @@ semver-diff@^2.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== +semver@4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.2.tgz#c7a07158a80bedd052355b770d82d6640f803be7" + integrity sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c= + semver@7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" @@ -4467,6 +4556,13 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" +split@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" + integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== + dependencies: + through "2" + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -4676,7 +4772,7 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= -through@^2.3.6: +through@2, through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= @@ -5050,6 +5146,11 @@ xdg-basedir@^3.0.0: resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ= +xtend@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + y18n@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" From d365a075806e3c1c4a4f34422af6480db59b6f1d Mon Sep 17 00:00:00 2001 From: Chidi Orji Date: Mon, 16 Mar 2020 14:56:10 +0100 Subject: [PATCH 09/12] chore: add model to communicate with db --- src/models/model.js | 19 +++++++++++++++++++ src/models/pool.js | 6 ++++++ 2 files changed, 25 insertions(+) create mode 100644 src/models/model.js create mode 100644 src/models/pool.js diff --git a/src/models/model.js b/src/models/model.js new file mode 100644 index 0000000..f457529 --- /dev/null +++ b/src/models/model.js @@ -0,0 +1,19 @@ +import { pool } from './pool'; + +class Model { + constructor(table) { + this.pool = pool; + this.table = table; + this.pool.on( + 'error', + (err, client) => `Error, ${err}, on idle client${client}` + ); + } + + async select(columns, clause) { + let query = `SELECT ${columns} FROM ${this.table}`; + if (clause) query += clause; + return this.pool.query(query); + } +} +export default Model; diff --git a/src/models/pool.js b/src/models/pool.js new file mode 100644 index 0000000..013986b --- /dev/null +++ b/src/models/pool.js @@ -0,0 +1,6 @@ +import { Pool } from 'pg'; +import dotenv from 'dotenv'; +import { connectionString } from '../settings'; + +dotenv.config(); +export const pool = new Pool({ connectionString }); From 4a7251de7f65fd19a2881e749beede3c7a0f3816 Mon Sep 17 00:00:00 2001 From: Chidi Orji Date: Mon, 16 Mar 2020 14:56:29 +0100 Subject: [PATCH 10/12] chore: add db utility functions --- src/utils/queries.js | 16 ++++++++++++++++ src/utils/queryFunctions.js | 18 ++++++++++++++++++ src/utils/runQuery.js | 6 ++++++ 3 files changed, 40 insertions(+) create mode 100644 src/utils/queries.js create mode 100644 src/utils/queryFunctions.js create mode 100644 src/utils/runQuery.js diff --git a/src/utils/queries.js b/src/utils/queries.js new file mode 100644 index 0000000..0e3a0c9 --- /dev/null +++ b/src/utils/queries.js @@ -0,0 +1,16 @@ +export const createMessageTable = ` +DROP TABLE IF EXISTS messages; +CREATE TABLE IF NOT EXISTS messages ( + id SERIAL PRIMARY KEY, + name VARCHAR DEFAULT '', + message VARCHAR NOT NULL + ) + `; + +export const insertMessages = ` +INSERT INTO messages(name, message) +VALUES ('chidimo', 'first message'), + ('orji', 'second message') +`; + +export const dropMessagesTable = 'DROP TABLE messages'; diff --git a/src/utils/queryFunctions.js b/src/utils/queryFunctions.js new file mode 100644 index 0000000..31c627b --- /dev/null +++ b/src/utils/queryFunctions.js @@ -0,0 +1,18 @@ +import { pool } from '../models/pool'; +import { + insertMessages, + dropMessagesTable, + createMessageTable, +} from './queries'; + +export const executeQueryArray = async arr => new Promise(resolve => { + const stop = arr.length; + arr.forEach(async (q, index) => { + await pool.query(q); + if (index + 1 === stop) resolve(); + }); +}); + +export const dropTables = () => executeQueryArray([ dropMessagesTable ]); +export const createTables = () => executeQueryArray([ createMessageTable ]); +export const insertIntoTables = () => executeQueryArray([ insertMessages ]); diff --git a/src/utils/runQuery.js b/src/utils/runQuery.js new file mode 100644 index 0000000..bdada9e --- /dev/null +++ b/src/utils/runQuery.js @@ -0,0 +1,6 @@ +import { createTables, insertIntoTables } from './queryFunctions'; + +(async () => { + await createTables(); + await insertIntoTables(); +})(); From a97098a9da54e93858d5e37ae222c661f3ae87e8 Mon Sep 17 00:00:00 2001 From: Chidi Orji Date: Mon, 16 Mar 2020 14:56:50 +0100 Subject: [PATCH 11/12] feat: add messages route and controller --- src/controllers/index.js | 1 + src/controllers/messages.js | 12 ++++++++++++ src/routes/index.js | 3 ++- src/settings.js | 1 + 4 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 src/controllers/messages.js diff --git a/src/controllers/index.js b/src/controllers/index.js index e20557b..686a7a0 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -1 +1,2 @@ export * from './home'; +export * from './messages'; diff --git a/src/controllers/messages.js b/src/controllers/messages.js new file mode 100644 index 0000000..6037e13 --- /dev/null +++ b/src/controllers/messages.js @@ -0,0 +1,12 @@ +import Model from '../models/model'; + +const messagesModel = new Model('messages'); + +export const messagesPage = async (req, res) => { + try { + const data = await messagesModel.select('name, message'); + res.status(200).json({ messages: data.rows }); + } catch (err) { + res.status(200).json({ messages: err.stack }); + } +}; diff --git a/src/routes/index.js b/src/routes/index.js index 442bf61..d33b704 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -1,7 +1,8 @@ import express from 'express'; -import { indexPage } from '../controllers'; +import { indexPage, messagesPage } from '../controllers'; const indexRouter = express.Router(); indexRouter.get('/', indexPage); +indexRouter.get('/messages', messagesPage); export default indexRouter; diff --git a/src/settings.js b/src/settings.js index 6c21089..53454aa 100644 --- a/src/settings.js +++ b/src/settings.js @@ -2,3 +2,4 @@ import dotenv from 'dotenv'; dotenv.config(); export const testEnvironmentVariable = process.env.TEST_ENV_VARIABLE; +export const connectionString = process.env.CONNECTION_STRING; From 3cf82c5c05e646a8e3579b5fceeae4fbf516a419 Mon Sep 17 00:00:00 2001 From: Chidi Orji Date: Mon, 16 Mar 2020 15:13:28 +0100 Subject: [PATCH 12/12] test: update test and ci-cd --- .appveyor.yml | 7 +++++++ .travis.yml | 13 +++++++++++++ test/hooks.js | 14 ++++++++++++++ test/messages.test.js | 18 ++++++++++++++++++ 4 files changed, 52 insertions(+) create mode 100644 test/hooks.js create mode 100644 test/messages.test.js diff --git a/.appveyor.yml b/.appveyor.yml index af7d72f..0566118 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -6,3 +6,10 @@ install: test_script: - yarn test build: off +before_test: + - SET PGUSER=postgres + - SET PGPASSWORD=Password12! + - PATH=C:\Program Files\PostgreSQL\10\bin\;%PATH% + - createdb testdb +services: + - postgresql101 diff --git a/.travis.yml b/.travis.yml index 769ec13..2551927 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ install: yarn after_success: yarn coverage before_script: + - psql -c 'create database testdb;' -U postgres - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter - chmod +x ./cc-test-reporter - ./cc-test-reporter before-build @@ -19,3 +20,15 @@ script: - yarn test after_script: - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT + +services: + - postgresql +addons: + postgresql: "10" + apt: + packages: + - postgresql-10 + - postgresql-client-10 +before_install: + - sudo cp /etc/postgresql/{9.6,10}/main/pg_hba.conf + - sudo /etc/init.d/postgresql restart diff --git a/test/hooks.js b/test/hooks.js new file mode 100644 index 0000000..d28c0f8 --- /dev/null +++ b/test/hooks.js @@ -0,0 +1,14 @@ +import { + dropTables, + createTables, + insertIntoTables, +} from '../src/utils/queryFunctions'; + +before(async () => { + await createTables(); + await insertIntoTables(); +}); + +after(async () => { + await dropTables(); +}); diff --git a/test/messages.test.js b/test/messages.test.js new file mode 100644 index 0000000..5afca48 --- /dev/null +++ b/test/messages.test.js @@ -0,0 +1,18 @@ +import { expect, server, BASE_URL } from './setup'; + +describe('Messages', () => { + it('get messages page', done => { + server + .get(`${BASE_URL}/messages`) + .expect(200) + .end((err, res) => { + expect(res.status).to.equal(200); + expect(res.body.messages).to.be.instanceOf(Array); + res.body.messages.forEach(m => { + expect(m).to.have.property('name'); + expect(m).to.have.property('message'); + }); + done(); + }); + }); +});