@andreasnicolaou/query-builder
Version:
A flexible and type-safe query builder for constructing complex conditional expressions with support for nested groups, various operators, and function calls.
2 lines (1 loc) • 4.56 kB
JavaScript
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).queryBuilder={})}(this,function(e){"use strict";class t{conditions=[];skipOptions={null:!0,undefined:!0,emptyString:!0,emptyArray:!0,nan:!0,emptyObject:!0};static fn(e,...t){return{$fn:e,args:t}}static validateOperator(e,t){return["is null","is not null","is empty","is not empty"].includes(e)&&void 0!==t?{valid:!1,error:`Operator '${e}' should not have a value`}:!["between","not between"].includes(e)||Array.isArray(t)&&2===t.length?["in","not in"].includes(e)&&!Array.isArray(t)?{valid:!1,error:`Operator '${e}' requires an array value`}:{valid:!0}:{valid:!1,error:`Operator '${e}' requires an array with exactly 2 values`}}between(e,t,n="and"){return this.where(e,"between",t,n)}equals(e,t,n="and"){return this.where(e,"=",t,n)}greaterThan(e,t,n="and"){return this.where(e,">",t,n)}greaterThanOrEqual(e,t,n="and"){return this.where(e,">=",t,n)}group(e,n="and"){const i=(new t).skipWhen(this.skipOptions);e(i);const r=i.toJSON();return r.length>0&&(this.conditions.length>0&&"string"!=typeof this.conditions[this.conditions.length-1]&&this.conditions.push(n),this.conditions.push({group:r})),this}ilike(e,t,n="and"){return this.where(e,"ilike",t,n)}in(e,t,n="and"){return this.where(e,"in",t,n)}isEmpty(e,t="and"){return this.where(e,"is empty",void 0,t)}isNotEmpty(e,t="and"){return this.where(e,"is not empty",void 0,t)}isNotNull(e,t="and"){return this.where(e,"is not null",void 0,t)}isNull(e,t="and"){return this.where(e,"is null",void 0,t)}lessThan(e,t,n="and"){return this.where(e,"<",t,n)}lessThanOrEqual(e,t,n="and"){return this.where(e,"<=",t,n)}like(e,t,n="and"){return this.where(e,"like",t,n)}looseEquals(e,t,n="and"){return this.where(e,"==",t,n)}notBetween(e,t,n="and"){return this.where(e,"not between",t,n)}notEquals(e,t,n="and"){return this.where(e,"!=",t,n)}notIn(e,t,n="and"){return this.where(e,"not in",t,n)}skipWhen(e){return this.skipOptions={null:!0,undefined:!0,emptyString:!0,emptyArray:!0,nan:!0,emptyObject:!1,...e},this}strictEquals(e,t,n="and"){return this.where(e,"===",t,n)}strictNotEquals(e,t,n="and"){return this.where(e,"!==",t,n)}toJSON(){return this.conditions}toString(e){return this.formatConditions(this.conditions,!1,e?.arrayStyle||"parens")}where(e,t,n,i="and"){return!["is null","is not null","is empty","is not empty"].includes(t)&&this.shouldSkipValue(n)||(this.conditions.length>0&&this.conditions.push(i),this.conditions.push({field:e,operator:t,value:n})),this}formatConditions(e,t=!1,n="parens"){const i=[];for(const t of e)if("string"==typeof t)i.push(t);else if("group"in t){const e=this.formatConditions(t.group,!0,n);e&&i.push(`(${e})`)}else{let e=`${t.field} ${t.operator}`;const r=["is null","is not null","is empty","is not empty"].includes(t.operator);if(r||void 0===t.value)r||(e+=" undefined");else if(Array.isArray(t.value)&&this.isConditionArray(t.value))e+=` ${this.formatConditions(t.value,!0,n)}`;else if(Array.isArray(t.value)){if(["between","not between"].includes(t.operator))e+=` ${t.value.flat().map(e=>this.valueToString(e,n)).join(" and ")}`;else{const i=t.value.flat().map(e=>this.valueToString(e,n)).join(", ");e+="brackets"===n?` [${i}]`:` (${i})`}}else e+=` ${this.valueToString(t.value,n)}`;i.push(e)}let r=i.join(" ");return r=r.replace(/\(\((.*?)\)\)/g,"($1)"),t?`(${r})`:r}isConditionArray(e){return Array.isArray(e)&&e.some(e=>"object"==typeof e&&null!==e&&"operator"in e)}shouldSkipValue(e){return!!this.skipOptions&&(null===e&&!1!==this.skipOptions.null||(void 0===e&&!1!==this.skipOptions.undefined||("string"==typeof e&&""===e&&!1!==this.skipOptions.emptyString||(!(!Array.isArray(e)||!1===this.skipOptions.emptyArray||0!==e.length&&!e.every(e=>null==e||""===e||"number"==typeof e&&isNaN(e)))||(!("number"!=typeof e||!isNaN(e)||!1===this.skipOptions.nan)||!("object"!=typeof e||null===e||Array.isArray(e)||"$fn"in e||0!==Object.keys(e).length||!this.skipOptions.emptyObject))))))}valueToString(e,t="parens"){if(null===e)return"null";if(void 0===e)return"undefined";if("string"==typeof e)return`'${e.replace(/'/g,"''")}'`;if("number"==typeof e||"boolean"==typeof e)return e.toString();if(Array.isArray(e)){const n=e.flat().map(e=>this.valueToString(e,t)).join(", ");return"brackets"===t?`[${n}]`:`(${n})`}if("object"==typeof e&&null!==e&&"$fn"in e){const n=e.args?.map(e=>this.valueToString(e,t)).join(", ")||"";return`${e.$fn}(${n})`}return JSON.stringify(e)}}e.QueryBuilder=t});