Skip to content

Instantly share code, notes, and snippets.

@vanhtuan0409
Last active December 12, 2020 09:21
Show Gist options
  • Save vanhtuan0409/ce50002458820ba7dba276e613fe9e04 to your computer and use it in GitHub Desktop.
Save vanhtuan0409/ce50002458820ba7dba276e613fe9e04 to your computer and use it in GitHub Desktop.
const formatValueForSQL = require("./formatValue");
class Visitor {
constructor() {
this.context = {};
}
// conditions as an object
visit(conditions) {
return Object.entries(conditions)
.map(([key, val]) => this.visit_pair(key, val))
.join(" AND ");
}
visit_pair(key, val) {
// handle nil type
if (val === null || val === undefined) {
return this.visit_null(key);
}
// handle primary type
if (typeof val === "number" || typeof val === "string") {
return this.visit_primary(key, val);
}
// handle not equal
if (typeof val === "object" && val.hasOwnProperty("$neq")) {
return this.visit_neq(key, val["$neq"]);
}
// handle condition op
if (typeof val === "object" && val.hasOwnProperty("$and")) {
return `(${this.visit_condition(key, "AND", val["$and"])})`;
}
if (typeof val === "object" && val.hasOwnProperty("$or")) {
return `(${this.visit_condition(key, "OR", val["$or"])})`;
}
// handle compare op
if (typeof val === "object" && val.hasOwnProperty("$gt")) {
return this.visit_compare(key, ">", val["$gt"]);
}
if (typeof val === "object" && val.hasOwnProperty("$gte")) {
return this.visit_compare(key, ">=", val["$gte"]);
}
if (typeof val === "object" && val.hasOwnProperty("$lt")) {
return this.visit_compare(key, "<", val["$lt"]);
}
if (typeof val === "object" && val.hasOwnProperty("$lte")) {
return this.visit_compare(key, "<=", val["$lte"]);
}
throw new Error(`Unknown condition pair: ${key}, ${val}`);
}
visit_null(key) {
return `${key} is null`;
}
visit_primary(key, val) {
return `${key} = ${formatValueForSQL(val)}`;
}
visit_neq(key, lhs) {
if (typeof lhs !== "number" && typeof lhs !== "string")
throw new Error(`Invalid neq lhs: ${lhs}`);
return `${key} is not ${formatValueForSQL(lhs)}`;
}
visit_condition(key, op, conditions) {
if (!Array.isArray(conditions))
throw new Error(`\`${op}\` operator must be an array`);
return conditions
.map((entry) => this.visit_pair(key, entry))
.join(` ${op} `);
}
visit_compare(key, op, lhs) {
if (op !== "<" && op !== "<=" && op !== ">" && op != ">=")
throw new Error(`Invalid compare op: ${op}`);
if (typeof lhs !== "number" && typeof lhs !== "string")
throw new Error(`Invalid compare lhs: ${lhs}`);
return `${key} ${op} ${formatValueForSQL(lhs)}`;
}
}
let visitor = new Visitor();
let result = visitor.visit({
created_by: "[email protected]",
date: "2020-12-18",
tag: "aaa",
created_at: {
$or: [
{
$and: [{ $gt: "2020-05-01" }, { $lt: "2020-05-30" }],
},
{
$and: [{ $gt: "2020-09-01" }, { $lt: "2020-09-30" }],
},
],
},
completed_at: null,
foo: {
$neq: "bar",
},
});
console.log(result);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment