Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge v4-beta/next to release/v4-beta #148

Merged
merged 34 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
037ab5a
feat: containedIn function implementation
harshithad0703 Feb 29, 2024
847a015
test: :white_check_mark: test case for conatinedIn function
harshithad0703 Feb 29, 2024
57040d5
Merge pull request #146 from contentstack/feat/cs-43910-containedIn-q…
harshithad0703 Mar 1, 2024
461f60f
feat: notContainedIn implementation
harshithad0703 Mar 1, 2024
88cf053
test: unit and api test case for not contained in
harshithad0703 Mar 1, 2024
9189d1b
changed the it statements in test cases
harshithad0703 Mar 1, 2024
1ae922c
updated docs and function name
harshithad0703 Mar 1, 2024
43487ff
updated docs and implementation
harshithad0703 Mar 1, 2024
5f9ad5e
chore: updated changeLog
harshithad0703 Mar 1, 2024
03ebd86
chore: :package: updated package files
harshithad0703 Mar 1, 2024
66534c4
Merge pull request #147 from contentstack/feat/cs-43911-notContainedI…
harshithad0703 Mar 1, 2024
e5ed42a
feat: notExists query operator implementation
harshithad0703 Mar 5, 2024
1524972
test: unit and api tests for notExists operator
harshithad0703 Mar 5, 2024
6530641
test: updated unit test assertion
harshithad0703 Mar 5, 2024
a3d6640
removed console log
harshithad0703 Mar 5, 2024
980b809
Merge pull request #151 from contentstack/feat/cs-43912-query-operato…
harshithad0703 Mar 5, 2024
ca901b7
fix: added tag latest to npm publish
abhinav-from-contentstack Mar 7, 2024
6346656
Merge branch 'v4-beta/next' of github.com:contentstack/contentstack-j…
abhinav-from-contentstack Mar 7, 2024
03231d2
refactor: :recycle: changes in query operators implementation
harshithad0703 Mar 7, 2024
0d4e502
docs: updated documentation for query operators
harshithad0703 Mar 7, 2024
75f4070
test: updated unit test cases
harshithad0703 Mar 7, 2024
6c14c97
feat: or operator implementation in query
harshithad0703 Mar 11, 2024
f3a0065
test: :white_check_mark: added unit and api tests for or operator
harshithad0703 Mar 11, 2024
667346a
docs: updated docs for or operator
harshithad0703 Mar 11, 2024
cfe3241
Merge pull request #156 from contentstack/feat/cs-43915-or-operator-q…
harshithad0703 Mar 11, 2024
4862591
feat: and query operator implementation
harshithad0703 Mar 12, 2024
432d11f
test: unit and api test cases for and operator query
harshithad0703 Mar 12, 2024
82987b9
Merge pull request #157 from contentstack/feat/cs-43916-and-operator-…
harshithad0703 Mar 12, 2024
4c26f05
feat: equalTo query operator implementation
harshithad0703 Mar 13, 2024
0df87b0
test: added unit and api test cases for equalTo operator
harshithad0703 Mar 13, 2024
c178ac4
docs: :memo: docs update for equalTo
harshithad0703 Mar 13, 2024
19d4261
feat: cs-43918-referenceIn operator implementation
harshithad0703 Mar 13, 2024
ddbb7eb
update changeLog and test->it
harshithad0703 Mar 13, 2024
fc55499
Merge pull request #158 from contentstack/feat/cs-43917-equalTo-query…
harshithad0703 Mar 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/npm-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
node-version: '18.x'
registry-url: 'https://registry.npmjs.org'
- run: npm ci
- run: npm publish --tag beta --access public
- run: npm publish --tag latest --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
publish-git:
Expand Down
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
## Change log

### Version: 4.0.0-beta.4
#### Date: March-14-2024
##### New Features:
- Query operators implementation

### Version: 4.0.0-beta.3
#### Date: February-13-2024
- Live preview support 1.0 and 2.0

### Version: v4.0.0-beta.2
#### Date: February-02-2024
- Includes adding of prepare script to build package

