Implement API to retrieve all dimensional test results for a dimensional column (#24255)

This commit is contained in:
IceS2 2025-11-11 00:09:28 +01:00 committed by GitHub
parent 9ad6783a99
commit bbd0ce1334
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 58 additions and 4 deletions

View File

@ -7,10 +7,12 @@ CREATE TABLE IF NOT EXISTS test_case_dimension_results_time_series (
id VARCHAR(36) GENERATED ALWAYS AS (json_unquote(json_extract(json,'$.id'))) STORED NOT NULL,
testCaseResultId VARCHAR(36) GENERATED ALWAYS AS (json_unquote(json_extract(json,'$.testCaseResultId'))) STORED NOT NULL,
dimensionKey VARCHAR(512) GENERATED ALWAYS AS (json_unquote(json_extract(json,'$.dimensionKey'))) STORED NOT NULL,
dimensionName VARCHAR(256) GENERATED ALWAYS AS (SUBSTRING_INDEX(json_unquote(json_extract(json,'$.dimensionKey')), '=', 1)) STORED,
timestamp BIGINT UNSIGNED GENERATED ALWAYS AS (json_unquote(json_extract(json,'$.timestamp'))) STORED NOT NULL,
testCaseStatus VARCHAR(36) GENERATED ALWAYS AS (json_unquote(json_extract(json,'$.testCaseStatus'))) STORED,
UNIQUE KEY test_case_dimension_results_unique_constraint (entityFQNHash, dimensionKey, timestamp),
INDEX test_case_dimension_results_main (entityFQNHash, timestamp, dimensionKey),
INDEX test_case_dimension_results_dimension_name (entityFQNHash, dimensionName, timestamp),
INDEX test_case_dimension_results_result_id (testCaseResultId),
INDEX test_case_dimension_results_ts (timestamp)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

View File

@ -7,6 +7,7 @@ CREATE TABLE IF NOT EXISTS test_case_dimension_results_time_series (
id VARCHAR(36) GENERATED ALWAYS AS (json ->> 'id') STORED NOT NULL,
testCaseResultId VARCHAR(36) GENERATED ALWAYS AS (json ->> 'testCaseResultId') STORED NOT NULL,
dimensionKey VARCHAR(512) GENERATED ALWAYS AS (json ->> 'dimensionKey') STORED NOT NULL,
dimensionName VARCHAR(256) GENERATED ALWAYS AS (SPLIT_PART(json ->> 'dimensionKey', '=', 1)) STORED,
timestamp BIGINT GENERATED ALWAYS AS ((json ->> 'timestamp')::bigint) STORED NOT NULL,
testCaseStatus VARCHAR(36) GENERATED ALWAYS AS (json ->> 'testCaseStatus') STORED,
CONSTRAINT test_case_dimension_results_unique_constraint UNIQUE (entityFQNHash, dimensionKey, timestamp)
@ -14,6 +15,7 @@ CREATE TABLE IF NOT EXISTS test_case_dimension_results_time_series (
-- Create indexes
CREATE INDEX IF NOT EXISTS test_case_dimension_results_main ON test_case_dimension_results_time_series (entityFQNHash, timestamp, dimensionKey);
CREATE INDEX IF NOT EXISTS test_case_dimension_results_dimension_name ON test_case_dimension_results_time_series (entityFQNHash, dimensionName, timestamp);
CREATE INDEX IF NOT EXISTS test_case_dimension_results_result_id ON test_case_dimension_results_time_series (testCaseResultId);
CREATE INDEX IF NOT EXISTS test_case_dimension_results_ts ON test_case_dimension_results_time_series (timestamp);
-- Add impersonatedBy column to all entity tables for tracking bot impersonation

View File

@ -6886,6 +6886,16 @@ public interface CollectionDAO {
@Bind("startTs") Long startTs,
@Bind("endTs") Long endTs);
@SqlQuery(
"SELECT json FROM test_case_dimension_results_time_series "
+ "WHERE entityFQNHash = :testCaseFQN AND dimensionName = :dimensionName AND timestamp >= :startTs AND timestamp <= :endTs "
+ "ORDER BY timestamp DESC")
List<String> listTestCaseDimensionResultsByDimensionName(
@BindFQN("testCaseFQN") String testCaseFQN,
@Bind("dimensionName") String dimensionName,
@Bind("startTs") Long startTs,
@Bind("endTs") Long endTs);
@SqlQuery(
"SELECT DISTINCT dimensionKey FROM test_case_dimension_results_time_series "
+ "WHERE entityFQNHash = :testCaseFQN AND timestamp >= :startTs AND timestamp <= :endTs")

View File

@ -36,9 +36,14 @@ public class TestCaseDimensionResultRepository
* @param startTs Start timestamp (optional)
* @param endTs End timestamp (optional)
* @param dimensionalityKey Optional filter by specific dimension key
* @param dimensionName Optional filter by dimension name
*/
public ResultList<TestCaseDimensionResult> listDimensionResults(
String testCaseFQN, Long startTs, Long endTs, String dimensionalityKey) {
String testCaseFQN,
Long startTs,
Long endTs,
String dimensionalityKey,
String dimensionName) {
startTs = Optional.ofNullable(startTs).orElse(Long.MIN_VALUE);
endTs = Optional.ofNullable(endTs).orElse(Long.MAX_VALUE);
@ -51,6 +56,13 @@ public class TestCaseDimensionResultRepository
dimensionResultDao.listTestCaseDimensionResultsByKey(
testCaseFQN, dimensionalityKey, startTs, endTs),
TestCaseDimensionResult.class);
} else if (dimensionName != null && !dimensionName.isEmpty()) {
// Filter by dimension name
results =
JsonUtils.readObjects(
dimensionResultDao.listTestCaseDimensionResultsByDimensionName(
testCaseFQN, dimensionName, startTs, endTs),
TestCaseDimensionResult.class);
} else {
// Get all dimension results
results =

View File

@ -67,7 +67,8 @@ public class TestCaseDimensionResultResource
"Get a list of dimensional results for a specific test case. "
+ "Results can be filtered by time range and specific dimension values. "
+ "Use `startTs` and `endTs` to filter results within a time range. "
+ "Use `dimensionalityKey` to filter results for a specific dimension value combination.",
+ "Use `dimensionalityKey` to filter results for a specific dimension value combination. "
+ "Use `dimensionName` to filter results for all values of a specific dimension (e.g., 'column' to get all column dimension results).",
responses = {
@ApiResponse(
responseCode = "200",
@ -99,7 +100,13 @@ public class TestCaseDimensionResultResource
description = "Filter by specific dimension key (e.g., 'column=address')",
schema = @Schema(type = "string"))
@QueryParam("dimensionalityKey")
String dimensionalityKey)
String dimensionalityKey,
@Parameter(
description =
"Filter by dimension name (e.g., 'column' to get all column dimension results)",
schema = @Schema(type = "string"))
@QueryParam("dimensionName")
String dimensionName)
throws IOException {
TestCase testCase = getTestCase(testCaseFQN);
ResourceContextInterface testCaseResourceContext =
@ -119,7 +126,8 @@ public class TestCaseDimensionResultResource
new AuthRequest(entityOperationContext, entityResourceContext));
authorizer.authorizeRequests(securityContext, authRequests, AuthorizationLogic.ANY);
return repository.listDimensionResults(testCaseFQN, startTs, endTs, dimensionalityKey);
return repository.listDimensionResults(
testCaseFQN, startTs, endTs, dimensionalityKey, dimensionName);
}
@GET

View File

@ -4483,6 +4483,26 @@ public class TestCaseResourceTest extends EntityResourceTest<TestCase, CreateTes
assertTrue(dimensions.containsKey("column"));
assertEquals(3, dimensions.get("column").size());
assertTrue(dimensions.get("column").containsAll(List.of("address", "email", "phone")));
// Test 5: Filter by dimension name (all column results regardless of value)
target =
getResource("dataQuality/testCases/dimensionResults")
.path("/" + testCase.getFullyQualifiedName())
.queryParam("dimensionName", "column");
response = SecurityUtil.addHeaders(target, ADMIN_AUTH_HEADERS).get();
assertEquals(OK.getStatusCode(), response.getStatus());
json = response.readEntity(String.class);
ResultList<TestCaseDimensionResult> columnDimensionResults =
JsonUtils.readValue(
json,
new com.fasterxml.jackson.core.type.TypeReference<
ResultList<TestCaseDimensionResult>>() {});
assertEquals(9, columnDimensionResults.getData().size()); // All 3 days × 3 columns
assertTrue(
columnDimensionResults.getData().stream()
.allMatch(r -> r.getDimensionKey().startsWith("column=")));
}
@Test