|
| 1 | +import { Condition } from "../Api/DataTypes/Condition"; |
| 2 | +import { Sort } from "../Api/DataTypes/Sort"; |
| 3 | +import { StringUtils } from "../Utils/StringUtils"; |
| 4 | + |
| 5 | +import { ObjectSearchQuery } from "./ObjectSearchQuery"; |
| 6 | +import { |
| 7 | + convertOperationToString, |
| 8 | + convertSortToString, |
| 9 | + convertStringToOperation, |
| 10 | + convertStringToSort, |
| 11 | +} from "./OperationsConverter"; |
| 12 | + |
| 13 | +interface SearchQueryStringified { |
| 14 | + conditions: string; |
| 15 | + sorts: string; |
| 16 | + count: string; |
| 17 | + offset: string; |
| 18 | + hiddenColumns?: string; |
| 19 | + shownColumns?: string; |
| 20 | +} |
| 21 | + |
| 22 | +export class ObjectSearchQueryMapping { |
| 23 | + public static normalize(query: ObjectSearchQuery, removeCounts: boolean): ObjectSearchQuery { |
| 24 | + return { |
| 25 | + ...query, |
| 26 | + count: removeCounts ? 0 : query.count, |
| 27 | + offset: removeCounts ? 0 : query.offset, |
| 28 | + hiddenColumns: [], |
| 29 | + }; |
| 30 | + } |
| 31 | + |
| 32 | + public static parse(query: string, columns: string[]): ObjectSearchQuery { |
| 33 | + const url = new URLSearchParams(query); |
| 34 | + const conditions = url.get("conditions"); |
| 35 | + const sorts = url.get("sorts"); |
| 36 | + const count = url.get("count"); |
| 37 | + const offset = url.get("offset"); |
| 38 | + const hiddenColumns = url.get("hiddenColumns"); |
| 39 | + const shownColumns = url.get("shownColumns"); |
| 40 | + |
| 41 | + return { |
| 42 | + conditions: parseConditions(conditions, columns), |
| 43 | + sorts: parseSorts(sorts), |
| 44 | + count: count ? parseInt(count) : 20, |
| 45 | + offset: offset ? parseInt(offset) : 0, |
| 46 | + hiddenColumns: parseHiddenColumns(shownColumns, hiddenColumns, columns), |
| 47 | + }; |
| 48 | + } |
| 49 | + |
| 50 | + public static stringify(query: ObjectSearchQuery, columns: string[]): string { |
| 51 | + let params: Partial<SearchQueryStringified> = {}; |
| 52 | + if (query.conditions.length !== 0) { |
| 53 | + params.conditions = stringifyConditions(query.conditions); |
| 54 | + } |
| 55 | + if (query.sorts.length !== 0) { |
| 56 | + params.sorts = stringifySorts(query.sorts); |
| 57 | + } |
| 58 | + if (query.count !== 20) { |
| 59 | + params.count = query.count.toString(); |
| 60 | + } |
| 61 | + if (query.offset !== 0) { |
| 62 | + params.offset = query.offset.toString(); |
| 63 | + } |
| 64 | + if (query.hiddenColumns.length !== 0) { |
| 65 | + params = { ...params, ...stringifyHiddenColumns(query.hiddenColumns, columns) }; |
| 66 | + } |
| 67 | + return `?${new URLSearchParams(params)}`; |
| 68 | + } |
| 69 | +} |
| 70 | + |
| 71 | +const outerSep = ";"; |
| 72 | +const innerSep = ":"; |
| 73 | + |
| 74 | +/* |
| 75 | + * note: Single condition has format path:operator:value; |
| 76 | + * complicated parse function to handle edge cases |
| 77 | + * eg. conditions = `Id:=:ab:cd:e;f;g;ScopeId:=:a;b`, columns = ["Id", "ScopeId"] |
| 78 | + * should return [ |
| 79 | + * { path: "Id", operator: Equals, value: "ab:cd:e;f;g" }, |
| 80 | + * { path: "ScopeId", operator: Equals, value: "a;b" }, |
| 81 | + * ] |
| 82 | + */ |
| 83 | +function parseConditions(conditions: string | null, columns: string[]): Condition[] { |
| 84 | + if (StringUtils.isNullOrWhitespace(conditions)) { |
| 85 | + return []; |
| 86 | + } |
| 87 | + const result: Condition[] = []; |
| 88 | + let current = 0; |
| 89 | + let next = 0; |
| 90 | + while ((next = conditions.indexOf(outerSep, next + 1)) !== -1) { |
| 91 | + const nextPath = conditions.substring(next + 1, conditions.indexOf(innerSep, next + 1)); |
| 92 | + if (columns.indexOf(nextPath) !== -1) { |
| 93 | + result.push(parseCondition(conditions, current, next)); |
| 94 | + current = next + 1; |
| 95 | + } |
| 96 | + } |
| 97 | + if (current >= 0 && current < conditions.length) { |
| 98 | + result.push(parseCondition(conditions, current)); |
| 99 | + } |
| 100 | + return result; |
| 101 | +} |
| 102 | + |
| 103 | +function parseCondition(conditions: string, start: number, end?: number): Condition { |
| 104 | + const sep1 = conditions.indexOf(innerSep, start); |
| 105 | + const sep2 = conditions.indexOf(innerSep, sep1 + 1); |
| 106 | + return { |
| 107 | + path: conditions.substring(start, sep1), |
| 108 | + operator: convertOperationToString(conditions.substring(sep1 + 1, sep2)), |
| 109 | + value: conditions.substring(sep2 + 1, end), |
| 110 | + }; |
| 111 | +} |
| 112 | + |
| 113 | +function parseSorts(sorts: string | null): Sort[] { |
| 114 | + if (StringUtils.isNullOrWhitespace(sorts)) { |
| 115 | + return []; |
| 116 | + } |
| 117 | + return sorts.split(outerSep).map(s => { |
| 118 | + const [path, order] = s.split(innerSep); |
| 119 | + return { |
| 120 | + path: path, |
| 121 | + sortOrder: convertStringToSort(order), |
| 122 | + }; |
| 123 | + }); |
| 124 | +} |
| 125 | + |
| 126 | +function parseHiddenColumns(shownColumns: string | null, hiddenColumns: string | null, columns: string[]): string[] { |
| 127 | + if (shownColumns != null) { |
| 128 | + const cols = shownColumns.split(outerSep); |
| 129 | + return columns.filter(c => cols.indexOf(c) === -1); |
| 130 | + } else if (hiddenColumns != null) { |
| 131 | + return hiddenColumns.split(outerSep); |
| 132 | + } |
| 133 | + return []; |
| 134 | +} |
| 135 | + |
| 136 | +function stringifyConditions(conditions: Condition[]): string { |
| 137 | + return conditions.map(c => [c.path, convertStringToOperation(c.operator), c.value].join(innerSep)).join(outerSep); |
| 138 | +} |
| 139 | + |
| 140 | +function stringifySorts(sorts: Sort[]): string { |
| 141 | + return sorts.map(s => [s.path, convertSortToString(s.sortOrder)].join(innerSep)).join(outerSep); |
| 142 | +} |
| 143 | + |
| 144 | +function stringifyHiddenColumns(hiddenColumns: string[], columns: string[]): Partial<SearchQueryStringified> { |
| 145 | + const result: Partial<SearchQueryStringified> = {}; |
| 146 | + if (hiddenColumns.length >= columns.length - hiddenColumns.length) { |
| 147 | + result.shownColumns = columns.filter(c => hiddenColumns.indexOf(c) === -1).join(outerSep); |
| 148 | + } else { |
| 149 | + result.hiddenColumns = hiddenColumns.join(outerSep); |
| 150 | + } |
| 151 | + return result; |
| 152 | +} |
0 commit comments