API#

Anything documented here is part of the public API that Magql-SQLAlchemy provides, unless otherwise indicated. Anything not documented here is considered internal or private and may change at any time.

Models#

class magql_sqlalchemy.ModelGroup(managers=None)#

Collects multiple model managers and manages higher-level APIs such as search and check delete.

Typically there will be one group for all the models. If more than one group is used for some reason, the field names for its search and check_delete instances should be changed.

Parameters:

managers (list[ModelManager] | None) – The model managers that are part of this group.

managers: dict[str, magql_sqlalchemy.manager.ModelManager]#

Maps SQLAlchemy model names to their ModelManager instance. Use add_manager() to add to this.

search: Search#

The Search instance model providers will be registered on.

check_delete: CheckDelete#

The CheckDelete instance models will be registered on.

classmethod from_declarative_base(base, *, search=True)#

Create a group of model managers for all models in the given SQLAlchemy declarative base class.

Parameters:
Return type:

ModelGroup

add_manager(manager)#

Add another model manager after the group was created.

Parameters:

manager (ModelManager) – The model manager to add.

Return type:

None

register(schema)#

Register this group’s managers and APIs on the given magql.Schema instance.

Parameters:

schema (Schema) – The schema instance to register on.

Return type:

None

class magql_sqlalchemy.ModelManager(model, search=False)#

The API for a single SQLAlchemy model class. Generates Magql types, fields, resolvers, etc. These are exposed as attributes on this manager, and can be further customized after generation.

Parameters:
  • model (type[Any]) – The SQLAlchemy model class.

  • search (bool) – Whether this model will provide results in global search.

object: Object#

The object type and fields representing the model and its columns. The type name is the model name.

type Model {
    id: Int!
    name: String!
}
model: type[Any]#

The SQLAlchemy model class.

item_field: Field#

Query that selects a row by id from the database. Will return null if the id doesn’t exist. The field name is the snake case model name with _item appended. Uses ItemResolver.

type Query {
    model_item(id: Int!): Model
}
list_result: Object#

The object type representing the result of the list query. The type name is the model name with ListResult appended. ListResult is the Python type corresponding to this Magql type.

list_field: Field#

Query that selects multiple rows from the database. The field name is the snake case model name with _list appended. Uses ListResolver.

type Query {
    model_list(
        filter: [[FilterItem!]!],
        sort: [String!],
        page: Int,
        per_page: Int
    ): ModelListResult!
}
create_field: Field#

Mutation that inserts a row into the database. The field name is the snake case model name with _create appended. An argument is generated for each column in the model except the primary key. An argument is required if its column is not nullable and doesn’t have a default. Uses CreateResolver.

type Mutation {
    model_create(name: String!): Model!
}
update_field: Field#

Mutation that updates a row in the database. The field name is the snake case model name with _update appended. An argument is generated for each column in the model. The primary key argument is required, all others are not. Columns are not updated if their argument is not given. Uses UpdateResolver.

type Mutation {
    model_update(id: Int!, name: String): Model!
}
delete_field: Field#

Mutation that deletes a row from the database. The field name is the snake case model name with _delete appended. Uses DeleteResolver.

type Mutation {
    model_delete(id: Int!): Boolean!
}
search_provider: SearchProvider | None = None#

A global search provider function. Enabling search will create a ColumnSearchProvider that checks if any of the model’s string columns contains the search term. This can be set to a custom function to change search behavior.

register(schema)#

Register this manager’s query and mutation fields on the given magql.Schema instance.

Parameters:

schema (Schema) – The schema instance to register on.

Return type:

None

If a search provider is enabled for this manager, register it on the given Search instance.

Typically the search instance is managed by the ModelGroup, which will register it on a schema.

Parameters:

search (Search) – The search instance to register on.

Return type:

None

Resolvers#

class magql_sqlalchemy.resolvers.ItemResolver(model)#

Get a single row from the database by id. Used by ModelManager.item_field. id is the only GraphQL argument. Returns a single model instance, or None if the id wasn’t found.

Parameters:

model (type[t.Any]) – The SQLAlchemy model.

build_query(parent, info, **kwargs)#

Build the query to execute.

Parameters:
Return type:

Select

transform_result(result)#

Get the model instance or list of instances from a SQLAlchemy result.

Parameters:

result (Result[Any]) –

Return type:

Any

class magql_sqlalchemy.resolvers.ListResolver(model)#

Get a list of rows from the database, with support for filtering, sorting, and pagination. If any relationships, arbitrarily nested, are selected, they are eagerly loaded to Used by ModelManager.list_field. Returns a ListResult, which has the list of model instances selected for this page, as well as the total available rows.

Pagination is always applied to the query to avoid returning thousands of results at once for large data sets. The default page is 1. The default per_page is 10, with a max of 100.

The sort argument is a list of (name: str, desc: bool) items from the ModelManager.sort enum. By default the rows are sorted by their primary key column, otherwise the order wouldn’t be guaranteed consistent across pages.

Filtering applies one or more filter rules to the query. The filter argument is a list of lists of rules. Each rule is a {path, op, not, value} dict. The rules in a list will be combined with AND, and the lists will be combined with OR. The path in a rule is the name of a column attribute on the model like name, or a dotted path to an arbitrarily nested relationship’s column like user.friend.color.name. Different op names are available based on the column’s type. The value can be any JSON data that the op understands. Most ops support a list of values in addition to a single value. See apply_filter_item() and type_ops.

If any relationships are selected anywhere in the GraphQL query, SQLAlchemy eager loads are generated them. This makes resolving the graph very efficient by letting SQLAlchemy preload related data rather than issuing individual queries for every attribute access.

Parameters:

model (type[t.Any]) – The SQLAlchemy model.

build_query(parent, info, **kwargs)#

Build the query to execute.

Parameters:
Return type:

Select

get_count(session, query)#

After generating the query with any filters, get the total row count for pagination purposes. Remove any eager loads, sorts, and pagination, then execute a SQL count() query.

Parameters:
  • session (Session) – The SQLAlchemy session.

  • query (Select) – The fully constructed list query.

Return type:

int

transform_result(result)#

Get the model instance or list of instances from a SQLAlchemy result.

Parameters:

result (Result[Any]) –

Return type:

Any

class magql_sqlalchemy.resolvers.CreateResolver(model)#

Create a new row in the database. Used by ModelManager.create_field. The field has arguments for each of the model’s column attributes. An argument is not required if its column is nullable or has a default. Unique constraints on will already be validated. Returns the new model instance.

Parameters:

model (type[t.Any]) – The SQLAlchemy model.

For all relationship arguments, replace the id values with their model instances.

Parameters:
Return type:

None

get_item(info, kwargs)#

Get the model instance by primary key value.

Parameters:
Return type:

Any

class magql_sqlalchemy.resolvers.UpdateResolver(model)#

Updates a row in the database by id. Used by ModelManager.update_field. The field has arguments for each of the model’s column attributes. Only the primary key argument is required. Columns are only updated if a value is provided, which is distinct from setting the value to None. Unique constraints will already be validated. Returns the updated model instance.

Parameters:

model (type[t.Any]) – The SQLAlchemy model.

For all relationship arguments, replace the id values with their model instances.

Parameters:
Return type:

None

get_item(info, kwargs)#

Get the model instance by primary key value.

Parameters:
Return type:

Any

class magql_sqlalchemy.resolvers.DeleteResolver(model)#

Deletes a row in the database by id. Used by ModelManager.update_field. Use the CheckDelete API first to check if the row can be safely deleted. Returns True.

Parameters:

model (type[t.Any]) – The SQLAlchemy model.

For all relationship arguments, replace the id values with their model instances.

Parameters:
Return type:

None

get_item(info, kwargs)#

Get the model instance by primary key value.

Parameters:
Return type:

Any

magql_sqlalchemy.filters.type_ops: dict[type[sqlalchemy.sql.type_api.TypeEngine], dict[str, Callable[[sqlalchemy.sql.schema.Column[Any], list[Any]], Any]]] = {<class 'sqlalchemy.sql.sqltypes.String'>: {'eq': <function op_eq>, 'like': <function op_like>}, <class 'sqlalchemy.sql.sqltypes.Integer'>: {'eq': <function op_eq>, 'lt': <function <lambda>>, 'le': <function <lambda>>, 'ge': <function <lambda>>, 'gt': <function <lambda>>}, <class 'sqlalchemy.sql.sqltypes.Float'>: {'eq': <function op_eq>, 'lt': <function <lambda>>, 'le': <function <lambda>>, 'ge': <function <lambda>>, 'gt': <function <lambda>>}, <class 'sqlalchemy.sql.sqltypes.Boolean'>: {'eq': <function <lambda>>}, <class 'sqlalchemy.sql.sqltypes.DateTime'>: {'eq': <function op_eq>, 'lt': <function <lambda>>, 'le': <function <lambda>>, 'ge': <function <lambda>>, 'gt': <function <lambda>>}, <class 'sqlalchemy.sql.sqltypes.Enum'>: {'eq': <function op_eq>}}#

Maps SQLAlchemy column types to available filter operations. The operations map names to callables that generate a SQL expression.

Check Delete#

class magql_sqlalchemy.check_delete.CheckDelete(managers, field_name='check_delete')#

Query field and resolver that shows what would be affected by deleting a row, without actually deleting it. Rather than creating a separate query per model, this is a generic API using the model name and id.

The resolver returns CheckDeleteResult, which is a collection of SearchResult items.

  • Affected - Items that will have references to the deleted item removed, such as many-to-many or nullable foreign keys.

  • Deleted - Items that will be deleted along with the deleted item.

  • Prevented - Items that will not be deleted or have references removed prevent the item from being deleted.

This shouldn’t need to be created directly, it’s managed by ModelGroup.

Parameters:
  • managers (dict[str, ModelManager]) – Maps model names to managers.

  • field_name (str) – The name to use for this field in the top-level query object.

managers#

Maps model names to managers. These are the models that can be checked.

register(schema)#

Register the field on the given Search instance.

Parameters:

schema (Schema) – The schema instance to register on.

Return type:

None

field: nodes.Field#

The query field.

type Query {
    check_delete(type: String!, id: ID!): CheckDeleteResult!
}
field_name: str#

The name to use for this field in the top-level query object.

Validators#

class magql_sqlalchemy.validators.ItemExistsValidator(model, key, col)#

Validate that an id exists for a model in the database. Used by update and delete mutations.

Parameters:
  • model (type[t.Any]) – The model to query.

  • key (str) – The primary key name, shown in the error message.

  • col (sa.Column[t.Any]) – The primary key column.

class magql_sqlalchemy.validators.ListExistsValidator(model, key, col)#

Validate that a list of ids all exist for a model in the database. Used by update mutations for to-many relationships. Each id that does not exist will generate its own error message.

Parameters:
  • model (type[t.Any]) – The model to query.

  • key (str) – The primary key name, shown in the error message.

  • col (sa.Column[t.Any]) – The primary key column.

class magql_sqlalchemy.validators.UniqueValidator(model, columns, pk_name, pk_col)#

Validate that a value for a column is unique, or values for a group of columns are unique together. Used by create and update mutations.

For create mutations, optional arguments that aren’t provided will use the column’s default. However, this can’t work for columns with callable defaults.

For update mutations, the row won’t conflict with itself. Optional arguments that aren’t provided will use the row’s data.

Parameters:
  • model (type[t.Any]) – The model to query.

  • columns (dict[str, sa.Column[t.Any]]) – One or more columns that must be unique together.

  • pk_name (str) – The primary key name. Used during update mutations.

  • pk_col (sa.Column[t.Any]) – The primary key column. Used during update mutations.

magql_sqlalchemy.pagination.validate_page(info, value, data)#

Validate the page argument to ListResolver.

Parameters:
Return type:

None

class magql_sqlalchemy.pagination.PerPageValidator(max_per_page=100)#

Validate the per_page argument to ListResolver.

Parameters:

max_per_page (int | None) – The maximum allowed value, or None for no maximum.