Searching

A model can be made searchable by setting the search attribute of the model to an SQLAlchemy Table object representing a fulltext search index table. The table must consist of a primary key column that references the model’s primary key, and an indexed TSVECTOR column.

For an example, to make our UserModel searchable we define a text search table:

from sqlalchemy.dialects.postgresql import TSVECTOR

users_ts = sa.Table(
    'users_ts', metadata,
    sa.Column('user_id', sa.Integer,
              sa.ForeignKey('users.id'),
              primary_key=True),
    sa.Column('tsvector', TSVECTOR,
              index=True, nullable=False))

And then we redefine the model:

class UserModel(Model):
    from_ = users_t, user_names_t
    fields = (...)
    search = users_ts

As an example, the following SQL can be used to populate the index table:

INSERT INTO users_ts (user_id, tsvector)
SELECT users.id,
       setweight(to_tsvector(users.email), 'A') ||
       setweight(to_tsvector(user_names.last), 'B') ||
       setweight(to_tsvector(user_names.first), 'B')
FROM users
         JOIN user_names ON users.id = user_names.user_id
ORDER BY users.id;

A Single Model

To search a single resource model, simply pass the fulltext search term as the search argument of Model.get_collection() or Model.get_related() for to-many relationships:

>>> await UserModel().get_collection({}, search='John')
>>> await UserModel().get_related(1, 'followers', search='John')

The result of a search query is always sorted by the search result ranking, and any sort option provided will be ignored.

Filtering and searching are not compatible, and cannot be used simultaneously. Doing so will raise an exception:

>>> await UserModel().get_collection({'filter[id]': '1,2,3'}, search='John')
Traceback (most recent call last):
...
jsonapi.exc.APIError: [UserModel] cannot filter and search at the same time

Multiple Models

Use the search() function to search multiple resource models at once and return a heterogeneous collection of objects:

>>> from jsonapi.model import search
>>> search({}, 'John', UserModel, ArticleModel)

The first argument is a dictionary of options representing the request parameters. The second argument is PostgreSQL full text search query string.

Any additional arguments are expected to be model classes or instances. At least two unique models are expected.

Pagination is supported, while filtering and sorting are not. To include related resources for a model type, provide an appropriate include[TYPE] option. A simple include option will be ignored:

>>> search({'include[user]': 'bio',
>>>         'include[article]': 'keywords,author.bio,publisher.bio',
>>>         'fields[user]': 'name,email',
>>>         'fields[user-bio]': 'birthday,age',
>>>         'fields[article]': 'title'},
>>>         'John', UserModel, ArticleModel)