Skip to content

Instantly share code, notes, and snippets.

@ds1371dani
Last active September 21, 2022 03:14
Show Gist options
  • Save ds1371dani/a03461aa0dfb2330afa718f07a26a47a to your computer and use it in GitHub Desktop.
Save ds1371dani/a03461aa0dfb2330afa718f07a26a47a to your computer and use it in GitHub Desktop.
Gridify query builder for typescript
import { GridifyConditionEnum, GridifyLogicalEnum, GridifyOrderEnum, FilterType, OperatorType, FiltersType } from "./types.ts";
function trimEnds(query: string): string {
let result = query;
// There should not be any starting or ending operator
if (result.startsWith(GridifyLogicalEnum.And)) result = result.slice(GridifyLogicalEnum.And.length);
if (result.startsWith(GridifyLogicalEnum.Or)) result = result.slice(GridifyLogicalEnum.Or.length);
if (result.endsWith(GridifyLogicalEnum.And)) result = result.slice(0, -GridifyLogicalEnum.And.length);
if (result.endsWith(GridifyLogicalEnum.Or)) result = result.slice(0, -GridifyLogicalEnum.Or.length);
return result;
}
export function createQuery(filters: FiltersType) {
const queries: string = filters.reduce((acc, filter) => {
// If current filter is an array inside the current array then it should be wrapped in Parentheses
if (Array.isArray(filter)) {
const childQueries = createQuery(filter);
return childQueries ? trimEnds(`${acc}(${childQueries})`) : trimEnds(acc);
}
// If current filter is an `string`, it means it is only an operator between two other filters
if (typeof filter === "string") return acc + filter;
const { key, operator, value, caseInsensitive, order } = filter;
if (value && operator)
return trimEnds(
acc +
key +
operator +
value +
(order ? ` ${order}` : "") +
(caseInsensitive ? GridifyLogicalEnum.CaseInsensitive : "")
);
return trimEnds(acc);
}, "");
return queries;
}
// Example
const filters: FiltersType = [
{ key: "createDate", operator: GridifyConditionEnum.GreaterThan, value: "2021-01-12" },
GridifyLogicalEnum.And,
[
{
key: "name",
operator: GridifyConditionEnum.Contains,
value: "joe",
caseInsensitive: true,
},
GridifyLogicalEnum.Or,
{
key: "count",
operator: GridifyConditionEnum.LessThan,
order: GridifyOrderEnum.Ascending,
value: "50",
},
GridifyLogicalEnum.Or,
{ key: "target", operator: GridifyConditionEnum.StartsWith, value: "https://", caseInsensitive: true },
],
GridifyLogicalEnum.And,
{ key: "hitCount", operator: GridifyConditionEnum.GreaterThanOrEqual, value: "50" },
];
// Final generated query
const query = createQuery(filters);
export enum GridifyConditionEnum {
Equal = "=",
NotEqual = "!=",
LessThan = "<",
GreaterThan = ">",
GreaterThanOrEqual = ">=",
LessThanOrEqual = "<=",
Contains = "=*",
NotContains = "!*",
StartsWith = "^",
NotStartsWith = "!^",
EndsWith = "$",
NotEndsWith = "!$",
}
export enum GridifyLogicalEnum {
And = ",",
Or = "|",
CaseInsensitive = "/i",
}
export enum GridifyOrderEnum {
Ascending = "asc",
Descending = "desc",
}
export interface FilterType {
key: string;
value?: string;
caseInsensitive?: boolean;
order?: GridifyOrderEnum;
operator?: GridifyConditionEnum;
}
export type OperatorType = GridifyLogicalEnum.Or | GridifyLogicalEnum.And;
export type FiltersType = (OperatorType | FilterType | FiltersType)[];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment