Last active
December 10, 2021 19:23
-
-
Save ivanauliaa/9a662cf8e2140bd2a6c5112f6f0ec7ea to your computer and use it in GitHub Desktop.
Express Microsoft OData filter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Generate AST from query, please check the test cases to find the correct | |
* input and output for this. | |
*/ | |
exports.generateASTFromQuery = async (req, res) => { | |
try { | |
let qrys_prefix = prefixExpr(req.query.$filter.match(/[a-zA-Z_]+|[0-9]+|[(]+|[)]/g)) | |
let qry_json = createJson(qrys_prefix) | |
return res.json(qry_json) | |
// return res.json({ value: {} }); | |
} catch (e) { | |
return res | |
.status(500) | |
.json({ error: e.message }); | |
} | |
}; | |
function prefixExpr(qrys) { | |
const log_opr = ['eq', 'ne', 'gt', 'ge', 'lt', 'le'] | |
const com_opr = ['and', 'or', 'not'] | |
const open_par = '(' | |
const close_par = ')' | |
let ent_stack = [] | |
let opr_stack = [] | |
qrys.filter(qry => { | |
if (qry == open_par) { | |
opr_stack.push(qry) | |
} else if(qry == close_par) { | |
let top_opr_stack = opr_stack[opr_stack.length - 1] | |
while(top_opr_stack != open_par) { | |
ent_stack.push(opr_stack.pop()) | |
top_opr_stack = opr_stack[opr_stack.length - 1] | |
} | |
if(opr_stack.length == 1) { | |
opr_stack = [] | |
} else { | |
opr_stack.pop() | |
} | |
} else if(log_opr.includes(qry) || com_opr.includes(qry)) { | |
if(!opr_stack.length) { | |
opr_stack.push(qry) | |
} else { | |
let top_opr_stack = opr_stack.pop() | |
if(top_opr_stack == open_par || (com_opr.includes(top_opr_stack) && log_opr.includes(qry))) { | |
opr_stack.push(top_opr_stack) | |
opr_stack.push(qry) | |
} else { | |
while(com_opr.includes(qry) && log_opr.includes(top_opr_stack)) { | |
ent_stack.push(top_opr_stack) | |
top_opr_stack = opr_stack.pop | |
} | |
opr_stack.push(top_opr_stack) | |
opr_stack.push(qry) | |
} | |
} | |
} else { | |
ent_stack.push(qry) | |
} | |
}) | |
ent_stack.reverse() | |
ent_stack.filter(ent => { | |
opr_stack.push(ent) | |
}) | |
opr_stack = opr_stack.filter(opr => typeof opr == 'string') | |
return opr_stack | |
} | |
function createJson(qrys_prefix) { | |
const log_opr = ['eq', 'ne', 'gt', 'ge', 'lt', 'le'] | |
const com_opr = ['and', 'or', 'not'] | |
let ent_stack = [] | |
qrys_prefix.reverse() | |
qrys_prefix.filter(qry => { | |
if(!log_opr.includes(qry) && !com_opr.includes(qry)) { | |
ent_stack.push(qry) | |
} else { | |
let ent1 = ent_stack.pop() | |
let ent2 = ent_stack.pop() | |
let qry_obj | |
if(log_opr.includes(qry)) { | |
qry_obj = createObject(ent2, ent1, qry, false) | |
} else { | |
qry_obj = createObject(ent2, ent1, qry, true) | |
} | |
ent_stack.push(qry_obj) | |
} | |
}) | |
return ent_stack[0] | |
} | |
function createObject(ent1, ent2, opr, is_com_opr) { | |
if(is_com_opr) { | |
return { | |
children: [ | |
ent1, | |
ent2 | |
], | |
value: opr | |
} | |
} else { | |
return { | |
children: [ | |
{ | |
value: ent1 | |
}, | |
{ | |
value: ent2 | |
} | |
], | |
value: opr | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment