{"id":28522179,"url":"https://github.com/phpro/dbal-tools","last_synced_at":"2026-02-10T08:03:02.183Z","repository":{"id":290313457,"uuid":"972577264","full_name":"phpro/dbal-tools","owner":"phpro","description":"Tools for working with DBAL in Symfony applications","archived":false,"fork":false,"pushed_at":"2026-01-26T13:58:28.000Z","size":153,"stargazers_count":10,"open_issues_count":1,"forks_count":3,"subscribers_count":5,"default_branch":"main","last_synced_at":"2026-01-27T02:40:58.893Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/phpro.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-04-25T09:57:48.000Z","updated_at":"2026-01-26T13:58:02.000Z","dependencies_parsed_at":null,"dependency_job_id":"be5d512b-6741-49b1-a4eb-79c0dad4e33b","html_url":"https://github.com/phpro/dbal-tools","commit_stats":null,"previous_names":["phpro/dbal-tools"],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/phpro/dbal-tools","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phpro%2Fdbal-tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phpro%2Fdbal-tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phpro%2Fdbal-tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phpro%2Fdbal-tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/phpro","download_url":"https://codeload.github.com/phpro/dbal-tools/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phpro%2Fdbal-tools/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29294402,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-10T03:42:42.660Z","status":"ssl_error","status_checked_at":"2026-02-10T03:42:41.897Z","response_time":65,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-09T09:08:28.410Z","updated_at":"2026-02-10T08:03:02.148Z","avatar_url":"https://github.com/phpro.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Installs](https://img.shields.io/packagist/dt/phpro/dbal-tools.svg)](https://packagist.org/packages/phpro/dbal-tools/stats)\n[![Packagist](https://img.shields.io/packagist/v/phpro/dbal-tools.svg)](https://packagist.org/packages/phpro/dbal-tools)\n\n\n# DBAL Tools\n\nThis package provides a set of tools to work with the Doctrine DBAL.\n\n## Installation\n\n```sh\ncomposer require phpro/dbal-tools\n```\n\nThe package can be used standalone or with Symfony.\nIf you are not using `symfony/flex`, you'll have to manually add the bundle to your bundles file:\n\n```php\n// config/bundles.php\n\nreturn [\n    // ...\n    Phpro\\DbalTools\\DbalToolsBundle::class =\u003e ['all' =\u003e true],\n];\n```\n\n## Schema\n\nThis package contains a set of schema tools to configure your database schema from within PHP.\nYou can configure following schema types:\n\n### Configuring a table\n\nA table consists out of 2 parts:\n\n- The class that declared the table\n- An enum that declares the available table columns:\n\n```php\nuse Phpro\\DbalTools\\Column\\TableColumnsInterface;\nuse Phpro\\DbalTools\\Column\\TableColumnsTrait;\n\nenum UsersTableColumns: string implements TableColumnsInterface\n{\n    case Id = 'user_id';\n    case Username = 'username';\n\n    use TableColumnsTrait;\n\n    public function linkedTableClass(): string\n    {\n        return UsersTable::class;\n    }\n}\n```\n\n```php\nuse Doctrine\\DBAL\\Schema\\Table as DoctrineTable;\nuse Doctrine\\DBAL\\Types\\Types;\nuse Phpro\\DbalTools\\Column\\Columns;\nuse Phpro\\DbalTools\\Schema\\Table;\n\nfinal class UsersTable extends Table\n{\n    public static function name(): string\n    {\n        return 'users';\n    }\n\n    public static function columns(): Columns\n    {\n        return Columns::for(UsersTableColumns::class);\n    }\n\n    public static function createTable(): DoctrineTable\n    {\n        $table = new DoctrineTable(self::name());\n        $table-\u003eaddColumn(UsersTableColumns::Id-\u003evalue, Types::GUID, [\n            'notnull' =\u003e true,\n        ]);\n        $table-\u003esetPrimaryKey([UsersTableColumns::Id-\u003evalue]);\n\n        $table-\u003eaddColumn(UsersTableColumns::Username-\u003evalue, Types::STRING, [\n            'length' =\u003e 255,\n            'notnull' =\u003e true,\n        ]);\n\n        return $table;\n    }\n}\n```\n\nYou can register this table configuration in your Symfony service configuration:\n\n```yaml\nservices:\n    App\\Dbal\\Schema\\UsersTable:\n        tags:\n            - 'phpro.dbal_tools.schema.table'\n```\n\nThis way, it is available inside the `Doctrine\\DBAL\\Schema\\Schema` service and can be used to create the table through migrations.\n\nIf you want to make sure that all columns are being used inside the table, you can add a PHPUnit `TableColumnEnumTestCase` for the implementation:\n\n```php\n\u003c?php\n\nuse Phpro\\DbalTools\\Test\\Column\\TableColumnEnumTestCase;\n\nfinal class UsersTableColumnsTest extends TableColumnEnumTestCase\n{\n    public function className(): string\n    {\n        return UsersTableColumns::class;\n    }\n}\n```\n\n### Configuring sequences\n\nFrom time to time, you might need a sequence.\nThis can be configured in the same way as a table:\n\n```php\nuse Phpro\\DbalTools\\Schema\\Sequence;\nuse Doctrine\\DBAL\\Schema\\Sequence as DoctrineSequence;\n\nfinal class UserNumberSequence extends Sequence\n{\n    public static function name(): string\n    {\n        return 'user_number_seq';\n    }\n\n    public static function createSequence(): DoctrineSequence\n    {\n        return new DoctrineSequence(self::name());\n    }\n}\n```\n\nNext, add the sequence to your service configuration:\n\n```yaml\nservices:\n    App\\Dbal\\Schema\\UserNumberSequence:\n        tags:\n            - 'phpro.dbal_tools.schema.sequence'\n```\n\n## Migrations\n\nThis package ships with [doctrine/DoctrineMigrationsBundle](https://github.com/doctrine/DoctrineMigrationsBundle).\nIt links the schema configuration to the migration commands.\nThis way, you can use doctrine:migrations, just like you would in a regular ORM based system.\n\n```sh\n./bin/console doctrine:migrations:diff\n./bin/console doctrine:migrations:migrate\n```\n\n## Building models and repositories\n\nSince no ORM is being used, the main structure for building models and repositories would follow following pattern:\n\n\nYou can build your entities in raw PHP without any mapping limitations:\n(just using public props here for simplicity)\n\n```php\nnamespace App\\Entity;\n\nclass User\n{\n    public function __construct(\n        public string $id,\n        public string $userName\n    ) {\n    }\n}\n```\n\nA repository could look like this:\n\n```php\nnamespace App\\Repository;\n\nuse App\\Doctrine\\Schema\\UsersTable;\nuse App\\Doctrine\\Schema\\UsersTableColumns;\nuse App\\Entity\\User;\nuse Doctrine\\DBAL\\Connection;\nuse Phpro\\DbalTools\\Expression\\Comparison;\nuse Phpro\\DbalTools\\Expression\\Factory\\NamedParameter;\n\nclass UsersRepository\n{\n    public function __construct(private Connection $connection)\n    {\n    }\n\n    public function findById(string $id): ?User\n    {\n        $qb = $this-\u003econnection-\u003ecreateQueryBuilder();\n        $qb-\u003eselect(...UsersTable::columns()-\u003eselect())\n            -\u003efrom(UsersTable::name())\n            -\u003ewhere(Comparison::equal(\n                UsersTableColumns::Id,\n                NamedParameter::createForTableColumn($qb, UsersTableColumns::Id, $id)\n            )-\u003etoSQL());\n\n        if (!$row = $qb-\u003efetchAssociative()) {\n            return null;\n        }\n\n        return new User(\n            $row[UsersTableColumns::Id-\u003evalue],\n            $row[UsersTableColumns::Username-\u003evalue],\n        );\n    }\n\n    public function create(User $user): void\n    {\n        $this-\u003econnection-\u003einsert(\n            UsersTable::name(),\n            [\n                UsersTableColumns::Id-\u003evalue =\u003e $user-\u003eid,\n                UsersTableColumns::Username-\u003evalue =\u003e $user-\u003euserName,\n            ],\n            UsersTable::columnTypes()\n        );\n    }\n}\n```\n\nAs you can see, you can use the schema configuration to build your queries.\nIf any of the table names or column names change, you will only have to change it in one place.\nIn a real application, you can split up a data mapper that maps the entity to the table and back.\nThat way, you have full control on how the data is made available in the entity.\n\n\n### Persisting relations\n\nInside your model, you might have relations to other models.\nFor example, a User can be linked to multiple companies.\nYou can use the `Phpro\\DbalTools\\CollectionPatchCollection` to detect changes in a collection of related entities and deal with the change accordingly:\n\n```php\nuse Phpro\\DbalTools\\CollectionPatchCollection;\n\n$patchCollection = new CollectionPatchCollection();\n$this-\u003epatchCollection-\u003epatch(\n    newCollection: $user-\u003ecompanies(),\n    previousCollection: $previous?-\u003ecompanies() ?? new Companies(),\n    idProvider: static fn (Company $company) =\u003e $company-\u003eid(),\n    insert: fn (Company $company) =\u003e $this-\u003econnection-\u003einsert(\n        UserCompaniesTableColumn::name(),\n        [\n            UserCompaniesTableColumn::UserId-\u003evalue =\u003e $user-\u003eid(),\n            UserCompaniesTableColumn::CompanyId-\u003evalue =\u003e $company-\u003eid(),\n        ],\n        UserCompaniesTableColumn::columnTypes()\n    ),\n    update: fn (Company $company) =\u003e null,\n    delete: fn (Company $company) =\u003e $this-\u003econnection-\u003edelete(\n        UserCompaniesTableColumn::name(),\n        [\n            UserCompaniesTableColumn::UserId-\u003evalue =\u003e $user-\u003eid(),\n            UserCompaniesTableColumn::CompanyId-\u003evalue =\u003e $company-\u003eid(),\n        ],\n        UserCompaniesTableColumn::columnTypes()\n    )\n);\n```\n\n## Fixtures\n\nThis package contains a command to load fixtures.\nIn order to create a fixture, you need to create a new PHP class per entity:\n\n```php\nuse App\\Doctrine\\Schema\\UsersTable;\nuse App\\Entity\\User;\nuse App\\Repository\\UsersRepository;\nuse Phpro\\DbalTools\\Fixtures\\Fixture;\n\n/**\n * @template-implements Fixture\u003cUser\u003e\n */\nfinal readonly class UserFixtures implements Fixture\n{\n    public function __construct(\n        private UsersRepository $userRepository,\n    ) {\n    }\n\n    public function type(): string\n    {\n        return User::class;\n    }\n\n    public function tables(): array\n    {\n        return [UsersTable::name()];\n    }\n\n    /**\n     * @return \\Generator\u003cstring, User\u003e\n     */\n    public function execute(): \\Generator\n    {\n        foreach ($this-\u003eprovideFixtures() as $fixture) {\n            if ($this-\u003eexists($fixture)) {\n                continue;\n            }\n\n            yield $fixture-\u003eid =\u003e $fixture;\n            $this-\u003euserRepository-\u003ecreate($fixture);\n        }\n    }\n\n    public function exists(object $x): bool\n    {\n        return (bool) $this-\u003euserRepository-\u003efindById($x-\u003eid);\n    }\n\n\n    /**\n     * @return \\Generator\u003cstring, User\u003e\n     */\n    private function provideFixtures(): \\Generator\n    {\n        yield 'admin' =\u003e new User(\n            '9080f592-3a1e-433d-8b27-0e109fd1d32c',\n            'admin',\n        );\n    }\n}\n```\n\nNext, you can register the fixture in your service configuration:\n\n```yaml\nservices:\n    App\\Doctrine\\Fixtures\\UserFixtures:\n        arguments:\n            - '@App\\Repository\\UsersRepository'\n        tags:\n            - 'phpro.dbal_tools.fixture'\n\n```\n\nYou can now load the fixtures using the command:\n\n```sh\n./bin/console doctrine:fixtures\n```\n\nFollowing options are available:\n\n```\n--type=TYPE           Only create / truncate specific type (FQCN) \"App\\Domain\\Model\\User\".\n-t, --truncate        Truncate all fixture tables and relations.\n-r, --reload          Truncate and Import all fixture.\n```\n\n## Testing\n\nThis package contains a set of tools that can be used to test your code against a database.\nIf you are using paratest, the system will automatically create a new database for each process.\nThis way, tests can independently run in parallel resulting in a super fast test-suite.\n\n### The DbalTestCase class\n\nIf you want to test a class that executes database queries, you can use the `DbalTestCase` class.\nThis class provides tools to build up the database schema, load testing fixtures and assert if database records exist.\nAn example on how to test the repository we created above:\n\n```php\nuse App\\Doctrine\\Schema\\UsersTable;\nuse App\\Doctrine\\Schema\\UsersTableColumns;\nuse App\\Entity\\User;\nuse App\\Repository\\UsersRepository;\nuse Phpro\\DbalTools\\Expression\\Comparison;\nuse Phpro\\DbalTools\\Expression\\Composite;\nuse Phpro\\DbalTools\\Expression\\LiteralString;\nuse Phpro\\DbalTools\\Test\\DbalTestCase;\nuse PHPUnit\\Framework\\Attributes\\Test;\n\nfinal class UsersRepositoryTest extends DbalTestCase\n{\n    protected function createFixtures(): void\n    {\n        self::insert(\n            UsersTable::name(),\n            UsersTable::columnTypes(),\n            $this-\u003efixtures['user1'] = [\n                UsersTableColumns::Id-\u003evalue =\u003e '07220bfb-00ff-4f69-9543-bb7a959ad452',\n                UsersTableColumns::Username-\u003evalue =\u003e 'user1',\n            ],\n        );\n    }\n\n    protected static function schemaTables(): array\n    {\n        return [UsersTable::class];\n    }\n\n    #[Test]\n    public function it_can_fetch_user_by_id(): void\n    {\n        $repository = $this-\u003ecreateRepository();\n        $user1 = $repository-\u003efindById($this-\u003efixtures['user1'][UsersTableColumns::Id-\u003evalue]);\n\n        self::assertSame($this-\u003efixtures['user1'][UsersTableColumns::Id-\u003evalue], $user1-\u003eid);\n        self::assertSame($this-\u003efixtures['user1'][UsersTableColumns::Username-\u003evalue], $user1-\u003euserName);\n    }\n\n    #[Test]\n    public function it_can_create_user(): void\n    {\n        $repository = $this-\u003ecreateRepository();\n        $repository-\u003ecreate(new User('dea2303c-0224-4765-9712-7847a49d8eb7', 'user2'));\n\n        self::assertRecordExists(UsersTable::name(), Composite::and(\n            Comparison::equal(UsersTableColumns::Id, new LiteralString('dea2303c-0224-4765-9712-7847a49d8eb7')),\n            Comparison::equal(UsersTableColumns::Username, new LiteralString('user2')),\n        ));\n    }\n\n    private function createRepository(): UsersRepository\n    {\n        return new UsersRepository($this-\u003econnection());\n    }\n}\n```\n\n### The DbalReaderTestCase class\n\nIf you have a class that performs a very specific database lookup, you can use the `DbalReaderTestCase` class.\nThis class will only load the fixtures that are needed for the test once instead of before each test, resulting in a faster test suite.\n\nExample:\n\n```php\nuse App\\Doctrine\\Schema\\UsersTable;\nuse App\\Doctrine\\Schema\\UsersTableColumns;\nuse Phpro\\DbalTools\\Test\\DbalReaderTestCase;\nuse PHPUnit\\Framework\\Attributes\\Test;\n\nfinal class UsersLookupTest extends DbalReaderTestCase\n{\n    protected function createFixtures(): void\n    {\n        self::insert(\n            UsersTable::name(),\n            UsersTable::columnTypes(),\n            $this-\u003efixtures['user1'] = [\n                UsersTableColumns::Id-\u003evalue =\u003e '07220bfb-00ff-4f69-9543-bb7a959ad452',\n                UsersTableColumns::Username-\u003evalue =\u003e 'user1',\n                UsersTableColumns::Active-\u003evalue =\u003e true,\n            ],\n            $this-\u003efixtures['user2'] = [\n                UsersTableColumns::Id-\u003evalue =\u003e '503beea0-1b37-4303-b8d7-e23f16db0ed6',\n                UsersTableColumns::Username-\u003evalue =\u003e 'user1',\n                UsersTableColumns::Active-\u003evalue =\u003e false,\n            ],\n        );\n    }\n\n    protected static function schemaTables(): array\n    {\n        return [UsersTable::class];\n    }\n\n    #[Test]\n    public function it_can_find_active_users(): void\n    {\n        $queryHandler = new FindActiveUsersHandler($this-\u003econnection());\n        $users = $queryHandler-\u003ehandle(new ActiveUsersQuery(isActive: true));\n\n        self::assertCount(1, $users);\n        self::assertSame($this-\u003efixtures['user1'][UsersTableColumns::Id-\u003evalue], $users[0]-\u003eid);\n        \n    }\n\n    #[Test]\n    public function it_can_find_inactive_users(): void\n    {\n        $queryHandler = new FindActiveUsersHandler($this-\u003econnection());\n        $users = $queryHandler-\u003ehandle(new ActiveUsersQuery(isActive: false));\n\n        self::assertCount(1, $users);\n        self::assertSame($this-\u003efixtures['user2'][UsersTableColumns::Id-\u003evalue], $users[0]-\u003eid);\n    }\n}\n```\n\n### The DoctrineValidatorTestCase class\n\nIf you are using `symfony/validator`, you can use the `DoctrineValidatorTestCase` class to test your validation rules.\nThis class will use symfony's `ConstraintValidatorTestCase` as a base and will automatically load the database schema and fixtures.\nThis way, you can test your validation rules against database records.\n\n```php\nuse Phpro\\DbalTools\\Test\\Validator\\DoctrineValidatorTestCase;\nuse PHPUnit\\Framework\\Attributes\\Test;\nuse Symfony\\Component\\Validator\\ConstraintValidatorInterface;\n\nfinal class UniqueUsernameValidatorTest extends DoctrineValidatorTestCase\n{\n    protected static function schemaTables(): array\n    {\n        return [UsersTable::class];\n    }\n\n    protected function createFixtures(): void\n    {\n        self::connection()-\u003einsert(\n            UsersTable::name(),\n            [\n                UsersTableColumns::Id-\u003evalue =\u003e '2c8c206c-0031-4c85-b36d-a7d5be16c138',\n                UsersTableColumns::Username-\u003evalue =\u003e 'noobslayer23',\n            ],\n            UsersTable::columnTypes(),\n        );\n    }\n\n    protected function createValidator(): ConstraintValidatorInterface\n    {\n        return new UniqueUsernameValidator(\n            self::connection()\n        );\n    }\n\n    #[Test]\n    public function it_must_have_a_unique_username(): void\n    {\n        $constraint = new UniqueUsernameConstraint();\n        $this-\u003evalidator-\u003evalidate(new User('f7e2c2df-1786-497b-b71e-43b66073ecc6', 'noobslayer23'), $constraint);\n\n        $violationList = $this-\u003econtext-\u003egetViolations();\n        self::assertSame(1, $violationList-\u003ecount());\n        self::assertSame(\n            'There is already a user with the username {{ username }}. Please choose another username.',\n            $violationList-\u003eget(0)-\u003egetMessage()\n        );\n    }\n}\n```\n\n## Validators\n\nThis package contains a set of common validators that can be used to validate your data against the database.\n\n### SchemaFieldValidator\n\nThis validator can be used to validate if a field exists in the database schema.\nIt will perform checks like: Does the provided input length exceed the length of the column in the database schema.\n\nExample configuration:\n\n```yaml\nApp\\Domain\\Model\\User:\n  properties:\n    userName:\n      - Phpro\\DbalTools\\Validator\\SchemaFieldConstraint:\n          table: App\\Infrastructure\\Doctrine\\Schema\\User\\UsersTable\n          column: !php/enum App\\Infrastructure\\Doctrine\\Schema\\User\\UsersTableColumns::Username\n```\n\n### TableKeyExistsValidator\n\nThis validator can be used to validate if a record identified by a key exists in the database.\nIt can be used to verify if a relation ID exists before storing it in the database.\n\nExample configuration:\n\n```yaml\nApp\\Domain\\Model\\User:\n  properties:\n    companyId:\n      - Phpro\\DbalTools\\Validator\\TableKeyExistsConstraint:\n          table: App\\Infrastructure\\Doctrine\\Schema\\Company\\CompaniesTable\n          column: !php/enum App\\Infrastructure\\Doctrine\\Schema\\Company\\CompaniesTableColumns::Id\n```\n\n### UniqueValidator\n\nThis validator can be used to validate if a record with the same value exists in the database already to ensure uniqueness.\n\nExample configuration:\n\n```yaml\nApp\\Domain\\Model\\User:\n  constraints:\n    - Phpro\\DbalTools\\Validator\\UniqueConstraint:\n        table: App\\Infrastructure\\Doctrine\\Schema\\User\\UsersTable\n        columns:\n          \"username\": !php/enum App\\Infrastructure\\Doctrine\\Schema\\User\\UsersTableColumns::Username\n        \n        # You can specify an alternate message and path name.\n        message: \"A user already exists with this username.\"\n        path: \"data.username\"\n        \n        # Can be used for updates to check if you are updating the existing record:\n        identifiers:\n          \"id\": !php/enum App\\Infrastructure\\Doctrine\\Schema\\User\\UsersTableColumns::Id\n        \n        # Enable case-insensitive comparison:\n        caseInsensitive: false\n```\n\n# Pagination\n\nDealing with pagination is a task that is often needed.\nThis package contains some tools to help you with that:\n\n```php\nuse Phpro\\DbalTools\\Pager\\MappingPager;\nuse Phpro\\DbalTools\\Pager\\Pager;\nuse Phpro\\DbalTools\\Pager\\Pagination;\nuse Phpro\\DbalTools\\Pager\\WindowCountPager;\n\n$query = $connection-\u003ecreateQueryBuilder()-\u003eselect('*')-\u003efrom('users');\n$userMapper = new UsersMapper()-\u003econvertFromDb(...);\n\n$usersPager = new MappingPager(\n    WindowCountPager::create(\n        new Pagination(page: $page limit: $limit),\n        $query,\n    ),\n    $userMapper,\n);\n\n// Iterating over the results:\n$totalResults = $usersPager-\u003etotalResults();\n$totalPages = $usersPager-\u003etotalPages();\n$users = [...$usersPager];\n```\n\n# Building queries\n\nThis package contains a set of tools that helps you build queries based on partial SQL Expressions.\nThe base of this is the `Phpro\\DbalTools\\Expression` interface.\n\nA few notable places:\n\n* Every column enum can be used directly as part of an SQL expression.\n* There is a `Phpro\\DbalTools\\Query\\CompositeQuery` that can be used to build composite queries (CTEs)\n* Inside the `Phpro\\DbalTools\\Expression` namespace, you can find a lot of classes that can be used to build partial SQL expressions.\n\n## About\n\n### Submitting bugs and feature requests\n\nBugs and feature request are tracked on [GitHub](https://github.com/phpro/dbal-tools/issues).\nPlease take a look at our rules before [contributing your code](CONTRIBUTING).\n\n### License\n\ndbal-tools is licensed under the [MIT License](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphpro%2Fdbal-tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphpro%2Fdbal-tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphpro%2Fdbal-tools/lists"}