This is an automated email from the ASF dual-hosted git repository.

pierrejeambrun pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new ddae5a548a5 Add variable key search support (#44794)
ddae5a548a5 is described below

commit ddae5a548a5d7b6f3ebdcbe858c79eb467335c36
Author: Shubham Raj <[email protected]>
AuthorDate: Tue Dec 10 20:40:59 2024 +0530

    Add variable key search support (#44794)
    
    * add primary search
    
    * added tests
    
    * fix tests
    
    * fix test
---
 airflow/api_fastapi/common/parameters.py           |  6 +++
 .../api_fastapi/core_api/openapi/v1-generated.yaml |  8 +++
 .../core_api/routes/public/variables.py            |  9 +++-
 airflow/ui/openapi-gen/queries/common.ts           |  4 +-
 airflow/ui/openapi-gen/queries/prefetch.ts         | 12 ++++-
 airflow/ui/openapi-gen/queries/queries.ts          | 12 ++++-
 airflow/ui/openapi-gen/queries/suspense.ts         | 12 ++++-
 airflow/ui/openapi-gen/requests/services.gen.ts    |  2 +
 airflow/ui/openapi-gen/requests/types.gen.ts       |  1 +
 .../core_api/routes/public/test_variables.py       | 61 ++++++++++++++++++----
 10 files changed, 111 insertions(+), 16 deletions(-)

diff --git a/airflow/api_fastapi/common/parameters.py 
b/airflow/api_fastapi/common/parameters.py
index dbaf4581ac1..423de808551 100644
--- a/airflow/api_fastapi/common/parameters.py
+++ b/airflow/api_fastapi/common/parameters.py
@@ -49,6 +49,7 @@ from airflow.models.asset import (
 from airflow.models.dag import DagModel, DagTag
 from airflow.models.dagrun import DagRun
 from airflow.models.taskinstance import TaskInstance
+from airflow.models.variable import Variable
 from airflow.typing_compat import Self
 from airflow.utils import timezone
 from airflow.utils.state import DagRunState, TaskInstanceState
@@ -583,3 +584,8 @@ QueryAssetAliasNamePatternSearch = Annotated[
 QueryAssetDagIdPatternSearch = Annotated[
     _DagIdAssetReferenceFilter, Depends(_DagIdAssetReferenceFilter().depends)
 ]
+
+# Variables
+QueryVariableKeyPatternSearch = Annotated[
+    _SearchParam, Depends(search_param_factory(Variable.key, 
"variable_key_pattern"))
+]
diff --git a/airflow/api_fastapi/core_api/openapi/v1-generated.yaml 
b/airflow/api_fastapi/core_api/openapi/v1-generated.yaml
index bd73d3a306a..3b6d55c9313 100644
--- a/airflow/api_fastapi/core_api/openapi/v1-generated.yaml
+++ b/airflow/api_fastapi/core_api/openapi/v1-generated.yaml
@@ -5549,6 +5549,14 @@ paths:
           type: string
           default: id
           title: Order By
+      - name: variable_key_pattern
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: string
+          - type: 'null'
+          title: Variable Key Pattern
       responses:
         '200':
           description: Successful Response
diff --git a/airflow/api_fastapi/core_api/routes/public/variables.py 
b/airflow/api_fastapi/core_api/routes/public/variables.py
index 0e1cebbe0a2..1b970444f31 100644
--- a/airflow/api_fastapi/core_api/routes/public/variables.py
+++ b/airflow/api_fastapi/core_api/routes/public/variables.py
@@ -22,7 +22,12 @@ from fastapi import Depends, HTTPException, Query, status
 from sqlalchemy import select
 
 from airflow.api_fastapi.common.db.common import SessionDep, paginated_select
-from airflow.api_fastapi.common.parameters import QueryLimit, QueryOffset, 
SortParam
+from airflow.api_fastapi.common.parameters import (
+    QueryLimit,
+    QueryOffset,
+    QueryVariableKeyPatternSearch,
+    SortParam,
+)
 from airflow.api_fastapi.common.router import AirflowRouter
 from airflow.api_fastapi.core_api.datamodels.variables import (
     VariableBody,
@@ -86,10 +91,12 @@ def get_variables(
         ),
     ],
     session: SessionDep,
+    varaible_key_pattern: QueryVariableKeyPatternSearch,
 ) -> VariableCollectionResponse:
     """Get all Variables entries."""
     variable_select, total_entries = paginated_select(
         statement=select(Variable),
+        filters=[varaible_key_pattern],
         order_by=order_by,
         offset=offset,
         limit=limit,
diff --git a/airflow/ui/openapi-gen/queries/common.ts 
b/airflow/ui/openapi-gen/queries/common.ts
index d1a5f20511d..b759c0f2f23 100644
--- a/airflow/ui/openapi-gen/queries/common.ts
+++ b/airflow/ui/openapi-gen/queries/common.ts
@@ -1597,15 +1597,17 @@ export const UseVariableServiceGetVariablesKeyFn = (
     limit,
     offset,
     orderBy,
+    variableKeyPattern,
   }: {
     limit?: number;
     offset?: number;
     orderBy?: string;
+    variableKeyPattern?: string;
   } = {},
   queryKey?: Array<unknown>,
 ) => [
   useVariableServiceGetVariablesKey,
-  ...(queryKey ?? [{ limit, offset, orderBy }]),
+  ...(queryKey ?? [{ limit, offset, orderBy, variableKeyPattern }]),
 ];
 export type MonitorServiceGetHealthDefaultResponse = Awaited<
   ReturnType<typeof MonitorService.getHealth>
diff --git a/airflow/ui/openapi-gen/queries/prefetch.ts 
b/airflow/ui/openapi-gen/queries/prefetch.ts
index 566f207f9ae..eab8ea6b356 100644
--- a/airflow/ui/openapi-gen/queries/prefetch.ts
+++ b/airflow/ui/openapi-gen/queries/prefetch.ts
@@ -2183,6 +2183,7 @@ export const prefetchUseVariableServiceGetVariable = (
  * @param data.limit
  * @param data.offset
  * @param data.orderBy
+ * @param data.variableKeyPattern
  * @returns VariableCollectionResponse Successful Response
  * @throws ApiError
  */
@@ -2192,10 +2193,12 @@ export const prefetchUseVariableServiceGetVariables = (
     limit,
     offset,
     orderBy,
+    variableKeyPattern,
   }: {
     limit?: number;
     offset?: number;
     orderBy?: string;
+    variableKeyPattern?: string;
   } = {},
 ) =>
   queryClient.prefetchQuery({
@@ -2203,8 +2206,15 @@ export const prefetchUseVariableServiceGetVariables = (
       limit,
       offset,
       orderBy,
+      variableKeyPattern,
     }),
-    queryFn: () => VariableService.getVariables({ limit, offset, orderBy }),
+    queryFn: () =>
+      VariableService.getVariables({
+        limit,
+        offset,
+        orderBy,
+        variableKeyPattern,
+      }),
   });
 /**
  * Get Health
diff --git a/airflow/ui/openapi-gen/queries/queries.ts 
b/airflow/ui/openapi-gen/queries/queries.ts
index 9b9a6dabce9..e90ae58e6b0 100644
--- a/airflow/ui/openapi-gen/queries/queries.ts
+++ b/airflow/ui/openapi-gen/queries/queries.ts
@@ -2580,6 +2580,7 @@ export const useVariableServiceGetVariable = <
  * @param data.limit
  * @param data.offset
  * @param data.orderBy
+ * @param data.variableKeyPattern
  * @returns VariableCollectionResponse Successful Response
  * @throws ApiError
  */
@@ -2592,21 +2593,28 @@ export const useVariableServiceGetVariables = <
     limit,
     offset,
     orderBy,
+    variableKeyPattern,
   }: {
     limit?: number;
     offset?: number;
     orderBy?: string;
+    variableKeyPattern?: string;
   } = {},
   queryKey?: TQueryKey,
   options?: Omit<UseQueryOptions<TData, TError>, "queryKey" | "queryFn">,
 ) =>
   useQuery<TData, TError>({
     queryKey: Common.UseVariableServiceGetVariablesKeyFn(
-      { limit, offset, orderBy },
+      { limit, offset, orderBy, variableKeyPattern },
       queryKey,
     ),
     queryFn: () =>
-      VariableService.getVariables({ limit, offset, orderBy }) as TData,
+      VariableService.getVariables({
+        limit,
+        offset,
+        orderBy,
+        variableKeyPattern,
+      }) as TData,
     ...options,
   });
 /**
diff --git a/airflow/ui/openapi-gen/queries/suspense.ts 
b/airflow/ui/openapi-gen/queries/suspense.ts
index ba8c34146b4..e7b21338760 100644
--- a/airflow/ui/openapi-gen/queries/suspense.ts
+++ b/airflow/ui/openapi-gen/queries/suspense.ts
@@ -2555,6 +2555,7 @@ export const useVariableServiceGetVariableSuspense = <
  * @param data.limit
  * @param data.offset
  * @param data.orderBy
+ * @param data.variableKeyPattern
  * @returns VariableCollectionResponse Successful Response
  * @throws ApiError
  */
@@ -2567,21 +2568,28 @@ export const useVariableServiceGetVariablesSuspense = <
     limit,
     offset,
     orderBy,
+    variableKeyPattern,
   }: {
     limit?: number;
     offset?: number;
     orderBy?: string;
+    variableKeyPattern?: string;
   } = {},
   queryKey?: TQueryKey,
   options?: Omit<UseQueryOptions<TData, TError>, "queryKey" | "queryFn">,
 ) =>
   useSuspenseQuery<TData, TError>({
     queryKey: Common.UseVariableServiceGetVariablesKeyFn(
-      { limit, offset, orderBy },
+      { limit, offset, orderBy, variableKeyPattern },
       queryKey,
     ),
     queryFn: () =>
-      VariableService.getVariables({ limit, offset, orderBy }) as TData,
+      VariableService.getVariables({
+        limit,
+        offset,
+        orderBy,
+        variableKeyPattern,
+      }) as TData,
     ...options,
   });
 /**
diff --git a/airflow/ui/openapi-gen/requests/services.gen.ts 
b/airflow/ui/openapi-gen/requests/services.gen.ts
index 9f8c9629bfb..c855ca58092 100644
--- a/airflow/ui/openapi-gen/requests/services.gen.ts
+++ b/airflow/ui/openapi-gen/requests/services.gen.ts
@@ -3010,6 +3010,7 @@ export class VariableService {
    * @param data.limit
    * @param data.offset
    * @param data.orderBy
+   * @param data.variableKeyPattern
    * @returns VariableCollectionResponse Successful Response
    * @throws ApiError
    */
