diff --git a/docs/api/databases/querying.md b/docs/api/databases/querying.md index 86250887c2..89ba863277 100644 --- a/docs/api/databases/querying.md +++ b/docs/api/databases/querying.md @@ -121,6 +121,23 @@ app.service('messages').find({ GET /messages?$or[0][archived][$ne]=true&$or[1][roomId]=2 ``` +### $and + +Find all records that match all of the given criteria. + +```js +// Find all messages that are not marked as archived and in room 2 +app.service('messages').find({ + query: { + $all: [{ archived: { $ne: true } }, { roomId: 2 }] + } +}) +``` + +``` +GET /messages?$and[0][archived][$ne]=true&$and[1][roomId]=2 +``` + ## Operators Operators either query a property for a specific value or determine nested special properties (starting with a `$`) that allow querying the property for certain conditions. When multiple operators are set, all conditions have to apply for a property to match. diff --git a/packages/adapter-commons/src/query.ts b/packages/adapter-commons/src/query.ts index 0d2daa88c6..b13edc258d 100644 --- a/packages/adapter-commons/src/query.ts +++ b/packages/adapter-commons/src/query.ts @@ -113,6 +113,13 @@ export const FILTERS: FilterSettings = { } return or + }, + $and: (and: any, { operators }: FilterQueryOptions) => { + if (Array.isArray(and)) { + return and.map((current) => validateQueryProperty(current, operators)) + } + + return and } } diff --git a/packages/adapter-tests/src/declarations.ts b/packages/adapter-tests/src/declarations.ts index 4c3f5b43e5..3268d46fed 100644 --- a/packages/adapter-tests/src/declarations.ts +++ b/packages/adapter-tests/src/declarations.ts @@ -82,6 +82,8 @@ export type AdapterSyntaxTestName = | '.find + $ne' | '.find + $gt + $lt + $sort' | '.find + $or nested + $sort' + | '.find + $and' + | '.find + $and + $or' | 'params.adapter + paginate' | 'params.adapter + multi' | '.find + paginate' diff --git a/packages/adapter-tests/src/syntax.ts b/packages/adapter-tests/src/syntax.ts index 3dd73821e9..dc0a8db6c3 100644 --- a/packages/adapter-tests/src/syntax.ts +++ b/packages/adapter-tests/src/syntax.ts @@ -274,6 +274,34 @@ export default (test: AdapterSyntaxTest, app: any, _errors: any, serviceName: st assert.strictEqual(data[1].name, 'Doug') }) + test('.find + $and', async () => { + const params = { + query: { + $and: [{ age: 19 }], + $sort: { name: 1 } + } + } + + const data = await service.find(params) + + assert.strictEqual(data.length, 1) + assert.strictEqual(data[0].name, 'Alice') + }) + + test('.find + $and + $or', async () => { + const params = { + query: { + $and: [{ $or: [{ name: 'Alice' }] }], + $sort: { name: 1 } + } + } + + const data = await service.find(params) + + assert.strictEqual(data.length, 1) + assert.strictEqual(data[0].name, 'Alice') + }) + describe('params.adapter', () => { test('params.adapter + paginate', async () => { const page = await service.find({ diff --git a/packages/knex/test/index.test.ts b/packages/knex/test/index.test.ts index 4161561218..28cbbc0a92 100644 --- a/packages/knex/test/index.test.ts +++ b/packages/knex/test/index.test.ts @@ -65,6 +65,7 @@ const testSuite = adapterTests([ '.find + $skip', '.find + $select', '.find + $or', + '.find + $and', '.find + $in', '.find + $nin', '.find + $lt', @@ -74,6 +75,7 @@ const testSuite = adapterTests([ '.find + $ne', '.find + $gt + $lt + $sort', '.find + $or nested + $sort', + '.find + $and + $or', 'params.adapter + paginate', 'params.adapter + multi', '.find + paginate', diff --git a/packages/mongodb/test/index.test.ts b/packages/mongodb/test/index.test.ts index 2b9e30d2ab..6b30394536 100644 --- a/packages/mongodb/test/index.test.ts +++ b/packages/mongodb/test/index.test.ts @@ -64,6 +64,7 @@ const testSuite = adapterTests([ '.find + $skip', '.find + $select', '.find + $or', + '.find + $and', '.find + $in', '.find + $nin', '.find + $lt', @@ -73,6 +74,7 @@ const testSuite = adapterTests([ '.find + $ne', '.find + $gt + $lt + $sort', '.find + $or nested + $sort', + '.find + $and + $or', '.find + paginate', '.find + paginate + $limit + $skip', '.find + paginate + $limit 0',