data service and endpoints

This commit is contained in:
Andrzej Stepien 2023-09-06 18:26:15 +02:00
commit 0c0465623c
13 changed files with 3372 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules

17
db.mjs Normal file
View File

@ -0,0 +1,17 @@
import knex from "knex";
export const db = knex({
client: 'sqlite3',
connection: {
filename: "./submissions"
},
useNullAsDefault: true
})
export const testDb = knex({
client: 'sqlite3',
connection: {
filename: "./test.db"
},
useNullAsDefault: true
})

28
logger.mjs Normal file
View File

@ -0,0 +1,28 @@
import pino from 'pino'
import path from 'path'
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// const transport = pino.transport({
// targets: [{
// level: 'trace',
// target: 'pino-pretty' // must be installed separately
// }, {
// level: 'trace',
// target: 'pino/file',
// options: { destination: `${__dirname}/app.log` }
// }]
// })
export default pino(
{
level: 'error',
formatters: {
level: (label) => {
return { level: label.toUpperCase() };
},
},
timestamp: pino.stdTimeFunctions.isoTime,
},
//pino.destination(`${__dirname}/app.log`)
);

36
objects/Data.mjs Normal file
View File

@ -0,0 +1,36 @@
export class Data {
#db
constructor(db) {
this.#db = db
}
async init() {
this.stories = await this.getStories()
this.publications = await this.getPublications()
this.submissions = await this.getSubmissions()
}
async getStories() {
return this.#db('stories')
.select('*')
}
async getPublications() {
return this.#db('pubs')
.select('*')
}
async getSubmissions() {
return this.#db('subs')
.join('stories', 'subs.story_id', 'stories.id')
.join('pubs', 'subs.pub_id', 'pubs.id')
.join('responses', 'subs.response_id', 'responses.id')
.select('subs.id',
'subs.story_id',
'stories.title as story',
'subs.pub_id',
'pubs.title as publication',
'subs.date_submitted',
'subs.date_responded',
'subs.response_id',
'responses.response'
)
}
}

31
objects/Endpoints.mjs Normal file
View File

@ -0,0 +1,31 @@
import express from "express";
import { Data } from "./Data.mjs";
export const getEndpoints = (data) => {
const router = express.Router()
router.get('/stories', (req,res)=>{
res.send(data.stories)
})
router.get('/publications', (req,res)=>{
res.statusCode=200
res.send(data.publications)
})
router.get('/submissions', (req,res)=>{
res.statusCode=200
res.send(data.submissions)
})
return router
}

2
objects/Entity.mjs Normal file
View File

@ -0,0 +1,2 @@

3130
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

20
package.json Normal file
View File

@ -0,0 +1,20 @@
{
"name": "sub-manager-backend",
"version": "1.0.0",
"description": "backend of a writing submissions manager",
"main": "index.mjs",
"scripts": {
"test": "mocha"
},
"author": "Andrzej Stepien",
"license": "GPL-3.0-or-later",
"dependencies": {
"chai": "^4.3.8",
"chai-http": "^4.4.0",
"express": "^4.18.2",
"knex": "^2.5.1",
"mocha": "^10.2.0",
"pino": "^8.15.0",
"sqlite3": "^5.1.6"
}
}

27
server.mjs Normal file
View File

@ -0,0 +1,27 @@
import express from "express";
const app = express()
const port = 4000
app.use(
pinoHTTP({
logger,
}),
cors({
origin: ['http://localhost:5173']
}),
bodyParser.json()
)
const data = new Data(db)
await data.init()
app.use('/api',getEndpoints(data))
app.listen(port, (err) => {
if (err) logger.error(err);
logger.info("Server listening on PORT " + port)
})
export default app

BIN
submissions Normal file

Binary file not shown.

BIN
test.db Normal file

Binary file not shown.

41
test/Data.test.mjs Normal file
View File

@ -0,0 +1,41 @@
import { describe } from "mocha";
import { expect} from "chai";
import { testDb as db } from "../db.mjs";
import { Data } from "../objects/Data.mjs";
describe("Testing Data object...",function(){
it("once initiated, it should serve arrays at .stories, .publications, and .submissions",async function(){
const data = new Data(db)
await data.init()
expect(data.stories).to.be.a('array')
expect(data.submissions).to.be.a('array')
expect(data.publications).to.be.a('array')
} )
it("every entry in .stories, .publications, and .submissions should be an object", async function(){
const data = new Data(db)
await data.init()
for (const row of data.stories) {
expect(row).to.be.a('object')
}
for (const row of data.submissions) {
expect(row).to.be.a('object')
}
for (const row of data.publications) {
expect(row).to.be.a('object')
}
})
it("every entry in .stories, .publications, and .submissions should contain an .id field", async function(){
const data = new Data(db)
await data.init()
for (const row of data.stories) {
expect(row).to.contain.key('id')
}
for (const row of data.submissions) {
expect(row).to.contain.key('id')
}
for (const row of data.publications) {
expect(row).to.contain.key('id')
}
})
})

39
test/endpoints.test.mjs Normal file
View File

@ -0,0 +1,39 @@
import {describe} from "mocha";
import chai, { expect } from "chai";
import express from 'express'
import chaiHttp from "chai-http";
import { testDb as db } from "../db.mjs";
import { Data } from "../objects/Data.mjs";
import { getEndpoints } from "../objects/Endpoints.mjs";
chai.use(chaiHttp)
const app = express()
const data = new Data(db)
await data.init()
app.use('/api',getEndpoints(data))
describe("Testing GET endpoints", async function(){
describe("GET stories",async function(){
it("should return a status code of 200 and an array", async function(){
const res = await chai.request(app).get('/api/stories')
expect(res).to.have.status(200)
expect(res.body).to.be.a('array')
})
})
describe("GET submissions",async function(){
it("should return a status code of 200 and an array", async function(){
const res = await chai.request(app).get('/api/submissions')
expect(res).to.have.status(200)
expect(res.body).to.be.a('array')
})
})
describe("GET publications",async function(){
it("should return a status code of 200 and an array", async function(){
const res = await chai.request(app).get('/api/publications')
expect(res).to.have.status(200)
expect(res.body).to.be.a('array')
})
})
})