From 7bd4fe9b4baebeab371e574d1ceff926c30ae856 Mon Sep 17 00:00:00 2001 From: satoshi-sh Date: Sat, 17 Feb 2024 18:25:19 -0600 Subject: [PATCH 01/11] Added dag_idsquery to the GET /datasets endpoint --- airflow/api_connexion/endpoints/dataset_endpoint.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/airflow/api_connexion/endpoints/dataset_endpoint.py b/airflow/api_connexion/endpoints/dataset_endpoint.py index 152ac6eecb2cf..a3c17c297eb1b 100644 --- a/airflow/api_connexion/endpoints/dataset_endpoint.py +++ b/airflow/api_connexion/endpoints/dataset_endpoint.py @@ -25,8 +25,10 @@ from airflow.api_connexion.exceptions import NotFound from airflow.api_connexion.parameters import apply_sorting, check_limit, format_parameters from airflow.api_connexion.schemas.dataset_schema import ( + DagScheduleDatasetReference, DatasetCollection, DatasetEventCollection, + TaskOutletDatasetReference, dataset_collection_schema, dataset_event_collection_schema, dataset_schema, @@ -66,6 +68,7 @@ def get_datasets( limit: int, offset: int = 0, uri_pattern: str | None = None, + dag_ids: str | None = None, order_by: str = "id", session: Session = NEW_SESSION, ) -> APIResponse: @@ -74,7 +77,13 @@ def get_datasets( total_entries = session.scalars(select(func.count(DatasetModel.id))).one() query = select(DatasetModel) - if uri_pattern: + if dag_ids: + dags_list = dag_ids.split(",") + query = query.filter( + (DatasetModel.consuming_dags.any(DagScheduleDatasetReference.dag_id.in_(dags_list))) + | (DatasetModel.producing_tasks.any(TaskOutletDatasetReference.dag_id.in_(dags_list))) + ) + elif uri_pattern: query = query.where(DatasetModel.uri.ilike(f"%{uri_pattern}%")) query = apply_sorting(query, order_by, {}, allowed_attrs) datasets = session.scalars( From b7009b6fa7ba048f7b6ff0d212f6d2c7d688495c Mon Sep 17 00:00:00 2001 From: satoshi-sh Date: Sat, 17 Feb 2024 18:31:03 -0600 Subject: [PATCH 02/11] Added documentation for the new dag_ids query to the GET /datasets endpoint --- airflow/api_connexion/openapi/v1.yaml | 7 +++++++ airflow/www/static/js/types/api-generated.ts | 2 ++ 2 files changed, 9 insertions(+) diff --git a/airflow/api_connexion/openapi/v1.yaml b/airflow/api_connexion/openapi/v1.yaml index b45ab68728720..0debed6e304a2 100644 --- a/airflow/api_connexion/openapi/v1.yaml +++ b/airflow/api_connexion/openapi/v1.yaml @@ -1911,6 +1911,13 @@ paths: required: false description: | If set, only return datasets with uris matching this pattern. + - name: dag_ids + in: query + schema: + type: string + required: false + description: | + One or more DAG IDs separated by commas to filter datasets by associated DAGs. responses: "200": description: Success. diff --git a/airflow/www/static/js/types/api-generated.ts b/airflow/www/static/js/types/api-generated.ts index e8d2684765fa0..cdb258a004eec 100644 --- a/airflow/www/static/js/types/api-generated.ts +++ b/airflow/www/static/js/types/api-generated.ts @@ -4260,6 +4260,8 @@ export interface operations { order_by?: components["parameters"]["OrderBy"]; /** If set, only return datasets with uris matching this pattern. */ uri_pattern?: string; + /** One or more DAG IDs separated by commas to filter datasets by associated DAGs. */ + dag_ids?: string; }; }; responses: { From 65ffb494f77184d3712186c70c46e033b1d65e08 Mon Sep 17 00:00:00 2001 From: satoshi-sh Date: Sat, 17 Feb 2024 18:33:13 -0600 Subject: [PATCH 03/11] Added a test for id_tags query to the GET /datasets endoint --- .../endpoints/test_dataset_endpoint.py | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tests/api_connexion/endpoints/test_dataset_endpoint.py b/tests/api_connexion/endpoints/test_dataset_endpoint.py index e06505dc4a99b..61698a04720da 100644 --- a/tests/api_connexion/endpoints/test_dataset_endpoint.py +++ b/tests/api_connexion/endpoints/test_dataset_endpoint.py @@ -22,7 +22,12 @@ from airflow.api_connexion.exceptions import EXCEPTIONS_LINK_MAP from airflow.models.dagrun import DagRun -from airflow.models.dataset import DatasetEvent, DatasetModel +from airflow.models.dataset import ( + DagScheduleDatasetReference, + DatasetEvent, + DatasetModel, + TaskOutletDatasetReference, +) from airflow.security import permissions from airflow.utils import timezone from airflow.utils.session import provide_session @@ -239,6 +244,21 @@ def test_filter_datasets_by_uri_pattern_works(self, url, expected_datasets, sess dataset_urls = {dataset["uri"] for dataset in response.json["datasets"]} assert expected_datasets == dataset_urls + def test_filter_datasets_by_dag_ids_works(self, session): + dataset1 = DatasetModel("s3://folder/key") + dataset2 = DatasetModel("gcp://bucket/key") + dataset3 = DatasetModel("somescheme://dataset/key") + dataset1.consuming_dags = [DagScheduleDatasetReference(dag_id="dag1")] + dataset2.producing_tasks = [TaskOutletDatasetReference(dag_id="dag4")] + dataset3.consuming_dags = [DagScheduleDatasetReference(dag_id="dag1")] + dataset3.producing_tasks = [TaskOutletDatasetReference(dag_id="dag2")] + session.add_all([dataset1, dataset2, dataset3]) + session.commit() + response = self.client.get("/api/v1/datasets?dag_ids=dag1,dag2") + assert response.status_code == 200 + response_data = response.json + assert len(response_data["datasets"]) == 2 + class TestGetDatasetsEndpointPagination(TestDatasetEndpoint): @pytest.mark.parametrize( From 1d50540231ce3bc35b56ca168c1f3ba1c2efc56b Mon Sep 17 00:00:00 2001 From: satoshi-sh Date: Sat, 17 Feb 2024 20:19:20 -0600 Subject: [PATCH 04/11] Fixed the test errors --- .../endpoints/test_dataset_endpoint.py | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/tests/api_connexion/endpoints/test_dataset_endpoint.py b/tests/api_connexion/endpoints/test_dataset_endpoint.py index 61698a04720da..60d5034dedf06 100644 --- a/tests/api_connexion/endpoints/test_dataset_endpoint.py +++ b/tests/api_connexion/endpoints/test_dataset_endpoint.py @@ -21,6 +21,7 @@ import pytest from airflow.api_connexion.exceptions import EXCEPTIONS_LINK_MAP +from airflow.models import DagModel from airflow.models.dagrun import DagRun from airflow.models.dataset import ( DagScheduleDatasetReference, @@ -244,20 +245,27 @@ def test_filter_datasets_by_uri_pattern_works(self, url, expected_datasets, sess dataset_urls = {dataset["uri"] for dataset in response.json["datasets"]} assert expected_datasets == dataset_urls - def test_filter_datasets_by_dag_ids_works(self, session): + @pytest.mark.parametrize("dag_ids, expected_num", [("dag1,dag2", 2), ("dag3", 1), ("dag2,dag3", 2)]) + def test_filter_datasets_by_dag_ids_works(self, dag_ids, expected_num, session): + session.query(DagModel).delete() + session.commit() + dag1 = DagModel(dag_id="dag1") + dag2 = DagModel(dag_id="dag2") + dag3 = DagModel(dag_id="dag3") dataset1 = DatasetModel("s3://folder/key") dataset2 = DatasetModel("gcp://bucket/key") dataset3 = DatasetModel("somescheme://dataset/key") - dataset1.consuming_dags = [DagScheduleDatasetReference(dag_id="dag1")] - dataset2.producing_tasks = [TaskOutletDatasetReference(dag_id="dag4")] - dataset3.consuming_dags = [DagScheduleDatasetReference(dag_id="dag1")] - dataset3.producing_tasks = [TaskOutletDatasetReference(dag_id="dag2")] - session.add_all([dataset1, dataset2, dataset3]) + dag_ref1 = DagScheduleDatasetReference(dag_id="dag1", dataset=dataset1) + dag_ref2 = DagScheduleDatasetReference(dag_id="dag2", dataset=dataset2) + task_ref1 = TaskOutletDatasetReference(dag_id="dag3", task_id="task1", dataset=dataset3) + session.add_all([dataset1, dataset2, dataset3, dag1, dag2, dag3, dag_ref1, dag_ref2, task_ref1]) session.commit() - response = self.client.get("/api/v1/datasets?dag_ids=dag1,dag2") + response = self.client.get( + f"/api/v1/datasets?dag_ids={dag_ids}", environ_overrides={"REMOTE_USER": "test"} + ) assert response.status_code == 200 response_data = response.json - assert len(response_data["datasets"]) == 2 + assert len(response_data["datasets"]) == expected_num class TestGetDatasetsEndpointPagination(TestDatasetEndpoint): From 47ac6d8fd59ceaac7e28706eff210b1468a58570 Mon Sep 17 00:00:00 2001 From: satoshi-sh Date: Tue, 20 Feb 2024 13:16:12 -0600 Subject: [PATCH 05/11] chained dag_ids and uri_patterns filters when both queried --- airflow/api_connexion/endpoints/dataset_endpoint.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/airflow/api_connexion/endpoints/dataset_endpoint.py b/airflow/api_connexion/endpoints/dataset_endpoint.py index a3c17c297eb1b..712f07b2f7d1d 100644 --- a/airflow/api_connexion/endpoints/dataset_endpoint.py +++ b/airflow/api_connexion/endpoints/dataset_endpoint.py @@ -77,7 +77,16 @@ def get_datasets( total_entries = session.scalars(select(func.count(DatasetModel.id))).one() query = select(DatasetModel) - if dag_ids: + + if dag_ids and uri_pattern: + dags_list = dag_ids.split(",") + query = query.filter( + DatasetModel.consuming_dags.any(DagScheduleDatasetReference.dag_id.in_(dags_list)) + ) | ( + DatasetModel.producing_tasks.any(TaskOutletDatasetReference.dag_id.in_(dags_list)) + & DatasetModel.uri.ilike(f"%{uri_pattern}%") + ) + elif dag_ids: dags_list = dag_ids.split(",") query = query.filter( (DatasetModel.consuming_dags.any(DagScheduleDatasetReference.dag_id.in_(dags_list))) From eb75c5e20dce990ece9ac5723f983c630c5805c7 Mon Sep 17 00:00:00 2001 From: satoshi-sh Date: Tue, 20 Feb 2024 13:41:39 -0600 Subject: [PATCH 06/11] Fixed syntax error --- airflow/api_connexion/endpoints/dataset_endpoint.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/airflow/api_connexion/endpoints/dataset_endpoint.py b/airflow/api_connexion/endpoints/dataset_endpoint.py index 712f07b2f7d1d..3e4148de8881c 100644 --- a/airflow/api_connexion/endpoints/dataset_endpoint.py +++ b/airflow/api_connexion/endpoints/dataset_endpoint.py @@ -81,10 +81,11 @@ def get_datasets( if dag_ids and uri_pattern: dags_list = dag_ids.split(",") query = query.filter( - DatasetModel.consuming_dags.any(DagScheduleDatasetReference.dag_id.in_(dags_list)) - ) | ( - DatasetModel.producing_tasks.any(TaskOutletDatasetReference.dag_id.in_(dags_list)) - & DatasetModel.uri.ilike(f"%{uri_pattern}%") + ( + DatasetModel.consuming_dags.any(DagScheduleDatasetReference.dag_id.in_(dags_list)) + | DatasetModel.producing_tasks.any(TaskOutletDatasetReference.dag_id.in_(dags_list)) + ), + DatasetModel.uri.ilike(f"%{uri_pattern}%"), ) elif dag_ids: dags_list = dag_ids.split(",") From 8136d280576f321f7c1274f27212f083a929ff20 Mon Sep 17 00:00:00 2001 From: satoshi-sh Date: Tue, 20 Feb 2024 13:54:05 -0600 Subject: [PATCH 07/11] Added test for dag_ids and uri_pattern filter --- .../endpoints/test_dataset_endpoint.py | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/api_connexion/endpoints/test_dataset_endpoint.py b/tests/api_connexion/endpoints/test_dataset_endpoint.py index 60d5034dedf06..6dbf0e4b9d578 100644 --- a/tests/api_connexion/endpoints/test_dataset_endpoint.py +++ b/tests/api_connexion/endpoints/test_dataset_endpoint.py @@ -246,6 +246,7 @@ def test_filter_datasets_by_uri_pattern_works(self, url, expected_datasets, sess assert expected_datasets == dataset_urls @pytest.mark.parametrize("dag_ids, expected_num", [("dag1,dag2", 2), ("dag3", 1), ("dag2,dag3", 2)]) + @provide_session def test_filter_datasets_by_dag_ids_works(self, dag_ids, expected_num, session): session.query(DagModel).delete() session.commit() @@ -267,6 +268,34 @@ def test_filter_datasets_by_dag_ids_works(self, dag_ids, expected_num, session): response_data = response.json assert len(response_data["datasets"]) == expected_num + @pytest.mark.parametrize( + "dag_ids, uri_pattern,expected_num", + [("dag1,dag2", "folder", 1), ("dag3", "nothing", 0), ("dag2,dag3", "key", 2)], + ) + def test_filter_datasets_by_dag_ids_and_uri_pattern_works( + self, dag_ids, uri_pattern, expected_num, session + ): + session.query(DagModel).delete() + session.commit() + dag1 = DagModel(dag_id="dag1") + dag2 = DagModel(dag_id="dag2") + dag3 = DagModel(dag_id="dag3") + dataset1 = DatasetModel("s3://folder/key") + dataset2 = DatasetModel("gcp://bucket/key") + dataset3 = DatasetModel("somescheme://dataset/key") + dag_ref1 = DagScheduleDatasetReference(dag_id="dag1", dataset=dataset1) + dag_ref2 = DagScheduleDatasetReference(dag_id="dag2", dataset=dataset2) + task_ref1 = TaskOutletDatasetReference(dag_id="dag3", task_id="task1", dataset=dataset3) + session.add_all([dataset1, dataset2, dataset3, dag1, dag2, dag3, dag_ref1, dag_ref2, task_ref1]) + session.commit() + response = self.client.get( + f"/api/v1/datasets?dag_ids={dag_ids}&uri_pattern={uri_pattern}", + environ_overrides={"REMOTE_USER": "test"}, + ) + assert response.status_code == 200 + response_data = response.json + assert len(response_data["datasets"]) == expected_num + class TestGetDatasetsEndpointPagination(TestDatasetEndpoint): @pytest.mark.parametrize( From f72a5a8d0bb818b034946925cb4a630e99995f4a Mon Sep 17 00:00:00 2001 From: satoshi-sh Date: Tue, 20 Feb 2024 16:14:56 -0600 Subject: [PATCH 08/11] Clarify the description of dag_ids including producing and consuming dags --- airflow/api_connexion/openapi/v1.yaml | 20 ++++++++++---------- airflow/www/static/js/types/api-generated.ts | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/airflow/api_connexion/openapi/v1.yaml b/airflow/api_connexion/openapi/v1.yaml index 3a7121fe507d2..e8ca1e1e16fb9 100644 --- a/airflow/api_connexion/openapi/v1.yaml +++ b/airflow/api_connexion/openapi/v1.yaml @@ -639,8 +639,8 @@ paths: "404": $ref: "#/components/responses/NotFound" - ? /dags/{dag_id}/dagRuns/{dag_run_id}/taskInstances/{task_id}/{map_index}/setNote - : parameters: + /dags/{dag_id}/dagRuns/{dag_run_id}/taskInstances/{task_id}/{map_index}/setNote: + parameters: - $ref: "#/components/parameters/DAGID" - $ref: "#/components/parameters/DAGRunID" - $ref: "#/components/parameters/TaskID" @@ -1767,8 +1767,8 @@ paths: "403": $ref: "#/components/responses/PermissionDenied" - ? /dags/{dag_id}/dagRuns/{dag_run_id}/taskInstances/{task_id}/xcomEntries/{xcom_key} - : parameters: + /dags/{dag_id}/dagRuns/{dag_run_id}/taskInstances/{task_id}/xcomEntries/{xcom_key}: + parameters: - $ref: "#/components/parameters/DAGID" - $ref: "#/components/parameters/DAGRunID" - $ref: "#/components/parameters/TaskID" @@ -1839,8 +1839,8 @@ paths: "404": $ref: "#/components/responses/NotFound" - ? /dags/{dag_id}/dagRuns/{dag_run_id}/taskInstances/{task_id}/logs/{task_try_number} - : parameters: + /dags/{dag_id}/dagRuns/{dag_run_id}/taskInstances/{task_id}/logs/{task_try_number}: + parameters: - $ref: "#/components/parameters/DAGID" - $ref: "#/components/parameters/DAGRunID" - $ref: "#/components/parameters/TaskID" @@ -2074,7 +2074,7 @@ paths: type: string required: false description: | - One or more DAG IDs separated by commas to filter datasets by associated DAGs. + One or more DAG IDs separated by commas to filter datasets by associated DAGs either consuming or producing. responses: "200": description: Success. @@ -4011,17 +4011,17 @@ components: ti_deps: type: array items: - type: string + type: string description: The plugin task instance dependencies listeners: type: array items: - type: string + type: string description: The plugin listeners timetables: type: array items: - type: string + type: string description: The plugin timetables PluginCollection: diff --git a/airflow/www/static/js/types/api-generated.ts b/airflow/www/static/js/types/api-generated.ts index 52695affc8fc5..2c3c4235b3b33 100644 --- a/airflow/www/static/js/types/api-generated.ts +++ b/airflow/www/static/js/types/api-generated.ts @@ -4504,7 +4504,7 @@ export interface operations { order_by?: components["parameters"]["OrderBy"]; /** If set, only return datasets with uris matching this pattern. */ uri_pattern?: string; - /** One or more DAG IDs separated by commas to filter datasets by associated DAGs. */ + /** One or more DAG IDs separated by commas to filter datasets by associated DAGs either consuming or producing. */ dag_ids?: string; }; }; From d091a9598a35d3fc298c34ecc144ed6e6b6aefab Mon Sep 17 00:00:00 2001 From: satoshi-sh Date: Tue, 20 Feb 2024 16:36:45 -0600 Subject: [PATCH 09/11] Simplified the filter logic --- airflow/api_connexion/endpoints/dataset_endpoint.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/airflow/api_connexion/endpoints/dataset_endpoint.py b/airflow/api_connexion/endpoints/dataset_endpoint.py index fd0b79c19728f..bf83c857d73aa 100644 --- a/airflow/api_connexion/endpoints/dataset_endpoint.py +++ b/airflow/api_connexion/endpoints/dataset_endpoint.py @@ -85,22 +85,13 @@ def get_datasets( total_entries = session.scalars(select(func.count(DatasetModel.id))).one() query = select(DatasetModel) - if dag_ids and uri_pattern: - dags_list = dag_ids.split(",") - query = query.filter( - ( - DatasetModel.consuming_dags.any(DagScheduleDatasetReference.dag_id.in_(dags_list)) - | DatasetModel.producing_tasks.any(TaskOutletDatasetReference.dag_id.in_(dags_list)) - ), - DatasetModel.uri.ilike(f"%{uri_pattern}%"), - ) - elif dag_ids: + if dag_ids: dags_list = dag_ids.split(",") query = query.filter( (DatasetModel.consuming_dags.any(DagScheduleDatasetReference.dag_id.in_(dags_list))) | (DatasetModel.producing_tasks.any(TaskOutletDatasetReference.dag_id.in_(dags_list))) ) - elif uri_pattern: + if uri_pattern: query = query.where(DatasetModel.uri.ilike(f"%{uri_pattern}%")) query = apply_sorting(query, order_by, {}, allowed_attrs) datasets = session.scalars( From ad2bc8ea3d160819650dc271d76d9c61bff34fc5 Mon Sep 17 00:00:00 2001 From: Satoshi S <73622805+Satoshi-Sh@users.noreply.github.com> Date: Tue, 20 Feb 2024 17:45:27 -0600 Subject: [PATCH 10/11] Added version information. Co-authored-by: Brent Bovenzi --- airflow/api_connexion/openapi/v1.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/airflow/api_connexion/openapi/v1.yaml b/airflow/api_connexion/openapi/v1.yaml index e8ca1e1e16fb9..9ac4b59b5f392 100644 --- a/airflow/api_connexion/openapi/v1.yaml +++ b/airflow/api_connexion/openapi/v1.yaml @@ -2075,6 +2075,8 @@ paths: required: false description: | One or more DAG IDs separated by commas to filter datasets by associated DAGs either consuming or producing. + + *New in version 2.9.0* responses: "200": description: Success. From a53aeb886a93aa688c79aa1b0dd249f6ba1ccc82 Mon Sep 17 00:00:00 2001 From: satoshi-sh Date: Wed, 21 Feb 2024 08:49:47 -0600 Subject: [PATCH 11/11] added new auto-generated file --- airflow/api_connexion/openapi/v1.yaml | 20 ++++++++++---------- airflow/www/static/js/types/api-generated.ts | 6 +++++- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/airflow/api_connexion/openapi/v1.yaml b/airflow/api_connexion/openapi/v1.yaml index 9ac4b59b5f392..8637612df8194 100644 --- a/airflow/api_connexion/openapi/v1.yaml +++ b/airflow/api_connexion/openapi/v1.yaml @@ -639,8 +639,8 @@ paths: "404": $ref: "#/components/responses/NotFound" - /dags/{dag_id}/dagRuns/{dag_run_id}/taskInstances/{task_id}/{map_index}/setNote: - parameters: + ? /dags/{dag_id}/dagRuns/{dag_run_id}/taskInstances/{task_id}/{map_index}/setNote + : parameters: - $ref: "#/components/parameters/DAGID" - $ref: "#/components/parameters/DAGRunID" - $ref: "#/components/parameters/TaskID" @@ -1767,8 +1767,8 @@ paths: "403": $ref: "#/components/responses/PermissionDenied" - /dags/{dag_id}/dagRuns/{dag_run_id}/taskInstances/{task_id}/xcomEntries/{xcom_key}: - parameters: + ? /dags/{dag_id}/dagRuns/{dag_run_id}/taskInstances/{task_id}/xcomEntries/{xcom_key} + : parameters: - $ref: "#/components/parameters/DAGID" - $ref: "#/components/parameters/DAGRunID" - $ref: "#/components/parameters/TaskID" @@ -1839,8 +1839,8 @@ paths: "404": $ref: "#/components/responses/NotFound" - /dags/{dag_id}/dagRuns/{dag_run_id}/taskInstances/{task_id}/logs/{task_try_number}: - parameters: + ? /dags/{dag_id}/dagRuns/{dag_run_id}/taskInstances/{task_id}/logs/{task_try_number} + : parameters: - $ref: "#/components/parameters/DAGID" - $ref: "#/components/parameters/DAGRunID" - $ref: "#/components/parameters/TaskID" @@ -2075,7 +2075,7 @@ paths: required: false description: | One or more DAG IDs separated by commas to filter datasets by associated DAGs either consuming or producing. - + *New in version 2.9.0* responses: "200": @@ -4013,17 +4013,17 @@ components: ti_deps: type: array items: - type: string + type: string description: The plugin task instance dependencies listeners: type: array items: - type: string + type: string description: The plugin listeners timetables: type: array items: - type: string + type: string description: The plugin timetables PluginCollection: diff --git a/airflow/www/static/js/types/api-generated.ts b/airflow/www/static/js/types/api-generated.ts index 2c3c4235b3b33..1184dd5323732 100644 --- a/airflow/www/static/js/types/api-generated.ts +++ b/airflow/www/static/js/types/api-generated.ts @@ -4504,7 +4504,11 @@ export interface operations { order_by?: components["parameters"]["OrderBy"]; /** If set, only return datasets with uris matching this pattern. */ uri_pattern?: string; - /** One or more DAG IDs separated by commas to filter datasets by associated DAGs either consuming or producing. */ + /** + * One or more DAG IDs separated by commas to filter datasets by associated DAGs either consuming or producing. + * + * *New in version 2.9.0* + */ dag_ids?: string; }; };