{"id":16423594,"url":"https://github.com/rougin/windstorm","last_synced_at":"2025-02-25T01:42:46.661Z","repository":{"id":57047493,"uuid":"152700449","full_name":"rougin/windstorm","owner":"rougin","description":"Chainable, expressive, and interoperable SQL query builder.","archived":false,"fork":false,"pushed_at":"2020-08-24T22:52:24.000Z","size":140,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-07T14:11:27.359Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://roug.in/windstorm/","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/rougin.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-10-12T05:52:19.000Z","updated_at":"2024-10-11T08:52:36.000Z","dependencies_parsed_at":"2022-08-23T19:00:22.263Z","dependency_job_id":null,"html_url":"https://github.com/rougin/windstorm","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rougin%2Fwindstorm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rougin%2Fwindstorm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rougin%2Fwindstorm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rougin%2Fwindstorm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rougin","download_url":"https://codeload.github.com/rougin/windstorm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240587528,"owners_count":19825004,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":"2024-10-11T07:40:22.778Z","updated_at":"2025-02-25T01:42:46.635Z","avatar_url":"https://github.com/rougin.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Windstorm\n\n[![Latest Version on Packagist][ico-version]][link-packagist]\n[![Software License][ico-license]][link-license]\n[![Build Status][ico-travis]][link-travis]\n[![Coverage Status][ico-scrutinizer]][link-scrutinizer]\n[![Quality Score][ico-code-quality]][link-code-quality]\n[![Total Downloads][ico-downloads]][link-downloads]\n\nWindstorm is an expressive SQL query builder based intially on top of Doctrine's [Database Abstraction Layer (DBAL)](https://www.doctrine-project.org/projects/dbal.html). It has the same functionalities from DBAL's query builder but the difference is it does not requires a `Doctrine\\DBAL\\Connection` instance. Its goal is to be a single interface for handling SQL query builders and [object-relational mappers](https://en.wikipedia.org/wiki/Object-relational_mapping). Windstorm currently has query implementations for [Doctrine](https://www.doctrine-project.org/projects/orm.html) (through DBAL) and [Eloquent](https://laravel.com/docs/5.7/eloquent).\n\n## Why\n\nI tried to unify `Doctrine` and `Eloquent` into a single interface for them to be swappable. Unfortunately the implementation is not possible because of the different core design patterns ([data mapper](https://en.wikipedia.org/wiki/Data_mapper_pattern) for Doctrine while [active record](https://en.wikipedia.org/wiki/Active_record_pattern) for Eloquent). I realized later that the one thing common for both is their query builder and it was also common on all existing ORM packages and SQL query builders.\n\n## Installation\n\nInstall `Windstorm` via [Composer](https://getcomposer.org):\n\n``` bash\n$ composer require rougin/windstorm:dev-master\n```\n\n## Basic Usage\n\n### Configuration\n\nSince the query builder does not require `Doctrine\\DBAL\\Connection` by default, it needs to have a specified platform defined:\n\n``` php\nuse Doctrine\\DBAL\\Platforms\\AbstractPlatform;\nuse Rougin\\Windstorm\\Doctrine\\Builder;\nuse Rougin\\Windstorm\\Doctrine\\Query;\n\n// $platform instanceof AbstractPlatform\n\n$query = new Query(new Builder($platform));\n```\n\nList of supported platforms for the Doctrine DBAL: https://www.doctrine-project.org/projects/doctrine-dbal/en/2.8/reference/platforms.html\n\n#### Using a `Connection` instance\n\nIf the platform needs to came from a database connection, use the `Connection::createQueryBuilder` method instead:\n\n``` php\nuse Doctrine\\DBAL\\Connection;\nuse Rougin\\Windstorm\\Doctrine\\Query;\n\n// $connection instanceof Connection\n\n$query = new Query($connection-\u003ecreateQueryBuilder());\n```\n\nFor a documentation on how to get a connection: https://www.doctrine-project.org/projects/doctrine-dbal/en/2.8/reference/configuration.html\n\n### Query Builder\n\nThe query builder syntax is similar when writing SQL queries:\n\n``` php\n// $query instanceof Rougin\\Windstorm\\QueryInterface\n\n$query = $query\n    -\u003eselect(array('u.id', 'u.name'))\n    -\u003efrom('users', 'u')\n    -\u003ewhere('name')-\u003elike('%winds%')\n    -\u003eorderBy('created_at')-\u003edescending();\n\n// SELECT u.id, u.name FROM users u WHERE u.name LIKE :u_name ORDER BY u.created_at DESC\n$sql = $query-\u003esql();\n\n// array(':u_name' =\u003e '%winds%')\n$bindings = $query-\u003ebindings();\n```\n\n### Returning results\n\nTo return the results from a defined query, an instance must be implemented in `ResultInterface`.\n\n``` php\n// $connection instanceof Doctrine\\DBAL\\Connection\n// $query instanceof Rougin\\Windstorm\\QueryInterface\n\nuse Rougin\\Windstorm\\Doctrine\\Result;\n\n$result = new Result($connection);\n\n$query = $query-\u003eselect(array('u.*'));\n\n$query = $query-\u003efrom('users');\n\n$result = $result-\u003eexecute($query);\n\nvar_dump((array) $result-\u003eitems());\n```\n\n``` bash\narray(3) {\n  [0] =\u003e\n  array(4) {\n    'id' =\u003e\n    string(1) \"1\"\n    'name' =\u003e\n    string(9) \"Windstorm\"\n    'created_at' =\u003e\n    string(19) \"2018-10-15 23:06:28\"\n    'updated_at' =\u003e\n    NULL\n  }\n  [1] =\u003e\n  array(4) {\n    'id' =\u003e\n    string(1) \"2\"\n    'name' =\u003e\n    string(11) \"SQL Builder\"\n    'created_at' =\u003e\n    string(19) \"2018-10-15 23:09:47\"\n    'updated_at' =\u003e\n    NULL\n  }\n  [2] =\u003e\n  array(4) {\n    'id' =\u003e\n    string(1) \"3\"\n    'name' =\u003e\n    string(12) \"Rougin Gutib\"\n    'created_at' =\u003e\n    string(19) \"2018-10-15 23:14:45\"\n    'updated_at' =\u003e\n    NULL\n  }\n}\n```\n\n### QueryRepository and mutators\n\nThe `QueryRepository` instance is a special class that will mutate the `QueryInterface` through the use of mutators (implemented in `MutatorInterface`). Using this approach will seperate conditions into classes instead of defining it as methods inside a repository.\n\n``` php\nnamespace Acme\\Mutators;\n\nuse Rougin\\Windstorm\\Mutators\\ReturnEntity;\n\nclass ReturnUser extends ReturnEntity\n{\n    protected $table = 'users';\n}\n```\n\nAvailable mutators that can be extended:\n\n* `CreateEntity(array $data)` - generates a `INSERT INTO` query\n* `DeleteEntity(integer $id)` - generates a `DELETE FROM` query\n* `ReturnEntities($limit, $offset)` - generates a `SELECT` query with a limit and offset\n* `ReturnEntity(integer $id)` - generates a `SELECT` query (use `first` in `ResultInterface`)\n* `UpdateEntity($id, array $data)` - generates a `UPDATE` query\n\n``` php\n// $query instanceof Rougin\\Windstorm\\QueryInterface;\n// $result instanceof Rougin\\Windstorm\\ResultInterface;\n\nuse Acme\\Mutators\\ReturnUser;\n\n$query = $query-\u003eselect(['*'])-\u003efrom('users');\n\n$query = new QueryRepository($query, $result);\n\n$query = $query-\u003emutate(new ReturnUser(1));\n\nvar_dump($query-\u003efirst());\n```\n\n``` bash\narray(4) {\n  'id' =\u003e\n  string(1) \"1\"\n  'name' =\u003e\n  string(9) \"Windstorm\"\n  'created_at' =\u003e\n  string(19) \"2018-10-15 23:06:28\"\n  'updated_at' =\u003e\n  NULL\n}\n```\n\nTo map the result into a class, implement a mapper into a `MapperInterface`:\n\n``` php\nnamespace Acme\\Mappers;\n\nuse Acme\\Models\\User;\n\nclass UserMapper implements MapperInterface\n{\n    public function map($data)\n    {\n        return new User($data['id'], $data['name']);\n    }\n}\n```\n\n``` php\n// $query instanceof Rougin\\Windstorm\\QueryRepository;\n\nuse Acme\\Mappers\\UserMapper;\n\n$query-\u003emapper(new UserMapper);\n\nvar_dump($query-\u003efirst());\n```\n\n``` bash\nclass Acme\\Models\\User#11 (2) {\n  protected $id =\u003e\n  string(1) \"1\"\n  protected $name =\u003e\n  string(6) \"Windstorm\"\n}\n```\n\nNot implementing a class based from the `MapperInterface` will return the data as it is from from `ResultInterface`.\n\n### Mixed queries\n\nIn executing SQL queries, only one `QueryInterface` is allowed to be executed in `ResultInterface`. But there can be scenarios wherein you need to execute a query instance then execute another query instance with the result returned from the former query. An attempt to solve this is to implement a `MixedInterface` which is still a `QueryInterface` but can be able to add child queries (implemented in `ChildInterface`).\n\n``` php\n// $users instanceof \\Rougin\\Windstorm\\QueryInterface\n// $posts instanceof \\Rougin\\Windstorm\\QueryInterface\n\nuse Rougin\\Windstorm\\Relation\\Mixed;\nuse Rougin\\Windstorm\\Relation\\Child;\n\n$mixed = new Mixed($users, 'id');\n\n$child = new Child($child, 'id', 'user_id');\n\n$mixed-\u003eadd($child, 'posts');\n\n// SELECT u.id, u.name FROM users u\necho $mixed-\u003esql();\n\n$child = current($mixed-\u003eall());\n\n// SELECT p.id, p.title, p.body, p.user_id FROM posts p\necho $child-\u003esql();\n```\n\n## Credits\n\n- [All contributors][link-contributors]\n\n## License\n\nThe MIT License (MIT). Please see [LICENSE][link-license] for more information.\n\n[ico-code-quality]: https://img.shields.io/scrutinizer/g/rougin/windstorm.svg?style=flat-square\n[ico-downloads]: https://img.shields.io/packagist/dt/rougin/windstorm.svg?style=flat-square\n[ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square\n[ico-scrutinizer]: https://img.shields.io/scrutinizer/coverage/g/rougin/windstorm.svg?style=flat-square\n[ico-travis]: https://img.shields.io/travis/rougin/windstorm/master.svg?style=flat-square\n[ico-version]: https://img.shields.io/packagist/v/rougin/windstorm.svg?style=flat-square\n\n[link-changelog]: https://github.com/rougin/windstorm/blob/master/CHANGELOG.md\n[link-code-quality]: https://scrutinizer-ci.com/g/rougin/windstorm\n[link-contributors]: https://github.com/rougin/windstorm/contributors\n[link-downloads]: https://packagist.org/packages/rougin/windstorm\n[link-license]: https://github.com/rougin/windstorm/blob/master/LICENSE.md\n[link-packagist]: https://packagist.org/packages/rougin/windstorm\n[link-scrutinizer]: https://scrutinizer-ci.com/g/rougin/windstorm/code-structure\n[link-travis]: https://travis-ci.org/rougin/windstorm","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frougin%2Fwindstorm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frougin%2Fwindstorm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frougin%2Fwindstorm/lists"}