diff --git a/README.md b/README.md index a435ef0..2acd756 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,7 @@ Note that all this eager related options are optional. [`allowGraph`](https://vincit.github.io/objection.js/api/query-builder/eager-methods.html#allowgraph) documentation. -- **`eagerOptions`** - Options object to use with `$eager` and `$joinEager` query operators. +- **`eagerOptions`** - options object to use with `$eager` and `$joinEager` query operators. See [`GraphOptions`](https://vincit.github.io/objection.js/api/types/#type-graphoptions) documentation. @@ -157,6 +157,9 @@ Note that all this eager related options are optional. #### Query Operators +- **`$modify`** - modifiers allow you to easily reuse snippets of query logic. See + [`modify`](https://vincit.github.io/objection.js/api/query-builder/other-methods.html#modify) documentation. + - **`$eager`** - eager load relations defined in models' `relationMappings` getter methods. See [`withGraphFetched`](https://vincit.github.io/objection.js/api/query-builder/eager-methods.html#withgraphfetched) documentation. diff --git a/package-lock.json b/package-lock.json index 7af8eb9..0bd2b12 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "feathers-objection", - "version": "5.1.1", + "version": "5.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 4f69937..c972ba2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "feathers-objection", "description": "A service plugin for ObjectionJS an ORM based on KnexJS", - "version": "5.1.1", + "version": "5.2.0", "homepage": "https://github.com/feathersjs-ecosystem/feathers-objection", "keywords": [ "feathers", diff --git a/src/index.js b/src/index.js index 3973738..be24723 100644 --- a/src/index.js +++ b/src/index.js @@ -162,6 +162,7 @@ class Service extends AdapterService { if (params.$modifyEager) { delete params.$modifyEager; } if (params.$mergeEager) { delete params.$mergeEager; } if (params.$noSelect) { delete params.$noSelect; } + if (params.$modify) { delete params.$modify; } Object.keys(params || {}).forEach(key => { let value = params[key]; @@ -303,6 +304,12 @@ class Service extends AdapterService { delete query.$mergeEager; } + if (query && query.$modify) { + q.modify(...query.$modify); + + delete query.$modify; + } + // apply eager filters if specified if (this.eagerFilters) { const eagerFilters = Array.isArray(this.eagerFilters) ? this.eagerFilters : [this.eagerFilters]; diff --git a/test/company.js b/test/company.js index c9e5233..bab48f9 100644 --- a/test/company.js +++ b/test/company.js @@ -12,6 +12,7 @@ export default class Company extends Model { id: { type: 'integer' }, name: { type: 'string' }, ceo: { type: ['integer', 'null'] }, + size: { type: ['string', 'null'], enum: ['small', 'medium', 'large', null] }, jsonObject: { type: ['object', 'null'], properties: { @@ -32,6 +33,24 @@ export default class Company extends Model { } } + static modifiers = { + google: (builder, hasCeo) => { + builder.where('name', 'Google'); + + if (hasCeo) { builder.whereNot('ceo', null); } + }, + apple: (builder, hasCeo) => { + builder.where('name', 'Apple'); + + if (hasCeo) { builder.whereNot('ceo', null); } + }, + large: (builder, hasCeo) => { + builder.where('size', 'large'); + + if (hasCeo) { builder.whereNot('ceo', null); } + } + } + // This object defines the relations to other models. static relationMappings = { ceos: { diff --git a/test/index.test.js b/test/index.test.js index 5fb2f34..743ada9 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -134,7 +134,7 @@ const app = feathers() model: Company, id: 'id', multi: ['create', 'remove', 'patch'], - whitelist: ['$eager', '$joinRelation', '$modifyEager', '$mergeEager', '$between', '$notBetween', '$containsKey', '$contains', '$contained', '$any', '$all', '$noSelect', '$like', '$null'], + whitelist: ['$eager', '$joinRelation', '$modifyEager', '$mergeEager', '$between', '$notBetween', '$containsKey', '$contains', '$contained', '$any', '$all', '$noSelect', '$like', '$null', '$modify'], allowedEager: '[ceos, clients, employees]', eagerFilters: [ { @@ -233,6 +233,7 @@ function clean (done) { table.increments('id'); table.string('name'); table.integer('ceo'); + table.enum('size', ['small', 'medium', 'large']); table.json('jsonObject'); table.json('jsonArray'); table.jsonb('jsonbObject'); @@ -1661,4 +1662,52 @@ describe('Feathers Objection Service', () => { }); }); }); + + describe('$modify', () => { + before(async () => { + await companies + .create([ + { + name: 'Google', + ceo: 1 + }, + { + name: 'Apple', + ceo: null, + size: 'large' + } + ]); + }); + + after(async () => { + await companies.remove(null); + }); + + it('allow $modify query', () => { + return companies.find({ query: { $modify: ['google'] } }).then(data => { + expect(data.length).to.be.equal(1); + expect(data[0].name).to.be.equal('Google'); + }); + }); + + it('allow $modify query with args', () => { + return companies.find({ query: { $modify: ['large', false] } }).then(data => { + expect(data.length).to.be.equal(1); + expect(data[0].name).to.be.equal('Apple'); + }); + }); + + it('allow $modify query with multiple modifiers', () => { + return companies.find({ query: { $modify: [['apple', 'large']] } }).then(data => { + expect(data.length).to.be.equal(1); + expect(data[0].name).to.be.equal('Apple'); + }); + }); + + it('allow $modify query with multiple modifiers and args', () => { + return companies.find({ query: { $modify: [['apple', 'large'], true] } }).then(data => { + expect(data.length).to.be.equal(0); + }); + }); + }); });