Customize

By default, GraphQL(source) derives typed filter, columns, and row from the schema. This can be done explicitly by calling implement on the ibis schema.

import ibis
import strawberry

from graphique import Dataset, GraphQL, implement

source = ibis.read_parquet("../../tests/fixtures/zipcodes.parquet")
Table = implement(source.schema())
issubclass(Table, Dataset)
True

Subclass Dataset - or Table to include the typed fields - and register additional fields.

Protected fields such as sql are denied by default; opt in with strawberry.field(Dataset.sql, ...).

@strawberry.type
class Zipcodes(Table):
    sql = strawberry.field(Dataset.sql, permission_classes=[])  # enable permissions

    @strawberry.field  # add schema-aware fields manually
    def states(self) -> list[str]:
        return self.table["state"].value_counts()[0].to_list()

Call GraphQL on a Query type with attributes, so that the root value is stored. The types are inferred.

class Query:
    zipcodes = Zipcodes(source=source)

app = GraphQL(Query)

Usage

def execute(query):
    result = app.schema.execute_sync(query, root_value=app.root_value)
    for error in result.errors or []:
        raise ValueError(error)
    return result.data

execute("""{ zipcodes {
    count
    filter(state: {eq: "CA"}) { count }
    sql(query: "select * from t where state = 'CA'", alias: "t") { count }
    states
} }""")
{'zipcodes': {'count': 41700,
  'filter': {'count': 2647},
  'sql': {'count': 2647},
  'states': ['PR',
   'ME',
   'VT',
   'CT',
   'DC',
   'VA',
   'WV',
   'FL',
   'MS',
   'IN',
   'IL',
   'NE',
   'LA',
   'AR',
   'ID',
   'RI',
   'NJ',
   'DE',
   'SC',
   'AL',
   'TN',
   'KY',
   'OH',
   'MI',
   'IA',
   'SD',
   'ND',
   'MT',
   'MO',
   'OK',
   'TX',
   'AZ',
   'NV',
   'CA',
   'OR',
   'AK',
   'NC',
   'GA',
   'WI',
   'MN',
   'KS',
   'UT',
   'NM',
   'HI',
   'NY',
   'MA',
   'NH',
   'PA',
   'MD',
   'CO',
   'WY',
   'WA']}}

Advanced

GraphQL implementations commonly treat top-level fields as static methods. Whereas graphique requires root values to function as expected. The above example is syntactic sugar for:

@strawberry.type
class Query:
    zipcodes: Zipcodes

app = GraphQL(Query(zipcodes=Zipcodes(source=source)))