### Version: 4.0.0-beta
#### Date: January-15-2024
- Beta release of Typescript SDK
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@contentstack/delivery-sdk",
"version": "4.0.0-beta.3",
"version": "4.0.0-beta.4",
"type": "commonjs",
"main": "./dist/cjs/src/index.js",
"types": "./dist/types/src/index.d.ts",
Expand Down
135 changes: 135 additions & 0 deletions src/lib/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,139 @@ export class Query extends BaseQuery {
getQuery(): { [key: string]: any } {
return this._parameters;
}

/**
* @method containedIn
* @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 = await query.containedIn('fieldUid', ['value1', 'value2']).find()
*
* @returns {Query}
*/
containedIn(key: string, value: (string | number | boolean)[]): Query {
this._parameters[key] = { '$in': value };
return this;
}

/**
* @method NoContainedIn
* @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 = await query.notContainedIn('fieldUid', ['value1', 'value2']).find()
*
* @returns {Query}
*/
notContainedIn(key: string, value: (string | number | boolean)[]): Query {
this._parameters[key] = { '$nin': value };
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 = await query.notExists('fieldUid').find()
*
* @returns {Query}
*/
notExists(key: string): Query {
this._parameters[key] = { '$exists': false };
return this;
}

/**
* @method or
* @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 = stack.contentType('contenttype_uid').Entry().query().containedIn('fieldUID', ['value']);
* const query2 = stack.contentType('contenttype_uid').Entry().query().where('fieldUID', QueryOperation.EQUALS, 'value2');
* const query = await stack.contentType('contenttype_uid').Entry().query().or(query1, query2).find();
*
* @returns {Query}
*/
or(...queries: Query[]): Query {
const paramsList: BaseQueryParameters[] = [];
for (const queryItem of queries) {
paramsList.push(queryItem._parameters);
}
this._parameters.$or = paramsList;
return this;
}

/**
* @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 = stack.contentType('contenttype_uid').Entry().query().containedIn('fieldUID', ['value']);
* const query2 = stack.contentType('contenttype_uid').Entry().query().where('fieldUID', QueryOperation.EQUALS, 'value2');
* const query = await stack.contentType('contenttype_uid').Entry().query().and(query1, query2).find();
*
* @returns {Query}
*/
and(...queries: Query[]): Query {
const paramsList: BaseQueryParameters[] = [];
for (const queryItem of queries) {
paramsList.push(queryItem._parameters);
}
this._parameters.$and = paramsList;
return this;
}

/**
* @method equalTo
* @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 = await stack.contentType('contenttype_uid').Entry().query().equalTo('fieldUid', 'value').find();
*
* @returns {Query}
*/
equalTo(key: string, value: string | number | boolean): Query {
this._parameters[key] = value;
return this;
}

/**
* @method equalTo
* @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('contenttype_uid').query().where('title', QueryOperation.EQUALS, 'value');
* const entryQuery = await stack.contentType('contenttype_uid').query().referenceIn('reference_uid', query).find<TEntry>();
*
* @returns {Query}
*/
referenceIn(key: string, query: Query) {
this._parameters[key] = { '$in_query': query._parameters }
return this;
}
}
2 changes: 1 addition & 1 deletion test/api/contenttype.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/* eslint-disable no-console */
/* eslint-disable promise/always-return */
import { BaseContentType, BaseEntry } from 'src';
import { ContentType } from '../../src/lib/content-type';
import { stackInstance } from '../utils/stack-instance';
import { TContentType, TEntry } from './types';
Expand All @@ -26,6 +25,7 @@ describe('ContentType API test cases', () => {
expect(result.schema).toBeDefined();
});
});

function makeContentType(uid = ''): ContentType {
const contentType = stack.ContentType(uid);

Expand Down
124 changes: 124 additions & 0 deletions test/api/entry-queryables.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { stackInstance } from '../utils/stack-instance';
import { Entries } from '../../src/lib/entries';
import { TEntry } from './types';
import { QueryOperation } from '../../src/lib/types';
import { Query } from '../../src/lib/query';

const stack = stackInstance();

describe('Query Operators API test cases', () => {
it('should get entries which matches the fieldUid and values', async () => {
const query = await makeEntries('contenttype_uid').query().containedIn('title', ['value']).find<TEntry>()
if (query.entries) {
expect(query.entries[0]._version).toBeDefined();
expect(query.entries[0].title).toBeDefined();
expect(query.entries[0].uid).toBeDefined();
expect(query.entries[0].created_at).toBeDefined();
}
});

it('should get entries which does not match the fieldUid and values', async () => {
const query = await makeEntries('contenttype_uid').query().notContainedIn('title', ['test', 'test2']).find<TEntry>()
if (query.entries) {
expect(query.entries[0]._version).toBeDefined();
expect(query.entries[0].title).toBeDefined();
expect(query.entries[0].uid).toBeDefined();
expect(query.entries[0].created_at).toBeDefined();
}
});

it('should get entries which does not match the fieldUid - notExists', async () => {
const query = await makeEntries('contenttype_uid').query().notExists('multi_line').find<TEntry>()
if (query.entries) {
expect(query.entries[0]._version).toBeDefined();
expect(query.entries[0].title).toBeDefined();
expect(query.entries[0].uid).toBeDefined();
expect(query.entries[0].created_at).toBeDefined();
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<TEntry>();

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');
expect(query.entries[1]._version).toBeDefined();
expect(query.entries[1].locale).toBeDefined();
expect(query.entries[1].uid).toBeDefined();
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<TEntry>();

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<TEntry>();

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<TEntry>();

if (query.entries) {
expect(query.entries).toHaveLength(0);

}
});

it('should return entry equal to the condition - equalTo', async () => {
const query = await makeEntries('contenttype_uid').query().equalTo('title', 'value').find<TEntry>();

if (query.entries) {
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 entry for referencedIn query', async () => {
const query = makeEntries('contenttype_uid').query().where('title', QueryOperation.EQUALS, 'value');
const entryQuery = await makeEntries('contenttype_uid').query().referenceIn('reference_uid', query).find<TEntry>();
if (entryQuery.entries) {
expect(entryQuery.entries[0]._version).toBeDefined();
expect(entryQuery.entries[0].locale).toBeDefined();
expect(entryQuery.entries[0].uid).toBeDefined();
expect(entryQuery.entries[0].title).toBe('test');
}
});
});

function makeEntries(contentTypeUid = ''): Entries {
const entries = stack.ContentType(contentTypeUid).Entry();
return entries;
}
1 change: 1 addition & 0 deletions test/unit/contenttype.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Entry } from '../../src/lib/entry';
import { contentTypeResponseMock } from '../utils/mocks';
import { Entries } from '../../src/lib/entries';
import { MOCK_CLIENT_OPTIONS } from '../utils/constant';
import { Query } from 'src/lib/query';

describe('ContentType class', () => {
let contentType: ContentType;
Expand Down
57 changes: 57 additions & 0 deletions test/unit/entry-queryable.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { AxiosInstance, httpClient } from '@contentstack/core';
import { ContentType } from '../../src/lib/content-type';
import MockAdapter from 'axios-mock-adapter';
import { MOCK_CLIENT_OPTIONS } from '../utils/constant';
import { Query } from '../../src/lib/query';
import { QueryOperation } from '../../src/lib/types';


describe('Query Operators API test cases', () => {
let contentType: ContentType;
let client: AxiosInstance;
let mockClient: MockAdapter;

beforeAll(() => {
client = httpClient(MOCK_CLIENT_OPTIONS);
mockClient = new MockAdapter(client as any);
});

beforeEach(() => {
contentType = new ContentType(client, 'contentTypeUid');
});
it('should get entries which matches the fieldUid and values', () => {
const query = contentType.Entry().query().containedIn('fieldUID', ['value']);
expect(query._parameters).toStrictEqual({'fieldUID': {'$in': ['value']}});
});
it('should get entries which does not match the fieldUid and values', () => {
const query = contentType.Entry().query().notContainedIn('fieldUID', ['value', 'value2']);
expect(query._parameters).toStrictEqual({'fieldUID': {'$nin': ['value', 'value2']}});
});
it('should get entries which does not match the fieldUid - notExists', () => {
const query = contentType.Entry().query().notExists('fieldUID');
expect(query._parameters).toStrictEqual({'fieldUID': {'$exists': false}});
});
it('should return entries matching any of the conditions - or', 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().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' } ] });
});
it('should return entry equal to the condition - equalTo', async () => {
const query = contentType.Entry().query().equalTo('fieldUID', 'value');
expect(query._parameters).toStrictEqual({ 'fieldUID': 'value' });
});
it('should return entry for referencedIn query', async () => {
const query1 = contentType.Entry().query().containedIn('fieldUID', ['value']);
const entryQuery = await contentType.Entry().query().referenceIn('reference_uid', query1);
if (entryQuery) {
expect(entryQuery._parameters).toEqual({ reference_uid: { '$in_query': { fieldUID: { '$in': [ 'value' ] } } } });
}
});
});