Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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/build-test-facade.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ jobs:
uses: ./.github/workflows/base-test-job.yaml
with:
package: facade
system: true
system: false
shutdown: facade-srv
7,540 changes: 4,674 additions & 2,866 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/chassis-srv/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"nice-grpc": "^2.1.13",
"nice-grpc-server-reflection": "^3.0.2",
"protobufjs": "^7.4.0",
"redis": "^4.7.0",
"redis": "4.7.0",
"remeda": "^2.31.1"
},
"devDependencies": {
Expand Down
293 changes: 106 additions & 187 deletions packages/chassis-srv/src/database/provider/arango/base.ts

Large diffs are not rendered by default.

83 changes: 34 additions & 49 deletions packages/chassis-srv/src/database/provider/arango/common.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
clone, isArray, isString, isDate, isBoolean, isNumber, keys, isNullish, forEach, isEmptyish, startsWith,
clone, isArray, isString, isDate, isBoolean, isNumber, keys, isNullish, isEmptyish, startsWith,
forEachObj,
mapKeys,
join
Expand All @@ -14,18 +14,16 @@ import Long from 'long';
* @param {Object} args list of arguments, optional
* @return {Promise} arangojs query result
*/
export const query = async (db: any, collectionName: string, query: string | any,
args?: object): Promise<any> => {
export const query = async (
db: any,
collectionName: string,
query: string | any,
args?: object
): Promise<any> => {
const collection = db.collection(collectionName);
const collectionExists = await collection.exists();
try {
if (!collectionExists) {
await collection.create();
}
} catch(err: any) {
if (err.message && err.message.indexOf('duplicate name') == -1) {
throw err;
}
if (!collectionExists) {
await collection.create();
}
return await db.query(query, args);
};
Expand Down Expand Up @@ -95,7 +93,10 @@ export const autoCastKey = (key: any, value?: any): any => {
if (isDate(value)) { // Date
return `DATE_TIMESTAMP(node.${key})`;
}
return 'node.' + key;
else if (key === 'id') {
return `node._key`;
}
return `node.${key}`;
};

/**
Expand All @@ -104,12 +105,12 @@ export const autoCastKey = (key: any, value?: any): any => {
* @param {object} value - raw value
* @returns {any} interpreted value
*/
export const autoCastValue = (value: any): any => {
export const autoCastValue = (key: string, value: any): any => {
if (isArray(value)) {
return value.map(value => value.toString());
return value.map((value: any) => key === 'id' ? idToKey(value) : value?.toString());
}
if (isString(value)) { // String
return value;
return key === 'id' ? idToKey(value) : value?.toString();
}
if (isBoolean(value)) { // Boolean
return Boolean(value);
Expand All @@ -118,7 +119,7 @@ export const autoCastValue = (value: any): any => {
return Number(value);
}
if (Long.isLong(value)) {
return (value as Long).toNumber();
return (value as Long)?.toNumber();
}
if (isDate(value)) { // Date
return new Date(value);
Expand Down Expand Up @@ -171,39 +172,39 @@ export const buildField = (key: any, value: any, index: number, bindVarsMap: any
const bindValueVar = `@value${index}`;
const bindValueVarWithOutPrefix = `value${index}`;
if (isString(value) || isBoolean(value) || isNumber(value || isDate(value))) {
bindVarsMap[bindValueVarWithOutPrefix] = autoCastValue(value);
bindVarsMap[bindValueVarWithOutPrefix] = autoCastValue(key, value);
return autoCastKey(key, value) + ' == ' + bindValueVar;
}
if (!isNullish(value.$eq)) {
bindVarsMap[bindValueVarWithOutPrefix] = autoCastValue(value.$eq);
bindVarsMap[bindValueVarWithOutPrefix] = autoCastValue(key, value.$eq);
return autoCastKey(key, value) + ' == ' + bindValueVar;
}
if (value.$gt) {
bindVarsMap[bindValueVarWithOutPrefix] = autoCastValue(value.$gt);
bindVarsMap[bindValueVarWithOutPrefix] = autoCastValue(key, value.$gt);
return autoCastKey(key, value) + ' > ' + bindValueVar;
}
if (value.$gte) {
bindVarsMap[bindValueVarWithOutPrefix] = autoCastValue(value.$gte);
bindVarsMap[bindValueVarWithOutPrefix] = autoCastValue(key, value.$gte);
return autoCastKey(key, value) + ' >= ' + bindValueVar;
}
if (value.$lt) {
bindVarsMap[bindValueVarWithOutPrefix] = autoCastValue(value.$lt);
bindVarsMap[bindValueVarWithOutPrefix] = autoCastValue(key, value.$lt);
return autoCastKey(key, value) + ' < ' + bindValueVar;
}
if (value.$lte) {
bindVarsMap[bindValueVarWithOutPrefix] = autoCastValue(value.$lte);
bindVarsMap[bindValueVarWithOutPrefix] = autoCastValue(key, value.$lte);
return autoCastKey(key, value) + ' <= ' + bindValueVar;
}
if (!isNullish(value.$ne)) {
bindVarsMap[bindValueVarWithOutPrefix] = autoCastValue(value.$ne);
bindVarsMap[bindValueVarWithOutPrefix] = autoCastValue(key, value.$ne);
return autoCastKey(key, value) + ' != ' + bindValueVar;
}
if (value.$inVal) {
bindVarsMap[bindValueVarWithOutPrefix] = autoCastValue(value.$inVal);
bindVarsMap[bindValueVarWithOutPrefix] = autoCastValue(key, value.$inVal);
return bindValueVar + ' IN ' + autoCastKey(key, value);
}
if (value.$in) {
bindVarsMap[bindValueVarWithOutPrefix] = autoCastValue(value.$in);
bindVarsMap[bindValueVarWithOutPrefix] = autoCastValue(key, value.$in);
if (isString(value.$in)) {
// if it is a field which should be an array
// (useful for querying within a document list-like attributen
Expand All @@ -213,11 +214,11 @@ export const buildField = (key: any, value: any, index: number, bindVarsMap: any
return autoCastKey(key, value) + ' IN ' + bindValueVar;
}
if (value.$nin) {
bindVarsMap[bindValueVarWithOutPrefix] = autoCastValue(value.$nin);
bindVarsMap[bindValueVarWithOutPrefix] = autoCastValue(key, value.$nin);
return autoCastKey(key, value) + ' NOT IN ' + bindValueVar;
}
if (value.$iLike) {
bindVarsMap[bindValueVarWithOutPrefix] = autoCastValue(value.$iLike);
bindVarsMap[bindValueVarWithOutPrefix] = autoCastValue(key, value.$iLike);
// @param 'true' is for case insensitive
return ' LIKE (' + autoCastKey(key, value) + ',' + bindValueVar + ', true)';
}
Expand All @@ -226,15 +227,15 @@ export const buildField = (key: any, value: any, index: number, bindVarsMap: any
return `!(${temp})`;
}
if ('$isEmpty' in value) {
bindVarsMap[bindValueVarWithOutPrefix] = autoCastValue('');
bindVarsMap[bindValueVarWithOutPrefix] = autoCastValue(key, '');
// will always search for an empty string
return autoCastKey(key, '') + ' == ' + bindValueVar;
}
if (!isNullish((value as any).$startswith)) {
const bindValueVar1 = `@value${index + 1}`;
const bindValueVarWithOutPrefix1 = `value${index + 1}`;
const k = autoCastKey(key);
const v = autoCastValue((value as any).$startswith);
const v = autoCastValue(key, (value as any).$startswith);
bindVarsMap[bindValueVarWithOutPrefix] = v;
bindVarsMap[bindValueVarWithOutPrefix1] = v;
return `LEFT(${k}, LENGTH(${bindValueVar})) == ${bindValueVar1}`;
Expand All @@ -243,7 +244,7 @@ export const buildField = (key: any, value: any, index: number, bindVarsMap: any
const bindValueVar1 = `@value${index + 1}`;
const bindValueVarWithOutPrefix1 = `value${index + 1}`;
const k = autoCastKey(key);
const v = autoCastValue((value as any).$endswith);
const v = autoCastValue(key, (value as any).$endswith);
bindVarsMap[bindValueVarWithOutPrefix] = v;
bindVarsMap[bindValueVarWithOutPrefix1] = v;
return `RIGHT(${k}, LENGTH(${bindValueVar})) == ${bindValueVar1}`;
Expand Down Expand Up @@ -350,28 +351,12 @@ export const buildSorter = (options: any, index?: number, bindVarsMap?: any): an
return '';
}

if (!index) {
index = 0;
}
if (!bindVarsMap) {
bindVarsMap = {};
}

const sort = mapKeys(options.sort, (key, value) => {
return autoCastKey(key);
});
let sortKeysOrder = '';
let i = 1;
const objLength = Object.keys(sort).length;
for (const key in sort) {
if (objLength == i) {
// Do not append ',' for the last element
sortKeysOrder = `${sortKeysOrder} ${key} ${sort[key]} `;
} else {
sortKeysOrder = `${sortKeysOrder} ${key} ${sort[key]},`;
}
i += 1;
}
const sortKeysOrder = Object.entries(sort).map(
([key, value]) => `${key} ${value}`
).join(' ');
return 'SORT ' + sortKeysOrder;
};

Expand Down
13 changes: 13 additions & 0 deletions packages/chassis-srv/src/database/provider/arango/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,16 @@ export interface ViewMap {
similarityThreshold: number;
analyzerOptions: AnalyzerOptions[];
}

export interface CustomQuery {
code: string; // AQL code
// filter - combinable with the generic `find` query
// query - standalone
type: 'filter' | 'query';
}

export interface ArangoDocument {
_key?: string;
id?: string;
[key: string]: any;
}
37 changes: 23 additions & 14 deletions packages/chassis-srv/src/database/provider/arango/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {
clone,
isArray,
find,
isEmptyish,
isDate,
Expand All @@ -9,7 +8,7 @@ import {
isNumber,
isNullish,
keys,
forEach, forEachObj,
forEachObj,
startsWith,
mapKeys,
isDeepEqual, intersection
Expand All @@ -20,6 +19,7 @@ import {
Options_Direction,
Options_Direction as Direction,
} from '@restorecommerce/rc-grpc-clients/dist/generated-server/io/restorecommerce/graph.js';
import { Logger } from '@restorecommerce/logger';

const filterOperationMap = new Map([
[0, 'eq'],
Expand Down Expand Up @@ -74,21 +74,21 @@ const convertFilterToObject = (filter: any, obj: any, operatorList: any) => {
}

for (let i = 0; i < operatorList.length; i++) {
if (isArray(temp)) {
if (Array.isArray(temp)) {
temp = find(temp, operatorList[i]);
} else {
temp = temp[operatorList[i]];
}
if (i === (operatorList.length - 1)) {
// push for final element in the operatorList array
if (filter.operation === 'eq' || filter.operation === 0) {
if (isArray(temp)) {
if (Array.isArray(temp)) {
temp.push({ [filter.field]: value });
} else {
(temp[operatorList[i]] as any).push({ [filter.field]: value });
}
} else if (filter.operation === 'neq' || filter.operation === 8) {
if (isArray(temp)) {
if (Array.isArray(temp)) {
temp.push({ [filter.field]: { $not: { $eq: value } } });
} else {
(temp[operatorList[i]] as any).push({ [filter.field]: { $not: { $eq: value } } });
Expand All @@ -101,7 +101,7 @@ const convertFilterToObject = (filter: any, obj: any, operatorList: any) => {
opValue = filterOperationMap.get(filter.operation);
}
const op = `$${opValue}`;
if (isArray(temp)) {
if (Array.isArray(temp)) {
temp.push({ [filter.field]: { [op]: value } });
} else {
(temp[operatorList[i]] as any).push({ [filter.field]: { [op]: value } });
Expand All @@ -121,7 +121,7 @@ const convertFilterToObject = (filter: any, obj: any, operatorList: any) => {
const insertNewOpAndUpdateObj = (obj: any, operatorList: any, operatorNew: any) => {
let pos = clone(obj);
for (let i = 0; i < operatorList.length; i++) {
if (isArray(pos)) {
if (Array.isArray(pos)) {
pos = find(pos, operatorList[i]);
} else {
pos = pos[operatorList[i]];
Expand Down Expand Up @@ -154,13 +154,13 @@ export const toTraversalFilterObject = (input: any, obj?: any, operatorList?: st
filters.operator = input.operator;
}
// by default use 'and' operator if no operator is specified
if (filters && isArray(filters.filters) && !filters.operator) {
if (filters && Array.isArray(filters.filters) && !filters.operator) {
filters.operator = 'and';
}
if (!obj) {
obj = {};
}
if (isArray(filters.filters) && filters.filters.length > 0) {
if (Array.isArray(filters.filters) && filters.filters.length > 0) {
let operatorValue;
if (typeof filters.operator === 'string' || filters.operator instanceof String) {
operatorValue = filters.operator;
Expand All @@ -178,7 +178,7 @@ export const toTraversalFilterObject = (input: any, obj?: any, operatorList?: st
}
// pass operatorList and obj recursively
obj = toTraversalFilterObject(filters.filters, obj, operatorList);
} else if (isArray(filters)) {
} else if (Array.isArray(filters)) {
if (!operatorList) {
const operator = input.operator ? `$${input.operator}` : '$and';
operatorList = [operator];
Expand Down Expand Up @@ -226,7 +226,7 @@ export const autoCastKey = (key: any, value?: any): any => {
* @returns {any} interpreted value
*/
export const autoCastValue = (value: any): any => {
if (isArray(value)) {
if (Array.isArray(value)) {
return value.map(value => value.toString());
}
if (isString(value)) { // String
Expand Down Expand Up @@ -256,7 +256,7 @@ export const autoCastValue = (value: any): any => {
*/
export const buildComparison = (filter: any, op: string, root?: boolean): any => {
const ele = filter.map((e: any) => {
if (!isArray(e)) {
if (!Array.isArray(e)) {
e = [e];
}
e = buildGraphFilter(e, root);
Expand Down Expand Up @@ -498,7 +498,7 @@ export const createGraphsAssociationFilter = (filters: GraphFilters[],
let rootEntityFilter;
// convert the filter from proto structure (field, operation, value and operand) to {field: value } mapping
if (filters && !isEmptyish(filters)) {
if (!isArray(filters)) {
if (!Array.isArray(filters)) {
filters = [filters];
}
for (const eachFilter of filters) {
Expand Down Expand Up @@ -526,7 +526,7 @@ export const createGraphsAssociationFilter = (filters: GraphFilters[],
}
}

if (!isArray(filterObj)) {
if (!Array.isArray(filterObj)) {
filterObj = [filterObj];
}

Expand Down Expand Up @@ -587,3 +587,12 @@ export const createGraphsAssociationFilter = (filters: GraphFilters[],
}
return { rootEntityFilter, associationFilter: filter };
};

export const toArray = <T>(t: T | T[]) => Array.isArray(t) || isNullish(t) ? t : [t];

export class LoggedError extends Error {
constructor(logger?: Logger, msg?: string, ...meta: any[]) {
logger?.error(msg, ...meta);
super(msg);
}
}
Loading
Loading