Dynamic GraphQL query builder
Project description
About this project
This project emerged from the frustrating experience when trying to write gql queries with dynamic filters. In some cases, think of a UI to beautifully display database contents, one desires to be able to set filters dynamically if some value is provided, yet just ignore it if not.
This behavior was guaranteed by Hasura versions 1.3.3v and below - but disabled by default in later versions, as described here.
The env var HASURA_GRAPHQL_V1_BOOLEAN_NULL_COLLAPSE preserves this functionality globally. However,
this as well is not always desired, when a more fine-grained control over when a value is strictly necessary
for where conditions, and when not, is of importance.
This project therefore provides a lightweight query builder that takes a simple gql query string as input and inserts the respective clauses if a value is presented, and does nothing, if not. This avoids nasty, error-prone, string concatenations while avoiding heavy-weight ASTs and the necessity of schema declarations as with gql-DSL.
Usage
All a user should be interacting with is located in the src.api package.
As of now it only contains the GQLDynamicQueryBuilder which is the heart of the project and
provides all the necessary functionality, while api.dsl provides a more user-friendly and convenient wrapper around the builder, as described here. To extend a query by an optional where clause one can do the
following:
query = """
query TestQuery {
product {
name
brand
}
}
"""
builder = GQLDynamicQueryBuilder(query)
builder = builder.with_where_clause(
table_name='product',
field_name='name',
value='tomato',
operation='_ilike',
skip_if_none=True
)
result = builder.build() # returns the transformed query as a string
This also works for queries with existing where clauses and other query parameters (e.g. limit). To access nested fields, simply use '.' as the delimiter:
builder.with_where_clause(
'product',
'brand.name', # will build brand { name: ...
'ABC',
'_eq',
skip_if_none=True
)
result = builder.build()
Furthermore, it is also possible to provide the following to with_where_clause:
values: listandoperation: strwhich allows for set-operations like_invalues: listandoperation: list[str]which allows for multiple operations for the same field (e.g.timestamp {_gte: <ts1> _lt: <ts2>})
As a fallback also explicit where clauses are supported via table_name: clause dictionaries:
builder.with_where_clauses(
{'product': 'name: {_ilike : "tomato"}'}
)
result = builder.build()
DSL
Since version 1.1.0 a more user-friendly DSL is provided under api.dsl.
The DSL is a wrapper around the builder pattern that enables a continuous flow of information, such as the table
name for which a filter is to be set. E.g. look at this builder-based query:
result = (GQLDynamicQueryBuilder(query)
.with_where_clause('product', 'name', ['a', 'b', 'c'], '_in', skip_if_none=True)
.with_offset('product', 15)
.with_limit('product', 25)
.with_where_clause('product', 'price', 5, '_gte')
).build()
All function calls in the above examples return a GQLDynamicQueryBuilder object, whose
state is modified along the way. Thereby, the table name is repeated 4 times and the code
is only marginally readable. Using the DSL on the other hand the same functionality can be achieved
through the following:
result = (dynamic_query(query).table('subquery_to_test')
.where('test', is_optional=True).
_in(['a', 'b', 'c'])
.offset(15)
.limit(25)
.where('test2')
._gte(5)
.build()
)
This way the query construction becomes much more readable and concise.
Furthermore, the method chaining is guarded by the type system, i.e.
there is no need to worry to e.g. chain build() to a where() as the dsl
is designed to only allow cohesive queries.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gql_dynamic_query_builder-1.1.0.tar.gz.
File metadata
- Download URL: gql_dynamic_query_builder-1.1.0.tar.gz
- Upload date:
- Size: 10.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1f2ba3886d0ee3d4930ae80c8de57988900353478e7a6fa8fc2bad22e4dbb168
|
|
| MD5 |
2b33d28934ed82d557ea56a4beb5fc81
|
|
| BLAKE2b-256 |
681d8eac5639d665c6c935931fa729edc663e6cff4835709b325c2f725a4894f
|
File details
Details for the file gql_dynamic_query_builder-1.1.0-py3-none-any.whl.
File metadata
- Download URL: gql_dynamic_query_builder-1.1.0-py3-none-any.whl
- Upload date:
- Size: 11.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fd364515c44ac56e333190c8a25cdf3c1a5a154f19a930bdea016d6b764ff319
|
|
| MD5 |
7212a3b863f1d4f77c8d894de42351af
|
|
| BLAKE2b-256 |
11374acf889dda2ba2926f3cd51905bda69e49507daadeb018cd3d8cdf08c9b4
|