feat(search): push AttributeFilter list into ClickHouse WHERE clause

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-24 10:13:30 +02:00
parent f9b5f235cc
commit 2dcbd5a772
2 changed files with 76 additions and 2 deletions

View File

@@ -1,6 +1,7 @@
package com.cameleer.server.app.search;
import com.cameleer.server.core.alerting.AlertMatchSpec;
import com.cameleer.server.core.search.AttributeFilter;
import com.cameleer.server.core.search.ExecutionSummary;
import com.cameleer.server.core.search.SearchRequest;
import com.cameleer.server.core.search.SearchResult;
@@ -256,6 +257,23 @@ public class ClickHouseSearchIndex implements SearchIndex {
params.add(likeTerm);
}
// Structured attribute filters. Keys were validated at AttributeFilter construction
// time against ^[a-zA-Z0-9._-]+$ so they are safe to single-quote-inline; the JSON path
// argument of JSONExtractString does not accept a ? placeholder in ClickHouse JDBC
// (same constraint as countExecutionsForAlerting below). Values are parameter-bound.
for (AttributeFilter filter : request.attributeFilters()) {
String escapedKey = filter.key().replace("'", "\\'");
if (filter.isKeyOnly()) {
conditions.add("JSONHas(attributes, '" + escapedKey + "')");
} else if (filter.isWildcard()) {
conditions.add("JSONExtractString(attributes, '" + escapedKey + "') LIKE ?");
params.add(filter.toLikePattern());
} else {
conditions.add("JSONExtractString(attributes, '" + escapedKey + "') = ?");
params.add(filter.value());
}
}
return String.join(" AND ", conditions);
}