cloud-castle / query-builder
Immutable, type-safe, cross-dialect SQL query builder for PHP 8.1+: 69 SQL dialects and 9 non-SQL languages, DDL/DML/DQL/DCL/TCL, safe parameterized generation.
Requires
- php: >=8.1
- cloud-castle/support: ^1.0
Requires (Dev)
- deptrac/deptrac: ^3.0 || ^4.0
- ergebnis/composer-normalize: ^2.45
- friendsofphp/php-cs-fixer: ^3.75
- icanhazstring/composer-unused: ^0.9
- infection/infection: ^0.29 || ^0.33
- php-parallel-lint/php-parallel-lint: ^1.4
- phpmd/phpmd: ^2.15
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^1.12 || ^2.1
- phpstan/phpstan-deprecation-rules: ^1.2 || ^2.0
- phpstan/phpstan-phpunit: ^1.4 || ^2.0
- phpstan/phpstan-strict-rules: ^1.6 || ^2.0
- phpunit/phpunit: ^10.5 || ^11.5
- psalm/plugin-phpunit: ^0.19 || ^0.20
- rector/rector: ^1.2 || ^2.0
- roave/security-advisories: dev-latest
- squizlabs/php_codesniffer: ^3.12 || ^4.0
- vimeo/psalm: ^6.0
- webmozart/assert: ^1.11
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-03 20:39:06 UTC
README
🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano
CloudCastle QueryBuilder
Иммутабельный, типобезопасный, кросс-диалектный конструктор SQL-запросов для PHP 8.1+. Строит запросы любой сложности и вложенности для максимально широкого спектра СУБД, генерируя безопасный SQL с плейсхолдерами. Библиотека не исполняет запросы — она их корректно порождает под 69 SQL-диалектов и 9 не-SQL языков из единого дерева выражений (AST).
Ключевые особенности
- 69 SQL-диалектов и 9 не-SQL языков — реляционные, NewSQL, колоночные/OLAP, встраиваемые, time-series, wide-column, search, streaming, federated, vector, multi-model, а также графовые и документные языки. Один AST компилируется под любой из них.
- Иммутабельность — каждый вызов возвращает новый строитель; базовый запрос безопасно переиспользуется и ветвится.
- Типобезопасность — строгая типизация, полные PHPDoc-типы, проверка PHPStan (max) и Psalm (level 1).
- Только параметризованные запросы — значения никогда не попадают в текст SQL; идентификаторы квотируются и экранируются по правилам диалекта (включая обратный слэш в ClickHouse/BigQuery/Spanner). Защита от инъекций на уровне архитектуры.
- Fail-safe контракт — при отсутствии нативной конструкции библиотека либо генерирует семантически эквивалентную эмуляцию, либо явно и безопасно отказывает; никогда не порождает молча запрос, возвращающий другой результат.
- Один AST — любой диалект — смена целевой СУБД без пересборки запроса.
Установка
composer require cloud-castle/query-builder
Требуется PHP 8.1+ (тестируется на 8.1–8.5).
Быстрый старт
<?php
use CloudCastle\QueryBuilder\Query;
use CloudCastle\QueryBuilder\Expr;
use CloudCastle\QueryBuilder\Enum\OrderDirection;
use CloudCastle\QueryBuilder\Grammar\PostgresDialect;
use CloudCastle\QueryBuilder\Grammar\MySqlDialect;
$query = Query::select('u.id', 'u.email', Expr::alias(Expr::count('orders.id'), 'orders_count'))
->from('users', 'u')
->leftJoin('orders', 'orders.user_id', 'u.id')
->where('u.status', '=', 'active')
->groupBy('u.id', 'u.email')
->having('orders_count', '>', 5)
->orderBy('orders_count', OrderDirection::Desc)
->limit(50);
$compiled = $query->toCompiled(new PostgresDialect());
// SELECT "u"."id", "u"."email", COUNT("orders"."id") AS "orders_count" FROM "users" AS "u"
// LEFT JOIN "orders" ON "orders"."user_id" = "u"."id" WHERE "u"."status" = $1
// GROUP BY "u"."id", "u"."email" HAVING "orders_count" > $2 ORDER BY "orders_count" DESC LIMIT 50
$compiled->sql();
$compiled->bindings(); // ['active', 5]
Тот же AST компилируется под другой диалект без пересборки:
$query->toCompiled(new MySqlDialect())->sql(); // тот же запрос в лексике MySQL
Возможности
| Категория | Что поддерживается |
|---|---|
| DQL | SELECT (подзапросы любой вложенности, CTE + рекурсивные + MATERIALIZED, оконные функции + рамки + именованные WINDOW, QUALIFY, GROUPING SETS/ROLLUP/CUBE, DISTINCT ON, LATERAL/APPLY/ASOF JOIN, FILTER, блокировки FOR UPDATE/SKIP LOCKED, keyset-пагинация), UNION/INTERSECT/EXCEPT (+ ALL), VALUES-источник, PIVOT/UNPIVOT, TABLESAMPLE |
| DML | INSERT (multi-row, DEFAULT VALUES, upsert/ON CONFLICT, INSERT ... SELECT, INSERT ALL), UPDATE (+FROM), DELETE (+USING), MERGE, RETURNING |
| DDL | CREATE/ALTER/DROP TABLE, ремап типов, PRIMARY KEY/FOREIGN KEY/UNIQUE/CHECK, GENERATED, ENUM, партиционирование; индексы (методы доступа, частичные, функциональные, покрывающие); VIEW/материализованные; SEQUENCE; SCHEMA; домены и типы; триггеры; события; CREATE TABLE AS SELECT; TRUNCATE |
| DCL | GRANT/REVOKE, CREATE/DROP ROLE/USER, RLS-политики, COMMENT ON |
| TCL | BEGIN/COMMIT/ROLLBACK, SAVEPOINT, уровни изоляции, двухфазный коммит (2PC) |
| Выражения | Фасад Expr + 15 категорий Fn\* (152 функции): строковые, математические, дата/время, агрегатные, JSON, условные, оконные, приведения, массивы, гео (PostGIS), regexp, кодирование, сеть, побитовые, системные. Любая функция — через Expr::func() |
| Federation | ATTACH DATABASE, FDW (сервер / внешняя таблица / маппинг), DBLINK (Oracle), OPENQUERY (SQL Server), табличные функции ClickHouse, 3/4-частные имена |
| Не-SQL | Cypher (Neo4j), SQL/PGQ (PGQL), GSQL, Gremlin, SPARQL, CQL (Cassandra), PartiQL, AQL (ArangoDB), Cosmos |
| Интроспекция | Catalog: таблицы, колонки, представления, ограничения, схемы, подпрограммы, триггеры через INFORMATION_SCHEMA |
| Прочее | CALL процедур, CREATE PROCEDURE/FUNCTION, EXPLAIN [ANALYZE], векторный поиск |
Сравнение с аналогами
Ниже — честное сопоставление с популярными PHP-конструкторами SQL. Оценки по функционалу даны на основе публичной документации проектов; сильная сторона CloudCastle QueryBuilder — беспрецедентная широта диалектов и кросс-диалектный fail-safe контракт, слабая — молодость и меньшая распространённость.
Функционал и охват
| Критерий | CloudCastle QueryBuilder | Doctrine DBAL | Laravel Query Builder | Cycle / Spiral | Latitude | Aura.SqlQuery | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| SQL-диалектов | 69 | ~10 | ~5 | ~5 | агностик¹ | 4 | QueryBuilder |
| Не-SQL языков (Cypher/SPARQL/…) | 9 | — | — | — | — | — | QueryBuilder |
| DDL (CREATE/ALTER/DROP …) | ✅ полн. | ✅ базовый | схемы миграций | схемы | — | — | QueryBuilder |
| DML (INSERT/UPDATE/DELETE/MERGE) | ✅ + MERGE | ✅ | ✅ | ✅ | ✅ | ✅ | QueryBuilder |
| DQL (CTE/окна/QUALIFY/PIVOT) | ✅ полн. | частично | частично | частично | базовый | базовый | QueryBuilder |
| DCL (GRANT/ROLE/RLS) | ✅ | — | — | — | — | — | QueryBuilder |
| TCL (изоляция/SAVEPOINT/2PC) | ✅ | ✅ через API | ✅ базовый | ✅ | — | — | QueryBuilder |
| Federation (FDW/DBLINK/ATTACH) | ✅ | — | — | — | — | — | QueryBuilder |
| Fail-safe (native→emulated→отказ) | ✅ | — | — | — | — | — | QueryBuilder |
| Иммутабельный AST | ✅ | частично | — | ✅ | ✅ | — | QueryBuilder |
¹ Latitude генерирует стандартный SQL и почти не различает диалекты.
Позиционирование
| Критерий | CloudCastle QueryBuilder | Doctrine DBAL | Laravel Query Builder |
|---|---|---|---|
| Исполняет запросы | ❌ (только генерация) | ✅ | ✅ |
| Зависимость от драйверов PDO | ❌ нет | ✅ | ✅ |
| Привязка к фреймворку | ❌ нет | ❌ | ✅ Laravel |
| Зрелость / экосистема | молодая (v1.0) | 🏆 высокая | 🏆 высокая |
| Широта СУБД / переносимость | 🏆 максимальная | средняя | низкая |
Безопасность и качество
| Критерий | CloudCastle QueryBuilder | Типичный аналог | 🏆 |
|---|---|---|---|
| Только параметризованные значения | ✅ на уровне архитектуры | ✅ | ➖ паритет |
| Экранирование идентификаторов (вкл. backslash CH/BQ/Spanner) | ✅ | частично | QueryBuilder |
| Белый список имён функций/типов | ✅ | ⚠️ редко | QueryBuilder |
| Покрытие строк тестами | 100% | варьируется | QueryBuilder |
| Mutation Score Indicator | 100% | редко замеряется | QueryBuilder |
| Статанализ (PHPStan max + Psalm) | ✅ | варьируется | QueryBuilder |
Преимущества и ограничения
Честная выжимка — без маркетинга.
Преимущества
- Беспрецедентная широта СУБД — 69 SQL-диалектов и 9 не-SQL языков из единого AST; ни один известный PHP-конструктор SQL не покрывает столько.
- Кросс-диалектность без пересборки — один и тот же запрос компилируется под любую целевую СУБД; смена базы не требует переписывания кода.
- Fail-safe контракт — либо нативная конструкция, либо семантически эквивалентная эмуляция, либо явный типизированный отказ; библиотека никогда не порождает молча SQL с другим результатом. Критично для финтеха и обработки данных.
- Безопасность на уровне архитектуры — только параметризованные значения, экранирование идентификаторов (включая обратный слэш в ClickHouse/BigQuery/Spanner), белый список имён функций и типов.
- Независимость — не привязан к фреймворку, не требует PDO/драйверов, встраивается в любой слой исполнения.
- Иммутабельность и типобезопасность — безопасное переиспользование и ветвление запросов; PHPStan (max) + Psalm (level 1).
- Полнота операций — DDL/DML/DQL/DCL/TCL, а также процедуры, оконные функции, триггеры, события, разные типы индексов и federation.
- Проверенное качество — 2724 теста, покрытие строк 100 %, MSI 100 %.
Ограничения
- Только генерация, не исполнение — библиотека порождает SQL и плейсхолдеры, но не выполняет запросы; слой исполнения (PDO/драйвер) остаётся за вами. Это осознанный дизайн (легковесность, совместимость с любым драйвером), а не «ORM из коробки».
- Не ORM — маппинг сущностей, миграции, lazy-loading, репозитории — вне области пакета по замыслу; это конструктор SQL, а не ORM.
- Молодость и меньшая распространённость — версия 1.0; экосистема, число интеграций и примеров пока меньше, чем у Doctrine/Laravel. Это единственный честный недостаток относительно зрелых аналогов — он уходит со временем.
- Экзотические диалекты выверены по документации — для нишевых СУБД синтаксис приведён по официальным докам; для редких edge-кейсов рекомендуется проверка на живом движке.
Где и когда применять
Подходит лучше всего
- Мультибазовые продукты и SaaS — одно приложение обслуживает клиентов на разных СУБД (PostgreSQL у одного, Oracle или SQL Server у другого) без ветвления кода.
- Аналитика и OLAP — генерация SQL под ClickHouse, BigQuery, Snowflake, Trino, Redshift, DuckDB, Spark из общего кода.
- Data-инжиниринг и ETL — целевые time-series (QuestDB, InfluxDB, Timestream), streaming (Flink, ksqlDB), распределённые OLAP (Doris, StarRocks, Druid, Pinot).
- Собственные ORM, DBAL и фреймворки — как безопасный кросс-диалектный генератор SQL внутри своего слоя исполнения.
- Финтех и обработка чувствительных данных — где молчаливо-неверный SQL недопустим: fail-safe контракт даёт либо корректный SQL, либо явный отказ.
- Графовые и документные базы — генерация Cypher, Gremlin, SPARQL, CQL, PartiQL, AQL из единого API.
- Миграция между СУБД — перенос запросов с одной базы на другую без ручного переписывания.
Стоит выбрать альтернативу
- Нужен готовый ORM с исполнением под 1–2 популярные СУБД — Doctrine ORM, Laravel Eloquent, Cycle (маппинг сущностей, миграции, репозитории «из коробки»).
- Проект жёстко в экосистеме Laravel/Symfony — нативные конструкторы фреймворка дадут более тесную интеграцию.
- Нужен простейший SQL под одну СУБД — лёгкого Latitude или нативного PDO может быть достаточно.
- Требуются исполнение, пул соединений и транзакции «из коробки» — DBAL с драйверами.
Fail-safe контракт
Для каждой возможности стратегия выбирается по порядку:
- native — нативная конструкция диалекта.
- emulated — семантически эквивалентная эмуляция, дающая тот же результат (например,
NULLS FIRST/LASTчерезCASEтам, где это валидно). - degraded — приблизительная эмуляция; разрешена только в режиме
lenientс регистрацией предупреждения. - unsupported — типизированное исключение
UnsupportedCapabilityExceptionс указанием возможности, диалекта и альтернативы.
use CloudCastle\QueryBuilder\Enum\CompilationMode;
// strict (по умолчанию): отказ при приблизительной эмуляции и отсутствии поддержки
$query->toCompiled($dialect);
// lenient: приблизительная эмуляция разрешена, предупреждения — в CompiledQuery::warnings()
$query->toCompiled($dialect, CompilationMode::Lenient);
Безопасность
- Только параметризованные запросы — значения передаются отдельно от текста SQL.
- Идентификаторы, алиасы и направления сортировки экранируются/квотируются по правилам диалекта, включая обратный слэш в квотированных идентификаторах ClickHouse/BigQuery/Spanner (защита от выхода из идентификатора через недоверенное имя).
- Имена функций, типов и полей проходят белый список символов; строковые литералы в DDL (
DEFAULT/CHECK/COMMENT/ENUM) экранируются, включая обратный слэш на MySQL-семействе, ClickHouse, BigQuery, Hive/Impala/Spark. - Библиотека не логирует значения привязок по умолчанию (потенциальные ПД/финданные).
Диалекты
69 SQL-диалектов, среди них PostgreSQL, MySQL, MariaDB, Oracle, SQL Server, SQLite, DB2, H2, HSQLDB, Firebird, Derby, SAP HANA, Teradata, Exasol, SAP ASE, Informix, MonetDB, NuoDB, VoltDB, DuckDB, ClickHouse, Snowflake, BigQuery, Redshift, Trino, Spark SQL, Vertica, Impala, Hive, Firebolt, Druid, Pinot, Kylin, Dremio, Drill, Spanner, CockroachDB, YugabyteDB, TiDB, SingleStore, StarRocks, Doris, Greenplum, Materialize, RisingWave, CrateDB, TimescaleDB, QuestDB, InfluxDB, TDengine, Timestream, Cassandra, ScyllaDB, Elasticsearch SQL, OpenSearch SQL, Solr SQL, Rockset, Couchbase, DynamoDB PartiQL, Cosmos DB, OrientDB, LanceDB, ksqlDB, Flink SQL, Beam SQL, Aurora (MySQL/PostgreSQL), HeatWave, pgvector и другие.
Плюс 9 не-SQL языков: Cypher (Neo4j), SQL/PGQ (PGQL), GSQL, Gremlin, SPARQL, CQL (Cassandra), PartiQL, AQL (ArangoDB), Cosmos.
Полный перечень с машинными именами и категориями — на странице Dialects в Wiki.
Качество
- 2724 теста, покрытие строк 100%, Mutation Score Indicator (MSI) 100%.
- Прогон анализаторов: phplint → Psalm (level 1) → PHPStan (max) → PHPMD → PHPCS (PSR-12) → Rector → Deptrac → Infection.
- PHP 8.1–8.5.
Разработка
composer install
composer check # линтеры + статический анализ + тесты
composer fix # автоисправления (Rector, PHP CS Fixer, PHPCBF)
composer ci # полный CI-пайплайн локально
Документация
- Репозиторий: https://gitverse.ru/cloud-castle/query-builder
- Wiki (обзор, диалекты, операции, функции, federation, безопасность, FAQ): https://gitverse.ru/cloud-castle/query-builder/wiki
- История изменений: CHANGELOG.md
- Как внести вклад: CONTRIBUTING.md
- Политика безопасности: SECURITY.md
Лицензия
MIT © CloudCastle (alex-4-17@yandex.ru)
🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano