Including Relationships
The include query parameter allows clients to eager-load Lucid relationships (preload) and relationship counts (withCount) on demand.
All includes must be explicitly allowed via .allowedIncludes() on the query builder or via the includes property on a Filterable Class.
Basic Usage
Pass relationship names defined on your Lucid model to .allowedIncludes():
// GET /users?include=posts,profile
// Calls query.preload('posts') and query.preload('profile')
const users = await User.query()
.withRequest(request)
.allowedIncludes('posts', 'profile');
// Or pass an array:
// .allowedIncludes(['posts', 'profile'])
If a client requests an include that is not allowed, an InvalidIncludeQuery exception (400 Bad Request) is thrown unless disableInvalidIncludesQueryException is enabled in Configuration.
Nested Relationships
You can allow nested relationships using dot-notation (posts.comments). Allowing a nested relationship automatically allows all parent segments along the path (posts and posts.comments):
// Allows ?include=posts, ?include=posts.comments, and ?include=posts.comments.author
const users = await User.query()
.withRequest(request)
.allowedIncludes('posts.comments.author');
Including Relationship Counts
Whenever you allow a top-level relationship with AllowedInclude.relationship('posts') (or by passing 'posts' as a string), the package automatically registers a count include suffixed with Count (configurable via countSuffix in config/apiquery.ts).
// GET /users?include=postsCount
// Executes query.withCount('posts'), exposing $extras.posts_count on each user
const users = await User.query()
.withRequest(request)
.allowedIncludes('posts');
If you only want to allow counting a relationship without allowing the full relationship records to be preloaded, use AllowedInclude.count() or pass 'postsCount' directly:
import { AllowedInclude } from '@eienjs/adonisjs-api-query';
// Allows ?include=postsCount, but rejects ?include=posts
const users = await User.query()
.withRequest(request)
.allowedIncludes([
AllowedInclude.count('postsCount'),
]);
Aliasing Includes
Use AllowedInclude.relationship(name, internalName) or AllowedInclude.count(name, internalName) to expose a public include name that maps to a different relationship name on your model:
import { AllowedInclude } from '@eienjs/adonisjs-api-query';
// GET /users?include=articles -> preloads the `posts` relationship
// GET /users?include=articlesCount -> calls withCount('posts')
const users = await User.query()
.withRequest(request)
.allowedIncludes([
AllowedInclude.relationship('articles', 'posts'),
]);
Callback Includes
Use AllowedInclude.callback() when you want to customize the preload subquery (for example, selecting specific columns, ordering related records, or filtering the preloaded relation):
import { AllowedInclude } from '@eienjs/adonisjs-api-query';
// GET /users?include=latestPosts
const users = await User.query()
.withRequest(request)
.allowedIncludes([
AllowedInclude.callback('latestPosts', (postsQuery) => {
void postsQuery
.where('isPublished', true)
.orderBy('createdAt', 'desc')
.limit(5);
}, 'posts'),
]);
include<Name>(query) method on your class and list 'name' in public includes = ['name']—it will automatically be bound as a callback include!Custom Include Classes
For reusable include strategies across multiple models, implement the Include<ParentModel> interface and register it with AllowedInclude.custom(). See Custom Filters, Sorts & Includes for details.
