Implement filter in devices page

This commit is contained in:
Zaid Abdulla committed 2018-12-26 00:20:47 -08:00
1 parent eda43083ec
commit ccf548081f
7 files changed
+198 -47

No files matched your search

+54 -19
View File
@@ -7,34 +7,68 @@ const querystring = require("querystring");
const config = require("./config");
const device = require("./device");
const filterParser = require("./filter-parser");
const commaAscii = ",".charCodeAt(0);
const newLineAscii = "\n".charCodeAt(0);
function filtersToQuery(filters) {
if (!Array.isArray(filters)) filters = [filters];
function filterToQuery(filter, negate = false, res = {}) {
const op = filter[0];
let queries = [];
for (let filter of filters) {
let q = {};
for (let [k, v] of Object.entries(filter)) {
let [param, op] = k.split(/([^a-zA-Z0-9\-_.].*)/, 2);
if (!op || op === "=") q[param] = v;
else if (op === ">") q[param] = { $gt: v };
else throw new Error(`Operator "${op}" not recognized`);
if ((!negate && op === "AND") || (negate && op === "OR")) {
for (let i = 1; i < filter.length; ++i)
filterToQuery(filter[i], negate, res);
} else if ((!negate && op === "OR") || (negate && op === "AND")) {
res["$or"] = res["$or"] || [];
for (let i = 1; i < filter.length; ++i)
res["$or"].push(filterToQuery(filter[i], negate));
} else if (op === "NOT") {
filterToQuery(filter[1], !negate, res);
} else if (op === "=") {
let p = (res[filter[1]] = res[filter[1]] || {});
if (negate) p["$ne"] = filter[2];
else p["$eq"] = filter[2];
} else if (op === "<>") {
let p = (res[filter[1]] = res[filter[1]] || {});
if (negate) {
p["$eq"] = filter[2];
} else {
p["$ne"] = filter[2];
p["$exists"] = true;
}
queries.push(q);
} else if (op === ">") {
let p = (res[filter[1]] = res[filter[1]] || {});
if (negate) p = p["$not"] = p["$not"] || {};
p["$gt"] = filter[2];
} else if (op === ">=") {
let p = (res[filter[1]] = res[filter[1]] || {});
if (negate) p = p["$not"] = p["$not"] || {};
p["$gte"] = filter[2];
} else if (op === "<") {
let p = (res[filter[1]] = res[filter[1]] || {});
if (negate) p = p["$not"] = p["$not"] || {};
p["$lt"] = filter[2];
} else if (op === "<=") {
let p = (res[filter[1]] = res[filter[1]] || {});
if (negate) p = p["$not"] = p["$not"] || {};
p["$lte"] = filter[2];
} else if (op === "IS NULL") {
res[filter[1]] = { $exists: negate };
} else if (op === "IS NOT NULL") {
res[filter[1]] = { $exists: !negate };
} else {
throw new Error(`Unrecognized operator ${op}`);
}
if (queries.length === 1) return queries[0];
else return { $or: queries };
return res;
}
function count(resource, filters, limit) {
function count(resource, filter, limit) {
return new Promise((resolve, reject) => {
let qs = {};
if (filters) {
let q = filtersToQuery(filters);
if (filter) {
let q = filterToQuery(filterParser.parse(filter));
if (resource === "devices") q = device.transposeQuery(q);
qs.query = JSON.stringify(q);
}
@@ -62,14 +96,15 @@ function count(resource, filters, limit) {
});
}
function query(resource, filters, limit, callback) {
function query(resource, filter, limit, callback) {
return new Promise((resolve, reject) => {
let ret;
if (!callback) ret = [];
let qs = {};
if (filters) {
let q = filtersToQuery(filters);
if (filter) {
let q = filterToQuery(filterParser.parse(filter));
if (resource === "devices") q = device.transposeQuery(q);
qs.query = JSON.stringify(q);
}
+4 -18
View File
@@ -17,14 +17,7 @@ const resources = {
for (let [resource, update] of Object.entries(resources)) {
router.head(`/${resource}`, async ctx => {
let filter, limit;
if (ctx.request.query.filter)
if (Array.isArray(ctx.request.query.filter))
filter = ctx.request.query.query.map(q => JSON.parse(q));
else {
filter = JSON.parse(ctx.request.query.filter);
if (!Array.isArray(filter)) filter = [filter];
}
if (ctx.request.query.filter) filter = ctx.request.query.filter;
if (ctx.request.query.limit) limit = +ctx.request.query.limit;
let count = await apiFunctions.count(resource, filter, limit);
@@ -34,28 +27,21 @@ for (let [resource, update] of Object.entries(resources)) {
router.get(`/${resource}`, async ctx => {
let filter, limit;
if (ctx.request.query.filter)
if (Array.isArray(ctx.request.query.filter))
filter = ctx.request.query.query.map(q => JSON.parse(q));
else {
filter = JSON.parse(ctx.request.query.filter);
if (!Array.isArray(filter)) filter = [filter];
}
if (ctx.request.query.filter) filter = ctx.request.query.filter;
if (ctx.request.query.limit) limit = +ctx.request.query.limit;
ctx.body = await apiFunctions.query(resource, filter, limit);
});
router.head(`/${resource}/:id`, async (ctx, next) => {
let filter = { _id: ctx.params.id };
let filter = `DeviceID.ID = "${ctx.params.id}"`;
let res = await apiFunctions.query(resource, filter);
if (!res.length) return next();
ctx.body = "";
});
router.get(`/${resource}/:id`, async (ctx, next) => {
let filter = { _id: ctx.params.id };
let filter = `DeviceID.ID = "${ctx.params.id}"`;
let res = await apiFunctions.query(resource, filter);
if (!res.length) return next();
ctx.body = res[0];
+23 -2
View File
@@ -142,8 +142,29 @@ function transposeQuery(query) {
const newQuery = {};
for (let [key, val] of Object.entries(query))
if (key.startsWith("$")) newQuery[key] = transposeQuery(val);
else if (key === "DeviceID.ID") newQuery["_id"] = val;
if (key.startsWith("$")) {
newQuery[key] = val.map(v => transposeQuery(v));
} else if (key === "DeviceID.ID") {
newQuery["_id"] = val;
} else if (key === "DeviceID.SerialNumber") {
newQuery["_deviceId._SerialNumber"] = val;
} else if (key === "DeviceID.OUI") {
newQuery["_deviceId._OUI"] = val;
} else if (key === "DeviceID.Manufacturer") {
newQuery["_deviceId._Manufacturer"] = val;
} else if (key.startsWith("Tags.")) {
if (val["$exists"] === true) {
newQuery["_tags"] = newQuery["_tags"] || {};
newQuery["_tags"]["$all"] = newQuery["_tags"]["$all"] || [];
newQuery["_tags"]["$all"].push(key.slice(5));
} else if (val["$exists"] === false) {
newQuery["_tags"] = newQuery["_tags"] || {};
newQuery["_tags"]["$nin"] = newQuery["_tags"]["$nin"] || [];
newQuery["_tags"]["$nin"].push(key.slice(5));
}
} else {
newQuery[key] = val;
}
return newQuery;
}