diff --git a/v1.13.x/api-reference/data-quality/test-cases/create.mdx b/v1.13.x/api-reference/data-quality/test-cases/create.mdx
index 888bb4bb..78661b7c 100644
--- a/v1.13.x/api-reference/data-quality/test-cases/create.mdx
+++ b/v1.13.x/api-reference/data-quality/test-cases/create.mdx
@@ -18,7 +18,7 @@ The server associates the test case with the basic suite of the table in `entity
- Fully qualified name (FQN) of the test definition to use. For example, `columnValueMaxToBeBetween`.
+ Fully qualified name (FQN) of the test definition to use. For example, `columnValueMaxToBeBetween`. For a custom SQL test (the **Custom SQL Query** test type in the UI), use `tableCustomSQLQuery`. For a test case on a custom test definition you created, use that definition's name, such as `columnValuesMaxLength`. For more information, see [Custom SQL Test Cases](#custom-sql-test-cases).
@@ -140,6 +140,39 @@ curl -X POST "{base_url}/api/v1/dataQuality/testCases" \
"description": "Validates shop_id max value stays between 1 and 100"
}'
```
+
+```bash POST /v1/dataQuality/testCases (custom SQL)
+curl -X POST "{base_url}/api/v1/dataQuality/testCases" \
+ -H "Authorization: Bearer {access_token}" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "name": "orders_no_negative_amounts",
+ "testDefinition": "tableCustomSQLQuery",
+ "entityLink": "<#E::table::sample_data.ecommerce_db.shopify.orders>",
+ "parameterValues": [
+ {"name": "sqlExpression", "value": "SELECT * FROM orders WHERE amount < 0"},
+ {"name": "strategy", "value": "ROWS"},
+ {"name": "operator", "value": "=="},
+ {"name": "threshold", "value": "0"}
+ ],
+ "computePassedFailedRowCount": true
+ }'
+```
+
+```bash POST /v1/dataQuality/testCases (custom test definition)
+curl -X POST "{base_url}/api/v1/dataQuality/testCases" \
+ -H "Authorization: Bearer {access_token}" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "name": "email_max_length",
+ "testDefinition": "columnValuesMaxLength",
+ "entityLink": "<#E::table::sample_data.ecommerce_db.shopify.dim_address::columns::email>",
+ "parameterValues": [
+ {"name": "maxLength", "value": "50"}
+ ],
+ "computePassedFailedRowCount": true
+ }'
+```
@@ -294,8 +327,15 @@ curl -X PUT "{base_url}/api/v1/dataQuality/testCases" \
## Custom SQL Test Cases
+OpenMetadata has two ways to run SQL in a test case:
+
+- **Custom SQL test**: the **Custom SQL Query** test type in the UI. The test case uses the built-in `tableCustomSQLQuery` test definition and carries the SQL itself in `parameterValues`. You don't create a test definition.
+- **Custom test definition**: a reusable SQL template you create once, with `{{ paramName }}` placeholders. Test cases then reference it by name. For more information, see [Test Cases for a Custom Test Definition](#test-cases-for-a-custom-test-definition).
+
A test case passes values to a SQL-based test definition through `parameterValues`. The server rejects any parameter that the test definition doesn't declare in `parameterDefinition`, and requires every parameter marked `required`.
+### Custom SQL Test
+
The built-in `tableCustomSQLQuery` test definition runs a SQL query against a table. It accepts these parameters:
| Parameter | Required | Description |
@@ -316,13 +356,37 @@ curl -X POST "{base_url}/api/v1/dataQuality/testCases" \
"entityLink": "<#E::table::sample_data.ecommerce_db.shopify.orders>",
"parameterValues": [
{"name": "sqlExpression", "value": "SELECT * FROM orders WHERE amount < 0"},
- {"name": "strategy", "value": "ROWS"}
+ {"name": "strategy", "value": "ROWS"},
+ {"name": "operator", "value": "=="},
+ {"name": "threshold", "value": "0"}
+ ],
+ "computePassedFailedRowCount": true
+ }'
+```
+
+### Test Cases for a Custom Test Definition
+
+A test case for a custom SQL test definition sets `testDefinition` to the definition's name and passes one `parameterValues` entry per `{{ paramName }}` placeholder. The following request uses a custom `columnValuesMaxLength` definition, which declares `maxLength`:
+
+```bash
+curl -X POST "{base_url}/api/v1/dataQuality/testCases" \
+ -H "Authorization: Bearer {access_token}" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "name": "email_max_length",
+ "testDefinition": "columnValuesMaxLength",
+ "entityLink": "<#E::table::sample_data.ecommerce_db.shopify.dim_address::columns::email>",
+ "parameterValues": [
+ {"name": "maxLength", "value": "50"}
],
"computePassedFailedRowCount": true
}'
```
-For a custom test definition that uses `{{ paramName }}` placeholders, pass one `parameterValues` entry per placeholder. For more information, see [Create a Test Definition](/v1.13.x/api-reference/data-quality/test-definitions/create#custom-sql-test-definitions).
+- **Pass condition**: The test case passes only when the number of rows the SQL returns is 0.
+- **Row counts**: Set `computePassedFailedRowCount` to `true` to report passed and failed row counts.
+
+For more information, see [Create a Test Definition](/v1.13.x/api-reference/data-quality/test-definitions/create#custom-sql-test-definitions).
## Error Handling
diff --git a/v1.13.x/api-reference/data-quality/test-definitions/create.mdx b/v1.13.x/api-reference/data-quality/test-definitions/create.mdx
index 7ff8a65a..80effe97 100644
--- a/v1.13.x/api-reference/data-quality/test-definitions/create.mdx
+++ b/v1.13.x/api-reference/data-quality/test-definitions/create.mdx
@@ -68,7 +68,12 @@ Create a custom test definition to define organization-specific data quality val
- Name of the validator that runs the test. For custom SQL-based tests, defaults to `ruleLibrarySqlExpressionValidator` when omitted.
+ Class name of the validator that runs the test. For a custom SQL test definition, set one of the following values. The OpenMetadata UI sets the same values when you create a custom SQL test definition:
+
+ - `ColumnRuleLibrarySqlExpressionValidator`: use when `entityType` is `COLUMN`.
+ - `TableRuleLibrarySqlExpressionValidator`: use when `entityType` is `TABLE`.
+
+ Built-in test definitions use their own validators, which you can't select for a custom definition. The server accepts any string for this field, so always set it explicitly for SQL-based definitions.
@@ -113,24 +118,21 @@ configure(
)
request = CreateTestDefinitionRequest(
- name="columnValuesToMatchBusinessRule",
- displayName="Column Values To Match Business Rule",
- description="Validates that column values conform to a custom business rule regex pattern",
+ name="columnValuesMaxLength",
+ displayName="Column Values Max Length",
+ description="Fails when a value is longer than the allowed length",
entityType="COLUMN",
testPlatforms=["OpenMetadata"],
+ dataQualityDimension="SQL",
supportedDataTypes=["STRING", "VARCHAR", "TEXT"],
+ sqlExpression="SELECT * FROM {{ table_name }} WHERE LENGTH({{ column_name }}) > {{ maxLength }}",
+ validatorClass="ColumnRuleLibrarySqlExpressionValidator",
parameterDefinition=[
{
- "name": "regexPattern",
- "dataType": "STRING",
- "required": True,
- "description": "The regex pattern to match against"
- },
- {
- "name": "threshold",
+ "name": "maxLength",
"dataType": "INT",
- "required": False,
- "description": "Maximum number of non-matching values allowed"
+ "required": True,
+ "description": "Maximum allowed length"
}
]
)
@@ -177,25 +179,17 @@ curl -X POST "{base_url}/api/v1/dataQuality/testDefinitions" \
-H "Authorization: Bearer {access_token}" \
-H "Content-Type: application/json" \
-d '{
- "name": "columnValuesToMatchBusinessRule",
- "displayName": "Column Values To Match Business Rule",
- "description": "Validates that column values conform to a custom business rule regex pattern",
+ "name": "columnValuesMaxLength",
+ "displayName": "Column Values Max Length",
+ "description": "Fails when a value is longer than the allowed length",
"entityType": "COLUMN",
"testPlatforms": ["OpenMetadata"],
+ "dataQualityDimension": "SQL",
"supportedDataTypes": ["STRING", "VARCHAR", "TEXT"],
+ "sqlExpression": "SELECT * FROM {{ table_name }} WHERE LENGTH({{ column_name }}) > {{ maxLength }}",
+ "validatorClass": "ColumnRuleLibrarySqlExpressionValidator",
"parameterDefinition": [
- {
- "name": "regexPattern",
- "dataType": "STRING",
- "required": true,
- "description": "The regex pattern to match against"
- },
- {
- "name": "threshold",
- "dataType": "INT",
- "required": false,
- "description": "Maximum number of non-matching values allowed"
- }
+ {"name": "maxLength", "dataType": "INT", "required": true, "description": "Maximum allowed length"}
]
}'
```
@@ -321,6 +315,8 @@ Returns the created test definition object with all specified properties and sys
## Custom SQL Test Definitions
+A custom test definition is a reusable SQL template. To run a one-off SQL query on a single table, such as the **Custom SQL Query** test type in the UI, create a test case with the built-in `tableCustomSQLQuery` definition instead. For more information, see [Custom SQL Test Cases](/v1.13.x/api-reference/data-quality/test-cases/create#custom-sql-test-cases).
+
To create a test definition that runs your own SQL, set `sqlExpression` and declare every `{{ paramName }}` placeholder in `parameterDefinition`. The following request creates a column-level test that fails when any value in the column is longer than a limit:
```bash
@@ -336,13 +332,9 @@ curl -X POST "{base_url}/api/v1/dataQuality/testDefinitions" \
"dataQualityDimension": "SQL",
"supportedDataTypes": ["STRING", "VARCHAR", "TEXT"],
"sqlExpression": "SELECT * FROM {{ table_name }} WHERE LENGTH({{ column_name }}) > {{ maxLength }}",
+ "validatorClass": "ColumnRuleLibrarySqlExpressionValidator",
"parameterDefinition": [
- {
- "name": "maxLength",
- "dataType": "INT",
- "required": true,
- "description": "Maximum allowed length"
- }
+ {"name": "maxLength", "dataType": "INT", "required": true, "description": "Maximum allowed length"}
]
}'
```
diff --git a/v2.0.x/api-reference/data-quality/test-cases/create.mdx b/v2.0.x/api-reference/data-quality/test-cases/create.mdx
index f049557c..15544a75 100644
--- a/v2.0.x/api-reference/data-quality/test-cases/create.mdx
+++ b/v2.0.x/api-reference/data-quality/test-cases/create.mdx
@@ -18,7 +18,7 @@ The server associates the test case with the basic suite of the table in `entity
- Fully qualified name (FQN) of the test definition to use. For example, `columnValueMaxToBeBetween`.
+ Fully qualified name (FQN) of the test definition to use. For example, `columnValueMaxToBeBetween`. For a custom SQL test (the **Custom SQL Query** test type in the UI), use `tableCustomSQLQuery`. For a test case on a custom test definition you created, use that definition's name, such as `columnValuesMaxLength`. For more information, see [Custom SQL Test Cases](#custom-sql-test-cases).
@@ -140,6 +140,39 @@ curl -X POST "{base_url}/api/v1/dataQuality/testCases" \
"description": "Validates shop_id max value stays between 1 and 100"
}'
```
+
+```bash POST /v1/dataQuality/testCases (custom SQL)
+curl -X POST "{base_url}/api/v1/dataQuality/testCases" \
+ -H "Authorization: Bearer {access_token}" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "name": "orders_no_negative_amounts",
+ "testDefinition": "tableCustomSQLQuery",
+ "entityLink": "<#E::table::sample_data.ecommerce_db.shopify.orders>",
+ "parameterValues": [
+ {"name": "sqlExpression", "value": "SELECT * FROM orders WHERE amount < 0"},
+ {"name": "strategy", "value": "ROWS"},
+ {"name": "operator", "value": "=="},
+ {"name": "threshold", "value": "0"}
+ ],
+ "computePassedFailedRowCount": true
+ }'
+```
+
+```bash POST /v1/dataQuality/testCases (custom test definition)
+curl -X POST "{base_url}/api/v1/dataQuality/testCases" \
+ -H "Authorization: Bearer {access_token}" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "name": "email_max_length",
+ "testDefinition": "columnValuesMaxLength",
+ "entityLink": "<#E::table::sample_data.ecommerce_db.shopify.dim_address::columns::email>",
+ "parameterValues": [
+ {"name": "maxLength", "value": "50"}
+ ],
+ "computePassedFailedRowCount": true
+ }'
+```
@@ -294,8 +327,15 @@ curl -X PUT "{base_url}/api/v1/dataQuality/testCases" \
## Custom SQL Test Cases
+OpenMetadata has two ways to run SQL in a test case:
+
+- **Custom SQL test**: the **Custom SQL Query** test type in the UI. The test case uses the built-in `tableCustomSQLQuery` test definition and carries the SQL itself in `parameterValues`. You don't create a test definition.
+- **Custom test definition**: a reusable SQL template you create once, with `{{ paramName }}` placeholders. Test cases then reference it by name. For more information, see [Test Cases for a Custom Test Definition](#test-cases-for-a-custom-test-definition).
+
A test case passes values to a SQL-based test definition through `parameterValues`. The server rejects any parameter that the test definition doesn't declare in `parameterDefinition`, and requires every parameter marked `required`.
+### Custom SQL Test
+
The built-in `tableCustomSQLQuery` test definition runs a SQL query against a table. It accepts these parameters:
| Parameter | Required | Description |
@@ -316,13 +356,37 @@ curl -X POST "{base_url}/api/v1/dataQuality/testCases" \
"entityLink": "<#E::table::sample_data.ecommerce_db.shopify.orders>",
"parameterValues": [
{"name": "sqlExpression", "value": "SELECT * FROM orders WHERE amount < 0"},
- {"name": "strategy", "value": "ROWS"}
+ {"name": "strategy", "value": "ROWS"},
+ {"name": "operator", "value": "=="},
+ {"name": "threshold", "value": "0"}
+ ],
+ "computePassedFailedRowCount": true
+ }'
+```
+
+### Test Cases for a Custom Test Definition
+
+A test case for a custom SQL test definition sets `testDefinition` to the definition's name and passes one `parameterValues` entry per `{{ paramName }}` placeholder. The following request uses a custom `columnValuesMaxLength` definition, which declares `maxLength`:
+
+```bash
+curl -X POST "{base_url}/api/v1/dataQuality/testCases" \
+ -H "Authorization: Bearer {access_token}" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "name": "email_max_length",
+ "testDefinition": "columnValuesMaxLength",
+ "entityLink": "<#E::table::sample_data.ecommerce_db.shopify.dim_address::columns::email>",
+ "parameterValues": [
+ {"name": "maxLength", "value": "50"}
],
"computePassedFailedRowCount": true
}'
```
-For a custom test definition that uses `{{ paramName }}` placeholders, pass one `parameterValues` entry per placeholder. For more information, see [Create a Test Definition](/v2.0.x/api-reference/data-quality/test-definitions/create#custom-sql-test-definitions).
+- **Pass condition**: The test case passes only when the number of rows the SQL returns is 0.
+- **Row counts**: Set `computePassedFailedRowCount` to `true` to report passed and failed row counts.
+
+For more information, see [Create a Test Definition](/v2.0.x/api-reference/data-quality/test-definitions/create#custom-sql-test-definitions).
## Error Handling
diff --git a/v2.0.x/api-reference/data-quality/test-definitions/create.mdx b/v2.0.x/api-reference/data-quality/test-definitions/create.mdx
index 312936df..a65a5e68 100644
--- a/v2.0.x/api-reference/data-quality/test-definitions/create.mdx
+++ b/v2.0.x/api-reference/data-quality/test-definitions/create.mdx
@@ -68,7 +68,12 @@ Create a custom test definition to define organization-specific data quality val
- Name of the validator that runs the test. For custom SQL-based tests, defaults to `ruleLibrarySqlExpressionValidator` when omitted.
+ Class name of the validator that runs the test. For a custom SQL test definition, set one of the following values. The OpenMetadata UI sets the same values when you create a custom SQL test definition:
+
+ - `ColumnRuleLibrarySqlExpressionValidator`: use when `entityType` is `COLUMN`.
+ - `TableRuleLibrarySqlExpressionValidator`: use when `entityType` is `TABLE`.
+
+ Built-in test definitions use their own validators, which you can't select for a custom definition. The server accepts any string for this field, so always set it explicitly for SQL-based definitions.
@@ -113,24 +118,21 @@ configure(
)
request = CreateTestDefinitionRequest(
- name="columnValuesToMatchBusinessRule",
- displayName="Column Values To Match Business Rule",
- description="Validates that column values conform to a custom business rule regex pattern",
+ name="columnValuesMaxLength",
+ displayName="Column Values Max Length",
+ description="Fails when a value is longer than the allowed length",
entityType="COLUMN",
testPlatforms=["OpenMetadata"],
+ dataQualityDimension="SQL",
supportedDataTypes=["STRING", "VARCHAR", "TEXT"],
+ sqlExpression="SELECT * FROM {{ table_name }} WHERE LENGTH({{ column_name }}) > {{ maxLength }}",
+ validatorClass="ColumnRuleLibrarySqlExpressionValidator",
parameterDefinition=[
{
- "name": "regexPattern",
- "dataType": "STRING",
- "required": True,
- "description": "The regex pattern to match against"
- },
- {
- "name": "threshold",
+ "name": "maxLength",
"dataType": "INT",
- "required": False,
- "description": "Maximum number of non-matching values allowed"
+ "required": True,
+ "description": "Maximum allowed length"
}
]
)
@@ -177,25 +179,17 @@ curl -X POST "{base_url}/api/v1/dataQuality/testDefinitions" \
-H "Authorization: Bearer {access_token}" \
-H "Content-Type: application/json" \
-d '{
- "name": "columnValuesToMatchBusinessRule",
- "displayName": "Column Values To Match Business Rule",
- "description": "Validates that column values conform to a custom business rule regex pattern",
+ "name": "columnValuesMaxLength",
+ "displayName": "Column Values Max Length",
+ "description": "Fails when a value is longer than the allowed length",
"entityType": "COLUMN",
"testPlatforms": ["OpenMetadata"],
+ "dataQualityDimension": "SQL",
"supportedDataTypes": ["STRING", "VARCHAR", "TEXT"],
+ "sqlExpression": "SELECT * FROM {{ table_name }} WHERE LENGTH({{ column_name }}) > {{ maxLength }}",
+ "validatorClass": "ColumnRuleLibrarySqlExpressionValidator",
"parameterDefinition": [
- {
- "name": "regexPattern",
- "dataType": "STRING",
- "required": true,
- "description": "The regex pattern to match against"
- },
- {
- "name": "threshold",
- "dataType": "INT",
- "required": false,
- "description": "Maximum number of non-matching values allowed"
- }
+ {"name": "maxLength", "dataType": "INT", "required": true, "description": "Maximum allowed length"}
]
}'
```
@@ -321,6 +315,8 @@ Returns the created test definition object with all specified properties and sys
## Custom SQL Test Definitions
+A custom test definition is a reusable SQL template. To run a one-off SQL query on a single table, such as the **Custom SQL Query** test type in the UI, create a test case with the built-in `tableCustomSQLQuery` definition instead. For more information, see [Custom SQL Test Cases](/v2.0.x/api-reference/data-quality/test-cases/create#custom-sql-test-cases).
+
To create a test definition that runs your own SQL, set `sqlExpression` and declare every `{{ paramName }}` placeholder in `parameterDefinition`. The following request creates a column-level test that fails when any value in the column is longer than a limit:
```bash
@@ -336,13 +332,9 @@ curl -X POST "{base_url}/api/v1/dataQuality/testDefinitions" \
"dataQualityDimension": "SQL",
"supportedDataTypes": ["STRING", "VARCHAR", "TEXT"],
"sqlExpression": "SELECT * FROM {{ table_name }} WHERE LENGTH({{ column_name }}) > {{ maxLength }}",
+ "validatorClass": "ColumnRuleLibrarySqlExpressionValidator",
"parameterDefinition": [
- {
- "name": "maxLength",
- "dataType": "INT",
- "required": true,
- "description": "Maximum allowed length"
- }
+ {"name": "maxLength", "dataType": "INT", "required": true, "description": "Maximum allowed length"}
]
}'
```
diff --git a/v2.1.x-SNAPSHOT/api-reference/data-quality/test-cases/create.mdx b/v2.1.x-SNAPSHOT/api-reference/data-quality/test-cases/create.mdx
index b800da98..20591182 100644
--- a/v2.1.x-SNAPSHOT/api-reference/data-quality/test-cases/create.mdx
+++ b/v2.1.x-SNAPSHOT/api-reference/data-quality/test-cases/create.mdx
@@ -18,7 +18,7 @@ The server associates the test case with the basic suite of the table in `entity
- Fully qualified name (FQN) of the test definition to use. For example, `columnValueMaxToBeBetween`.
+ Fully qualified name (FQN) of the test definition to use. For example, `columnValueMaxToBeBetween`. For a custom SQL test (the **Custom SQL Query** test type in the UI), use `tableCustomSQLQuery`. For a test case on a custom test definition you created, use that definition's name, such as `columnValuesMaxLength`. For more information, see [Custom SQL Test Cases](#custom-sql-test-cases).
@@ -144,6 +144,41 @@ curl -X POST "{base_url}/api/v1/dataQuality/testCases" \
"description": "Validates shop_id max value stays between 1 and 100"
}'
```
+
+```bash POST /v1/dataQuality/testCases (custom SQL)
+curl -X POST "{base_url}/api/v1/dataQuality/testCases" \
+ -H "Authorization: Bearer {access_token}" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "name": "orders_no_negative_amounts",
+ "testDefinition": "tableCustomSQLQuery",
+ "entityLink": "<#E::table::sample_data.ecommerce_db.shopify.orders>",
+ "parameterValues": [
+ {"name": "sqlExpression", "value": "SELECT * FROM orders WHERE amount < 0"},
+ {"name": "strategy", "value": "ROWS"},
+ {"name": "operator", "value": "=="},
+ {"name": "threshold", "value": "0"}
+ ],
+ "computePassedFailedRowCount": true
+ }'
+```
+
+```bash POST /v1/dataQuality/testCases (custom test definition)
+curl -X POST "{base_url}/api/v1/dataQuality/testCases" \
+ -H "Authorization: Bearer {access_token}" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "name": "email_max_length",
+ "testDefinition": "columnValuesMaxLength",
+ "entityLink": "<#E::table::sample_data.ecommerce_db.shopify.dim_address::columns::email>",
+ "parameterValues": [
+ {"name": "maxLength", "value": "50"},
+ {"name": "threshold", "value": "5"},
+ {"name": "thresholdUnit", "value": "PERCENTAGE"}
+ ],
+ "computePassedFailedRowCount": true
+ }'
+```
@@ -298,8 +333,15 @@ curl -X PUT "{base_url}/api/v1/dataQuality/testCases" \
## Custom SQL Test Cases
+OpenMetadata has two ways to run SQL in a test case:
+
+- **Custom SQL test**: the **Custom SQL Query** test type in the UI. The test case uses the built-in `tableCustomSQLQuery` test definition and carries the SQL itself in `parameterValues`. You don't create a test definition.
+- **Custom test definition**: a reusable SQL template you create once, with `{{ paramName }}` placeholders. Test cases then reference it by name. For more information, see [Test Cases for a Custom Test Definition](#test-cases-for-a-custom-test-definition).
+
A test case passes values to a SQL-based test definition through `parameterValues`. The server rejects any parameter that the test definition doesn't declare in `parameterDefinition`, and requires every parameter marked `required`.
+### Custom SQL Test
+
The built-in `tableCustomSQLQuery` test definition runs a SQL query against a table. It accepts these parameters:
| Parameter | Required | Description |
@@ -321,13 +363,40 @@ curl -X POST "{base_url}/api/v1/dataQuality/testCases" \
"entityLink": "<#E::table::sample_data.ecommerce_db.shopify.orders>",
"parameterValues": [
{"name": "sqlExpression", "value": "SELECT * FROM orders WHERE amount < 0"},
- {"name": "strategy", "value": "ROWS"}
+ {"name": "strategy", "value": "ROWS"},
+ {"name": "operator", "value": "=="},
+ {"name": "threshold", "value": "0"}
+ ],
+ "computePassedFailedRowCount": true
+ }'
+```
+
+### Test Cases for a Custom Test Definition
+
+A test case for a custom SQL test definition sets `testDefinition` to the definition's name and passes one `parameterValues` entry per `{{ paramName }}` placeholder. The following request uses a custom `columnValuesMaxLength` definition, which declares `maxLength`, `threshold`, and `thresholdUnit`:
+
+```bash
+curl -X POST "{base_url}/api/v1/dataQuality/testCases" \
+ -H "Authorization: Bearer {access_token}" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "name": "email_max_length",
+ "testDefinition": "columnValuesMaxLength",
+ "entityLink": "<#E::table::sample_data.ecommerce_db.shopify.dim_address::columns::email>",
+ "parameterValues": [
+ {"name": "maxLength", "value": "50"},
+ {"name": "threshold", "value": "5"},
+ {"name": "thresholdUnit", "value": "PERCENTAGE"}
],
"computePassedFailedRowCount": true
}'
```
-For a custom test definition that uses `{{ paramName }}` placeholders, pass one `parameterValues` entry per placeholder. For more information, see [Create a Test Definition](/v2.1.x-SNAPSHOT/api-reference/data-quality/test-definitions/create#custom-sql-test-definitions).
+- **Pass condition**: The test case passes when the number of rows the SQL returns is within the tolerance. With no `threshold`, any returned row fails the test case.
+- **Threshold**: `threshold` and `thresholdUnit` apply only if the test definition declares `thresholdUnit`. With `ABSOLUTE`, `threshold` is a row count. With `PERCENTAGE`, it is a share of the evaluated rows and can't exceed `100`. A negative or non-numeric `threshold` returns a `400` error.
+- **Row counts**: Set `computePassedFailedRowCount` to `true` to report passed and failed row counts.
+
+For more information, see [Create a Test Definition](/v2.1.x-SNAPSHOT/api-reference/data-quality/test-definitions/create#custom-sql-test-definitions).
## Error Handling
diff --git a/v2.1.x-SNAPSHOT/api-reference/data-quality/test-definitions/create.mdx b/v2.1.x-SNAPSHOT/api-reference/data-quality/test-definitions/create.mdx
index c792908f..f645daf1 100644
--- a/v2.1.x-SNAPSHOT/api-reference/data-quality/test-definitions/create.mdx
+++ b/v2.1.x-SNAPSHOT/api-reference/data-quality/test-definitions/create.mdx
@@ -64,11 +64,16 @@ Create a custom test definition to define organization-specific data quality val
- `{{ column_name }}`: the column the test case runs against. Available only when `entityType` is `COLUMN`.
- `{{ paramName }}`: the value of a parameter declared in `parameterDefinition`.
- OpenMetadata doesn't substitute single-brace placeholders, which produce invalid SQL. The test passes only when the rendered query returns 0 rows. `table_name` is reserved for all definitions, and `column_name` is also reserved when `entityType` is `COLUMN`. Don't use reserved names as parameter names. For more information, see [Custom SQL Test Definitions](#custom-sql-test-definitions).
+ OpenMetadata doesn't substitute single-brace placeholders, which produce invalid SQL. By default, the test passes only when the rendered query returns 0 rows. To tolerate some violating rows, set a failure threshold. `table_name` is reserved for all definitions, and `column_name` is also reserved when `entityType` is `COLUMN`. Don't use reserved names as parameter names. For more information, see [Custom SQL Test Definitions](#custom-sql-test-definitions).
- Name of the validator that runs the test. For custom SQL-based tests, defaults to `ruleLibrarySqlExpressionValidator` when omitted.
+ Class name of the validator that runs the test. For a custom SQL test definition, set one of the following values. The OpenMetadata UI sets the same values when you create a custom SQL test definition:
+
+ - `ColumnRuleLibrarySqlExpressionValidator`: use when `entityType` is `COLUMN`.
+ - `TableRuleLibrarySqlExpressionValidator`: use when `entityType` is `TABLE`.
+
+ Built-in test definitions use their own validators, which you can't select for a custom definition. The server accepts any string for this field, so always set it explicitly for SQL-based definitions.
@@ -113,24 +118,33 @@ configure(
)
request = CreateTestDefinitionRequest(
- name="columnValuesToMatchBusinessRule",
- displayName="Column Values To Match Business Rule",
- description="Validates that column values conform to a custom business rule regex pattern",
+ name="columnValuesMaxLength",
+ displayName="Column Values Max Length",
+ description="Fails when a value is longer than the allowed length",
entityType="COLUMN",
testPlatforms=["OpenMetadata"],
+ dataQualityDimension="SQL",
supportedDataTypes=["STRING", "VARCHAR", "TEXT"],
+ sqlExpression="SELECT * FROM {{ table_name }} WHERE LENGTH({{ column_name }}) > {{ maxLength }}",
+ validatorClass="ColumnRuleLibrarySqlExpressionValidator",
parameterDefinition=[
{
- "name": "regexPattern",
- "dataType": "STRING",
+ "name": "maxLength",
+ "dataType": "INT",
"required": True,
- "description": "The regex pattern to match against"
+ "description": "Maximum allowed length"
},
{
"name": "threshold",
- "dataType": "INT",
+ "dataType": "NUMBER",
"required": False,
- "description": "Maximum number of non-matching values allowed"
+ "description": "Number of failing rows to tolerate before the test fails"
+ },
+ {
+ "name": "thresholdUnit",
+ "dataType": "STRING",
+ "required": False,
+ "description": "ABSOLUTE for a row count or PERCENTAGE for a share of rows"
}
]
)
@@ -177,25 +191,19 @@ curl -X POST "{base_url}/api/v1/dataQuality/testDefinitions" \
-H "Authorization: Bearer {access_token}" \
-H "Content-Type: application/json" \
-d '{
- "name": "columnValuesToMatchBusinessRule",
- "displayName": "Column Values To Match Business Rule",
- "description": "Validates that column values conform to a custom business rule regex pattern",
+ "name": "columnValuesMaxLength",
+ "displayName": "Column Values Max Length",
+ "description": "Fails when a value is longer than the allowed length",
"entityType": "COLUMN",
"testPlatforms": ["OpenMetadata"],
+ "dataQualityDimension": "SQL",
"supportedDataTypes": ["STRING", "VARCHAR", "TEXT"],
+ "sqlExpression": "SELECT * FROM {{ table_name }} WHERE LENGTH({{ column_name }}) > {{ maxLength }}",
+ "validatorClass": "ColumnRuleLibrarySqlExpressionValidator",
"parameterDefinition": [
- {
- "name": "regexPattern",
- "dataType": "STRING",
- "required": true,
- "description": "The regex pattern to match against"
- },
- {
- "name": "threshold",
- "dataType": "INT",
- "required": false,
- "description": "Maximum number of non-matching values allowed"
- }
+ {"name": "maxLength", "dataType": "INT", "required": true, "description": "Maximum allowed length"},
+ {"name": "threshold", "dataType": "NUMBER", "required": false, "description": "Number of failing rows to tolerate before the test fails"},
+ {"name": "thresholdUnit", "dataType": "STRING", "required": false, "description": "ABSOLUTE for a row count or PERCENTAGE for a share of rows"}
]
}'
```
@@ -321,6 +329,8 @@ Returns the created test definition object with all specified properties and sys
## Custom SQL Test Definitions
+A custom test definition is a reusable SQL template. To run a one-off SQL query on a single table, such as the **Custom SQL Query** test type in the UI, create a test case with the built-in `tableCustomSQLQuery` definition instead. For more information, see [Custom SQL Test Cases](/v2.1.x-SNAPSHOT/api-reference/data-quality/test-cases/create#custom-sql-test-cases).
+
To create a test definition that runs your own SQL, set `sqlExpression` and declare every `{{ paramName }}` placeholder in `parameterDefinition`. The following request creates a column-level test that fails when any value in the column is longer than a limit:
```bash
@@ -336,23 +346,33 @@ curl -X POST "{base_url}/api/v1/dataQuality/testDefinitions" \
"dataQualityDimension": "SQL",
"supportedDataTypes": ["STRING", "VARCHAR", "TEXT"],
"sqlExpression": "SELECT * FROM {{ table_name }} WHERE LENGTH({{ column_name }}) > {{ maxLength }}",
+ "validatorClass": "ColumnRuleLibrarySqlExpressionValidator",
"parameterDefinition": [
- {
- "name": "maxLength",
- "dataType": "INT",
- "required": true,
- "description": "Maximum allowed length"
- }
+ {"name": "maxLength", "dataType": "INT", "required": true, "description": "Maximum allowed length"},
+ {"name": "threshold", "dataType": "NUMBER", "required": false, "description": "Number of failing rows to tolerate before the test fails"},
+ {"name": "thresholdUnit", "dataType": "STRING", "required": false, "description": "ABSOLUTE for a row count or PERCENTAGE for a share of rows"}
]
}'
```
How OpenMetadata evaluates the SQL:
-- **Pass condition**: The test case passes only when the rendered query returns 0 rows. Write the query so that it returns the rows that violate the rule.
+- **Pass condition**: By default, the test case passes only when the rendered query returns 0 rows. Write the query so that it returns the rows that violate the rule.
+- **Failure threshold**: To let a test case tolerate some violating rows, declare both `threshold` and `thresholdUnit` in `parameterDefinition`. The server ignores `threshold` unless the definition declares `thresholdUnit`. For more information, see [Failure Thresholds](#failure-thresholds).
- **Reserved names**: `table_name` is reserved for table-level definitions. `table_name` and `column_name` are reserved for column-level definitions. Do not declare them in `parameterDefinition`, because the validator supplies their values at runtime.
- **Parameters**: A test case supplies values for `{{ paramName }}` through `parameterValues`. For more information, see [Create a Test Case](/v2.1.x-SNAPSHOT/api-reference/data-quality/test-cases/create#custom-sql-test-cases).
+### Failure Thresholds
+
+A failure threshold is the number of violating rows a test case tolerates before it fails. It turns the default "fail on any row" pass condition into a tolerance.
+
+| Parameter | Data type | Description |
+|-----------|-----------|-------------|
+| `threshold` | `NUMBER` | Tolerated violations. Must be a non-negative number. Defaults to `0`. |
+| `thresholdUnit` | `STRING` | `ABSOLUTE` reads `threshold` as a row count. `PERCENTAGE` reads it as a share of the evaluated rows, up to `100`. |
+
+The test case supplies the values in `parameterValues`. For more information, see [Create a Test Case](/v2.1.x-SNAPSHOT/api-reference/data-quality/test-cases/create#custom-sql-test-cases) and [Failure Thresholds](/v2.1.x-SNAPSHOT/how-to-guides/data-quality-observability/quality/failure-thresholds).
+
## Create or Update (PUT)
Use `PUT /v1/dataQuality/testDefinitions` instead of `POST` to perform an upsert. If a test definition with the same name already exists, it will be updated; otherwise, a new test definition is created. The request body is the same as `POST`.