PHPackages                             abdulelahragih/querybuilder - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. abdulelahragih/querybuilder

ActiveLibrary[Database &amp; ORM](/categories/database)

abdulelahragih/querybuilder
===========================

Fast, lightweight and simple SQL query builder that does not depend on any third-party library besides PDO to execute the queries in a safe way. The syntax is inspired by Laravel Query Builder.

1.3.0(8mo ago)71.8k↓33.3%2[2 PRs](https://github.com/abdulelahragih/QueryBuilder/pulls)GPL-3.0-onlyPHPPHP &gt;=8.1CI passing

Since Sep 1Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/abdulelahragih/QueryBuilder)[ Packagist](https://packagist.org/packages/abdulelahragih/querybuilder)[ RSS](/packages/abdulelahragih-querybuilder/feed)WikiDiscussions main Synced 3d ago

READMEChangelog (10)Dependencies (1)Versions (34)Used By (0)

QueryBuilder
============

[](#querybuilder)

Fast, lightweight, and simple SQL query builder that does not depend on any third-party library besides PDO to execute the queries in a safe way. The syntax is inspired by Laravel Query Builder.

Features
--------

[](#features)

- Automatic parameter binding via an internal bindings manager.
- Comprehensive WHERE builder: nested groups, `IN/NOT IN`, `LIKE/NOT LIKE`, `NULL/NOT NULL`, `BETWEEN/NOT BETWEEN`.
- Rich JOINs: `INNER`, `LEFT`, `RIGHT`, and `FULL` (only on dialects that support it, e.g., PostgreSQL) with nested conditions and `on` helpers.
- Pagination: `paginate` (length-aware) and `simplePaginate` (no total count) with page name support.
- Dialect-aware SQL generation with automatic detection (MySQL &amp; Postgres for now).
- Inserts, updates, deletes with safety checks (no UPDATE/DELETE without WHERE).
- Upserts with dialect-specific behavior.
- Convenience helpers: `first`, `pluck`, `distinct`, `orderBy`, `limit`, `offset`, `raw` expressions, `objectConverter`.
- Results as a fluent `Collection` and paginator objects.

Installation
------------

[](#installation)

Install via Composer:

```
composer require abdulelahragih/querybuilder
```

Getting Started
---------------

[](#getting-started)

Create a builder from a `PDO` instance. Dialect is auto-detected from `PDO::ATTR_DRIVER_NAME` (`pgsql` → Postgres; otherwise MySQL):

```
use Abdulelahragih\QueryBuilder\QueryBuilder;

$pdo = /* your PDO connection */;
$qb = new QueryBuilder($pdo);

$rows = $qb->table('users')
    ->select('id', 'username', 'phone_number', 'gender')
    ->where('role_id', '=', 1)
    ->join('images', 'images.user_id', '=', 'users.id')
    ->orderBy('id', 'DESC')
    ->limit(10)
    ->get(); // returns Collection
```

You can also use the thin `DB` wrapper (instance-based) or the `DBSingleton` for a static facade if you prefer:

```
use Abdulelahragih\QueryBuilder\DB;
use Abdulelahragih\QueryBuilder\DBSingleton;

// Instance wrapper
$db = new DB($pdo);
$users = $db->table('users')->select('id')->get();

// Static facade
DBSingleton::init($pdo);
$firstId = DBSingleton::table('users')->first('id');
```

Pagination
----------

[](#pagination)

Length-aware pagination returns totals and page info:

```
$p = $qb->table('users')
    ->orderBy('id', 'DESC')
    ->paginate($page, $perPage, pageName: 'page');
// $p is LengthAwarePaginator (items + total, pages, prev/next)
```

Simple pagination is lighter weight:

```
$p = $qb->table('users')->simplePaginate($page, $perPage);
// $p is SimplePaginator (items + prev/next)
```

Inserts and Upserts
-------------------

[](#inserts-and-upserts)

- Insert single or multiple rows:

```
$qb->table('users')->insert(['id' => 100, 'name' => 'John']);
$qb->table('users')->insert([
    ['id' => 100, 'name' => 'John'],
    ['id' => 101, 'name' => 'Jane'],
]);
```

- Upsert with a unified API across dialects:

```
use Abdulelahragih\QueryBuilder\Grammar\Expression;

// Update non-unique columns automatically when conflicts occur
$qb->table('users')->upsert(
    ['id' => 100, 'name' => 'John', 'age' => 26],
    uniqueBy: ['id'],
);

// Explicit assignments (MySQL uses VALUES(), Postgres uses EXCLUDED)
$qb->table('users')->upsert(
    ['id' => 100, 'name' => 'John', 'age' => 26],
    uniqueBy: ['id'],
    updateOnDuplicate: [
        'name',                   // infer from column name
        'updated_at' => Expression::make('NOW()'), // raw expression
    ],
);
```

- Do-nothing on conflict (Postgres):

```
$qb->table('users')->insertOrIgnore(['id' => 100, 'name' => 'John'], uniqueColumns: ['id']);
```

- Insert and get the generated id (Postgres supports RETURNING, MySQL uses lastInsertId):

```
$id = $qb->table('users')->insertGetId(['name' => 'John']);
// Optionally specify id column name
$id = $qb->table('users')->insertGetId(['name' => 'Jane'], 'user_id');
```

Updates and Deletes
-------------------

[](#updates-and-deletes)

Both operations require a WHERE clause for safety and return the affected rows count:

```
$updated = $qb->table('users')->where('id', '=', 1)->update(['name' => 'Sam']);
$deleted = $qb->table('users')->whereIn('id', [1, 2])->delete();
```

WHERE and JOIN Builders
-----------------------

[](#where-and-join-builders)

- WHERE helpers: `where`, `orWhere`, `whereIn`, `whereNotIn`, `whereLike`, `whereNotLike`, `whereNull`, `whereNotNull`, `whereBetween`, `whereNotBetween`, nested closures.
- JOIN helpers: `join`, `leftJoin`, `rightJoin`, `fullJoin`, plus nested `where`/`orWhere` inside join closures and `on`/`orOn` for column comparisons.

Examples (WHERE):

```
// Basic where and multiple conditions (AND)
$qb->table('users')
   ->where('role_id', '=', 1)
   ->where('status', '=', 'active')
   ->toSql();

// OR conditions
$qb->table('users')
   ->where('role_id', '=', 1)
   ->orWhere('role_id', '=', 2)
   ->toSql();

// Nested groups
$qb->table('users')
   ->where('id', '=', 1)
   ->orWhere(function ($w) {
       $w->where('id', '=', 2)
         ->where(function ($inner) {
             $inner->where('name', '=', 'Sam')
                   ->orWhere('name', '=', 'John');
         });
   })
   ->toSql();

// IN / NOT IN
$qb->table('users')
   ->whereIn('id', [1, 2, 3])
   ->whereNotIn('status', ['banned'])
   ->toSql();

// LIKE / NOT LIKE
$qb->table('users')
   ->whereLike('name', '%Sam%')
   ->whereNotLike('email', '%@spam.com')
   ->toSql();

// NULL / NOT NULL
$qb->table('users')
   ->whereNull('deleted_at')
   ->whereNotNull('email')
   ->toSql();

// BETWEEN / NOT BETWEEN
$qb->table('orders')
   ->whereBetween('amount', 10, 100)
   ->whereNotBetween('discount', 20, 30)
   ->toSql();
```

Examples (JOIN):

```
// Simple inner join with column-to-column comparison
$qb->table('users')
   ->join('images', 'images.user_id', '=', 'users.id')
   ->toSql();

// LEFT / RIGHT / FULL joins
$qb->table('users')
   ->leftJoin('orders', 'orders.user_id', '=', 'users.id')
   ->rightJoin('profiles', 'profiles.user_id', '=', 'users.id')
   ->toSql();

// Join with additional filters and nested groups
$qb->table('users')
   ->join('images', function ($j) {
       $j->on('images.user_id', '=', 'users.id');
       $j->orWhere('images.user_id', '=', 1);
       $j->where(function ($nested) {
           $nested->where('images.user_id', '=', 3);
           $nested->orWhere('images.id', '=', 1);
       });
   })
   ->toSql();

// Using orOn for alternative column matches
$qb->table('users')
   ->join('orders', function ($j) {
       $j->on('orders.user_id', '=', 'users.id')
         ->orOn('orders.alt_user_id', '=', 'users.id');
   })
   ->toSql();

// Multiple joins chained
$qb->table('users u')
   ->join('orders o', 'o.user_id', '=', 'u.id')
   ->join('comments c', 'c.user_id', '=', 'u.id')
   ->select('u.id', 'o.amount')
   ->toSql();
```

Object Conversion
-----------------

[](#object-conversion)

Map rows to custom objects after fetching:

```
$users = $qb->table('users')
    ->objectConverter(fn(array $row) => (object) $row)
    ->get();
```

Transactions (Using the `DB` Wrapper)
-------------------------------------

[](#transactions-using-the-db-wrapper)

Let the builder handle transactions:

```
use Abdulelahragih\QueryBuilder\DB;

$db = new DB($pdo);
$db->transaction(function () use ($db) {
    $db->table('users')->insert(['id' => 200, 'name' => 'Txn']);
});
```

Or manually:

```
use Abdulelahragih\QueryBuilder\DB;

$db = new DB($pdo);
$db->beginTransaction();
try {
    $db->table('users')->insert(['id' => 200, 'name' => 'Txn']);
    $db->commit();
} catch (Exception $e) {
    $db->rollBack();
}
```

Notes
-----

[](#notes)

- Update/Delete without a WHERE clause throws an exception by default.
- `insertGetId` expects a single row payload.
- Feature set varies slightly by dialect (e.g., Postgres `RETURNING`, `ON CONFLICT ... DO NOTHING`).

Contribution
------------

[](#contribution)

Contributions are welcome!

###  Health Score

47

—

FairBetter than 93% of packages

Maintenance73

Regular maintenance activity

Popularity25

Limited adoption so far

Community12

Small or concentrated contributor base

Maturity64

Established project with proven stability

 Bus Factor1

Top contributor holds 95.8% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~26 days

Recently: every ~65 days

Total

30

Last Release

261d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/1eda2545dc8ecd76cb76df8217c60e5ccd696d6482075ac404b7bf599ed006be?d=identicon)[AbdulelahAGR](/maintainers/AbdulelahAGR)

---

Top Contributors

[![abdulelahragih](https://avatars.githubusercontent.com/u/51064016?v=4)](https://github.com/abdulelahragih "abdulelahragih (115 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (4 commits)")[![LancelotProgrammer](https://avatars.githubusercontent.com/u/88593320?v=4)](https://github.com/LancelotProgrammer "LancelotProgrammer (1 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/abdulelahragih-querybuilder/health.svg)

```
[![Health](https://phpackages.com/badges/abdulelahragih-querybuilder/health.svg)](https://phpackages.com/packages/abdulelahragih-querybuilder)
```

###  Alternatives

[jdorn/sql-formatter

a PHP SQL highlighting library

3.9k117.2M118](/packages/jdorn-sql-formatter)[propel/propel1

Propel is an open-source Object-Relational Mapping (ORM) for PHP5.

8351.6M87](/packages/propel-propel1)[jfelder/oracledb

Oracle DB driver for Laravel

11518.4k](/packages/jfelder-oracledb)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
