SlintORM
Docsnpm

Joins

SlintORM supports INNER, LEFT, RIGHT, and FULL OUTER joins. RIGHT and FULL OUTER are available via model.advanced().

INNER join

// .join(table, left, op, right) — INNER JOIN
const posts = await Post.query()
  .join('users', 'posts.userId', '=', 'users.id')
  .select('posts.id', 'posts.title', 'users.name', 'users.email')
  .get();
// SELECT posts.id, posts.title, users.name, users.email
// FROM posts
// INNER JOIN users ON posts.userId = users.id

LEFT join

// .leftJoin(table, left, op, right) — LEFT JOIN
// Returns all posts, even those without a matching user
const posts = await Post.query()
  .leftJoin('users', 'posts.userId', '=', 'users.id')
  .select('posts.*', 'users.name')
  .get();

RIGHT join

// .rightJoin(table, left, op, right) — RIGHT JOIN
// Available via advanced() (AdvancedQueryBuilder)
const data = await Post.advanced()
  .rightJoin('users', 'posts.userId', '=', 'users.id')
  .select('users.name', 'posts.title')
  .get();

FULL OUTER join

// .fullOuterJoin(table, left, op, right) — FULL OUTER JOIN
// Available via advanced() (AdvancedQueryBuilder)
// Note: SQLite does not support FULL OUTER JOIN natively
const data = await Post.advanced()
  .fullOuterJoin('users', 'posts.userId', '=', 'users.id')
  .get();

Multiple joins

// Multiple joins
const results = await Post.query()
  .join('users', 'posts.userId', '=', 'users.id')
  .join('categories', 'posts.categoryId', '=', 'categories.id')
  .select(
    'posts.id',
    'posts.title',
    'users.name',
    'categories.name'
  )
  .where('users.role', '=', 'author')
  .orderBy('posts.createdAt', 'DESC')
  .get();

Complex conditions with whereRaw

// Complex join conditions with whereRaw
const results = await Post.query()
  .join('post_tags', 'posts.id', '=', 'post_tags.postId')
  .join('tags', 'post_tags.tagId', '=', 'tags.id')
  .whereRaw('tags.name IN (?, ?)', ['typescript', 'orm'])
  .select('posts.id', 'posts.title')
  .get();

Auto-qualification

When joins are active and no explicit select() is provided, SlintORM automatically qualifies the root table to table.*to avoid ambiguous column errors on shared names like id.

// When joins are present and no .select() is called,
// SlintORM auto-qualifies root table columns to "table.*"
// to prevent "ambiguous column" errors from the database

const posts = await Post.query()
  .join('users', 'posts.userId', '=', 'users.id')
  // No .select() — SlintORM emits: SELECT posts.* FROM posts ...
  .get();
Prefer preloads over joins for relations

Manual joins are best for arbitrary SQL relationships. For loading related records declared in model annotations (@relation), use .preload("relation") instead. Preloads batch-fetch related records without N+1 queries.

Previouswhere()NextOrdering & Pagination