JCC Express

JCC Eloquent ORM

Retrieving Models

Introduction

JCC-Eloquent models expose static retrieval methods through Model + QueryBuilder.

Use these for common fetch patterns before dropping to raw SQL.


Basic retrieval

TypeScript
const users = await User.all();
const user = await User.find(1);

Query constraints

TypeScript
const rows = await User.where("status", "active")
  .orderBy("created_at", "desc")
  .limit(20)
  .get();

const first = await User.where("email", "admin@example.com").first();

Existence and value helpers

TypeScript
const exists = await User.where("email", email).exists();
const missing = await User.where("email", email).doesntExist();
const email = await User.where("id", 1).value("email");

Select and raw

TypeScript
const slim = await User.select("id", "name", "email").get();
const rows = await User.runQuery("select * from users where active = ?", [1]);

Aggregates

TypeScript
const total = await User.count("id");
const maxScore = await User.max("score");
const minScore = await User.min("score");
const avgScore = await User.avg("score");
const sumScore = await User.sum("score");

Advanced where variants

Available static methods include:

  • whereNot, orWhereNot
  • whereNotNull, whereNull
  • whereIn, whereBetween, whereNotBetween, orWhereBetween
  • whereExists, orWhereExists
  • whereDate, whereMonth, whereDay, whereYear, whereTime
  • whereRaw, orWhereRaw
  • whereLike, orWhereLike

Hydrating raw data

Model.hydrate() converts plain objects (e.g. from a raw query) into model instances:

TypeScript
const rows = await DB.table("users").where("active", true).getRaw();
const users = await User.hydrate(rows) as User[];

Also works with eager loading:

TypeScript
const users = await User.hydrate(rows, { posts: null }) as User[];

Executing without events

Run a block of writes without firing model events (creating, updating, etc.):

TypeScript
await User.executeWithoutEvents(async () => {
  await User.create({ name: "Seed User", email: "seed@example.com" });
  await User.where("role", "guest").update({ active: false });
});

Useful in seeders and migrations where lifecycle hooks are unwanted.


Loading relations on existing instances

Use load() to fetch relations after a model is already retrieved:

TypeScript
const user = await User.find(1);

// Load later without re-fetching the user
await user.load("posts");
await user.load(["posts", "profile"]);
await user.load({ posts: (q) => q.where("published", true) });

Saving without events

saveQuietly() persists changes without triggering any model events:

TypeScript
const user = await User.find(1);
user.name = "Updated silently";
await user.saveQuietly();

Similarly: updateQuietly(attrs), deleteQuietly().


Summary

  • Start with all, find, where(...).get(), and first().
  • Use existence/value/aggregate helpers for efficient reads.
  • Use hydrate() to wrap raw query results in model instances.
  • Use executeWithoutEvents() in seeders and batch operations.
  • Use saveQuietly() / updateQuietly() / deleteQuietly() to skip event hooks.
  • Use runQuery and raw clauses only when builder expressions are not enough.