@@ -3023,6 +3024,7 @@ export class VariableService {
         limit: data.limit,
         offset: data.offset,
         order_by: data.orderBy,
+        variable_key_pattern: data.variableKeyPattern,
       },
       errors: {
         401: "Unauthorized",
diff --git a/airflow/ui/openapi-gen/requests/types.gen.ts 
b/airflow/ui/openapi-gen/requests/types.gen.ts
index 76319152010..96a159bad07 100644
--- a/airflow/ui/openapi-gen/requests/types.gen.ts
+++ b/airflow/ui/openapi-gen/requests/types.gen.ts
@@ -2054,6 +2054,7 @@ export type GetVariablesData = {
   limit?: number;
   offset?: number;
   orderBy?: string;
+  variableKeyPattern?: string | null;
 };
 
 export type GetVariablesResponse = VariableCollectionResponse;
diff --git a/tests/api_fastapi/core_api/routes/public/test_variables.py 
b/tests/api_fastapi/core_api/routes/public/test_variables.py
index 348ca4c1af6..2c7419680dc 100644
--- a/tests/api_fastapi/core_api/routes/public/test_variables.py
+++ b/tests/api_fastapi/core_api/routes/public/test_variables.py
@@ -40,6 +40,11 @@ TEST_VARIABLE_VALUE3 = '{"password": "some_password"}'
 TEST_VARIABLE_DESCRIPTION3 = "Some description for the variable"
 
 
+TEST_VARIABLE_SEARCH_KEY = "test_variable_search_key"
+TEST_VARIABLE_SEARCH_VALUE = "random search value"
+TEST_VARIABLE_SEARCH_DESCRIPTION = "Some description for the variable"
+
+
 @provide_session
 def _create_variables(session) -> None:
     Variable.set(
@@ -63,6 +68,13 @@ def _create_variables(session) -> None:
         session=session,
     )
 
+    Variable.set(
+        key=TEST_VARIABLE_SEARCH_KEY,
+        value=TEST_VARIABLE_SEARCH_VALUE,
+        description=TEST_VARIABLE_SEARCH_DESCRIPTION,
+        session=session,
+    )
+
 
 class TestVariableEndpoint:
     @pytest.fixture(autouse=True)
@@ -80,11 +92,11 @@ class TestDeleteVariable(TestVariableEndpoint):
     def test_delete_should_respond_204(self, test_client, session):
         self.create_variables()
         variables = session.query(Variable).all()
-        assert len(variables) == 3
+        assert len(variables) == 4
         response = test_client.delete(f"/public/variables/{TEST_VARIABLE_KEY}")
         assert response.status_code == 204
         variables = session.query(Variable).all()
-        assert len(variables) == 2
+        assert len(variables) == 3
 
     def test_delete_should_respond_404(self, test_client):
         response = test_client.delete(f"/public/variables/{TEST_VARIABLE_KEY}")
@@ -122,6 +134,14 @@ class TestGetVariable(TestVariableEndpoint):
                     "description": TEST_VARIABLE_DESCRIPTION3,
                 },
             ),
