diff --git a/CHANGELOG.md b/CHANGELOG.md index 88c87ac0f77..187b4481680 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ### Bug fixes and improvements +- server: add jsonb to string cast support - postgres - server: improve performance of fetching postgres catalog metadata for tables and functions - server: Queries present in query collections, such as allow-list, and rest-endpoints are now validated (against the schema) - server: Redesigns internal implementation of webhook transforms. diff --git a/docs/graphql/core/api-reference/graphql-api/query.rst b/docs/graphql/core/api-reference/graphql-api/query.rst index d7e1ad08d18..da48c165d04 100644 --- a/docs/graphql/core/api-reference/graphql-api/query.rst +++ b/docs/graphql/core/api-reference/graphql-api/query.rst @@ -814,7 +814,10 @@ CastExp .. note:: - Currently, only casting between ``geometry`` and ``geography`` types is allowed. + Currently, only the following type casts are supported: + + - between PostGIS ``geometry`` and ``geography`` types + - from Postgres ``jsonb`` type to ``string`` type. .. _OrderByExp: diff --git a/docs/graphql/core/databases/ms-sql-server/queries/query-filters.rst b/docs/graphql/core/databases/ms-sql-server/queries/query-filters.rst index 878caa1cfd0..4f5032eacbd 100644 --- a/docs/graphql/core/databases/ms-sql-server/queries/query-filters.rst +++ b/docs/graphql/core/databases/ms-sql-server/queries/query-filters.rst @@ -558,7 +558,7 @@ Fetch a list of articles whose titles contain the word “amet”: "city": "Bengaluru", "state": "Karnataka", "pincode": 560095, - "phone": "9090909090", + "phone": "9090909090" } } ] diff --git a/docs/graphql/core/databases/postgres/queries/query-filters.rst b/docs/graphql/core/databases/postgres/queries/query-filters.rst index 9d68eadface..f5cf448b247 100644 --- a/docs/graphql/core/databases/postgres/queries/query-filters.rst +++ b/docs/graphql/core/databases/postgres/queries/query-filters.rst @@ -644,7 +644,7 @@ Fetch all authors living within a particular pincode (present in ``address`` JSO "city": "Bengaluru", "state": "Karnataka", "pincode": 560095, - "phone": "9090909090", + "phone": "9090909090" } } ] @@ -2026,13 +2026,55 @@ Cast a field to a different type before filtering (_cast) --------------------------------------------------------- The ``_cast`` operator can be used to cast a field to a different type, which allows type-specific -operators to be used on fields that otherwise would not support them. Currently, only casting -between PostGIS ``geometry`` and ``geography`` types is supported. +operators to be used on fields that otherwise would not support them. + +Currently, only the following type casts are supported: + +- between PostGIS ``geometry`` and ``geography`` types +- from Postgres ``jsonb`` type to ``string`` type. Casting using ``_cast`` corresponds directly to `SQL type casts `__. -**Example: cast ``geometry`` to ``geography``** +**Example: cast jsonb to string** + +Columns of type ``jsonb`` can be cast to ``String`` to use :ref:`text operators ` on a +``jsonb`` field: + +.. graphiql:: + :view_only: + :query: + query get_authors_in_bengaluru { + authors( + where: { + address: {_cast: {String: {_ilike: "%bengaluru%"}}} + } + ) { + id + name + address + } + } + :response: + { + "data": { + "authors": [ + { + "id": 1, + "name": "Ash", + "address": { + "street_address": "161, 19th Main Road, Koramangala 6th Block", + "city": "Bengaluru", + "state": "Karnataka", + "pincode": 560095, + "phone": "9090909090" + } + } + ] + } + } + +**Example: cast geometry to geography** Filtering using ``_st_d_within`` over large distances can be inaccurate for location data stored in ``geometry`` columns. For accurate queries, cast the field to ``geography`` before comparing: @@ -2073,7 +2115,7 @@ Filtering using ``_st_d_within`` over large distances can be inaccurate for loca "distance": 1000000 } -**Example: cast ``geography`` to ``geometry``** +**Example: cast geography to geometry** Columns of type ``geography`` are more accurate, but they don’t support as many operations as ``geometry``. Cast to ``geometry`` to use those operations in a filter: diff --git a/server/src-lib/Hasura/Backends/Postgres/DDL/BoolExp.hs b/server/src-lib/Hasura/Backends/Postgres/DDL/BoolExp.hs index dd6519487fc..e97e7b4cca5 100644 --- a/server/src-lib/Hasura/Backends/Postgres/DDL/BoolExp.hs +++ b/server/src-lib/Hasura/Backends/Postgres/DDL/BoolExp.hs @@ -208,6 +208,7 @@ parseBoolExpOperations rhsParser rootTable fim columnRef value = do checkValidCast targetType = case (colTy, targetType) of (ColumnScalar PGGeometry, PGGeography) -> return () (ColumnScalar PGGeography, PGGeometry) -> return () + (ColumnScalar PGJSONB, PGText) -> return () _ -> throw400 UnexpectedPayload $ "cannot cast column of type " <> colTy <<> " to type " <>> targetType diff --git a/server/src-lib/Hasura/Backends/Postgres/Instances/Schema.hs b/server/src-lib/Hasura/Backends/Postgres/Instances/Schema.hs index f7562e7ce2e..1b0682ad367 100644 --- a/server/src-lib/Hasura/Backends/Postgres/Instances/Schema.hs +++ b/server/src-lib/Hasura/Backends/Postgres/Instances/Schema.hs @@ -599,6 +599,7 @@ comparisonExps = P.memoize 'comparisonExps \columnType -> do let maybeScalars = case sourceType of ColumnScalar PGGeography -> Just (PGGeography, PGGeometry) ColumnScalar PGGeometry -> Just (PGGeometry, PGGeography) + ColumnScalar PGJSONB -> Just (PGJSONB, PGText) _ -> Nothing forM maybeScalars $ \(sourceScalar, targetScalar) -> do diff --git a/server/tests-py/queries/graphql_query/boolexp/jsonb/query_cast_jsonb_to_string.yaml b/server/tests-py/queries/graphql_query/boolexp/jsonb/query_cast_jsonb_to_string.yaml new file mode 100644 index 00000000000..67c6a6c5d3c --- /dev/null +++ b/server/tests-py/queries/graphql_query/boolexp/jsonb/query_cast_jsonb_to_string.yaml @@ -0,0 +1,18 @@ +description: Test casting from jsonb to string +url: /v1/graphql +status: 200 +query: + query: | + query { + article(where: {tags: {_cast: {String: {_like: "%bestseller%"}}}}){ + id + tags + } + } +response: + data: + article: + - id: 2 + tags: + - bestseller + - latest diff --git a/server/tests-py/test_graphql_queries.py b/server/tests-py/test_graphql_queries.py index 8b4fdb9e888..2c43dba07b0 100644 --- a/server/tests-py/test_graphql_queries.py +++ b/server/tests-py/test_graphql_queries.py @@ -934,6 +934,9 @@ class TestGraphQLQueryBoolExpSearchMSSQL: @usefixtures('per_class_tests_db_state') class TestGraphQLQueryBoolExpJsonB: + def test_query_cast_geometry_to_geography(self, hge_ctx, transport): + check_query_f(hge_ctx, self.dir() + '/query_cast_jsonb_to_string.yaml', transport) + def test_jsonb_contains_article_latest(self, hge_ctx, transport): check_query_f(hge_ctx, self.dir() + '/select_article_author_jsonb_contains_latest.yaml', transport)