Skip to content

Commit

Permalink
Merge pull request #148 from contentstack/v4-beta/next
Browse files Browse the repository at this point in the history
merge v4-beta/next to release/v4-beta
  • Loading branch information
harshithad0703 authored Mar 15, 2024
2 parents 9d08893 + fc55499 commit 4fd162e
Show file tree
Hide file tree
Showing 9 changed files with 335 additions and 5 deletions.
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' ] } } } });
}
});
});

0 comments on commit 4fd162e

Please sign in to comment.