Persistence

Database Query Builder

Fluent SQL query builder backed by DatabaseDriverInterface identifier protection and value bindings.

Purpose

QueryBuilder builds SQL for common reads and writes while delegating execution and identifier protection to DatabaseDriverInterface. Create it through Database::table() or QueryBuilder::make($driver)->table($table).

Selecting rows

Use table(), select(), distinct(), where(), orderBy(), groupBy(), having(), limit(), offset() and getArray() for typical read queries. get() returns DatabaseResultInterface or false; getArray() returns an array of associative rows.

$rows = $db->table('articles')
    ->select(['id', 'title', 'created_at'])
    ->where('published', 1)
    ->whereLike('title', 'framework')
    ->orderBy('created_at', 'DESC')
    ->limit(20)
    ->getArray();

Single values

first() returns one associative row or null. value() returns one selected column from the first row. pluck() returns a list of values or an associative array when a key column is supplied. exists() and doesntExist() check presence efficiently.

$article = $db->table('articles')->where('id', $id)->first();
$title = $db->table('articles')->where('id', $id)->value('title');
$ids = $db->table('articles')->where('published', 1)->pluck('id');

Conditions

Condition helpers include where(), orWhere(), whereLike(), whereNotLike(), whereIn(), whereNotIn(), whereNull(), whereNotNull(), whereBetween(), whereNotBetween(), subquery variants, raw variants and matching having* methods. Array where payloads are treated as equality conditions.

Joins and subqueries

join() accepts a table and explicit join condition. joinSubquery(), leftJoinSubquery(), selectSubquery() and fromSubquery() compose nested QueryBuilder instances with merged bindings.

$rows = $db->table('articles AS a')
    ->select(['a.id', 'a.title'])
    ->join('users AS u', 'u.id = a.author_id', 'LEFT')
    ->where('a.published', 1)
    ->getArray();

Writes

Write helpers include insert(), batchInsert(), insertOrIgnore(), upsert(), update(), batchUpdate(), delete(), increment() and decrement(). update(), delete(), increment() and decrement() return false when no WHERE condition is present to avoid accidental table-wide writes.

$db->table('articles')->insert([
    'title' => 'Hello',
    'published' => 1,
]);

$db->table('articles')
    ->where('id', $id)
    ->update(['title' => 'Updated']);

Streaming and chunks

cursor() yields rows from the driver cursor. For model-level chunking use Model::chunk(); QueryBuilder itself exposes limit/offset and cursor primitives.

Locks and portability

lockForUpdate() appends FOR UPDATE and sharedLock() appends LOCK IN SHARE MODE. These lock clauses are MySQL-oriented and may not be portable to every ODBC or PDO target.

Safety

Normal table and column APIs accept identifiers and protect them. Raw SQL APIs such as selectRaw(), whereRaw(), havingRaw() and fromRaw() are explicit escape hatches. Do not concatenate user input into raw SQL; pass values through bindings.