q3-schema-utils
Advanced tools
Comparing version 1.18.5 to 1.19.0
@@ -6,2 +6,11 @@ # Change Log | ||
# [1.19.0](https://github.com/3merge/q3-api/compare/v1.18.5...v1.19.0) (2021-08-16) | ||
**Note:** Version bump only for package q3-schema-utils | ||
## [1.18.5](https://github.com/3merge/q3-api/compare/v1.18.4...v1.18.5) (2021-07-27) | ||
@@ -8,0 +17,0 @@ |
{ | ||
"name": "q3-schema-utils", | ||
"version": "1.18.5", | ||
"version": "1.19.0", | ||
"main": "index.js", | ||
@@ -10,6 +10,6 @@ "dependencies": { | ||
"mongoose": "^5.11.8", | ||
"q3-core-responder": "^1.18.5" | ||
"q3-core-responder": "^1.19.0" | ||
}, | ||
"devDependencies": { | ||
"q3-test-utils": "^1.18.5" | ||
"q3-test-utils": "^1.19.0" | ||
}, | ||
@@ -24,3 +24,3 @@ "jest": { | ||
}, | ||
"gitHead": "21bf04f31308ceffc2078e4954b10d58b07b7cc9" | ||
"gitHead": "8915133b3a5b239dd2e61a4e0bb094bc5a68831d" | ||
} |
@@ -40,19 +40,2 @@ const mongoose = require('mongoose'); | ||
const countDogsAfterPush = async (doc, expected) => { | ||
const { dogs } = await doc.pushSubDocument('dogs', { | ||
breed: 'Terrier', | ||
}); | ||
return expect(dogs).toHaveLength(expected); | ||
}; | ||
const countDogsAfterDeletion = async ( | ||
doc, | ||
id, | ||
expected, | ||
) => { | ||
const { dogs } = await doc.removeSubDocument('dogs', id); | ||
return expect(dogs).toHaveLength(expected); | ||
}; | ||
beforeAll(async () => { | ||
@@ -82,16 +65,2 @@ mongoose.plugin(plugin); | ||
describe('findStrictly', () => { | ||
it('should throw', () => | ||
expect( | ||
Model.findStrictly(mongoose.Types.ObjectId()), | ||
).rejects.toThrowError()); | ||
it('should return single result with virtuals', async () => { | ||
const { _id: id } = await Model.create(stub); | ||
return expect( | ||
Model.findStrictly(id), | ||
).resolves.toHaveProperty('id'); | ||
}); | ||
}); | ||
describe('archive', () => { | ||
@@ -112,120 +81,2 @@ it('should set document active property to false', async () => { | ||
describe('getSubDocument', () => { | ||
it('should throw an error', async () => { | ||
const resp = await Model.create(stub); | ||
return expect(() => | ||
resp.getSubDocument( | ||
'dogs', | ||
mongoose.Types.ObjectId(), | ||
), | ||
).toThrowError(); | ||
}); | ||
it('should return the sub document', async () => { | ||
const resp = await Model.create(stub); | ||
const { | ||
dogs: [{ _id: id }], | ||
} = resp; | ||
return expect( | ||
resp.getSubDocument('dogs', id), | ||
).toHaveProperty('breed', stub.dogs[0].breed); | ||
}); | ||
}); | ||
describe('pushSubDocument', () => { | ||
it('should add a new sub document', async () => { | ||
const resp = await Model.create(stub); | ||
return countDogsAfterPush(resp, 4); | ||
}); | ||
it('should insert first sub document', async () => { | ||
const resp = await Model.create({ name: 'Test' }); | ||
return countDogsAfterPush(resp, 1); | ||
}); | ||
it('should catch error before validating the parent', async () => { | ||
const resp = await Model.create({ name: 'Test' }); | ||
return expect( | ||
resp.pushSubDocument('dogs', { | ||
breed: { | ||
type: 'Corgi', | ||
}, | ||
}), | ||
).rejects.toMatchObject({ | ||
errors: expect.objectContaining({ | ||
breed: expect.any(Object), | ||
}), | ||
}); | ||
}); | ||
}); | ||
describe('removeSubDocument', () => { | ||
it('should remove single subdocument', async () => { | ||
const resp = await Model.create(stub); | ||
const { | ||
dogs: [{ _id: id }], | ||
} = resp; | ||
return countDogsAfterDeletion(resp, id, 2); | ||
}); | ||
it('should remove all subdocument', async () => { | ||
const resp = await Model.create(stub); | ||
return countDogsAfterDeletion( | ||
resp, | ||
getIds(resp.dogs), | ||
0, | ||
); | ||
}); | ||
}); | ||
describe('updateSubDocument', () => { | ||
it('should update a single document', async () => { | ||
const resp = await Model.create(stub); | ||
const { | ||
dogs: [{ _id: id }], | ||
} = resp; | ||
const breed = 'Boston'; | ||
const { dogs } = await resp.updateSubDocument( | ||
'dogs', | ||
id, | ||
{ breed }, | ||
); | ||
return expect(dogs[0].breed).toBe(breed); | ||
}); | ||
it('should catch validation errors early', async () => { | ||
const resp = await Model.create(stub); | ||
const { | ||
dogs: [{ _id: id }], | ||
} = resp; | ||
const breed = { type: 'Boston' }; | ||
return expect( | ||
resp.updateSubDocument('dogs', id, { breed }), | ||
).rejects.toMatchObject({ | ||
errors: expect.objectContaining({ | ||
breed: expect.any(Object), | ||
}), | ||
}); | ||
}); | ||
}); | ||
describe('updateSubDocuments', () => { | ||
it('should update a single document', async () => { | ||
const resp = await Model.create(stub); | ||
const { | ||
dogs: [{ _id: id1 }, { _id: id2 }], | ||
} = resp; | ||
const breed = 'Boston'; | ||
const { dogs } = await resp.updateSubDocuments( | ||
'dogs', | ||
[id1, id2], | ||
{ breed }, | ||
); | ||
expect(dogs[0].breed).toBe(breed); | ||
expect(dogs[1].breed).toBe(breed); | ||
expect(dogs[2].breed).not.toBe(breed); | ||
}); | ||
}); | ||
describe('findOrCreate', () => { | ||
@@ -232,0 +83,0 @@ it('should create then return duplicate document', async () => { |
/* eslint-disable func-names, no-param-reassign */ | ||
const { invoke, get } = require('lodash'); | ||
const { exception } = require('q3-core-responder'); | ||
const { executeOn } = require('..'); | ||
const removeEmpty = (obj) => { | ||
Object.keys(obj).forEach((key) => { | ||
if (obj[key] && typeof obj[key] === 'object') | ||
removeEmpty(obj[key]); | ||
else if (obj[key] === undefined) delete obj[key]; | ||
}); | ||
return obj; | ||
}; | ||
const getPathsRecursively = ([key, v]) => { | ||
@@ -59,92 +48,2 @@ if (v.schema) | ||
async function findStrictly(id, options = {}) { | ||
const doc = await this.findOne({ | ||
_id: id, | ||
active: true, | ||
}) | ||
.setOptions({ | ||
redact: true, | ||
...options, | ||
}) | ||
.exec(); | ||
if (!doc) | ||
exception('ResourceNotFound').msg('missing').throw(); | ||
return doc; | ||
} | ||
function getSubDocument(field, id) { | ||
const subdoc = invoke(get(this, field), 'id', id); | ||
if (!subdoc) | ||
exception('ResourceNotFound') | ||
.msg('subdocumentNotFound') | ||
.throw(); | ||
return subdoc; | ||
} | ||
async function pushSubDocument(field, args) { | ||
let preValidationResult; | ||
if (Array.isArray(this[field])) { | ||
this[field].push(args); | ||
} else { | ||
this[field] = [args]; | ||
} | ||
try { | ||
preValidationResult = | ||
this[field][this[field].length - 1].validateSync(); | ||
} catch (e) { | ||
// noop | ||
} | ||
if (preValidationResult) throw preValidationResult; | ||
return this.save({ | ||
redact: true, | ||
}); | ||
} | ||
async function removeSubDocument(field, id) { | ||
const removeChild = async (v) => { | ||
const subdoc = this.getSubDocument(field, v); | ||
return new Promise((res, rej) => | ||
subdoc.remove((err, product) => { | ||
if (err) rej(err); | ||
else res(product); | ||
}), | ||
); | ||
}; | ||
await executeOn(id, removeChild); | ||
return this.save({ | ||
redact: true, | ||
op: 'Delete', | ||
}); | ||
} | ||
async function updateSubDocuments(field, ids, args) { | ||
ids.map((id) => { | ||
const d = invoke(get(this, field), 'id', id); | ||
return d ? d.set(args) : null; | ||
}); | ||
return this.save(); | ||
} | ||
async function updateSubDocument(field, id, args) { | ||
const subdoc = await this.getSubDocument(field, id); | ||
subdoc.set(removeEmpty(args)); | ||
const e = subdoc.validateSync(); | ||
if (e) throw e; | ||
return this.save({ | ||
redact: true, | ||
op: 'Update', | ||
}); | ||
} | ||
function getAllFields() { | ||
@@ -198,8 +97,2 @@ return Object.entries(this.schema.paths) | ||
const plugin = (schema) => { | ||
schema.statics.findStrictly = findStrictly; | ||
schema.methods.getSubDocument = getSubDocument; | ||
schema.methods.pushSubDocument = pushSubDocument; | ||
schema.methods.removeSubDocument = removeSubDocument; | ||
schema.methods.updateSubDocument = updateSubDocument; | ||
schema.methods.updateSubDocuments = updateSubDocuments; | ||
schema.statics.getAllFields = getAllFields; | ||
@@ -206,0 +99,0 @@ schema.statics.getReferentialPaths = getReferentialPaths; |
43635
535
Updatedq3-core-responder@^1.19.0