I have this deeply nested array with group of node which i want to create query string something like
(FULL_NAME="x" AND NOT(AGE="30" OR AGE="40" AND (ADDRESS="y" AND STREET="z" AND NOT(USER="admin" OR USER="super admin"))) AND TITLE="Developer")
The json data i have is,
NOT (X="y" AND Y="x")
NOT
operator, this container becomes a group and will have another container inside it having AND
or OR
NOT
, AND
, OR
but cannot have same operator if they tries to group them which only applicable if it was NOT
operator.My array looks like:
[
{
"uuid":"b7f0ddf4-0290-4c7e-bb59-771aa46bc850",
"operator":"AND",
"isMain":true,
"nodes":[
{
"values":{
"fieldValue":{
"FieldName":"ORIGINAL_FILE_NAME",
},
"operator":"=",
"primaryOperandValue":"new"
},
"uuid":"779fb920-eb7f-4441-9b5a-886c7a41e271"
}
],
"children":[
{
"uuid":"7467b8c9-212e-41b8-ac02-04296b95c88c",
"operator":"NOT",
"nodes":[],
"children":[
{
"operator":"AND",
"uuid":"eaad7c96-0e8f-466b-a255-1075a8e68647",
"nodes":[
{
"uuid":"f6057d1b-56d7-4ee6-ac5b-332fbd180fd4",
"values":{
"fieldValue":{
"FieldName":"CONTROL_NUMBER",
},
"operator":"BETWEEN",
"primaryOperandValue":"x",
"secondaryOperandValue":"y"
}
}
],
"children":[
{
"uuid":"95fd2b08-cc49-498a-bd9f-c50dc55bc39f",
"operator":"NOT",
"nodes":[],
"children":[
{
"uuid":"7637ecc1-28b4-47d7-a602-cd172fb5e269",
"operator":"OR",
"nodes":[
{
"uuid":"0598a915-5818-4c6e-a3d5-6724f893871a",
"values":{
"fieldValue":{
"FieldName":"CONTROL_NUMBER",
},
"operator":" > ",
"primaryOperandValue":"30",
"secondaryOperandValue":null
}
}
],
"children":[]
}
]
}
]
}
]
},
{
"uuid":"78218b5b-b18b-4418-beed-b3418361785f",
"operator":"OR",
"nodes":[
{
"uuid":"ec956407-4fc6-46df-baa7-d2233711dc20",
"values":{
"fieldValue":{
"FieldName":"EMAIL_ANY_ADDRESS",
},
"operator":"ENDS_WITH",
"primaryOperandValue":"log",
"secondaryOperandValue":null
}
},
{
"values":{
"fieldValue":{
"FieldName":"EMAIL_ANY_ADDRESS",
},
"operator":"BEGINS_WITH",
"primaryOperandValue":"log",
"secondaryOperandValue":null
},
"uuid":"6724e913-6e98-47b6-b6af-972a20f0173d"
}
],
"children":[
]
}
]
}
]
which looks like this in the UI
I've tried several ways to generate string out of it but I am having trouble with grouping deeply nested nodes.
Thanks.
You could take for nodes and children different callbacks and collect the items for getting a string.
const
data = [{ uuid: "b7f0ddf4-0290-4c7e-bb59-771aa46bc850", operator: "AND", isMain: true, nodes: [{ values: { fieldValue: { FieldName: "ORIGINAL_FILE_NAME" }, operator: "=", primaryOperandValue: "new" }, uuid: "779fb920-eb7f-4441-9b5a-886c7a41e271" }], children: [{ uuid: "7467b8c9-212e-41b8-ac02-04296b95c88c", operator: "NOT", nodes: [], children: [{ operator: "AND", uuid: "eaad7c96-0e8f-466b-a255-1075a8e68647", nodes: [{ uuid: "f6057d1b-56d7-4ee6-ac5b-332fbd180fd4", values: { fieldValue: { FieldName: "CONTROL_NUMBER" }, operator: "BETWEEN", primaryOperandValue: "x", secondaryOperandValue: "y" } }], children: [{ uuid: "95fd2b08-cc49-498a-bd9f-c50dc55bc39f", operator: "NOT", nodes: [], children: [{ uuid: "7637ecc1-28b4-47d7-a602-cd172fb5e269", operator: "OR", nodes: [{ uuid: "0598a915-5818-4c6e-a3d5-6724f893871a", values: { fieldValue: { FieldName: "CONTROL_NUMBER" }, operator: " > ", primaryOperandValue: "30", secondaryOperandValue: null } }], children: [] }] }] }] }, { uuid: "78218b5b-b18b-4418-beed-b3418361785f", operator: "OR", nodes: [{ uuid: "ec956407-4fc6-46df-baa7-d2233711dc20", values: { fieldValue: { FieldName: "EMAIL_ANY_ADDRESS" }, operator: "ENDS_WITH", primaryOperandValue: "log", secondaryOperandValue: null } }, { values: { fieldValue: { FieldName: "EMAIL_ANY_ADDRESS" }, operator: "BEGINS_WITH", primaryOperandValue: "log", secondaryOperandValue: null }, uuid: "6724e913-6e98-47b6-b6af-972a20f0173d" }], children: [] }] }],
QUOTE = '"',
wrap = string => `(${string})`,
quote = string => `${QUOTE}${string}${QUOTE}`,
isUnary = s => ['NOT'].includes(s),
getNodes = ({ values: { fieldValue: { FieldName }, operator, primaryOperandValue, secondaryOperandValue } }) => secondaryOperandValue === null || secondaryOperandValue === undefined
? `${FieldName} ${operator.trim()} ${quote(primaryOperandValue)}`
: `${FieldName} ${operator.trim()} ${quote(primaryOperandValue)} AND ${quote(secondaryOperandValue)}`,
getChildren = ({ operator, nodes = [], children = [] }) => {
const values = [...nodes.map(getNodes), ...children.map(getChildren)]
return isUnary(operator)
? `${operator} ${values.join('')}`
: wrap(values.join(` ${operator} `));
},
result = data.map(getChildren).join('');
console.log(result);
Try using recursion, e.g
const queryObject = [
{
"uuid":"b7f0ddf4-0290-4c7e-bb59-771aa46bc850",
"operator":"AND",
"isMain":true,
"nodes":[
{
"values":{
"fieldValue":{
"FieldName":"ORIGINAL_FILE_NAME",
},
"operator":"=",
"primaryOperandValue":"new"
},
"uuid":"779fb920-eb7f-4441-9b5a-886c7a41e271"
}
],
"children":[
{
"uuid":"7467b8c9-212e-41b8-ac02-04296b95c88c",
"operator":"NOT",
"nodes":[],
"children":[
{
"operator":"AND",
"uuid":"eaad7c96-0e8f-466b-a255-1075a8e68647",
"nodes":[
{
"uuid":"f6057d1b-56d7-4ee6-ac5b-332fbd180fd4",
"values":{
"fieldValue":{
"FieldName":"CONTROL_NUMBER",
},
"operator":"BETWEEN",
"primaryOperandValue":"x",
"secondaryOperandValue":"y"
}
}
],
"children":[
{
"uuid":"95fd2b08-cc49-498a-bd9f-c50dc55bc39f",
"operator":"NOT",
"nodes":[],
"children":[
{
"uuid":"7637ecc1-28b4-47d7-a602-cd172fb5e269",
"operator":"OR",
"nodes":[
{
"uuid":"0598a915-5818-4c6e-a3d5-6724f893871a",
"values":{
"fieldValue":{
"FieldName":"CONTROL_NUMBER",
},
"operator":" > ",
"primaryOperandValue":"30",
"secondaryOperandValue":null
}
}
],
"children":[]
}
]
}
]
}
]
},
{
"uuid":"78218b5b-b18b-4418-beed-b3418361785f",
"operator":"OR",
"nodes":[
{
"uuid":"ec956407-4fc6-46df-baa7-d2233711dc20",
"values":{
"fieldValue":{
"FieldName":"EMAIL_ANY_ADDRESS",
},
"operator":"ENDS_WITH",
"primaryOperandValue":"log",
"secondaryOperandValue":null
}
},
{
"values":{
"fieldValue":{
"FieldName":"EMAIL_ANY_ADDRESS",
},
"operator":"BEGINS_WITH",
"primaryOperandValue":"log",
"secondaryOperandValue":null
},
"uuid":"6724e913-6e98-47b6-b6af-972a20f0173d"
}
],
"children":[
]
}
]
}
]
const operatorString = (items) => items.map(
({operator, nodes, children, isMain }) => {
const nodeString = nodes.map(({ values }) => {
const {fieldValue, operator, primaryOperandValue, secondaryOperandValue} = values
return fieldValue.FieldName + ' ' + operator + (secondaryOperandValue ? '("' + primaryOperandValue + '", "' + secondaryOperandValue + '")' : ' "' + primaryOperandValue + '"')
}).join(" " + operator + " ")
return "( " + nodeString + ' ' + operator + operatorString(children) + " )"
}
).join("")
console.log(operatorString(queryObject))
Not complete, but hopefully this can give you a good, readable start
function processNodes( node ) {
var nodeStr = " Node [" + node.values.operator + "]";
switch (node.values.operator) {
case "=":
case " > ":
case "<":
case "ENDS_WITH":
case "BEGINS_WITH":
nodeStr = node.values.fieldValue.FieldName;
nodeStr += " " + node.values.operator;
nodeStr += " " + node.values.primaryOperandValue;
break;
}
return nodeStr;
}
function processCommands ( cmdArray, operator ) {
var cmdStr = '';
for (var i = 0; i < cmdArray.length; i++)
{
if (cmdArray[i].nodes.length > 0) {
cmdStr += " ( ";
for (var j = 0; j < cmdArray[i].nodes.length; j++) {
if (j > 0) {
cmdStr += " " + cmdArray[i].operator + " ";
}
cmdStr += processNodes(cmdArray[i].nodes[j]);
}
cmdStr += " ) ";
}
if ( cmdStr || cmdArray[i].children.length > 0) {
cmdStr += " " + cmdArray[i].operator + " ";
}
if (cmdArray[i].children.length > 0) {
cmdStr += " " + processCommands(cmdArray[i].children, cmdArray[i].operator);
}
}
return cmdStr;
}
var cmdArray = [
{
"uuid":"b7f0ddf4-0290-4c7e-bb59-771aa46bc850",
"operator":"AND",
"isMain":true,
"nodes":[
{
"values":{
"fieldValue":{
"FieldName":"ORIGINAL_FILE_NAME",
},
"operator":"=",
"primaryOperandValue":"new"
},
"uuid":"779fb920-eb7f-4441-9b5a-886c7a41e271"
}
],
"children":[
{
"uuid":"7467b8c9-212e-41b8-ac02-04296b95c88c",
"operator":"NOT",
"nodes":[],
"children":[
{
"operator":"AND",
"uuid":"eaad7c96-0e8f-466b-a255-1075a8e68647",
"nodes":[
{
"uuid":"f6057d1b-56d7-4ee6-ac5b-332fbd180fd4",
"values":{
"fieldValue":{
"FieldName":"CONTROL_NUMBER",
},
"operator":"BETWEEN",
"primaryOperandValue":"x",
"secondaryOperandValue":"y"
}
}
],
"children":[
{
"uuid":"95fd2b08-cc49-498a-bd9f-c50dc55bc39f",
"operator":"NOT",
"nodes":[],
"children":[
{
"uuid":"7637ecc1-28b4-47d7-a602-cd172fb5e269",
"operator":"OR",
"nodes":[
{
"uuid":"0598a915-5818-4c6e-a3d5-6724f893871a",
"values":{
"fieldValue":{
"FieldName":"CONTROL_NUMBER",
},
"operator":" > ",
"primaryOperandValue":"30",
"secondaryOperandValue":null
}
}
],
"children":[]
}
]
}
]
}
]
},
{
"uuid":"78218b5b-b18b-4418-beed-b3418361785f",
"operator":"OR",
"nodes":[
{
"uuid":"ec956407-4fc6-46df-baa7-d2233711dc20",
"values":{
"fieldValue":{
"FieldName":"EMAIL_ANY_ADDRESS",
},
"operator":"ENDS_WITH",
"primaryOperandValue":"log",
"secondaryOperandValue":null
}
},
{
"values":{
"fieldValue":{
"FieldName":"EMAIL_ANY_ADDRESS",
},
"operator":"BEGINS_WITH",
"primaryOperandValue":"log",
"secondaryOperandValue":null
},
"uuid":"6724e913-6e98-47b6-b6af-972a20f0173d"
}
],
"children":[
]
}
]
}
];
console.log(processCommands(cmdArray));
You could do something like this. It uses a handful of helper functions and a main recursive function
const init = () => {
// special logic to handle javascript to SQL
const nodeToClause = (node) => {
let r = [];
switch (node.values.operator) {
case 'BETWEEN':
r = [node.values.fieldValue.FieldName,node.values.operator,node.values.primaryOperandValue,node.values.secondaryOperandValue];
break;
case '=':
case 'BEGINS_WITH':
case 'ENDS_WITH':
r = [node.values.fieldValue.FieldName,node.values.operator,`"${node.values.primaryOperandValue}"`];
break;
default:
r = [node.values.fieldValue.FieldName,node.values.operator,node.values.primaryOperandValue];
break;
}
return r.join(' ');
};
// serialize
const toSQL = (statement) => {
let r = '';
const glue = ' ' + statement.operator + ' ';
if (statement.nodes.length) {
r = statement.nodes.map(nodeToClause).join(glue);
}
return r;
};
// helps with formatting. not necessary, but nice
const tabs = (n) => {
const t = ['\n'];
let i = 0;
while (i < n) {
t.push('\t');
i++;
}
return t.join('');
};
// the recursive function that does all the work
const recurse = (queryFragment, joiner, level=0) => {
let r = "";
if (Array.isArray(queryFragment)) {
r = queryFragment.map(frag => {
return recurse(frag, frag.operator, level);
}).join(joiner);
} else {
r = tabs(level) + toSQL(queryFragment);
if ("children" in queryFragment && queryFragment.children.length) {
r += ' ' + queryFragment.operator + ' (' + recurse(queryFragment.children,queryFragment.operator,level+1) + tabs(level) + ') ';
}
}
return r;
};
// load the data into DOM
const x = recurse(query,';');
output.innerText = x;
};
// output to screen
window.setTimeout(init, 997);
const output = document.getElementById('output');
// test data
const query = [
{
"uuid":"b7f0ddf4-0290-4c7e-bb59-771aa46bc850",
"operator":"AND",
"isMain":true,
"nodes":[
{
"values":{
"fieldValue":{
"FieldName":"ORIGINAL_FILE_NAME",
},
"operator":"=",
"primaryOperandValue":"new"
},
"uuid":"779fb920-eb7f-4441-9b5a-886c7a41e271"
}
],
"children":[
{
"uuid":"7467b8c9-212e-41b8-ac02-04296b95c88c",
"operator":"NOT",
"nodes":[],
"children":[
{
"operator":"AND",
"uuid":"eaad7c96-0e8f-466b-a255-1075a8e68647",
"nodes":[
{
"uuid":"f6057d1b-56d7-4ee6-ac5b-332fbd180fd4",
"values":{
"fieldValue":{
"FieldName":"CONTROL_NUMBER",
},
"operator":"BETWEEN",
"primaryOperandValue":"x",
"secondaryOperandValue":"y"
}
}
],
"children":[
{
"uuid":"95fd2b08-cc49-498a-bd9f-c50dc55bc39f",
"operator":"NOT",
"nodes":[],
"children":[
{
"uuid":"7637ecc1-28b4-47d7-a602-cd172fb5e269",
"operator":"OR",
"nodes":[
{
"uuid":"0598a915-5818-4c6e-a3d5-6724f893871a",
"values":{
"fieldValue":{
"FieldName":"CONTROL_NUMBER",
},
"operator":" > ",
"primaryOperandValue":"30",
"secondaryOperandValue":null
}
}
],
"children":[]
}
]
}
]
}
]
},
{
"uuid":"78218b5b-b18b-4418-beed-b3418361785f",
"operator":"OR",
"nodes":[
{
"uuid":"ec956407-4fc6-46df-baa7-d2233711dc20",
"values":{
"fieldValue":{
"FieldName":"EMAIL_ANY_ADDRESS",
},
"operator":"ENDS_WITH",
"primaryOperandValue":"log",
"secondaryOperandValue":null
}
},
{
"values":{
"fieldValue":{
"FieldName":"EMAIL_ANY_ADDRESS",
},
"operator":"BEGINS_WITH",
"primaryOperandValue":"log",
"secondaryOperandValue":null
},
"uuid":"6724e913-6e98-47b6-b6af-972a20f0173d"
}
],
"children":[
]
}
]
}
];
pre {
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
font-family: "Courier";
font-weight: bold;
color: saddlebrown;
}
body {
background-color: #bbbf3e94;
}
<pre class="text" id="output"></pre>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With