@camunda/ccma-shared-types 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_tests/constants/failoverRegionPairs.const.spec.d.ts +1 -0
- package/dist/_tests/search/compiler.spec.d.ts +1 -0
- package/dist/_tests/search/parser.spec.d.ts +1 -0
- package/dist/_tests/search/registry.spec.d.ts +1 -0
- package/dist/_tests/types/ClusterPlanFields.type.spec.d.ts +1 -0
- package/dist/_tests/utils/failoverKeyPolicy.utils.spec.d.ts +1 -0
- package/dist/constants/failoverRegionPairs.const.d.ts +8 -1
- package/dist/constants/failoverRegionPairs.const.js +9 -4
- package/dist/constants/failoverRegionPairs.const.js.map +2 -2
- package/dist/constants/misc.const.d.ts +0 -55
- package/dist/constants/misc.const.js +0 -82
- package/dist/constants/misc.const.js.map +2 -2
- package/dist/dtos/Backup.dto.d.ts +5 -0
- package/dist/dtos/ClusterPlan.dto.d.ts +5 -0
- package/dist/dtos/ClusterPlanType.dto.d.ts +6 -0
- package/dist/dtos/CommonCluster.dto.d.ts +18 -0
- package/dist/dtos/ControlV2.dto.d.ts +62 -14
- package/dist/dtos/K8sContext.dto.d.ts +6 -0
- package/dist/dtos/Organization.dto.d.ts +2 -0
- package/dist/dtos/Organization.dto.js.map +1 -1
- package/dist/dtos/ReleaseTrainSanity.dto.d.ts +51 -0
- package/dist/dtos/ReleaseTrainSanity.dto.js +1 -0
- package/dist/dtos/ReleaseTrainSanity.dto.js.map +7 -0
- package/dist/dtos/SalesPlan.dto.d.ts +11 -0
- package/dist/dtos/SalesPlan.dto.js +14 -0
- package/dist/dtos/SalesPlan.dto.js.map +2 -2
- package/dist/enums/OrganizationRole.enum.d.ts +1 -0
- package/dist/enums/OrganizationRole.enum.js +7 -0
- package/dist/enums/OrganizationRole.enum.js.map +2 -2
- package/dist/enums/SystemAuditEntity.enum.d.ts +7 -2
- package/dist/enums/SystemAuditEntity.enum.js +5 -0
- package/dist/enums/SystemAuditEntity.enum.js.map +2 -2
- package/dist/index.d.ts +8 -2
- package/dist/index.js +48 -2
- package/dist/index.js.map +2 -2
- package/dist/permissions/combo.js +3 -0
- package/dist/permissions/combo.js.map +2 -2
- package/dist/permissions/console.permissions.d.ts +2 -0
- package/dist/permissions/console.permissions.js +7 -0
- package/dist/permissions/console.permissions.js.map +2 -2
- package/dist/search/ast.d.ts +52 -0
- package/dist/search/ast.js +18 -0
- package/dist/search/ast.js.map +7 -0
- package/dist/search/cluster-search-fields.d.ts +11 -0
- package/dist/search/cluster-search-fields.js +136 -0
- package/dist/search/cluster-search-fields.js.map +7 -0
- package/dist/search/compiler.d.ts +48 -0
- package/dist/search/compiler.js +217 -0
- package/dist/search/compiler.js.map +7 -0
- package/dist/search/fields.d.ts +24 -0
- package/dist/search/fields.js +5 -0
- package/dist/search/fields.js.map +7 -0
- package/dist/search/index.d.ts +6 -0
- package/dist/search/index.js +33 -0
- package/dist/search/index.js.map +7 -0
- package/dist/search/organization-search-fields.d.ts +9 -0
- package/dist/search/organization-search-fields.js +50 -0
- package/dist/search/organization-search-fields.js.map +7 -0
- package/dist/search/parser.d.ts +7 -0
- package/dist/search/parser.js +324 -0
- package/dist/search/parser.js.map +7 -0
- package/dist/types/ClusterModification.type.d.ts +1 -0
- package/dist/types/ClusterPlanFields.type.d.ts +24 -0
- package/dist/types/ClusterPlanFields.type.js +591 -0
- package/dist/types/ClusterPlanFields.type.js.map +7 -0
- package/dist/types/ClusterPlanModification.type.d.ts +3 -0
- package/dist/types/EnterpriseIncludingValueMetrics.type.d.ts +1 -0
- package/dist/types/HdpTenantUsage.type.d.ts +4 -0
- package/dist/types/HdpTenantUsage.type.js +1 -0
- package/dist/types/HdpTenantUsage.type.js.map +7 -0
- package/dist/utils/enterpriseTerm.utils.d.ts +78 -0
- package/dist/utils/enterpriseTerm.utils.js +69 -0
- package/dist/utils/enterpriseTerm.utils.js.map +7 -0
- package/dist/utils/enterpriseTerm.utils.spec.d.ts +1 -0
- package/dist/utils/failoverKeyPolicy.utils.d.ts +26 -0
- package/dist/utils/failoverKeyPolicy.utils.js +15 -0
- package/dist/utils/failoverKeyPolicy.utils.js.map +7 -0
- package/package.json +2 -2
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LuceneQueryError
|
|
3
|
+
} from "./ast.js";
|
|
4
|
+
class Compiler {
|
|
5
|
+
constructor(ctx) {
|
|
6
|
+
this.ctx = ctx;
|
|
7
|
+
this.lookup = new Map(
|
|
8
|
+
Object.entries(ctx.bindings).map(([field, binding]) => [
|
|
9
|
+
field.toLowerCase(),
|
|
10
|
+
{ canonical: field, binding }
|
|
11
|
+
])
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
ctx;
|
|
15
|
+
params = {};
|
|
16
|
+
counter = 0;
|
|
17
|
+
/** Lowercased field name → { canonical, binding }, for case-insensitive lookup. */
|
|
18
|
+
lookup;
|
|
19
|
+
compile(node) {
|
|
20
|
+
return { sql: this.node(node), params: this.params };
|
|
21
|
+
}
|
|
22
|
+
node(node) {
|
|
23
|
+
switch (node.kind) {
|
|
24
|
+
case "and":
|
|
25
|
+
return `(${this.node(node.left)} AND ${this.node(node.right)})`;
|
|
26
|
+
case "or":
|
|
27
|
+
return `(${this.node(node.left)} OR ${this.node(node.right)})`;
|
|
28
|
+
case "not":
|
|
29
|
+
return `(NOT ${this.node(node.child)})`;
|
|
30
|
+
case "term":
|
|
31
|
+
return this.term(node);
|
|
32
|
+
case "range":
|
|
33
|
+
return this.range(node);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
term(node) {
|
|
37
|
+
if (node.field === void 0) {
|
|
38
|
+
return this.bareTerm(node.value);
|
|
39
|
+
}
|
|
40
|
+
const { canonical, binding } = this.resolveField(node.field);
|
|
41
|
+
switch (binding.kind) {
|
|
42
|
+
case "string":
|
|
43
|
+
this.requireMatchOperator(canonical, node.operator);
|
|
44
|
+
return this.stringMatch(binding, node.value);
|
|
45
|
+
case "boolean":
|
|
46
|
+
this.requireMatchOperator(canonical, node.operator);
|
|
47
|
+
return `${binding.column} = ${this.bind(this.parseBoolean(canonical, node.value))}`;
|
|
48
|
+
case "nullable":
|
|
49
|
+
this.requireMatchOperator(canonical, node.operator);
|
|
50
|
+
return this.parseBoolean(canonical, node.value) ? `${binding.column} IS NOT NULL` : `${binding.column} IS NULL`;
|
|
51
|
+
case "computed":
|
|
52
|
+
this.requireMatchOperator(canonical, node.operator);
|
|
53
|
+
return this.computedMatch(binding, node.value);
|
|
54
|
+
case "date":
|
|
55
|
+
return this.dateTerm(binding, canonical, node.operator, node.value);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
range(node) {
|
|
59
|
+
const { canonical, binding } = this.resolveField(node.field);
|
|
60
|
+
if (binding.kind !== "date") {
|
|
61
|
+
throw new LuceneQueryError(
|
|
62
|
+
`Field "${canonical}" does not support ranges.`,
|
|
63
|
+
"bad-operator"
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
const lowerOp = node.lowerInclusive ? ">=" : ">";
|
|
67
|
+
const upperOp = node.upperInclusive ? "<=" : "<";
|
|
68
|
+
const lower = this.bind(this.parseDate(canonical, node.lower));
|
|
69
|
+
const upper = this.bind(this.parseDate(canonical, node.upper));
|
|
70
|
+
return `(${binding.column} ${lowerOp} ${lower} AND ${binding.column} ${upperOp} ${upper})`;
|
|
71
|
+
}
|
|
72
|
+
// --- field kinds ----------------------------------------------------------
|
|
73
|
+
bareTerm(value) {
|
|
74
|
+
const clauses = this.ctx.defaultFields.map((field) => {
|
|
75
|
+
const entry = this.lookup.get(field.toLowerCase());
|
|
76
|
+
if (!entry || entry.binding.kind !== "string") {
|
|
77
|
+
throw new Error(
|
|
78
|
+
`Search misconfigured: default field "${field}" must be a string binding.`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
const { column, cast } = entry.binding;
|
|
82
|
+
const target = cast ? `CAST(${column} AS TEXT)` : column;
|
|
83
|
+
return `${target} ILIKE ${this.bind(likeArgument(value, "substring"))}`;
|
|
84
|
+
});
|
|
85
|
+
return clauses.length === 1 ? clauses[0] : `(${clauses.join(" OR ")})`;
|
|
86
|
+
}
|
|
87
|
+
stringMatch(binding, value) {
|
|
88
|
+
const target = binding.cast ? `CAST(${binding.column} AS TEXT)` : binding.column;
|
|
89
|
+
return `${target} ILIKE ${this.bind(likeArgument(value, binding.match))}`;
|
|
90
|
+
}
|
|
91
|
+
computedMatch(binding, value) {
|
|
92
|
+
const ids = binding.resolve(value);
|
|
93
|
+
if (ids.length === 0) {
|
|
94
|
+
return "1 = 0";
|
|
95
|
+
}
|
|
96
|
+
return `${binding.idColumn} IN (${this.bind(ids, true)})`;
|
|
97
|
+
}
|
|
98
|
+
dateTerm(binding, canonical, operator, value) {
|
|
99
|
+
if (operator === ":") {
|
|
100
|
+
const start = this.parseDate(canonical, value);
|
|
101
|
+
const startDay = new Date(
|
|
102
|
+
Date.UTC(
|
|
103
|
+
start.getUTCFullYear(),
|
|
104
|
+
start.getUTCMonth(),
|
|
105
|
+
start.getUTCDate()
|
|
106
|
+
)
|
|
107
|
+
);
|
|
108
|
+
const nextDay = new Date(startDay.getTime() + 24 * 60 * 60 * 1e3);
|
|
109
|
+
return `(${binding.column} >= ${this.bind(startDay.toISOString())} AND ${binding.column} < ${this.bind(nextDay.toISOString())})`;
|
|
110
|
+
}
|
|
111
|
+
const bound = this.parseDate(canonical, value).toISOString();
|
|
112
|
+
return `${binding.column} ${operator} ${this.bind(bound)}`;
|
|
113
|
+
}
|
|
114
|
+
// --- validation helpers ---------------------------------------------------
|
|
115
|
+
resolveField(field) {
|
|
116
|
+
const entry = this.lookup.get(field.toLowerCase());
|
|
117
|
+
if (!entry) {
|
|
118
|
+
const suggestion = closestField(
|
|
119
|
+
field,
|
|
120
|
+
[...this.lookup.values()].map((value) => value.canonical)
|
|
121
|
+
);
|
|
122
|
+
throw new LuceneQueryError(
|
|
123
|
+
`Unknown field "${field}".${suggestion ? ` Did you mean "${suggestion}"?` : ""}`,
|
|
124
|
+
"unknown-field",
|
|
125
|
+
suggestion
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
return entry;
|
|
129
|
+
}
|
|
130
|
+
requireMatchOperator(field, operator) {
|
|
131
|
+
if (operator !== ":") {
|
|
132
|
+
throw new LuceneQueryError(
|
|
133
|
+
`Field "${field}" supports only "field:value", not "${operator}".`,
|
|
134
|
+
"bad-operator"
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
parseBoolean(field, value) {
|
|
139
|
+
const normalized = value.trim().toLowerCase();
|
|
140
|
+
if (normalized === "true") {
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
if (normalized === "false") {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
throw new LuceneQueryError(
|
|
147
|
+
`Field "${field}" expects true or false, got "${value}".`,
|
|
148
|
+
"bad-value"
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
parseDate(field, value) {
|
|
152
|
+
const parsed = new Date(value);
|
|
153
|
+
if (Number.isNaN(parsed.getTime())) {
|
|
154
|
+
throw new LuceneQueryError(
|
|
155
|
+
`Field "${field}" expects a date (e.g. 2024-01-31), got "${value}".`,
|
|
156
|
+
"bad-value"
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
return parsed;
|
|
160
|
+
}
|
|
161
|
+
bind(value, isList = false) {
|
|
162
|
+
const name = `${this.ctx.paramPrefix}_${this.counter++}`;
|
|
163
|
+
this.params[name] = value;
|
|
164
|
+
return isList ? `:...${name}` : `:${name}`;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const compileQuery = (node, ctx) => new Compiler(ctx).compile(node);
|
|
168
|
+
const likeArgument = (value, match) => {
|
|
169
|
+
const escaped = value.replace(/([\\%_])/g, "\\$1");
|
|
170
|
+
if (/[*?]/.test(value)) {
|
|
171
|
+
return escaped.replace(/\*/g, "%").replace(/\?/g, "_");
|
|
172
|
+
}
|
|
173
|
+
return match === "substring" ? `%${escaped}%` : escaped;
|
|
174
|
+
};
|
|
175
|
+
const closestField = (input, candidates) => {
|
|
176
|
+
const needle = input.toLowerCase();
|
|
177
|
+
let best;
|
|
178
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
179
|
+
for (const candidate of candidates) {
|
|
180
|
+
const distance = editDistance(needle, candidate.toLowerCase());
|
|
181
|
+
if (distance < bestDistance) {
|
|
182
|
+
bestDistance = distance;
|
|
183
|
+
best = candidate;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return bestDistance <= 3 ? best : void 0;
|
|
187
|
+
};
|
|
188
|
+
const editDistance = (left, right) => {
|
|
189
|
+
const rows = left.length + 1;
|
|
190
|
+
const cols = right.length + 1;
|
|
191
|
+
const dist = Array.from(
|
|
192
|
+
{ length: rows },
|
|
193
|
+
() => new Array(cols).fill(0)
|
|
194
|
+
);
|
|
195
|
+
for (let row = 0; row < rows; row += 1) {
|
|
196
|
+
dist[row][0] = row;
|
|
197
|
+
}
|
|
198
|
+
for (let col = 0; col < cols; col += 1) {
|
|
199
|
+
dist[0][col] = col;
|
|
200
|
+
}
|
|
201
|
+
for (let row = 1; row < rows; row += 1) {
|
|
202
|
+
for (let col = 1; col < cols; col += 1) {
|
|
203
|
+
const cost = left[row - 1] === right[col - 1] ? 0 : 1;
|
|
204
|
+
dist[row][col] = Math.min(
|
|
205
|
+
dist[row - 1][col] + 1,
|
|
206
|
+
dist[row][col - 1] + 1,
|
|
207
|
+
dist[row - 1][col - 1] + cost
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return dist[rows - 1][cols - 1];
|
|
212
|
+
};
|
|
213
|
+
export {
|
|
214
|
+
compileQuery,
|
|
215
|
+
likeArgument
|
|
216
|
+
};
|
|
217
|
+
//# sourceMappingURL=compiler.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/search/compiler.ts"],
|
|
4
|
+
"sourcesContent": ["/*\n * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH\n * under one or more contributor license agreements. Licensed under a commercial license.\n * You may not use this file except in compliance with the commercial license.\n */\n\nimport {\n LuceneQueryError,\n type QueryNode,\n type RangeNode,\n type SearchTermOperator,\n type TermNode,\n} from './ast.js'\n\n// ============================================================================\n// AST \u2192 parameterized SQL compiler.\n//\n// Entity-agnostic: the backend supplies a per-field {@link FieldBinding} map (the\n// SQL columns / computed resolvers stay backend-side), and this turns a parsed\n// query into a single parameterized SQL string for `qb.andWhere(sql, params)`.\n// Field names are whitelisted against the bindings; every value is a bound\n// parameter; wildcards are escaped \u2014 so a query can never inject SQL.\n// ============================================================================\n\n/** SQL binding for one searchable field (values live backend-side, not in the FE). */\nexport type FieldBinding =\n | {\n kind: 'string'\n /** SQL column expression, e.g. `c.name` or `planType.name`. */\n column: string\n /** Cast the column to text before matching (uuid columns). */\n cast?: boolean\n /** `substring` \u2192 ILIKE %v%; `exact` \u2192 case-insensitive equality. */\n match: 'substring' | 'exact'\n }\n | { kind: 'boolean'; column: string }\n /** Presence/absence of a nullable column (e.g. active-modification FK). */\n | { kind: 'nullable'; column: string }\n | { kind: 'date'; column: string }\n | {\n kind: 'computed'\n /** Column the resolved id set is matched against (e.g. `c.uuid`). */\n idColumn: string\n /** Resolve an equality value to matching ids (in-memory / config). */\n resolve: (value: string) => string[]\n }\n\nexport interface CompileContext {\n /** Field name \u2192 SQL binding. Keys are the whitelisted, canonical field names. */\n bindings: Record<string, FieldBinding>\n /** Fields a bare term ORs over (must be `string` bindings); always substring. */\n defaultFields: readonly string[]\n /** Unique-per-call-site parameter prefix (avoids clashing with other params). */\n paramPrefix: string\n}\n\nexport interface CompiledQuery {\n sql: string\n params: Record<string, unknown>\n}\n\nclass Compiler {\n private readonly params: Record<string, unknown> = {}\n private counter = 0\n /** Lowercased field name \u2192 { canonical, binding }, for case-insensitive lookup. */\n private readonly lookup: Map<\n string,\n { canonical: string; binding: FieldBinding }\n >\n\n constructor(private readonly ctx: CompileContext) {\n this.lookup = new Map(\n Object.entries(ctx.bindings).map(([field, binding]) => [\n field.toLowerCase(),\n { canonical: field, binding },\n ]),\n )\n }\n\n compile(node: QueryNode): CompiledQuery {\n return { sql: this.node(node), params: this.params }\n }\n\n private node(node: QueryNode): string {\n switch (node.kind) {\n case 'and':\n return `(${this.node(node.left)} AND ${this.node(node.right)})`\n case 'or':\n return `(${this.node(node.left)} OR ${this.node(node.right)})`\n case 'not':\n return `(NOT ${this.node(node.child)})`\n case 'term':\n return this.term(node)\n case 'range':\n return this.range(node)\n }\n }\n\n private term(node: TermNode): string {\n if (node.field === undefined) {\n return this.bareTerm(node.value)\n }\n const { canonical, binding } = this.resolveField(node.field)\n switch (binding.kind) {\n case 'string':\n this.requireMatchOperator(canonical, node.operator)\n return this.stringMatch(binding, node.value)\n case 'boolean':\n this.requireMatchOperator(canonical, node.operator)\n return `${binding.column} = ${this.bind(this.parseBoolean(canonical, node.value))}`\n case 'nullable':\n this.requireMatchOperator(canonical, node.operator)\n return this.parseBoolean(canonical, node.value)\n ? `${binding.column} IS NOT NULL`\n : `${binding.column} IS NULL`\n case 'computed':\n this.requireMatchOperator(canonical, node.operator)\n return this.computedMatch(binding, node.value)\n case 'date':\n return this.dateTerm(binding, canonical, node.operator, node.value)\n }\n }\n\n private range(node: RangeNode): string {\n const { canonical, binding } = this.resolveField(node.field)\n if (binding.kind !== 'date') {\n throw new LuceneQueryError(\n `Field \"${canonical}\" does not support ranges.`,\n 'bad-operator',\n )\n }\n const lowerOp = node.lowerInclusive ? '>=' : '>'\n const upperOp = node.upperInclusive ? '<=' : '<'\n const lower = this.bind(this.parseDate(canonical, node.lower))\n const upper = this.bind(this.parseDate(canonical, node.upper))\n return `(${binding.column} ${lowerOp} ${lower} AND ${binding.column} ${upperOp} ${upper})`\n }\n\n // --- field kinds ----------------------------------------------------------\n\n private bareTerm(value: string): string {\n const clauses = this.ctx.defaultFields.map((field) => {\n const entry = this.lookup.get(field.toLowerCase())\n if (!entry || entry.binding.kind !== 'string') {\n // A server-side registry/binding bug, not a bad query \u2014 throw a plain\n // Error so the routers surface it as a 5xx, never a 400.\n throw new Error(\n `Search misconfigured: default field \"${field}\" must be a string binding.`,\n )\n }\n const { column, cast } = entry.binding\n const target = cast ? `CAST(${column} AS TEXT)` : column\n return `${target} ILIKE ${this.bind(likeArgument(value, 'substring'))}`\n })\n return clauses.length === 1 ? clauses[0] : `(${clauses.join(' OR ')})`\n }\n\n private stringMatch(\n binding: Extract<FieldBinding, { kind: 'string' }>,\n value: string,\n ): string {\n const target = binding.cast\n ? `CAST(${binding.column} AS TEXT)`\n : binding.column\n return `${target} ILIKE ${this.bind(likeArgument(value, binding.match))}`\n }\n\n private computedMatch(\n binding: Extract<FieldBinding, { kind: 'computed' }>,\n value: string,\n ): string {\n const ids = binding.resolve(value)\n if (ids.length === 0) {\n // No entity matches this value \u2014 a guaranteed-false predicate (a\n // surrounding NOT correctly flips it to all-rows).\n return '1 = 0'\n }\n return `${binding.idColumn} IN (${this.bind(ids, true)})`\n }\n\n private dateTerm(\n binding: Extract<FieldBinding, { kind: 'date' }>,\n canonical: string,\n operator: SearchTermOperator,\n value: string,\n ): string {\n if (operator === ':') {\n // Equality on a date means \"that calendar day\" (UTC): [day, nextDay).\n const start = this.parseDate(canonical, value)\n const startDay = new Date(\n Date.UTC(\n start.getUTCFullYear(),\n start.getUTCMonth(),\n start.getUTCDate(),\n ),\n )\n const nextDay = new Date(startDay.getTime() + 24 * 60 * 60 * 1000)\n return `(${binding.column} >= ${this.bind(startDay.toISOString())} AND ${binding.column} < ${this.bind(nextDay.toISOString())})`\n }\n const bound = this.parseDate(canonical, value).toISOString()\n return `${binding.column} ${operator} ${this.bind(bound)}`\n }\n\n // --- validation helpers ---------------------------------------------------\n\n private resolveField(field: string): {\n canonical: string\n binding: FieldBinding\n } {\n const entry = this.lookup.get(field.toLowerCase())\n if (!entry) {\n const suggestion = closestField(\n field,\n [...this.lookup.values()].map((value) => value.canonical),\n )\n throw new LuceneQueryError(\n `Unknown field \"${field}\".${suggestion ? ` Did you mean \"${suggestion}\"?` : ''}`,\n 'unknown-field',\n suggestion,\n )\n }\n return entry\n }\n\n private requireMatchOperator(\n field: string,\n operator: SearchTermOperator,\n ): void {\n if (operator !== ':') {\n throw new LuceneQueryError(\n `Field \"${field}\" supports only \"field:value\", not \"${operator}\".`,\n 'bad-operator',\n )\n }\n }\n\n private parseBoolean(field: string, value: string): boolean {\n const normalized = value.trim().toLowerCase()\n if (normalized === 'true') {\n return true\n }\n if (normalized === 'false') {\n return false\n }\n throw new LuceneQueryError(\n `Field \"${field}\" expects true or false, got \"${value}\".`,\n 'bad-value',\n )\n }\n\n private parseDate(field: string, value: string): Date {\n const parsed = new Date(value)\n if (Number.isNaN(parsed.getTime())) {\n throw new LuceneQueryError(\n `Field \"${field}\" expects a date (e.g. 2024-01-31), got \"${value}\".`,\n 'bad-value',\n )\n }\n return parsed\n }\n\n private bind(value: unknown, isList = false): string {\n const name = `${this.ctx.paramPrefix}_${this.counter++}`\n this.params[name] = value\n return isList ? `:...${name}` : `:${name}`\n }\n}\n\n/** Compile a parsed query into a single parameterized SQL fragment. */\nexport const compileQuery = (\n node: QueryNode,\n ctx: CompileContext,\n): CompiledQuery => new Compiler(ctx).compile(node)\n\n/**\n * Turn a user value into an ILIKE argument: SQL wildcards (`%`, `_`, `\\`) are\n * escaped to literals, then the user's `*`/`?` become `%`/`_`; a plain\n * substring value is wrapped in `%\u2026%`.\n */\nexport const likeArgument = (\n value: string,\n match: 'substring' | 'exact',\n): string => {\n const escaped = value.replace(/([\\\\%_])/g, '\\\\$1')\n if (/[*?]/.test(value)) {\n return escaped.replace(/\\*/g, '%').replace(/\\?/g, '_')\n }\n return match === 'substring' ? `%${escaped}%` : escaped\n}\n\n/** Closest field name within edit distance 3, for \"did you mean\u2026\" hints. */\nconst closestField = (\n input: string,\n candidates: readonly string[],\n): string | undefined => {\n const needle = input.toLowerCase()\n let best: string | undefined\n let bestDistance = Number.POSITIVE_INFINITY\n for (const candidate of candidates) {\n const distance = editDistance(needle, candidate.toLowerCase())\n if (distance < bestDistance) {\n bestDistance = distance\n best = candidate\n }\n }\n return bestDistance <= 3 ? best : undefined\n}\n\n/** Standard Levenshtein distance. */\nconst editDistance = (left: string, right: string): number => {\n const rows = left.length + 1\n const cols = right.length + 1\n const dist = Array.from({ length: rows }, () =>\n new Array<number>(cols).fill(0),\n )\n for (let row = 0; row < rows; row += 1) {\n dist[row][0] = row\n }\n for (let col = 0; col < cols; col += 1) {\n dist[0][col] = col\n }\n for (let row = 1; row < rows; row += 1) {\n for (let col = 1; col < cols; col += 1) {\n const cost = left[row - 1] === right[col - 1] ? 0 : 1\n dist[row][col] = Math.min(\n dist[row - 1][col] + 1,\n dist[row][col - 1] + 1,\n dist[row - 1][col - 1] + cost,\n )\n }\n }\n return dist[rows - 1][cols - 1]\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** How a field's values are typed — drives which operators are valid. */
|
|
2
|
+
export type SearchFieldType = 'string' | 'enum' | 'boolean' | 'date';
|
|
3
|
+
/**
|
|
4
|
+
* Comparison capabilities a field offers, shown in the help popover. `match`
|
|
5
|
+
* covers `:` (equality / substring / wildcard); `range` covers comparison and
|
|
6
|
+
* `[a TO b]` operators (dates only in v1).
|
|
7
|
+
*/
|
|
8
|
+
export type SearchFieldCapability = 'match' | 'range';
|
|
9
|
+
export interface SearchFieldSpec {
|
|
10
|
+
/** Field name as typed in a query, e.g. `plan`. */
|
|
11
|
+
field: string;
|
|
12
|
+
/** Human label for the help popover. */
|
|
13
|
+
label: string;
|
|
14
|
+
/** One-line description of what the field matches. */
|
|
15
|
+
description: string;
|
|
16
|
+
type: SearchFieldType;
|
|
17
|
+
capabilities: SearchFieldCapability[];
|
|
18
|
+
/** For `enum` fields: the allowed values (also used for value hints). */
|
|
19
|
+
enumValues?: string[];
|
|
20
|
+
/** A copy-pasteable example clause, e.g. `plan:Trial`. */
|
|
21
|
+
example: string;
|
|
22
|
+
}
|
|
23
|
+
/** Look up a field spec by name (case-insensitive), or `undefined`. */
|
|
24
|
+
export declare const findSearchField: (fields: readonly SearchFieldSpec[], name: string) => SearchFieldSpec | undefined;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/search/fields.ts"],
|
|
4
|
+
"sourcesContent": ["/*\n * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH\n * under one or more contributor license agreements. Licensed under a commercial license.\n * You may not use this file except in compliance with the commercial license.\n */\n\n// ============================================================================\n// Searchable-field metadata (Control table search).\n//\n// The single source of truth for \"which fields can a query use, and how\". This\n// is deliberately pure metadata \u2014 no SQL, no resolvers \u2014 so the frontend can\n// import it to power the search-help popover and value hints, while each backend\n// pairs it with its own SQL bindings (see the compiler) to build the query.\n//\n// v1 exposes exactly the fields the orgs/clusters `/v2` list endpoints already\n// support as structured filters, now expressible with operators the dropdown\n// filters can't (ranges, OR, negation).\n// ============================================================================\n\n/** How a field's values are typed \u2014 drives which operators are valid. */\nexport type SearchFieldType = 'string' | 'enum' | 'boolean' | 'date'\n\n/**\n * Comparison capabilities a field offers, shown in the help popover. `match`\n * covers `:` (equality / substring / wildcard); `range` covers comparison and\n * `[a TO b]` operators (dates only in v1).\n */\nexport type SearchFieldCapability = 'match' | 'range'\n\nexport interface SearchFieldSpec {\n /** Field name as typed in a query, e.g. `plan`. */\n field: string\n /** Human label for the help popover. */\n label: string\n /** One-line description of what the field matches. */\n description: string\n type: SearchFieldType\n capabilities: SearchFieldCapability[]\n /** For `enum` fields: the allowed values (also used for value hints). */\n enumValues?: string[]\n /** A copy-pasteable example clause, e.g. `plan:Trial`. */\n example: string\n}\n\n/** Look up a field spec by name (case-insensitive), or `undefined`. */\nexport const findSearchField = (\n fields: readonly SearchFieldSpec[],\n name: string,\n): SearchFieldSpec | undefined =>\n fields.find((spec) => spec.field.toLowerCase() === name.toLowerCase())\n"],
|
|
5
|
+
"mappings": "AA6CO,MAAM,kBAAkB,CAC7B,QACA,SAEA,OAAO,KAAK,CAAC,SAAS,KAAK,MAAM,YAAY,MAAM,KAAK,YAAY,CAAC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { type AndNode, isLuceneQueryError, LuceneQueryError, type NotNode, type OrNode, type QueryNode, type RangeNode, type SearchTermOperator, type TermNode, } from './ast.js';
|
|
2
|
+
export { CLUSTER_DEFAULT_SEARCH_FIELDS, CLUSTER_SEARCH_FIELDS, } from './cluster-search-fields.js';
|
|
3
|
+
export { type CompileContext, type CompiledQuery, compileQuery, type FieldBinding, likeArgument, } from './compiler.js';
|
|
4
|
+
export { findSearchField, type SearchFieldCapability, type SearchFieldSpec, type SearchFieldType, } from './fields.js';
|
|
5
|
+
export { ORG_DEFAULT_SEARCH_FIELDS, ORGANIZATION_SEARCH_FIELDS, } from './organization-search-fields.js';
|
|
6
|
+
export { parseLuceneQuery } from './parser.js';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isLuceneQueryError,
|
|
3
|
+
LuceneQueryError
|
|
4
|
+
} from "./ast.js";
|
|
5
|
+
import {
|
|
6
|
+
CLUSTER_DEFAULT_SEARCH_FIELDS,
|
|
7
|
+
CLUSTER_SEARCH_FIELDS
|
|
8
|
+
} from "./cluster-search-fields.js";
|
|
9
|
+
import {
|
|
10
|
+
compileQuery,
|
|
11
|
+
likeArgument
|
|
12
|
+
} from "./compiler.js";
|
|
13
|
+
import {
|
|
14
|
+
findSearchField
|
|
15
|
+
} from "./fields.js";
|
|
16
|
+
import {
|
|
17
|
+
ORG_DEFAULT_SEARCH_FIELDS,
|
|
18
|
+
ORGANIZATION_SEARCH_FIELDS
|
|
19
|
+
} from "./organization-search-fields.js";
|
|
20
|
+
import { parseLuceneQuery } from "./parser.js";
|
|
21
|
+
export {
|
|
22
|
+
CLUSTER_DEFAULT_SEARCH_FIELDS,
|
|
23
|
+
CLUSTER_SEARCH_FIELDS,
|
|
24
|
+
LuceneQueryError,
|
|
25
|
+
ORGANIZATION_SEARCH_FIELDS,
|
|
26
|
+
ORG_DEFAULT_SEARCH_FIELDS,
|
|
27
|
+
compileQuery,
|
|
28
|
+
findSearchField,
|
|
29
|
+
isLuceneQueryError,
|
|
30
|
+
likeArgument,
|
|
31
|
+
parseLuceneQuery
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/search/index.ts"],
|
|
4
|
+
"sourcesContent": ["/*\n * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH\n * under one or more contributor license agreements. Licensed under a commercial license.\n * You may not use this file except in compliance with the commercial license.\n */\n\nexport {\n type AndNode,\n isLuceneQueryError,\n LuceneQueryError,\n type NotNode,\n type OrNode,\n type QueryNode,\n type RangeNode,\n type SearchTermOperator,\n type TermNode,\n} from './ast.js'\nexport {\n CLUSTER_DEFAULT_SEARCH_FIELDS,\n CLUSTER_SEARCH_FIELDS,\n} from './cluster-search-fields.js'\nexport {\n type CompileContext,\n type CompiledQuery,\n compileQuery,\n type FieldBinding,\n likeArgument,\n} from './compiler.js'\nexport {\n findSearchField,\n type SearchFieldCapability,\n type SearchFieldSpec,\n type SearchFieldType,\n} from './fields.js'\nexport {\n ORG_DEFAULT_SEARCH_FIELDS,\n ORGANIZATION_SEARCH_FIELDS,\n} from './organization-search-fields.js'\nexport { parseLuceneQuery } from './parser.js'\n"],
|
|
5
|
+
"mappings": "AAMA;AAAA,EAEE;AAAA,EACA;AAAA,OAOK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP;AAAA,EAGE;AAAA,EAEA;AAAA,OACK;AACP;AAAA,EACE;AAAA,OAIK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,wBAAwB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SearchFieldSpec } from './fields.js';
|
|
2
|
+
/**
|
|
3
|
+
* Searchable fields for the Organizations list (mirrors
|
|
4
|
+
* `ListOrganizationsV2Params.filter` — the fields the endpoint already filters
|
|
5
|
+
* on). A bare term (no `field:`) searches {@link ORG_DEFAULT_SEARCH_FIELDS}.
|
|
6
|
+
*/
|
|
7
|
+
export declare const ORGANIZATION_SEARCH_FIELDS: readonly SearchFieldSpec[];
|
|
8
|
+
/** Fields a bare term searches for orgs (name or id substring — matches `q`). */
|
|
9
|
+
export declare const ORG_DEFAULT_SEARCH_FIELDS: readonly ["name", "id"];
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { SalesPlanType } from "../types/SalesPlanType.type.js";
|
|
2
|
+
const ORGANIZATION_SEARCH_FIELDS = [
|
|
3
|
+
{
|
|
4
|
+
field: "name",
|
|
5
|
+
label: "Name",
|
|
6
|
+
description: "Organization name (substring match; supports * and ?).",
|
|
7
|
+
type: "string",
|
|
8
|
+
capabilities: ["match"],
|
|
9
|
+
example: "name:acme"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
field: "id",
|
|
13
|
+
label: "ID",
|
|
14
|
+
description: "Organization UUID (substring match).",
|
|
15
|
+
type: "string",
|
|
16
|
+
capabilities: ["match"],
|
|
17
|
+
example: "id:2f1a"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
field: "internal",
|
|
21
|
+
label: "Internal",
|
|
22
|
+
description: "Whether the organization is Camunda-internal.",
|
|
23
|
+
type: "boolean",
|
|
24
|
+
capabilities: ["match"],
|
|
25
|
+
example: "internal:true"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
field: "salesPlanType",
|
|
29
|
+
label: "Sales plan",
|
|
30
|
+
description: "The organization\u2019s sales-plan type.",
|
|
31
|
+
type: "enum",
|
|
32
|
+
capabilities: ["match"],
|
|
33
|
+
enumValues: Object.values(SalesPlanType),
|
|
34
|
+
example: "salesPlanType:enterprise"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
field: "created",
|
|
38
|
+
label: "Created",
|
|
39
|
+
description: "Creation date (ISO, e.g. 2024-01-31). Supports ranges.",
|
|
40
|
+
type: "date",
|
|
41
|
+
capabilities: ["match", "range"],
|
|
42
|
+
example: "created:>2024-01-01"
|
|
43
|
+
}
|
|
44
|
+
];
|
|
45
|
+
const ORG_DEFAULT_SEARCH_FIELDS = ["name", "id"];
|
|
46
|
+
export {
|
|
47
|
+
ORGANIZATION_SEARCH_FIELDS,
|
|
48
|
+
ORG_DEFAULT_SEARCH_FIELDS
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=organization-search-fields.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/search/organization-search-fields.ts"],
|
|
4
|
+
"sourcesContent": ["/*\n * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH\n * under one or more contributor license agreements. Licensed under a commercial license.\n * You may not use this file except in compliance with the commercial license.\n */\n\nimport { SalesPlanType } from '../types/SalesPlanType.type.js'\nimport type { SearchFieldSpec } from './fields.js'\n\n/**\n * Searchable fields for the Organizations list (mirrors\n * `ListOrganizationsV2Params.filter` \u2014 the fields the endpoint already filters\n * on). A bare term (no `field:`) searches {@link ORG_DEFAULT_SEARCH_FIELDS}.\n */\nexport const ORGANIZATION_SEARCH_FIELDS: readonly SearchFieldSpec[] = [\n {\n field: 'name',\n label: 'Name',\n description: 'Organization name (substring match; supports * and ?).',\n type: 'string',\n capabilities: ['match'],\n example: 'name:acme',\n },\n {\n field: 'id',\n label: 'ID',\n description: 'Organization UUID (substring match).',\n type: 'string',\n capabilities: ['match'],\n example: 'id:2f1a',\n },\n {\n field: 'internal',\n label: 'Internal',\n description: 'Whether the organization is Camunda-internal.',\n type: 'boolean',\n capabilities: ['match'],\n example: 'internal:true',\n },\n {\n field: 'salesPlanType',\n label: 'Sales plan',\n description: 'The organization\u2019s sales-plan type.',\n type: 'enum',\n capabilities: ['match'],\n enumValues: Object.values(SalesPlanType),\n example: 'salesPlanType:enterprise',\n },\n {\n field: 'created',\n label: 'Created',\n description: 'Creation date (ISO, e.g. 2024-01-31). Supports ranges.',\n type: 'date',\n capabilities: ['match', 'range'],\n example: 'created:>2024-01-01',\n },\n] as const\n\n/** Fields a bare term searches for orgs (name or id substring \u2014 matches `q`). */\nexport const ORG_DEFAULT_SEARCH_FIELDS = ['name', 'id'] as const\n"],
|
|
5
|
+
"mappings": "AAMA,SAAS,qBAAqB;AAQvB,MAAM,6BAAyD;AAAA,EACpE;AAAA,IACE,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,cAAc,CAAC,OAAO;AAAA,IACtB,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,cAAc,CAAC,OAAO;AAAA,IACtB,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,cAAc,CAAC,OAAO;AAAA,IACtB,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,cAAc,CAAC,OAAO;AAAA,IACtB,YAAY,OAAO,OAAO,aAAa;AAAA,IACvC,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,cAAc,CAAC,SAAS,OAAO;AAAA,IAC/B,SAAS;AAAA,EACX;AACF;AAGO,MAAM,4BAA4B,CAAC,QAAQ,IAAI;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type QueryNode } from './ast.js';
|
|
2
|
+
/**
|
|
3
|
+
* Parse a Lucene-subset query into an AST. Returns `undefined` for an empty or
|
|
4
|
+
* whitespace-only query (a no-op filter). Throws {@link LuceneQueryError} on any
|
|
5
|
+
* syntax problem.
|
|
6
|
+
*/
|
|
7
|
+
export declare const parseLuceneQuery: (input: string) => QueryNode | undefined;
|