Skip to content

Query Builder

The Rubik ORM Query Builder provides a fluent, driver-aware API to construct and execute SQL queries programmatically — while still giving you full control over the final SQL.

It supports:

  • SELECT, UPDATE, and DELETE operations
  • Conditions, joins, grouping, ordering, and pagination
  • Automatic hydration into model instances

Rubik’s query builder is intentionally minimal, predictable, and close to SQL, without hiding what’s really happening.


🧩 Creating Queries

Each model comes with a static query() method that returns a Query instance bound to that model:

use App\Models\User;

$query = User::query();

Alternatively, you can manually create a new builder:

use AdaiasMagdiel\Rubik\Query;

$query = (new Query())->setModel(User::class);

🎯 Selecting Data

The simplest way to retrieve data:

$users = User::query()->all();

You can specify selected fields:

$users = User::query()
    ->select(['id', 'name', 'email'])
    ->all();

If you omit .select(), Rubik defaults to SELECT *.

You can also get only the first record:

$user = User::query()->first();

Or fetch by primary key (shortcut):

$user = User::find(1);

🔍 Filtering with where

Rubik provides fluent where() and orWhere() methods.

Examples

// Simple equals
User::query()->where('id', 1)->first();

// Custom operator
User::query()->where('age', '>=', 18)->all();

// Multiple conditions
User::query()
    ->where('country', 'Brazil')
    ->orWhere('country', 'Portugal')
    ->all();

Each call adds a condition with its conjunction (AND or OR). Supported operators: =, <>, <, >, <=, >=, LIKE.


🧰 WHERE IN

Filter values with whereIn():

$users = User::query()
    ->whereIn('id', [1, 2, 3])
    ->all();

Rubik handles placeholder binding safely under the hood.


🧮 Ordering, Grouping, and Having

Order results:

User::query()
    ->orderBy('name', 'ASC')
    ->orderBy('id', 'DESC')
    ->all();

Group and filter aggregates:

User::query()
    ->select(['country', 'COUNT(*) AS total'])
    ->groupBy('country')
    ->having('COUNT(*) > 10')
    ->orderBy('total', 'DESC')
    ->all();

🔗 Joins

Rubik supports INNER JOIN, LEFT JOIN, and RIGHT JOIN:

User::query()
    ->join('posts', 'users.id', '=', 'posts.user_id')
    ->select(['users.name', 'posts.title'])
    ->all();

Available join methods

Method Description
join($table, $left, $op, $right) Standard INNER JOIN
leftJoin($table, $left, $op, $right) LEFT JOIN
rightJoin($table, $left, $op, $right) RIGHT JOIN

💡 You can chain multiple joins for complex queries.


🧾 Limits and Offsets

Limit and offset your results easily:

User::query()
    ->orderBy('id')
    ->limit(10)
    ->offset(20)
    ->all();

🧭 Pagination

Use paginate() to get structured pagination data:

$paginated = User::query()
    ->where('country', 'Brazil')
    ->orderBy('id')
    ->paginate(page: 2, perPage: 5);

print_r($paginated);

Output:

[
    'data' => [ ... array of User models ... ],
    'total' => 43,
    'per_page' => 5,
    'current_page' => 2,
    'last_page' => 9
]

Pagination automatically uses COUNT(*) internally.


✏️ Updating Records

Perform updates directly via the builder:

User::query()
    ->where('country', 'Brazil')
    ->update(['active' => false]);

Returns true if successful, or throws an exception on error.

Or use the model API instead:

$user = User::find(1);
$user->name = 'Updated';
$user->save();

🗑️ Deleting Records

Delete records via the builder:

User::query()
    ->where('id', 10)
    ->delete();

Or delete via the model API:

$user = User::find(10);
$user->delete();

🧪 Counting Records

Count results matching your filters:

$total = User::query()
    ->where('active', true)
    ->count();

echo "Active users: {$total}";

⚙️ Building SQL Strings

You can inspect the raw SQL generated by the builder:

$sql = User::query()
    ->where('id', '>', 10)
    ->orderBy('name')
    ->getSql();

echo $sql;

Example output:

SELECT users.id, users.name, users.email FROM users WHERE id > :id_0 ORDER BY name ASC

Rubik safely binds parameters, but you can preview SQL to debug complex queries.


🧩 Model Hydration

When using a model-bound query (User::query()), Rubik hydrates each record into a model instance:

$users = User::query()->where('id', '<', 5)->all();

foreach ($users as $user) {
    echo $user->name;
}

Each hydrated model supports full ORM features:

  • save()
  • delete()
  • toArray()
  • Relationships (hasMany, belongsTo, etc.)

If you use the builder without a model:

use AdaiasMagdiel\Rubik\Query;

$results = (new Query())->setTable('users')->all();

then results are returned as plain associative arrays instead.


💾 Executing Arbitrary Queries

You can run any SQL using Rubik’s connection:

$conn = AdaiasMagdiel\Rubik\Rubik::getConn();
$stmt = $conn->query('SELECT COUNT(*) AS total FROM users');
$total = $stmt->fetchColumn();

Rubik doesn’t restrict direct SQL — the Query Builder is optional for convenience.


🧠 Error Handling

Rubik throws RuntimeException or InvalidArgumentException on:

  • Invalid SQL operations
  • Missing table or driver
  • Incorrect operators
  • Invalid pagination parameters

You can safely wrap builder calls in try/catch blocks:

try {
    $users = User::query()->where('id', '>', 10)->all();
} catch (RuntimeException $e) {
    echo "Query failed: " . $e->getMessage();
}

🧾 Summary of Query Methods

Method Description
select($fields) Specify columns to select
where($key, $operatorOrValue, $value = null) Add a WHERE condition
orWhere($key, $operatorOrValue, $value = null) Add an OR condition
whereIn($key, array $values) Add a WHERE IN condition
join($table, $left, $op, $right) Add an INNER JOIN
leftJoin($table, $left, $op, $right) Add a LEFT JOIN
rightJoin($table, $left, $op, $right) Add a RIGHT JOIN
orderBy($column, $direction) Sort results
groupBy($column) Group results
having($condition) Filter aggregates
limit($n) Limit results
offset($n) Skip results
count() Count total records
paginate($page, $perPage) Paginate results
update($data) Update records
delete() Delete records
getSql() Return raw SQL string
first() Return first record
all() Return all records

🧭 Next Steps

  • Models — Learn how models integrate with queries
  • Relationships — Load related data elegantly