+            (
+                TEST_VARIABLE_SEARCH_KEY,
+                {
+                    "key": TEST_VARIABLE_SEARCH_KEY,
+                    "value": TEST_VARIABLE_SEARCH_VALUE,
+                    "description": TEST_VARIABLE_SEARCH_DESCRIPTION,
+                },
+            ),
         ],
     )
     def test_get_should_respond_200(self, test_client, session, key, 
expected_response):
@@ -143,14 +163,37 @@ class TestGetVariables(TestVariableEndpoint):
         "query_params, expected_total_entries, expected_keys",
         [
             # Filters
-            ({}, 3, [TEST_VARIABLE_KEY, TEST_VARIABLE_KEY2, 
TEST_VARIABLE_KEY3]),
-            ({"limit": 1}, 3, [TEST_VARIABLE_KEY]),
-            ({"limit": 1, "offset": 1}, 3, [TEST_VARIABLE_KEY2]),
+            ({}, 4, [TEST_VARIABLE_KEY, TEST_VARIABLE_KEY2, 
TEST_VARIABLE_KEY3, TEST_VARIABLE_SEARCH_KEY]),
+            ({"limit": 1}, 4, [TEST_VARIABLE_KEY]),
+            ({"limit": 1, "offset": 1}, 4, [TEST_VARIABLE_KEY2]),
             # Sort
-            ({"order_by": "id"}, 3, [TEST_VARIABLE_KEY, TEST_VARIABLE_KEY2, 
TEST_VARIABLE_KEY3]),
-            ({"order_by": "-id"}, 3, [TEST_VARIABLE_KEY3, TEST_VARIABLE_KEY2, 
TEST_VARIABLE_KEY]),
-            ({"order_by": "key"}, 3, [TEST_VARIABLE_KEY3, TEST_VARIABLE_KEY2, 
TEST_VARIABLE_KEY]),
-            ({"order_by": "-key"}, 3, [TEST_VARIABLE_KEY, TEST_VARIABLE_KEY2, 
TEST_VARIABLE_KEY3]),
+            (
+                {"order_by": "id"},
+                4,
+                [TEST_VARIABLE_KEY, TEST_VARIABLE_KEY2, TEST_VARIABLE_KEY3, 
TEST_VARIABLE_SEARCH_KEY],
+            ),
+            (
+                {"order_by": "-id"},
+                4,
+                [TEST_VARIABLE_SEARCH_KEY, TEST_VARIABLE_KEY3, 
TEST_VARIABLE_KEY2, TEST_VARIABLE_KEY],
+            ),
+            (
+                {"order_by": "key"},
+                4,
+                [TEST_VARIABLE_KEY3, TEST_VARIABLE_KEY2, TEST_VARIABLE_KEY, 
TEST_VARIABLE_SEARCH_KEY],
+            ),
+            (
+                {"order_by": "-key"},
+                4,
+                [TEST_VARIABLE_SEARCH_KEY, TEST_VARIABLE_KEY, 
TEST_VARIABLE_KEY2, TEST_VARIABLE_KEY3],
+            ),
+            # Search
+            (
+                {"variable_key_pattern": "~"},
+                4,
+                [TEST_VARIABLE_KEY, TEST_VARIABLE_KEY2, TEST_VARIABLE_KEY3, 
TEST_VARIABLE_SEARCH_KEY],
+            ),
+            ({"variable_key_pattern": "search"}, 1, 
[TEST_VARIABLE_SEARCH_KEY]),
         ],
     )
     def test_should_respond_200(

Reply via email to