From eb40822142ed7d2a515894935e1381593ef43e88 Mon Sep 17 00:00:00 2001 From: Andrzej Stepien Date: Thu, 7 Sep 2023 11:39:09 +0200 Subject: [PATCH] create Title object and children --- objects/Data.mjs | 2 +- objects/Entity.mjs | 25 +++++++++++++++++++++++++ objects/Publication.mjs | 12 ++++++++++++ objects/Story.mjs | 10 ++++++++++ objects/Title.mjs | 16 ++++++++++++++++ objects/dv.mjs | 23 +++++++++++++++++++++++ package-lock.json | 13 +++++++++++++ package.json | 2 ++ test/Entity.test.mjs | 27 +++++++++++++++++++++++++++ test/Publication.test.mjs | 19 +++++++++++++++++++ test/Story.test.mjs | 17 +++++++++++++++++ test/Title.test.mjs | 37 +++++++++++++++++++++++++++++++++++++ 12 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 objects/Publication.mjs create mode 100644 objects/Story.mjs create mode 100644 objects/Title.mjs create mode 100644 objects/dv.mjs create mode 100644 test/Entity.test.mjs create mode 100644 test/Publication.test.mjs create mode 100644 test/Story.test.mjs create mode 100644 test/Title.test.mjs diff --git a/objects/Data.mjs b/objects/Data.mjs index 128a706..991bca1 100644 --- a/objects/Data.mjs +++ b/objects/Data.mjs @@ -17,7 +17,7 @@ export class Data { } async getStories() { return this.#db('stories') - .select('*') + .select('id','title','word_count') } async getPublications() { return this.#db('pubs') diff --git a/objects/Entity.mjs b/objects/Entity.mjs index 139597f..c06ab25 100644 --- a/objects/Entity.mjs +++ b/objects/Entity.mjs @@ -1,2 +1,27 @@ +import dv from "./dv.mjs" +export default class Entity{ + constructor(data){ + if(data?.id){ + if(!Number.isInteger(data.id)){throw new TypeError("id must be an integer!")} + this.id = data.id + } + } + + async insert(db){ + return db(this.table) + .insert(this) + } + async update(db){ + return db(this.table) + .where('id',this.id) + .update(this) + } + async del(db){ + if(!this?.id){throw new Error("cannot delete without an id!")} + return db(this.table) + .where('id',this.id) + this.del() + } +} diff --git a/objects/Publication.mjs b/objects/Publication.mjs new file mode 100644 index 0000000..8c1113a --- /dev/null +++ b/objects/Publication.mjs @@ -0,0 +1,12 @@ +import Title from "./Title.mjs"; +import dv from "./dv.mjs"; +export default class Publication extends Title{ + constructor(data){ + super(data) + if(data?.link){ + if(!dv.isString(data.link)){throw new TypeError("link must be a string")} + this.link=data.link + } + + } +} \ No newline at end of file diff --git a/objects/Story.mjs b/objects/Story.mjs new file mode 100644 index 0000000..b83befe --- /dev/null +++ b/objects/Story.mjs @@ -0,0 +1,10 @@ +import Title from "./Title.mjs" +export default class Story extends Title{ + constructor(data){ + super(data) + if(data?.word_count){ + if(!Number.isInteger(data.word_count)){throw new TypeError("word_count must be integer!")} + this.word_count=data.word_count + } + } +} \ No newline at end of file diff --git a/objects/Title.mjs b/objects/Title.mjs new file mode 100644 index 0000000..8c36fde --- /dev/null +++ b/objects/Title.mjs @@ -0,0 +1,16 @@ +import Entity from "./Entity.mjs"; +import dv from "./dv.mjs"; +//THIS CLASS WILL HANDLE JUNCTION TABLE STUFF +export default class Title extends Entity{ + constructor(data){ + super(data) + if(data?.title){ + if(!dv.isString(data.title)){throw new TypeError("title must be a string")} + this.title=data.title + } + if(data?.genres){ + if(!dv.isObject(data.genres)){throw new TypeError("genres must be an object")} + this.genres=data.genres + } + } +} \ No newline at end of file diff --git a/objects/dv.mjs b/objects/dv.mjs new file mode 100644 index 0000000..22c1791 --- /dev/null +++ b/objects/dv.mjs @@ -0,0 +1,23 @@ +import { DateTime } from "luxon" + +export default { + isNumber (n){ + if(isNaN(n)){return false} + if (typeof n === "number") { return true } + return false + }, + isString (s){ + if (typeof s === 'string') { return true } + return false + }, + dateStringIsValid(str){ + if(str===null){return true} + if(DateTime.fromFormat(str,'yyyy-MM-dd').isValid){ + return true + } + return false + }, + isObject(objValue) { + return objValue && typeof objValue === 'object' && objValue.constructor === Object; + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index e21a587..07a781e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,10 +11,12 @@ "dependencies": { "body-parser": "^1.20.2", "chai": "^4.3.8", + "chai-as-promised": "^7.1.1", "chai-http": "^4.4.0", "cors": "^2.8.5", "express": "^4.18.2", "knex": "^2.5.1", + "lodash": "^4.17.21", "luxon": "^3.4.3", "mocha": "^10.2.0", "pino": "^8.15.0", @@ -476,6 +478,17 @@ "node": ">=4" } }, + "node_modules/chai-as-promised": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", + "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", + "dependencies": { + "check-error": "^1.0.2" + }, + "peerDependencies": { + "chai": ">= 2.1.2 < 5" + } + }, "node_modules/chai-http": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/chai-http/-/chai-http-4.4.0.tgz", diff --git a/package.json b/package.json index 291ad72..7a4009c 100644 --- a/package.json +++ b/package.json @@ -11,10 +11,12 @@ "dependencies": { "body-parser": "^1.20.2", "chai": "^4.3.8", + "chai-as-promised": "^7.1.1", "chai-http": "^4.4.0", "cors": "^2.8.5", "express": "^4.18.2", "knex": "^2.5.1", + "lodash": "^4.17.21", "luxon": "^3.4.3", "mocha": "^10.2.0", "pino": "^8.15.0", diff --git a/test/Entity.test.mjs b/test/Entity.test.mjs new file mode 100644 index 0000000..f130479 --- /dev/null +++ b/test/Entity.test.mjs @@ -0,0 +1,27 @@ +import { describe } from "mocha"; +import Entity from "../objects/Entity.mjs"; +import chaiAsPromised from "chai-as-promised"; +import chai from "chai"; +import { expect} from "chai"; +import { testDb as db } from "../db.mjs"; +chai.use(chaiAsPromised) + +describe("tetsing Entity object",async function(){ + it("should throw with code:400 if passed an invalid data.id",async function(){ + expect(()=>{new Entity({id:"string"})}).to.throw(TypeError) + expect(()=>{new Entity({id:1.1})}).to.throw(TypeError) + expect(()=>{new Entity({id:{}})}).to.throw(TypeError) + expect(()=>{new Entity({id:[]})}).to.throw(TypeError) + }) + it("should not throw if given a valid id",function(){ + expect(()=>{new Entity({id:1})}).not.to.throw() + }) + it(".delete() should throw if initialised without .id",function(){ + const entity = new Entity() + return expect(entity.del(db)).to.eventually.be.rejectedWith(Error) + }) + it(".delete() should throw if not passed a db",function(){ + const entity = new Entity({id:1}) + return expect(entity.del()).to.eventually.be.rejectedWith(Error) + }) +}) \ No newline at end of file diff --git a/test/Publication.test.mjs b/test/Publication.test.mjs new file mode 100644 index 0000000..ec27b0b --- /dev/null +++ b/test/Publication.test.mjs @@ -0,0 +1,19 @@ +import { describe } from "mocha"; +import chaiAsPromised from "chai-as-promised"; +import chai from "chai"; +import { expect} from "chai"; +import { testDb as db } from "../db.mjs"; +import Publication from "../objects/Publication.mjs"; +chai.use(chaiAsPromised) +describe("testing Publication object",function(){ + it("should throw TypeError if passed invalid .link data",function(){ + expect(()=>{new Publication({link:1})}).to.throw(TypeError) + expect(()=>{new Publication({link:[]})}).to.throw(TypeError) + expect(()=>{new Publication({link:{}})}).to.throw(TypeError) + }) + it("should have a .link if initialised with valid data, and .link should be a string",function(){ + const pub = new Publication({link:'string'}) + expect(pub).to.contain.key('link') + expect(pub.link).to.be.a('string') + }) +}) \ No newline at end of file diff --git a/test/Story.test.mjs b/test/Story.test.mjs new file mode 100644 index 0000000..93bc3b1 --- /dev/null +++ b/test/Story.test.mjs @@ -0,0 +1,17 @@ +import { describe } from "mocha"; +import chaiAsPromised from "chai-as-promised"; +import chai from "chai"; +import { expect} from "chai"; +import { testDb as db } from "../db.mjs"; +import Story from "../objects/Story.mjs"; +chai.use(chaiAsPromised) +describe("testing Story object",function(){ + it("should throw TypeError if .word_count is not an integer",function(){ + expect(()=>{new Story({word_count:1.1})}).to.throw(TypeError) + }) + it("should have .word_count if created with valid data, and .word_count should be an integer",function(){ + const story = new Story({word_count:100}) + expect(story).to.contain.key('word_count') + expect(story.word_count).to.satisfy(Number.isInteger) + }) +}) \ No newline at end of file diff --git a/test/Title.test.mjs b/test/Title.test.mjs new file mode 100644 index 0000000..e6551d2 --- /dev/null +++ b/test/Title.test.mjs @@ -0,0 +1,37 @@ +import { describe } from "mocha"; +import Title from "../objects/Title.mjs"; +import chaiAsPromised from "chai-as-promised"; +import chai from "chai"; +import { expect} from "chai"; +import { testDb as db } from "../db.mjs"; +import _ from "lodash"; +chai.use(chaiAsPromised) + +describe("testing Title object",function(){ + it("should throw if passed an invalid title",function(){ + expect(()=>{new Title({title:1})}).to.throw() + expect(()=>{new Title({title:{}})}).to.throw() + expect(()=>{new Title({title:[]})}).to.throw() + }) + it("should have .title if it has been passed a valid one, and it should be a string",function(){ + const title = new Title({title:'Title'}) + expect(title).to.contain.key('title') + expect(title.title).to.be.a('string') + }) + it("should throw a TypeError if passed invalid .genres data",function(){ + expect(()=>{new Title({genres:1})}).to.throw(TypeError) + expect(()=>{new Title({genres:"string"})}).to.throw(TypeError) + expect(()=>{new Title({genres:[]})}).to.throw(TypeError) + }) + it("should have .genres if intitialised with valid data, and .genres should be an object",function(){ + const story = new Title({genres:{fantasy:true,horror:false}}) + expect(story).to.contain.key('genres') + expect(story.genres).to.be.a('object') + }) + it("every value in correctly initialised .genres should be a boolean",function(){ + const story = new Title({genres:{fantasy:true,horror:false}}) + expect(story?.genres&& + Object.keys(story.genres).length>0&& + _.every(story.genres,genre=>{return typeof genre === 'boolean'})).to.equal(true) + }) +}) \ No newline at end of file