Reputation: 276
I'm doing an API and the following code is used to retrieve users depending on filter. ( POST /users/search )
At the end of the function, I'm working with "LIMIT" and "OFFSET" in SQL because I want that nobody can retrieve more than 10 entries.
The code to generate the SQL query from WHERE is terrible. I am looking to improve it but I can't find a more effective way. Do you have any ideas?
function getSqlFilter(filter) {
var filterSql = '';
if (!util.isEmpty(filter)) {
var isFiltered = false;
if (filter.userId != null) {
if (!isFiltered) filterSql += ' WHERE ';
if (isFiltered) filterSql += ' AND ';
filterSql += 'pk_user in (' + filter.userId.toString() + ')';
isFiltered = true;
}
if (filter.username != null) {
if (!isFiltered) filterSql += ' WHERE ';
if (isFiltered) filterSql += ' AND ';
filterSql += 'username in (' + filter.username.toString() + ')';
isFiltered = true;
}
if (filter.email != null) {
if (!isFiltered) filterSql += ' WHERE ';
if (isFiltered) filterSql += ' AND ';
filterSql += 'email in (' + filter.email.toString() + ')';
isFiltered = true;
}
if (filter.society != null) {
if (!isFiltered) filterSql += ' WHERE ';
if (isFiltered) filterSql += ' AND ';
filterSql += 'society in (' + filter.society.toString() + ')';
isFiltered = true;
}
if (filter.firstname != null) {
if (!isFiltered) filterSql += ' WHERE ';
if (isFiltered) filterSql += ' AND ';
filterSql += 'firstname in (' + filter.firstname.toString() + ')';
isFiltered = true;
}
if ((filter.start != null) && (filter.end != null)) {
filter.start -= 1;
var limit = filter.end - filter.start;
if (limit <= 10) {
filterSql += 'LIMIT ' + limit + ' OFFSET ' + filter.start;
}
} else if (filter.start != null) {
filterSql += 'LIMIT 10 OFFSET ' + filter.start;
} else {
filterSql += 'LIMIT 10 OFFSET 0';
}
} else {
filterSql += 'LIMIT 10 OFFSET 0';
}
return filterSql;
}
Thanks for helping
Upvotes: 0
Views: 89
Reputation: 4205
You can simplify the redundant logic and utilize ES6 features for shorter syntax.
function getSqlFilter(filter = {}) {
const searches = Object.keys(filter);
const sLength = searches.length
let filterSql = sLength === 0 ? "LIMIT 10 OFFSET 0" : "WHERE ";
const map = {
userId: "pk_user",
username: "username",
email: "email",
society: "society"
}
const { start, end } = filter;
const hasOnlyStart = start !== undefined && end === undefined;
const hasStartAndEnd = start !== undefined && end !== undefined;
if (sLength) {
filterSql += searches.map(search => {
if(search === "start") {
return hasOnlyStart ? `LIMIT ${filter[search]} OFFSET 10` : "";
}
if(search === "end") {
return hasStartAndEnd ? `LIMIT ${filter[search]} OFFSET ${end - start}` : "";
}
return `${map[search]} in (${filter[search].toString()})`;
}).join(' AND ');
}
return filterSql;
}
Upvotes: 1
Reputation: 396
It is my anwser:
function getSqlFilter(filter) {
let sql = '';
let start = parseInt(filter.start);
let end = parseInt(filter.end);
delete filter.start;
delete filter.end;
const conditions = [];
const validKey = [...your key];
for (const key in filter){
if(validKey.indexOf(key) !== -1){
if(key === 'userId') conditions.push(`pk_user in (${filter[key].toString()})`);
else conditions.push(`${key} in (${filter[key].toString()})`);
}
}
if(conditions.length){
sql = ` WHERE ${conditions.join(' AND ')}`;
}
let limit = 10;
if (start) {
if(start < 0) start = 0;
if (end) {
let be_limit = start - end + 1;
if(be_limit <= 10 && be_limit >= 0) limit = be_limit;
}
} else {
start = 0;
}
sql += ` LIMIT ${limit} OFFSET ${start}`;
return sql;
}
If you don't want to change filter, please clone it before delete props.
Upvotes: 1
Reputation: 4044
I normally do this by starting with an always true condition
let filter= `...
WHERE 1 = 1`
Then you can simply append the filter
if (filter.username != null) {
filter += ' AND username in (' + filter.username.toString() + ')'
}
...
Hope this helps.
Upvotes: 1