From 48625916594c4668918f6a05f8b733587f4f04f8 Mon Sep 17 00:00:00 2001 From: harshithad0703 Date: Tue, 12 Mar 2024 11:35:21 +0530 Subject: [PATCH 1/2] feat: and query operator implementation --- src/lib/query.ts | 54 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/src/lib/query.ts b/src/lib/query.ts index ba9a1cfd..3415ab73 100644 --- a/src/lib/query.ts +++ b/src/lib/query.ts @@ -201,6 +201,24 @@ export class Query extends BaseQuery { return this; } + /** + * @method notExists + * @memberof Query + * @description Returns the raw (JSON) query based on the filters applied on Query object. + * @example + * import contentstack from '@contentstack/delivery-sdk' + * + * const stack = contentstack.Stack({ apiKey: "apiKey", deliveryToken: "deliveryToken", environment: "environment" }); + * const query = stack.contentType("contentTypeUid").entry().query(); + * const result = notExists('fieldUid').find() + * + * @returns {Query} + */ + notExists(key: string): Query { + this._parameters[key] = { '$exists': false }; + return this; + } + /** * @method or * @memberof Query @@ -215,19 +233,35 @@ export class Query extends BaseQuery { * * @returns {Query} */ - notExists(key: string): Query { - this._parameters[key] = { '$exists': false }; + or(...queries: Query[]): Query { + const paramsList: BaseQueryParameters[] = []; + for (const queryItem of queries) { + paramsList.push(queryItem._parameters); + } + this._parameters.$or = paramsList; return this; } - or(...queries: Query[]): Query { - const combinedQuery: any = { $or: [] }; - for (const query of queries) { - combinedQuery.$or.push(query._parameters); + /** + * @method and + * @memberof Query + * @description Returns the raw (JSON) query based on the filters applied on Query object. + * @example + * import contentstack from '@contentstack/delivery-sdk' + * + * const stack = contentstack.Stack({ apiKey: "apiKey", deliveryToken: "deliveryToken", environment: "environment" }); + * const query1 = await contentType.Entry().query().containedIn('fieldUID', ['value']); + * const query2 = await contentType.Entry().query().where('fieldUID', QueryOperation.EQUALS, 'value2'); + * const query = await contentType.Entry().query().and(query1, query2).find(); + * + * @returns {Query} + */ + and(...queries: Query[]): Query { + const paramsList: BaseQueryParameters[] = []; + for (const queryItem of queries) { + paramsList.push(queryItem._parameters); } - const newQuery: Query = Object.create(this); - newQuery._parameters = combinedQuery; - - return newQuery; + this._parameters.$and = paramsList; + return this; } } From 432d11fbd77d6c650708c50977d5509b571f916d Mon Sep 17 00:00:00 2001 From: harshithad0703 Date: Tue, 12 Mar 2024 11:39:08 +0530 Subject: [PATCH 2/2] test: unit and api test cases for and operator query --- test/api/entry-queryables.spec.ts | 42 ++++++++++++++++++++++++++++++- test/unit/entry-queryable.spec.ts | 8 +++++- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/test/api/entry-queryables.spec.ts b/test/api/entry-queryables.spec.ts index d05d9919..f5657243 100644 --- a/test/api/entry-queryables.spec.ts +++ b/test/api/entry-queryables.spec.ts @@ -37,13 +37,14 @@ describe('Query Operators API test cases', () => { expect((query.entries[0] as any).multi_line).not.toBeDefined() } }); + it('should return entries matching any of the conditions - or', async () => { const query1: Query = await makeEntries('contenttype_uid').query().containedIn('title', ['value']); const query2: Query = await makeEntries('contenttype_uid').query().where('title', QueryOperation.EQUALS, 'value2'); const query = await makeEntries('contenttype_uid').query().or(query1, query2).find(); if (query.entries) { - expect(query.entries).toHaveLength(2); + expect(query.entries.length).toBeGreaterThan(0); expect(query.entries[0]._version).toBeDefined(); expect(query.entries[0].locale).toBeDefined(); expect(query.entries[0].uid).toBeDefined(); @@ -54,6 +55,45 @@ describe('Query Operators API test cases', () => { expect(query.entries[1].title).toBe('value'); } }); + + it('should return entries when at least 1 entry condition is matching - or', async () => { + const query1: Query = await makeEntries('contenttype_uid').query().containedIn('title', ['value0']); + const query2: Query = await makeEntries('contenttype_uid').query().where('title', QueryOperation.EQUALS, 'value2'); + const query = await makeEntries('contenttype_uid').query().or(query1, query2).find(); + + if (query.entries) { + expect(query.entries.length).toBeGreaterThan(0); + expect(query.entries[0]._version).toBeDefined(); + expect(query.entries[0].locale).toBeDefined(); + expect(query.entries[0].uid).toBeDefined(); + expect(query.entries[0].title).toBe('value2'); + } + }); + + it('should return entry both conditions are matching - and', async () => { + const query1: Query = await makeEntries('contenttype_uid').query().containedIn('title', ['value']); + const query2: Query = await makeEntries('contenttype_uid').query().where('locale', QueryOperation.EQUALS, 'en-us'); + const query = await makeEntries('contenttype_uid').query().and(query1, query2).find(); + + if (query.entries) { + expect(query.entries.length).toBeGreaterThan(0); + expect(query.entries[0]._version).toBeDefined(); + expect(query.entries[0].locale).toBeDefined(); + expect(query.entries[0].uid).toBeDefined(); + expect(query.entries[0].title).toBe('value'); + } + }); + + it('should return null when any one condition is not matching - and', async () => { + const query1: Query = await makeEntries('contenttype_uid').query().containedIn('title', ['value0']); + const query2: Query = await makeEntries('contenttype_uid').query().where('locale', QueryOperation.EQUALS, 'fr-fr'); + const query = await makeEntries('contenttype_uid').query().and(query1, query2).find(); + + if (query.entries) { + expect(query.entries).toHaveLength(0); + + } + }); }); function makeEntries(contentTypeUid = ''): Entries { diff --git a/test/unit/entry-queryable.spec.ts b/test/unit/entry-queryable.spec.ts index e3c12acd..06763e25 100644 --- a/test/unit/entry-queryable.spec.ts +++ b/test/unit/entry-queryable.spec.ts @@ -36,5 +36,11 @@ describe('Query Operators API test cases', () => { const query2: Query = await contentType.Entry().query().where('fieldUID', QueryOperation.EQUALS, 'value2'); const query = await contentType.Entry().query().or(query1, query2); expect(query._parameters).toStrictEqual({ '$or': [ {'fieldUID': {'$in': ['value']}}, { 'fieldUID': 'value2' } ] }); - }); + }); + it('should return entry when both conditions are matching - and', async () => { + const query1: Query = await contentType.Entry().query().containedIn('fieldUID', ['value']); + const query2: Query = await contentType.Entry().query().where('fieldUID', QueryOperation.EQUALS, 'value2'); + const query = await contentType.Entry().query().and(query1, query2); + expect(query._parameters).toStrictEqual({ '$and': [ {'fieldUID': {'$in': ['value']}}, { 'fieldUID': 'value2' } ] }); + }); }); \ No newline at end of file