Skip to content

Commit

Permalink
feat: added nested and/or criteria, inq, neq, like operators
Browse files Browse the repository at this point in the history
  • Loading branch information
dkrantsberg committed Jul 10, 2020
1 parent e43aa48 commit 97aa5d7
Show file tree
Hide file tree
Showing 5 changed files with 959 additions and 44 deletions.
28 changes: 25 additions & 3 deletions lib/buildWhere.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,35 @@ function buildWhere(modelName, where) {
const model = self._models[modelName];
const filter = {};
const keys = Object.keys(where);
if (keys.length === 1 && model.properties.hasOwnProperty(keys[0])) {
// Simple condition with only 1 property
if (keys.length === 1 && model.properties.hasOwnProperty(keys[0]) && !_.isObject(where[keys[0]])) {
// Simple WHERE filter with single property-value match. Example: where = {property: value}
filter.type = 'terms';
const palantirField = self.getPalantirPropertyName(modelName, keys[0]);
filter.terms = {terms: [where[keys[0]]], field: `${palantirField}.raw`};
} else if (keys.length === 1 && model.properties.hasOwnProperty(keys[0]) && _.isObject(where[keys[0]])) {
// WHERE filter with and expression. Example: where = {property: {neq: value}}
const palantirField = self.getPalantirPropertyName(modelName, keys[0]);
const expression = where[keys[0]];
const operator = Object.keys(expression)[0];
const subExpression = expression[operator];
switch (operator) {
case 'neq':
filter.type = 'not';
filter.not = {type: 'terms', terms: {terms: [subExpression], field: `${palantirField}.raw`}};
break;
case 'inq':
filter.type = 'terms';
filter.terms = {terms: subExpression, field: `${palantirField}.raw`};
break;
case 'like':
filter.type = 'wildcard';
filter.wildcard = {field: `${palantirField}.raw`, value: subExpression};
break;
default:
throw new Error(`'${operator}' operator is not supported.`);
}
} else if (keys.length === 1 && (keys[0] === 'and' || keys[0] === 'or')) {
// a logical condition with collection AND or OR
// WHERE filter with AND or OR operators. Example: where = {or: [{property1: value1}, {property2: value2}]}
const logicalOperator = keys[0];
filter.type = logicalOperator;
const innerFilters = _.map(where[logicalOperator], lbCondition => buildWhere.call(self, modelName, lbCondition));
Expand Down
2 changes: 1 addition & 1 deletion lib/palantir.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ function PalantirConnector(settings, dataSource) {
debug('Settings %j', settings);
}
this.dataSource = dataSource;
this._models = this._models || this.dataSource.modelBuilder.definitions;
this._models = this.dataSource.modelBuilder.definitions;
axios.defaults.baseURL = settings.serviceUrl;
axios.defaults.timeout = settings.timeout || 2000;
axios.defaults.headers['Authorization'] = `Bearer ${settings.apiToken}`;
Expand Down
146 changes: 146 additions & 0 deletions test/buildWhere.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
'use strict';
const {expect} = require('chai');
const {PalantirConnector} = require('../lib/palantir');

describe('buildWhere', () => {
let palantirConnector;
let buildWhere;

before(() => {
const ds = global.getDataSource();
const Project = ds.define('Project',
{
id: {type: String, id: true, palantir: {primaryKey: true, propertyName: 'project_uid'}},
title: {type: String, palantir: {unique: true, propertyName: 'project'}},
objectTypeId: {type: String},
team: {type: String},
projectId: {type: Number, palantir: {propertyName: 'project_id'}}
},
{
palantir: {
objectTypeId: process.env.PALANTIR_OBJECT_TYPE
}
});
const settings = {
objectType: 'TestType'
};
palantirConnector = new PalantirConnector(settings, Project);
palantirConnector._models = Project.modelBuilder.definitions;
buildWhere = (where) => palantirConnector.buildWhere('Project', where);
});

it('should build query for simple key-value WHERE filter', () => {
const query = buildWhere({team: 'Bioprinting'});
expect(query).to.eql({
type: 'terms',
terms: {
terms: [
'Bioprinting'
],
field: 'team.raw'
}
});
});

it('should build query for WHERE filter containing "and"', () => {
const query = buildWhere({
and: [
{team: 'Bioprinting'},
{title: 'Test Title 1'}
]
});
expect(query).to.eql({
type: 'and',
and: [
{
type: 'terms',
terms: {
terms: ['Bioprinting'],
field: 'team.raw'
}
},
{
type: 'terms',
terms: {
terms: ['Test Title 1'],
field: 'project.raw'
}
}
]
});
});

it('should build query for WHERE filter containing nested "and" and "or"', () => {
const query = buildWhere({
and: [
{team: 'Bioprinting'},
{or: [{title: 'Test Title 1'}, {title: 'Test Title 2'}]}
]
});
expect(query).to.eql({
type: 'and',
and: [{
type: 'terms',
terms: {
terms: ['Bioprinting'],
field: 'team.raw'
}
}, {
type: 'or',
or: [{
type: 'terms',
terms: {
terms: ['Test Title 1'],
field: 'project.raw'
}
}, {
type: 'terms',
terms: {
terms: ['Test Title 2'],
field: 'project.raw'
}
}]
}]
});
});

it('should build query for WHERE filter with "inq" operator', () => {
const query = buildWhere({title: {inq: ['Project 1', 'Project 2']}});
expect(query).to.eql({
type: 'terms',
terms: {
terms: [
'Project 1',
'Project 2'
],
field: 'project.raw'
}
});
});

it('should build query for WHERE filter with "neq" operator', () => {
const query = buildWhere({title: {neq: 'Project1'}});
expect(query).to.eql({
type: 'not',
not: {
type: 'terms',
terms: {
terms: ['Project1'],
field: 'project.raw'
}
}
});
});

it('should build query for WHERE filter with "like" operator', () => {
const query = buildWhere({title: {like: 'Project*'}});
expect(query).to.eql({
type: 'wildcard',
wildcard: {
field: 'project.raw',
value: 'Project*'
}
});
});
});

Loading

0 comments on commit 97aa5d7

Please sign in to comment.