PHPackages                             johnnyjoy/uda - 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. johnnyjoy/uda

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

johnnyjoy/uda
=============

Universal Data Abstractor (UDA) — PHP 8.2+ deterministic SQL execution and query composition

v1.1.0(1mo ago)01↓90%MITPHPPHP &gt;=8.2CI passing

Since Jun 4Pushed 1mo agoCompare

[ Source](https://github.com/johnnyjoy/uda)[ Packagist](https://packagist.org/packages/johnnyjoy/uda)[ RSS](/packages/johnnyjoy-uda/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (2)Dependencies (8)Versions (3)Used By (0)

Universal Data Abstractor (UDA)
===============================

[](#universal-data-abstractor-uda)

**Slim SQL execution for PHP repositories** — one API across major databases, optional read cache, explicit queries under project control.

PHP APIs and services can keep **SQL in repository classes** — methods the team names, SQL visible in PR review. UDA is the **engine under that layer**: connect, run named-parameter SQL, use dialect-aware fluent builders when they help, and keep the same code when the database changes.

- **Readable data layer** — SQL stays in methods that are reviewable in PRs and explainable to ops.
- **Many databases, one habit** — Postgres today, SQL Server or Oracle tomorrow; edit `uda.json`, not every query file.
- **Stable team contract** — one handle (`Database` or `Link`), named params only, integration-tested engines in CI.
- **More speed when needed** — transparent read cache (Redis, Memcached, in-memory, …); enable in config, keep table hints on reads.
- **Explicit query ownership** — repositories and `Link`; domain methods, not generated `find()` helpers.

What UDA does
-------------

[](#what-uda-does)

AreaUDA provides…**Connect**`connectDefault()`, `connectNamed()`, `connectWithConfig()`; one pooled `Database` + PDO per connection name per process; transparent reconnect on dropped connections**Raw reads**`row`, `rows`, `value`, `values` (first column of each row), `list` (first row as numeric list) — all accept SQL string, `Sql::of()`, or compiled `Query\Sql`**Large reads**`each($sql, $params, $callback)` — row-by-row without loading the full result into memory**Raw writes**`exec`, `returning()` (engines that support it)**Fluent**`select()`, `insert()`, `update()`, `delete()`, `upsert()` — joins, CTEs (`with` / `withRecursive`), `union` / `unionAll`, `groupBy` / `having`, subqueries, `RETURNING` / `OUTPUT` where supported**Bulk &amp; copy**`insert()->rows([...])`, `insert()->columns(...)->select($subquery)`**Upsert**`upsert()->into()->values()` or `rows()`, `key()`, `update()`, `doNothing()` — dialect-specific `ON CONFLICT` / `MERGE` / etc.**Reuse**Same SQL + new binds; partial fluent clones + `->end()`; `toSql()` on another same-engine connection; `Sql::of()` templates**Safe dynamic SQL**`inList()`, `q()`, `orderByAllowed()`, `limitOffset()`, `whereRaw()` with named params — not string-concatenated values**Transactions**`transaction(callable)`; savepoints where the engine supports them**Guardrails**Unbounded `UPDATE` / `DELETE` blocked by default; `->unsafe()` when intentionally global**Cache**Config-driven read cache; table hints on raw reads; `flushCache()` for ops — repositories stay unchanged**Debug**`lastSql()`, `lastParams()`, builder `toSql()` (compile only)**Errors**`QueryException` with `category()`, `sqlState()`, `driverCode()` for mapping in the application API layer**Structure**`UDA\Link` on repository classes, or dependency injection of `Database` from the project container**Observe**Optional `Database::setQueryObserver()` at bootstrap ([metrics.md](docs/metrics.md))```
HTTP / CLI / worker
    → application controller or job
    → application repository (SQL or builders here)
    → UDA\Database or UDA\Link
    → (internal) Driver → PDO → engine

```

Supported databases
-------------------

[](#supported-databases)

EngineIn UDATested in GitHub Actions on every push/PRSQLiteYesYesPostgreSQLYesYesMariaDB / MySQLYesYesSQL ServerYesYes (`pdo_dblib` on Linux CI)OracleYesYesDB2YesYes (`pdo_ibm`)FirebirdYesYes (`pdo_firebird`)Sybase ASEYesNo — no public CI license; local opt-in onlyInformixNoNot supported — see note belowCUBRIDYesYes (`pdo_cubrid`)Per-engine config and CI detail: [engines.md](docs/engines.md), [integration/README.md](docs/integration/README.md).

> **Informix note:** Informix is not currently supported. The PHP PDO ecosystem for Informix has a fundamental compatibility gap: `pdo_informix` requires the IBM Informix Client SDK (CSDK), which is not included in the freely-available `informix-developer-database` Docker image and is not redistributable. The alternative, `pdo_ibm` (IBM DB2 CLI driver connecting via DRDA), ignores `PDO::ATTR_EMULATE_PREPARES` — it calls `SQLNumResultCols` and `SQLDescribeParam`unconditionally after every `SQLPrepare`, and Informix's DRDA server returns error -201 for both on pagination and MERGE statements. Support may be revisited when the PDO driver situation improves.

Install
-------

[](#install)

PHP 8.2+, ext-pdo. MIT.

```
composer require johnnyjoy/uda
```

[github.com/johnnyjoy/uda](https://github.com/johnnyjoy/uda)

Quick start
-----------

[](#quick-start)

```
export UDA_CONFIG=/etc/app/uda.json
```

Repository with **`Link`** — SQL on the class; controllers call it:

```
