mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2026-01-04 19:37:48 +00:00
Implement API to retrieve all dimensional test results for a dimensional column (#24255)
This commit is contained in:
parent
9ad6783a99
commit
bbd0ce1334
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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 =
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user