Добавлен цикл проверки сайтов

This commit is contained in:
2024-08-12 15:14:49 +03:00
parent 0b56cd37b5
commit 6b7199a326
115 changed files with 15964 additions and 88 deletions

View File

@ -0,0 +1 @@
repo_token: LFYrNmWM52pVO2g5dKuvf8NXd9mQLukDM

View File

@ -0,0 +1,4 @@
build/
vendor/
bin/
composer.lock

View File

@ -0,0 +1,22 @@
language: php
php:
- "5.6"
- "7.0"
- "7.1"
- "7.2"
- "7.3"
- "7.4"
before_script:
- composer install
script:
- bin/phpunit --coverage-text
matrix:
allow_failures:
- php: "hhvm"
branches:
only:
- master

View File

@ -0,0 +1,41 @@
# Changelog
## Unreleased
### Added
- Added parentQuery field to Select Object
- New test for orderBy method in Select Class
### Altered
- Changed orderBy method logic in Select Class. Now every select query has access to his parent object. You can manipulate sequence of your orderBy clause.
## 1.0.2 - TBA
### Added
- Added @shadowhand (Woody Gilk) to the **composer.json** under authors.
- Comments for queries using the **setComment** method.
- Table aliasing.
### Altered
- Changed PSR-0 loading to PSR-4.
- Changed the class loading in GenericBuilder. Now a classmap is used to load the query builder classes only when required.
- Changed test method names to camelCase format.
- Normalized the way select, insert and update behave internally.
## 1.0.1 - 2014-09-23
### Altered
- Big change in class loading to reducing memory usage.
## 1.0.0 - 2014-09-13
- First stable release
## 0.0.5-alpha - 2014-07-01
- Initial release

View File

@ -0,0 +1,33 @@
Contributing
============
First of all, **thank you** for contributing, **you are awesome**!
Here are a few rules to follow in order to ease code reviews, and discussions before
maintainers accept and merge your work.
You MUST follow the [PSR-1](http://www.php-fig.org/psr/1/) and
[PSR-2](http://www.php-fig.org/psr/2/). If you don't know about any of them, you
should really read the recommendations. Can't wait? Use the [PHP-CS-Fixer
tool](http://cs.sensiolabs.org/).
You MUST run the test suite.
You MUST write (or update) unit tests.
You SHOULD write documentation.
Please, write [commit messages that make
sense](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html),
and [rebase your branch](http://git-scm.com/book/en/Git-Branching-Rebasing)
before submitting your Pull Request.
One may ask you to [squash your
commits](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html)
too. This is used to "clean" your Pull Request before merging it (we don't want
commits such as `fix tests`, `fix 2`, `fix 3`, etc.).
Also, while creating your Pull Request on GitHub, you MUST write a description
which gives the context and/or explains why you are creating it.
Thank you!

View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Nil Portugués Calderó
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,1159 @@
SQL Query Builder
=================
[![Build Status](https://travis-ci.org/nilportugues/php-sql-query-builder.svg)](https://travis-ci.org/nilportugues/php-sql-query-builder) [![Coverage Status](https://img.shields.io/coveralls/nilportugues/sql-query-builder.svg)](https://coveralls.io/r/nilportugues/sql-query-builder) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/nilportugues/sql-query-builder/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/nilportugues/sql-query-builder/?branch=master) [![SensioLabsInsight](https://insight.sensiolabs.com/projects/89ec1003-4227-43a2-8432-67a9fc2d3ba3/mini.png)](https://insight.sensiolabs.com/projects/89ec1003-4227-43a2-8432-67a9fc2d3ba3) [![Latest Stable Version](https://poser.pugx.org/nilportugues/sql-query-builder/v/stable)](https://packagist.org/packages/nilportugues/sql-query-builder) [![Total Downloads](https://poser.pugx.org/nilportugues/sql-query-builder/downloads)](https://packagist.org/packages/nilportugues/sql-query-builder) [![License](https://poser.pugx.org/nilportugues/sql-query-builder/license)](https://packagist.org/packages/nilportugues/sql-query-builder)
[![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://paypal.me/nilportugues)
An elegant lightweight and efficient SQL Query Builder with fluid interface SQL syntax supporting bindings and complicated query generation. **Works without establishing a connection to the database.**
<a name="index_block"></a>
* [1. Installation](#block1)
* [2. The Builder](#block2)
* [2.1. Generic Builder](#block2.1)
* [2.2. MySQL Builder](#block2.2)
* [2.3. Human Readable Output](#block2.3)
* [3. Building Queries](#block3)
* [3.1. SELECT Statement](#block3.1)
* [3.1.1. Basic SELECT statement](#block3.1.1)
* [3.1.2. Aliased SELECT statement](#block3.1.2)
* [3.1.3. SELECT with WHERE statement](#block3.1.3)
* [3.1.4. Complex WHERE conditions](#block3.1.4)
* [3.1.5. JOIN & LEFT/RIGHT/INNER/CROSS JOIN SELECT statements](#block3.1.5)
* [3.1.6. COUNT rows](#block3.1.6)
* [3.2. INSERT Statement](#block3.2)
* [3.2.1. Basic INSERT statement](#block3.2.1)
* [3.3. UPDATE Statement](#block3.3)
* [3.3.1. Basic UPDATE statement](#block3.3.1)
* [3.3.2. Elaborated UPDATE statement](#block3.3.2)
* [3.4. DELETE Statement](#block3.4)
* [3.4.1. Empty table with DELETE statement](#block3.4.1)
* [3.4.2. Basic DELETE statement](#block3.4.2)
* [3.4.3. Elaborated DELETE statement](#block3.4.3)
* [3.5. INTERSECT Statement](#block3.5)
* [3.6. MINUS Statement](#block3.6)
* [3.7. UNION Statement](#block3.7)
* [3.8. UNION ALL Statement](#block3.8)
* [4. Advanced Quering](#block4)
* [4.1. Filtering using WHERE](#block4.1)
* [4.1.1. Changing WHERE logical operator](#block4.2)
* [4.1.2. Writing complicated WHERE conditions](#block4.2)
* [4.3. Grouping with GROUP BY and HAVING](#block4.3)
* [4.3.1 Available HAVING operators](#block4.3.1)
* [4.4. Changing HAVING logical operator](#block4.4)
* [4.5. Columns as SELECT statements](#block4.5)
* [4.6. Columns being Values](#block4.6)
* [4.7. Columns using FUNCTIONS](#block4.7)
* [5. Commenting queries](#block5)
* [6. Quality Code](#block6)
* [7. Author](#block7)
* [8. License](#block8)
<a name="block1"></a>
## 1. Installation [↑](#index_block)
The recommended way to install the SQL Query Builder is through [Composer](http://getcomposer.org). Run the following command to install it:
```sh
php composer.phar require nilportugues/sql-query-builder
```
<a name="block2"></a>
## 2. The Builder [↑](#index_block)
The SQL Query Builder allows to generate complex SQL queries standard using the `SQL-2003` dialect (default) and the `MySQL` dialect, that extends the `SQL-2003` dialect.
<a name="block2.1"></a>
### 2.1. Generic Builder [↑](#index_block)
The Generic Query Builder is the default builder for this class and writes standard SQL-2003.
**All column aliases are escaped using the `'` sign by default.**
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$query = $builder->select()->setTable('user');
echo $builder->write($query);
```
#### Output:
```sql
SELECT user.* FROM user
```
<a name="block2.2"></a>
### 2.2. MySQL Builder [↑](#index_block)
The MySQL Query Builder has its own class, that inherits from the SQL-2003 builder. All columns will be wrapped with the tilde **`** sign.
**All table and column aliases are escaped using the tilde sign by default.**
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\MySqlBuilder;
$builder = new MySqlBuilder();
$query = $builder->select()->setTable('user');
echo $builder->write($query);
```
#### Output:
```sql
SELECT user.* FROM `user`
```
<a name="block2.3"></a>
#### 2.3. Human Readable Output [↑](#index_block)
Both Generic and MySQL Query Builder can write complex SQL queries.
Every developer out there needs at some point revising the output of a complicated query, the SQL Query Builder includes a human-friendly output method, and therefore the `writeFormatted` method is there to aid the developer when need.
Keep in mind `writeFormatted` is to be avoided at all cost in production mode as it adds unneeded overhead due to parsing and re-formatting of the generated statement.
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$query = $builder->select()->setTable('user');
echo $builder->writeFormatted($query);
```
#### Output:
```sql
SELECT
user.*
FROM
user
```
More complicated examples can be found in the documentation.
<a name="block3"></a>
## 3. Building Queries [↑](#index_block)
<a name="block3.1"></a>
### 3.1. SELECT Statement [↑](#index_block)
<a name="block3.1.1"></a>
#### 3.1.1. Basic SELECT statement [↑](#index_block)
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$query = $builder->select()
->setTable('user')
->setColumns(['user_id','name','email']);
echo $builder->write($query);
```
#### Output:
```sql
SELECT user.user_id, user.name, user.email FROM user
```
<a name="block3.1.2"></a>
#### 3.1.2. Aliased SELECT statement [↑](#index_block)
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$query = $builder->select()
->setTable('user')
->setColumns(['userId' => 'user_id', 'username' => 'name', 'email' => 'email']);
echo $builder->write($query);
```
#### Output:
```sql
SELECT user.user_id AS 'userId', user.name AS 'username', user.email AS 'email' FROM user
```
<a name="block3.1.3"></a>
#### 3.1.3. SELECT with WHERE statement [↑](#index_block)
Default logical operator for filtering using `WHERE` conditions is `AND`.
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$query = $builder->select()
->setTable('user')
->setColumns([
'userId' => 'user_id',
'username' => 'name',
'email' => 'email'
])
->where()
->greaterThan('user_id', 5)
->notLike('username', 'John')
->end();
echo $builder->writeFormatted($query);
```
#### Output:
```sql
SELECT
user.user_id AS 'userId',
user.name AS 'username',
user.email AS 'email'
FROM
user
WHERE
(user.user_id < :v1)
AND (user.username NOT LIKE :v2)
```
<a name="block3.1.4"></a>
#### 3.1.4. Complex WHERE conditions [↑](#index_block)
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$query = $builder->select()
->setTable('user')
->where()
->equals('user_id', 1)
->equals('user_id', 2)
->subWhere("OR")
->lessThan($column, 10)
->greaterThan('user_id', 100)
->end();
echo $builder->writeFormatted($query);
```
#### Output:
```sql
SELECT
user.*
FROM
user
WHERE
(user.user_id = :v1)
AND (user.user_id = :v2)
AND (
(user.user_id < :v3)
OR (user.user_id > :v4)
)
```
<a name="block3.1.5"></a>
#### 3.1.5. JOIN & LEFT/RIGHT/INNER/CROSS JOIN SELECT statements [↑](#index_block)
Syntax for `JOIN`, `LEFT JOIN`, `RIGHT JOIN`, `INNER JOIN`, `CROSS JOIN` work the exactly same way.
Here's an example selecting both table and joined table columns and doing sorting using columns from both the table and the joined table.
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$query = $builder->select()
->setTable('user')
->setColumns([
'userId' => 'user_id',
'username' => 'name',
'email' => 'email',
'created_at'
])
->orderBy('user_id', OrderBy::DESC)
->leftJoin(
'news', //join table
'user_id', //origin table field used to join
'author_id', //join column
['newsTitle' => 'title', 'body', 'created_at', 'updated_at']
)
->on()
->equals('author_id', 1); //enforcing a condition on the join column
$query
->where()
->greaterThan('user_id', 5)
->notLike('username', 'John')
->end();
$query
->orderBy('created_at', OrderBy::DESC);
echo $builder->writeFormatted($query);
```
#### Output:
```sql
SELECT
user.user_id AS 'userId',
user.name AS 'username',
user.email AS 'email',
user.created_at,
news.title AS 'newsTitle',
news.body,
news.created_at,
news.updated_at
FROM
user
LEFT JOIN
news
ON
(news.author_id = user.user_id)
AND (news.author_id = :v1)
WHERE
(user.user_id < :v2)
AND (user.username NOT LIKE :v3)
ORDER BY
user.user_id DESC,
news.created_at DESC;
```
<a name="block3.1.6"></a>
#### 3.1.6. COUNT rows [↑](#index_block)
Counting rows comes in 3 possible ways, using the ALL selector `*`, stating a column or stating a column and its alias.
#### 3.1.6.1. Count using ALL selector
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$query = $builder->select()
->setTable('user')
->count()
echo $builder->write($query);
```
#### Output:
```sql
SELECT COUNT(*) FROM user;
```
#### 3.1.6.2. Count using column as a selector
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$query = $builder->select()
->setTable('user')
->count('user_id')
echo $builder->write($query);
```
#### Output:
```sql
SELECT COUNT(user.user_id) FROM user;
```
#### 3.1.6.3. Count using column as a selector
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$query = $builder->select()
->setTable('user')
->count('user_id', 'total_users')
echo $builder->write($query);
```
#### Output:
```sql
SELECT COUNT(user.user_id) AS 'total_users' FROM user;
```
<a name="block3.2"></a>
### 3.2. INSERT Statement [↑](#index_block)
The `INSERT` statement is really straightforward.
<a name="block3.2.1"></a>
#### 3.2.1 Basic INSERT statement [↑](#index_block)
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$query = $builder->insert()
->setTable('user')
->setValues([
'user_id' => 1,
'name' => 'Nil',
'contact' => 'contact@nilportugues.com',
]);
$sql = $builder->writeFormatted($query);
$values = $builder->getValues();
```
#### Output
```sql
INSERT INTO user (user.user_id, user.name, user.contact) VALUES (:v1, :v2, :v3)
```
```php
[':v1' => 1, ':v2' => 'Nil', ':v3' => 'contact@nilportugues.com'];
```
<a name="block3.3"></a>
### 3.3. UPDATE Statement [↑](#index_block)
The `UPDATE` statement works just like expected, set the values and the conditions to match the row and you're set.
Examples provided below.
<a name="block3.3.1"></a>
#### 3.3.1 Basic UPDATE statement [↑](#index_block)
Important including the the `where` statement is critical, or all table rows will be replaced with the provided values if the statement is executed.
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$query = $builder->update()
->setTable('user')
->setValues([
'user_id' => 1,
'name' => 'Nil',
'contact' => 'contact@nilportugues.com'
])
->where()
->equals('user_id', 1)
->end();
$sql = $builder->writeFormatted($query);
$values = $builder->getValues();
```
#### Output:
```sql
UPDATE
user
SET
user.user_id = :v1,
user.name = :v2,
user.contact = :v3
WHERE
(user.user_id = :v4)
```
```php
[':v1' => 1, ':v2' => 'Nil', ':v3' => 'contact@nilportugues.com', ':v4' => 1];
```
<a name="block3.3.2"></a>
#### 3.3.2. Elaborated UPDATE statement [↑](#index_block)
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Syntax\OrderBy;
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$query = $builder->update()
->setTable('user')
->setValues([
'name' => 'UpdatedName',
]);
$query
->where()
->like('username', '%N')
->between('user_id', 1, 2000)
->end();
$query
->orderBy('user_id', OrderBy::ASC)
->limit(1);
$sql = $builder->writeFormatted($query);
$values = $builder->getValues();
```
#### Output:
```sql
UPDATE
user
SET
user.name = :v1
WHERE
(user.username LIKE :v2)
AND (user.user_id BETWEEN :v3 AND :v4)
ORDER BY
user.user_id ASC
LIMIT :v5
```
<a name="block3.4"></a>
### 3.4. DELETE Statement [↑](#index_block)
The `DELETE` statement is used just like `UPDATE`, but no values are set.
Examples provided below.
<a name="block3.4.1"></a>
#### 3.4.1. Empty table with DELETE statement [↑](#index_block)
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$query = $builder->delete()
->setTable('user');
$sql = $builder->write($query);
```
#### Output:
```sql
DELETE FROM user
```
<a name="block3.4.2"></a>
#### 3.4.2. Basic DELETE statement [↑](#index_block)
Important including the the `where` statement is critical, or all table rows will be deleted with the provided values if the statement is executed.
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$query = $builder->delete()
->setTable('user');
$query
->where()
->equals('user_id', 100)
->end();
$query
->limit(1);
$sql = $builder->write($query);
$values = $builder->getValues();
```
#### Output:
```sql
DELETE FROM user WHERE (user.user_id = :v1) LIMIT :v2
```
```php
[':v1' => 100, ':v2' => 1];
```
<a name="block3.4.2"></a>
#### 3.4.2. Elaborated DELETE statement [↑](#index_block)
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Syntax\OrderBy;
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$query = $builder->delete()
->setTable('user');
$query
->where()
->like('username', '%N')
->between('user_id', 1, 2000)
->end();
$query
->orderBy('user_id', OrderBy::ASC)
->limit(1);
$sql = $builder->writeFormatted($query);
$values = $builder->getValues();
```
#### Output:
```sql
DELETE FROM
user
WHERE
(user.username LIKE :v1)
AND (user.user_id BETWEEN :v2 AND :v3)
ORDER BY
user.user_id ASC
LIMIT :v4
```
<a name="block3.5"></a>
### 3.5. INTERSECT Statement [↑](#index_block)
***
INTERSECT is not supported by MySQL.
Same results can be achieved by using INNER JOIN statement instead.
***
The `INTERSECT` statement is really straightforward.
<a name="block3.5.1"></a>
#### 3.5.1 Basic INTERSECT statement [↑](#index_block)
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$select1 = $builder->select()->setTable('user');
$select2 = $builder->select()->setTable('user_emails');
$query = $builder->intersect()
->add($select1)
->add($select2);
$sql = $builder->writeFormatted($query);
$values = $builder->getValues();
```
#### Output
```sql
SELECT user.* FROM user
INTERSECT
SELECT user_email.* FROM user_email
```
<a name="block3.6"></a>
### 3.6. MINUS Statement [↑](#index_block)
***
MINUS is not supported by MySQL.
Same results can be achieved by using a LEFT JOIN statement
in combination with an IS NULL or NOT IN condition instead.
***
The `MINUS` statement is really straightforward.
<a name="block3.6.1"></a>
#### 3.6.1 Basic MINUS statement [↑](#index_block)
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$select1 = $builder->select()->setTable('user');
$select2 = $builder->select()->setTable('user_emails');
$query = $builder->minus($select1, $select2);
$sql = $builder->writeFormatted($query);
$values = $builder->getValues();
```
#### Output
```sql
SELECT user.* FROM user
MINUS
SELECT user_email.* FROM user_email
```
<a name="block3.7"></a>
### 3.7. UNION Statement [↑](#index_block)
The `UNION` statement is really straightforward.
<a name="block3.7.1"></a>
#### 3.7.1 Basic UNION statement [↑](#index_block)
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$select1 = $builder->select()->setTable('user');
$select2 = $builder->select()->setTable('user_emails');
$query = $builder->union()
->add($select1)
->add($select2);
$sql = $builder->writeFormatted($query);
$values = $builder->getValues();
```
#### Output
```sql
SELECT user.* FROM user
UNION
SELECT user_email.* FROM user_email
```
<a name="block3.8"></a>
### 3.8. UNION ALL Statement [↑](#index_block)
The `UNION ALL` statement is really straightforward.
<a name="block3.8.1"></a>
#### 3.8.1 Basic UNION ALL statement [↑](#index_block)
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$select1 = $builder->select()->setTable('user');
$select2 = $builder->select()->setTable('user_emails');
$query = $builder->unionAll()
->add($select1)
->add($select2);
$sql = $builder->writeFormatted($query);
$values = $builder->getValues();
```
#### Output
```sql
SELECT user.* FROM user
UNION ALL
SELECT user_email.* FROM user_email
```
<a name="block4"></a>
## 4. Advanced Quering [↑](#index_block)
<a name="block4.1"></a>
### 4.1. Filtering using WHERE [↑](#index_block)
The following operators are available for filtering using WHERE conditionals:
```php
public function subWhere($operator = 'OR');
public function equals($column, $value);
public function notEquals($column, $value);
public function greaterThan($column, $value);
public function greaterThanOrEqual($column, $value);
public function lessThan($column, $value);
public function lessThanOrEqual($column, $value);
public function like($column, $value);
public function notLike($column, $value);
public function match(array $columns, array $values);
public function matchBoolean(array $columns, array $values);
public function matchWithQueryExpansion(array $columns, array $values);
public function in($column, array $values);
public function notIn($column, array $values);
public function between($column, $a, $b);
public function notBetween($column, $a, $b);
public function isNull($column);
public function isNotNull($column);
public function exists(Select $select);
public function notExists(Select $select);
public function addBitClause($column, $value);
public function asLiteral($literal);
```
<a name="block4.2"></a>
### 4.2. Changing WHERE logical operator [↑](#index_block)
`WHERE` default's operator must be changed passing to the `where` method the logical operator `OR`.
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$query = $builder->select()
->setTable('user')
->where('OR')
->equals('user_id', 1)
->like('name', '%N%')
->end();
$sql = $builder->writeFormatted($query);
$values = $builder->getValues();
```
#### Output:
```sql
SELECT user.* FROM user WHERE (user.user_id = :v1) OR (user.name LIKE :v2)
```
<a name="block4.3"></a>
### 4.3. Grouping with GROUP BY and HAVING [↑](#index_block)
Default logical operator for joining more than one `HAVING` condition is `AND`.
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$query = $builder->select()
->setTable('user')
->setColumns([
'userId' => 'user_id',
'username' => 'name',
'email' => 'email',
'created_at'
])
->groupBy(['user_id', 'name'])
->having()
->equals('user_id', 1)
->equals('user_id', 2);
$sql = $builder->writeFormatted($query);
$values = $builder->getValues();
```
#### Output:
```sql
SELECT
user.user_id AS 'userId',
user.name AS 'username',
user.email AS 'email',
user.created_at
FROM
user
GROUP BY
user.user_id, user.name
HAVING
(user.user_id = :v1)
AND (user.user_id = :v2)
```
<a name="block4.3.1"></a>
#### 4.3.1 Available HAVING operators [↑](#index_block)
Same operators used in the WHERE statement are available for HAVING operations.
<a name="block4.4"></a>
### 4.4. Changing HAVING logical operator [↑](#index_block)
`HAVING` default's operator must be changed passing to the `having` method the logical operator `OR`.
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$query = $builder->select()
->setTable('user')
->setColumns([
'userId' => 'user_id',
'username' => 'name',
'email' => 'email',
'created_at'
])
->groupBy(['user_id', 'name'])
->having('OR')
->equals('user_id', 1)
->equals('user_id', 2);
$sql = $builder->writeFormatted($query);
$values = $builder->getValues();
```
#### Output:
```sql
SELECT
user.user_id AS 'userId',
user.name AS 'username',
user.email AS 'email',
user.created_at
FROM
user
GROUP BY
user.user_id, user.name
HAVING
(user.user_id = :v1)
OR (user.user_id = :v2)
```
<a name="block4.5"></a>
### 4.5. Columns as SELECT statements [↑](#index_block)
Sometimes, a column needs to be set as a column. SQL Query Builder got you covered on this one too! Check the example below.
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$selectRole = $builder->select()
->setTable('role')
->setColumns(array('role_name'))
->limit(1)
->where()
->equals('role_id', 3);
$query = $builder->select()
->setTable('user')
->setColumns(array('user_id', 'username'))
->setSelectAsColumn(array('user_role' => $selectRole))
->setSelectAsColumn(array($selectRole))
->where()
->equals('user_id', 4)
->end();
$sql = $builder->writeFormatted($query);
$values = $builder->getValues();
```
#### Output:
```sql
SELECT
user.user_id,
user.username,
(
SELECT
role.role_name
FROM
role
WHERE
(role.role_id = :v1)
LIMIT :v2, :v3
) AS 'user_role',
(
SELECT
role.role_name
FROM
role
WHERE
(role.role_id = :v4)
LIMIT :v5, :v6
) AS 'role'
FROM
user
WHERE
(user.user_id = :v7)
```
<a name="block4.6"></a>
### 4.6. Columns being Values [↑](#index_block)
There are time where you need to force the same column structure (eg: UNIONs) even when lacking of a column or value. Forcing column with values gets you covered.
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$query = $builder->select()
->setTable('user')
->setColumns(array('user_id', 'username'))
->setValueAsColumn('10', 'priority')
->where()
->equals('user_id', 1)
->end();
$sql = $builder->writeFormatted($query);
$values = $builder->getValues();
```
#### Output:
```sql
SELECT
user.user_id,
user.username,
:v1 AS 'priority'
FROM
user
WHERE
(user.user_id = :v2)
```
<a name="block4.7"></a>
### 4.7. Columns using FUNCTIONS [↑](#index_block)
Example for MAX function.
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$query = $builder->select()
->setTable('user')
->setColumns(array('user_id', 'username'))
->setFunctionAsColumn('MAX', array('user_id'), 'max_id')
->where()
->equals('user_id', 1)
->end();
$sql = $builder->writeFormatted($query);
$values = $builder->getValues();
```
#### Output:
```sql
SELECT
user.user_id,
user.username,
MAX(user_id) AS 'max_id'
FROM
user
WHERE
(user.user_id = :v1)
```
Example for CURRENT_TIMESTAMP function.
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$query = $builder->select()
->setTable('user')
->setColumns(array('user_id', 'username'))
->setFunctionAsColumn('CURRENT_TIMESTAMP', array(), 'server_time')
->where()
->equals('user_id', 1)
->end();
$sql = $builder->writeFormatted($query);
$values = $builder->getValues();
```
#### Output:
```sql
SELECT
user.user_id,
user.username,
CURRENT_TIMESTAMP AS 'server_time'
FROM
user
WHERE
(user.user_id = :v1)
```
<a name="block5"></a>
## 5. Commenting queries [↑](#index_block)
The query builder allows adding comments to all query methods by using the `setComment` method.
Some useful use cases examples can be :
- Explain difficult queries or why of its existence.
- Finding slow queries from its comments.
#### Usage:
```php
<?php
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
$builder = new GenericBuilder();
$query = $builder->select()
->setTable('user')
->setComment('This is a comment');
$sql = $builder->write($query);
```
#### Output:
```sql
-- This is a comment
SELECT user.* FROM user
```
<a name="block6"></a>
## 6. Quality Code [↑](#index_block)
Testing has been done using PHPUnit and [Travis-CI](https://travis-ci.org). All code has been tested to be compatible from PHP 5.4 up to PHP 5.6 and [HHVM](http://hhvm.com/).
To run the test suite, you need [Composer](http://getcomposer.org):
```bash
php composer.phar install --dev
php bin/phpunit
```
<a name="block7"></a>
## 7. Author [↑](#index_block)
Nil Portugués Calderó
- <contact@nilportugues.com>
- [http://nilportugues.com](http://nilportugues.com)
<a name="block8"></a>
## 8. License [↑](#index_block)
SQL Query Builder is licensed under the MIT license.
```
Copyright (c) 2014 Nil Portugués Calderó
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
```

View File

@ -0,0 +1,53 @@
{
"name":"nilportugues/sql-query-builder",
"description":"An elegant lightweight and efficient SQL QueryInterface BuilderInterface supporting bindings and complicated query generation.",
"keywords": [ "sql", "mysql", "query", "builder", "query builder", "orm"],
"type":"library",
"license":"MIT",
"homepage":"http://nilportugues.com",
"authors":
[
{
"name":"Nil Portugués Calderó",
"email":"contact@nilportugues.com",
"homepage":"http://nilportugues.com",
"role":"Lead Developer"
},
{
"name":"Woody Gilk",
"email":"woody.gilk@gmail.com",
"homepage":"http://shadowhand.me/",
"role":"Contributor"
}
],
"autoload":{
"psr-4":{
"NilPortugues\\Sql\\QueryBuilder\\":"src/"
}
},
"autoload-dev":{
"psr-4":{
"NilPortugues\\Tests\\Sql\\QueryBuilder\\":"tests/"
}
},
"require":
{
"php": ">=5.5",
"nilportugues/sql-query-formatter": "~1.2"
},
"require-dev": {
"phpunit/phpunit": "4.*",
"fabpot/php-cs-fixer": "~1.9",
"nilportugues/php_backslasher": "~0.2"
},
"config":
{
"bin-dir": "bin"
},
"minimum-stability": "stable",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
}
}

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit cacheTokens="false"
backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
stopOnError="false"
stopOnFailure="false"
stopOnIncomplete="false"
stopOnSkipped="false"
syntaxCheck="true"
bootstrap="vendor/autoload.php"
verbose="true">
<php>
<ini name="intl.default_locale" value="en_US.UTF-8" />
<ini name="intl.error_level" value="0" />
<ini name="memory_limit" value="-1" />
<ini name="max_execution_time" value="-1"/>
<ini name="date.timezone" value="Europe/Madrid" />
<ini name="error_reporting" value="E_ALL" />
</php>
<testsuites>
<testsuite name="Test Suite">
<directory>./tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./</directory>
<exclude>
<directory>./vendor/</directory>
<directory>./tests/</directory>
</exclude>
</whitelist>
</filter>
<logging>
<log type="junit" target="build/logs/junit.xml"/>
<log type="coverage-clover" target="build/logs/clover.xml"/>
<log type="coverage-html" target="build/coverage"/>
</logging>
</phpunit>

View File

@ -0,0 +1,18 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/3/14
* Time: 12:07 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Builder;
/**
* Class BuilderException.
*/
final class BuilderException extends \Exception
{
}

View File

@ -0,0 +1,33 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/3/14
* Time: 12:07 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Builder;
use NilPortugues\Sql\QueryBuilder\Manipulation\QueryInterface;
/**
* Interface BuilderInterface.
*/
interface BuilderInterface
{
/**
* @param QueryInterface $query
*
* @return string
*/
public function write(QueryInterface $query);
/**
* @param QueryInterface $query
*
* @return string
*/
public function writeFormatted(QueryInterface $query);
}

View File

@ -0,0 +1,401 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/3/14
* Time: 12:07 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Builder;
use NilPortugues\Sql\QueryBuilder\Builder\Syntax\WriterFactory;
use NilPortugues\Sql\QueryBuilder\Manipulation\AbstractBaseQuery;
use NilPortugues\Sql\QueryBuilder\Manipulation\QueryInterface;
use NilPortugues\Sql\QueryBuilder\Manipulation\QueryFactory;
use NilPortugues\Sql\QueryBuilder\Manipulation\Select;
use NilPortugues\Sql\QueryBuilder\Syntax\Column;
use NilPortugues\Sql\QueryBuilder\Syntax\Table;
/**
* Class Generic.
*/
class GenericBuilder implements BuilderInterface
{
/**
* The placeholder parameter bag.
*
* @var \NilPortugues\Sql\QueryBuilder\Builder\Syntax\PlaceholderWriter
*/
protected $placeholderWriter;
/**
* The Where writer.
*
* @var \NilPortugues\Sql\QueryBuilder\Builder\Syntax\WhereWriter
*/
protected $whereWriter;
/**
* The SQL formatter.
*
* @var \NilPortugues\Sql\QueryFormatter\Formatter
*/
protected $sqlFormatter;
/**
* Class namespace for the query pretty output formatter.
* Required to create the instance only if required.
*
* @var string
*/
protected $sqlFormatterClass = 'NilPortugues\Sql\QueryFormatter\Formatter';
/**
* Array holding the writers for each query part. Methods are called upon request and stored in
* the $queryWriterInstances array.
*
* @var array
*/
protected $queryWriterArray = [
'SELECT' => '\NilPortugues\Sql\QueryBuilder\Builder\Syntax\WriterFactory::createSelectWriter',
'INSERT' => '\NilPortugues\Sql\QueryBuilder\Builder\Syntax\WriterFactory::createInsertWriter',
'UPDATE' => '\NilPortugues\Sql\QueryBuilder\Builder\Syntax\WriterFactory::createUpdateWriter',
'DELETE' => '\NilPortugues\Sql\QueryBuilder\Builder\Syntax\WriterFactory::createDeleteWriter',
'INTERSECT' => '\NilPortugues\Sql\QueryBuilder\Builder\Syntax\WriterFactory::createIntersectWriter',
'MINUS' => '\NilPortugues\Sql\QueryBuilder\Builder\Syntax\WriterFactory::createMinusWriter',
'UNION' => '\NilPortugues\Sql\QueryBuilder\Builder\Syntax\WriterFactory::createUnionWriter',
'UNION ALL' => '\NilPortugues\Sql\QueryBuilder\Builder\Syntax\WriterFactory::createUnionAllWriter',
];
/**
* Array that stores instances of query writers.
*
* @var array
*/
protected $queryWriterInstances = [
'SELECT' => null,
'INSERT' => null,
'UPDATE' => null,
'DELETE' => null,
'INTERSECT' => null,
'MINUS' => null,
'UNION' => null,
'UNION ALL' => null,
];
/**
* Creates writers.
*/
public function __construct()
{
$this->placeholderWriter = WriterFactory::createPlaceholderWriter();
}
/**
* @param string $table
* @param array $columns
*
* @return \NilPortugues\Sql\QueryBuilder\Manipulation\Select
*/
public function select($table = null, array $columns = null)
{
return $this->injectBuilder(QueryFactory::createSelect($table, $columns));
}
/**
* @param \NilPortugues\Sql\QueryBuilder\Manipulation\AbstractBaseQuery
*
* @return \NilPortugues\Sql\QueryBuilder\Manipulation\AbstractBaseQuery
*/
protected function injectBuilder(AbstractBaseQuery $query)
{
return $query->setBuilder($this);
}
/**
* @param string $table
* @param array $values
*
*@return AbstractBaseQuery
*/
public function insert($table = null, array $values = null)
{
return $this->injectBuilder(QueryFactory::createInsert($table, $values));
}
/**
* @param string $table
* @param array $values
*
*@return AbstractBaseQuery
*/
public function update($table = null, array $values = null)
{
return $this->injectBuilder(QueryFactory::createUpdate($table, $values));
}
/**
* @param string $table
*
* @return \NilPortugues\Sql\QueryBuilder\Manipulation\Delete
*/
public function delete($table = null)
{
return $this->injectBuilder(QueryFactory::createDelete($table));
}
/**
* @return \NilPortugues\Sql\QueryBuilder\Manipulation\Intersect
*/
public function intersect()
{
return QueryFactory::createIntersect();
}
/**
* @return \NilPortugues\Sql\QueryBuilder\Manipulation\Union
*/
public function union()
{
return QueryFactory::createUnion();
}
/**
* @return \NilPortugues\Sql\QueryBuilder\Manipulation\UnionAll
*/
public function unionAll()
{
return QueryFactory::createUnionAll();
}
/**
* @param \NilPortugues\Sql\QueryBuilder\Manipulation\Select $first
* @param \NilPortugues\Sql\QueryBuilder\Manipulation\Select $second
*
* @return \NilPortugues\Sql\QueryBuilder\Manipulation\Minus
*/
public function minus(Select $first, Select $second)
{
return QueryFactory::createMinus($first, $second);
}
/**
* @return array
*/
public function getValues()
{
return $this->placeholderWriter->get();
}
/**
* Returns a SQL string in a readable human-friendly format.
*
* @param QueryInterface $query
*
* @return string
*/
public function writeFormatted(QueryInterface $query)
{
if (null === $this->sqlFormatter) {
$this->sqlFormatter = (new \ReflectionClass($this->sqlFormatterClass))->newInstance();
}
return $this->sqlFormatter->format($this->write($query));
}
/**
* @param QueryInterface $query
* @param bool $resetPlaceholders
*
* @return string
*
* @throws \RuntimeException
*/
public function write(QueryInterface $query, $resetPlaceholders = true)
{
if ($resetPlaceholders) {
$this->placeholderWriter->reset();
}
$queryPart = $query->partName();
if (false === empty($this->queryWriterArray[$queryPart])) {
$this->createQueryObject($queryPart);
return $this->queryWriterInstances[$queryPart]->write($query);
}
throw new \RuntimeException('Query builder part not defined.');
}
/**
* @param Select $select
*
* @return string
*/
public function writeJoin(Select $select)
{
if (null === $this->whereWriter) {
$this->whereWriter = WriterFactory::createWhereWriter($this, $this->placeholderWriter);
}
$sql = ($select->getJoinType()) ? "{$select->getJoinType()} " : '';
$sql .= 'JOIN ';
$sql .= $this->writeTableWithAlias($select->getTable());
$sql .= ' ON ';
$sql .= $this->whereWriter->writeWhere($select->getJoinCondition());
return $sql;
}
/**
* @param Table $table
*
* @return string
*/
public function writeTableWithAlias(Table $table)
{
$alias = ($table->getAlias()) ? " AS {$this->writeTableAlias($table->getAlias())}" : '';
$schema = ($table->getSchema()) ? "{$table->getSchema()}." : '';
return $schema.$this->writeTableName($table).$alias;
}
/**
* @param $alias
*
* @return mixed
*/
public function writeTableAlias($alias)
{
return $alias;
}
/**
* Returns the table name.
*
* @param Table $table
*
* @return string
*/
public function writeTableName(Table $table)
{
return $table->getName();
}
/**
* @param string $alias
*
* @return string
*/
public function writeColumnAlias($alias)
{
return sprintf('"%s"', $alias);
}
/**
* @param Table $table
*
* @return string
*/
public function writeTable(Table $table)
{
$schema = ($table->getSchema()) ? "{$table->getSchema()}." : '';
return $schema.$this->writeTableName($table);
}
/**
* @param array $values
*
* @return array
*/
public function writeValues(array &$values)
{
\array_walk(
$values,
function (&$value) {
$value = $this->writePlaceholderValue($value);
}
);
return $values;
}
/**
* @param $value
*
* @return string
*/
public function writePlaceholderValue($value)
{
return $this->placeholderWriter->add($value);
}
/**
* @param $operator
*
* @return string
*/
public function writeConjunction($operator)
{
return ' '.$operator.' ';
}
/**
* @return string
*/
public function writeIsNull()
{
return ' IS NULL';
}
/**
* @return string
*/
public function writeIsNotNull()
{
return ' IS NOT NULL';
}
/**
* Returns the column name.
*
* @param Column $column
*
* @return string
*/
public function writeColumnName(Column $column)
{
$name = $column->getName();
if ($name === Column::ALL) {
return $this->writeColumnAll();
}
return $name;
}
/**
* @return string
*/
protected function writeColumnAll()
{
return '*';
}
/**
* @param string $queryPart
*/
protected function createQueryObject($queryPart)
{
if (null === $this->queryWriterInstances[$queryPart]) {
$this->queryWriterInstances[$queryPart] = \call_user_func_array(
\explode('::', $this->queryWriterArray[$queryPart]),
[$this, $this->placeholderWriter]
);
}
}
}

View File

@ -0,0 +1,91 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/3/14
* Time: 12:07 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Builder;
use NilPortugues\Sql\QueryBuilder\Syntax\Column;
use NilPortugues\Sql\QueryBuilder\Syntax\Table;
/**
* Class MySqlBuilder.
*/
class MySqlBuilder extends GenericBuilder
{
/**
* {@inheritdoc}
*
* @param Column $column
*
* @return string
*/
public function writeColumnName(Column $column)
{
if ($column->isAll()) {
return '*';
}
if (false !== strpos($column->getName(), '(')) {
return parent::writeColumnName($column);
}
return $this->wrapper(parent::writeColumnName($column));
}
/**
* {@inheritdoc}
*
* @param Table $table
*
* @return string
*/
public function writeTableName(Table $table)
{
return $this->wrapper(parent::writeTableName($table));
}
/**
* {@inheritdoc}
*
* @param $alias
*
* @return string
*/
public function writeTableAlias($alias)
{
return $this->wrapper(parent::writeTableAlias($alias));
}
/**
* {@inheritdoc}
*
* @param $alias
*
* @return string
*/
public function writeColumnAlias($alias)
{
return $this->wrapper($alias);
}
/**
* @param $string
* @param string $char
*
* @return string
*/
protected function wrapper($string, $char = '`')
{
if (0 === strlen($string)) {
return '';
}
return $char.$string.$char;
}
}

View File

@ -0,0 +1,96 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 12/24/14
* Time: 1:14 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
use NilPortugues\Sql\QueryBuilder\Manipulation\AbstractBaseQuery;
/**
* Class AbstractBaseWriter.
*/
abstract class AbstractBaseWriter
{
/**
* @var GenericBuilder
*/
protected $writer;
/**
* @var PlaceholderWriter
*/
protected $placeholderWriter;
/**
* @var ColumnWriter
*/
protected $columnWriter;
/**
* @param GenericBuilder $writer
* @param PlaceholderWriter $placeholder
*/
public function __construct(GenericBuilder $writer, PlaceholderWriter $placeholder)
{
$this->writer = $writer;
$this->placeholderWriter = $placeholder;
$this->columnWriter = WriterFactory::createColumnWriter($writer, $placeholder);
}
/**
* @param AbstractBaseQuery $class
*
* @return string
*/
public static function writeQueryComment(AbstractBaseQuery $class)
{
$comment = '';
if ('' !== $class->getComment()) {
$comment = $class->getComment();
}
return $comment;
}
/**
* @param AbstractBaseQuery $class
* @param GenericBuilder $writer
* @param PlaceholderWriter $placeholderWriter
* @param array $parts
*/
public static function writeWhereCondition(
AbstractBaseQuery $class,
$writer, PlaceholderWriter
$placeholderWriter,
array &$parts
) {
if (!is_null($class->getWhere())) {
$whereWriter = WriterFactory::createWhereWriter($writer, $placeholderWriter);
$parts[] = "WHERE {$whereWriter->writeWhere($class->getWhere())}";
}
}
/**
* @param AbstractBaseQuery $class
* @param PlaceholderWriter $placeholderWriter
* @param array $parts
*/
public static function writeLimitCondition(
AbstractBaseQuery $class,
PlaceholderWriter $placeholderWriter,
array &$parts
) {
if (!is_null($class->getLimitStart())) {
$start = $placeholderWriter->add($class->getLimitStart());
$parts[] = "LIMIT {$start}";
}
}
}

View File

@ -0,0 +1,51 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 12/24/14
* Time: 12:55 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
use NilPortugues\Sql\QueryBuilder\Syntax\QueryPartInterface;
/**
* Class AbstractSetWriter.
*/
abstract class AbstractSetWriter
{
/**
* @var GenericBuilder
*/
protected $writer;
/**
* @param GenericBuilder $writer
*/
public function __construct(GenericBuilder $writer)
{
$this->writer = $writer;
}
/**
* @param QueryPartInterface $setClass
* @param string $setOperation
* @param $glue
*
* @return string
*/
protected function abstractWrite(QueryPartInterface $setClass, $setOperation, $glue)
{
$selects = [];
foreach ($setClass->$setOperation() as $select) {
$selects[] = $this->writer->write($select, false);
}
return \implode("\n".$glue."\n", $selects);
}
}

View File

@ -0,0 +1,162 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/12/14
* Time: 1:28 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
use NilPortugues\Sql\QueryBuilder\Manipulation\Select;
use NilPortugues\Sql\QueryBuilder\Syntax\Column;
use NilPortugues\Sql\QueryBuilder\Syntax\SyntaxFactory;
/**
* Class ColumnWriter.
*/
class ColumnWriter
{
/**
* @var \NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder
*/
protected $writer;
/**
* @var PlaceholderWriter
*/
protected $placeholderWriter;
/**
* @param GenericBuilder $writer
* @param PlaceholderWriter $placeholderWriter
*/
public function __construct(GenericBuilder $writer, PlaceholderWriter $placeholderWriter)
{
$this->writer = $writer;
$this->placeholderWriter = $placeholderWriter;
}
/**
* @param Select $select
*
* @return array
*/
public function writeSelectsAsColumns(Select $select)
{
$selectAsColumns = $select->getColumnSelects();
if (!empty($selectAsColumns)) {
$selectWriter = WriterFactory::createSelectWriter($this->writer, $this->placeholderWriter);
$selectAsColumns = $this->selectColumnToQuery($selectAsColumns, $selectWriter);
}
return $selectAsColumns;
}
/**
* @param array $selectAsColumns
* @param SelectWriter $selectWriter
*
* @return mixed
*/
protected function selectColumnToQuery(array &$selectAsColumns, SelectWriter $selectWriter)
{
\array_walk(
$selectAsColumns,
function (&$column) use (&$selectWriter) {
$keys = \array_keys($column);
$key = \array_pop($keys);
$values = \array_values($column);
$value = $values[0];
if (\is_numeric($key)) {
/* @var Column $value */
$key = $this->writer->writeTableName($value->getTable());
}
$column = $selectWriter->selectToColumn($key, $value);
}
);
return $selectAsColumns;
}
/**
* @param Select $select
*
* @return array
*/
public function writeValueAsColumns(Select $select)
{
$valueAsColumns = $select->getColumnValues();
$newColumns = [];
if (!empty($valueAsColumns)) {
foreach ($valueAsColumns as $alias => $value) {
$value = $this->writer->writePlaceholderValue($value);
$newValueColumn = array($alias => $value);
$newColumns[] = SyntaxFactory::createColumn($newValueColumn, null);
}
}
return $newColumns;
}
/**
* @param Select $select
*
* @return array
*/
public function writeFuncAsColumns(Select $select)
{
$funcAsColumns = $select->getColumnFuncs();
$newColumns = [];
if (!empty($funcAsColumns)) {
foreach ($funcAsColumns as $alias => $value) {
$funcName = $value['func'];
$funcArgs = (!empty($value['args'])) ? '('.implode(', ', $value['args']).')' : '';
$newFuncColumn = array($alias => $funcName.$funcArgs);
$newColumns[] = SyntaxFactory::createColumn($newFuncColumn, null);
}
}
return $newColumns;
}
/**
* @param Column $column
*
* @return string
*/
public function writeColumnWithAlias(Column $column)
{
if (($alias = $column->getAlias()) && !$column->isAll()) {
return $this->writeColumn($column).' AS '.$this->writer->writeColumnAlias($alias);
}
return $this->writeColumn($column);
}
/**
* @param Column $column
*
* @return string
*/
public function writeColumn(Column $column)
{
$alias = $column->getTable()->getAlias();
$table = ($alias) ? $this->writer->writeTableAlias($alias) : $this->writer->writeTable($column->getTable());
$columnString = (empty($table)) ? '' : "{$table}.";
$columnString .= $this->writer->writeColumnName($column);
return $columnString;
}
}

View File

@ -0,0 +1,57 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/11/14
* Time: 1:50 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
use NilPortugues\Sql\QueryBuilder\Manipulation\Delete;
/**
* Class DeleteWriter.
*/
class DeleteWriter
{
/**
* @var GenericBuilder
*/
protected $writer;
/**
* @var PlaceholderWriter
*/
protected $placeholderWriter;
/**
* @param GenericBuilder $writer
* @param PlaceholderWriter $placeholder
*/
public function __construct(GenericBuilder $writer, PlaceholderWriter $placeholder)
{
$this->writer = $writer;
$this->placeholderWriter = $placeholder;
}
/**
* @param Delete $delete
*
* @return string
*/
public function write(Delete $delete)
{
$table = $this->writer->writeTable($delete->getTable());
$parts = array("DELETE FROM {$table}");
AbstractBaseWriter::writeWhereCondition($delete, $this->writer, $this->placeholderWriter, $parts);
AbstractBaseWriter::writeLimitCondition($delete, $this->placeholderWriter, $parts);
$comment = AbstractBaseWriter::writeQueryComment($delete);
return $comment.implode(' ', $parts);
}
}

View File

@ -0,0 +1,103 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/11/14
* Time: 1:51 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
use NilPortugues\Sql\QueryBuilder\Manipulation\Insert;
use NilPortugues\Sql\QueryBuilder\Manipulation\QueryException;
/**
* Class InsertWriter.
*/
class InsertWriter
{
/**
* @var GenericBuilder
*/
protected $writer;
/**
* @var ColumnWriter
*/
protected $columnWriter;
/**
* @param GenericBuilder $writer
* @param PlaceholderWriter $placeholder
*/
public function __construct(GenericBuilder $writer, PlaceholderWriter $placeholder)
{
$this->writer = $writer;
$this->columnWriter = WriterFactory::createColumnWriter($this->writer, $placeholder);
}
/**
* @param Insert $insert
*
* @throws QueryException
*
* @return string
*/
public function write(Insert $insert)
{
$columns = $insert->getColumns();
if (empty($columns)) {
throw new QueryException('No columns were defined for the current schema.');
}
$columns = $this->writeQueryColumns($columns);
$values = $this->writeQueryValues($insert->getValues());
$table = $this->writer->writeTable($insert->getTable());
$comment = AbstractBaseWriter::writeQueryComment($insert);
return $comment."INSERT INTO {$table} ($columns) VALUES ($values)";
}
/**
* @param $columns
*
* @return string
*/
protected function writeQueryColumns($columns)
{
return $this->writeCommaSeparatedValues($columns, $this->columnWriter, 'writeColumn');
}
/**
* @param $collection
* @param $writer
* @param string $method
*
* @return string
*/
protected function writeCommaSeparatedValues($collection, $writer, $method)
{
\array_walk(
$collection,
function (&$data) use ($writer, $method) {
$data = $writer->$method($data);
}
);
return \implode(', ', $collection);
}
/**
* @param $values
*
* @return string
*/
protected function writeQueryValues($values)
{
return $this->writeCommaSeparatedValues($values, $this->writer, 'writePlaceholderValue');
}
}

View File

@ -0,0 +1,29 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/12/14
* Time: 7:15 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Manipulation\Intersect;
/**
* Class IntersectWriter.
*/
class IntersectWriter extends AbstractSetWriter
{
/**
* @param Intersect $intersect
*
* @return string
*/
public function write(Intersect $intersect)
{
return $this->abstractWrite($intersect, 'getIntersects', Intersect::INTERSECT);
}
}

View File

@ -0,0 +1,46 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/12/14
* Time: 7:15 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
use NilPortugues\Sql\QueryBuilder\Manipulation\Minus;
/**
* Class MinusWriter.
*/
class MinusWriter
{
/**
* @var GenericBuilder
*/
protected $writer;
/**
* @param GenericBuilder $writer
*/
public function __construct(GenericBuilder $writer)
{
$this->writer = $writer;
}
/**
* @param Minus $minus
*
* @return string
*/
public function write(Minus $minus)
{
$first = $this->writer->write($minus->getFirst());
$second = $this->writer->write($minus->getSecond());
return $first."\n".Minus::MINUS."\n".$second;
}
}

View File

@ -0,0 +1,147 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/4/14
* Time: 12:02 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Builder\Syntax;
/**
* Class PlaceholderWriter.
*/
class PlaceholderWriter
{
/**
* @var int
*/
protected $counter = 1;
/**
* @var array
*/
protected $placeholders = [];
/**
* @return array
*/
public function get()
{
return $this->placeholders;
}
/**
* @return $this
*/
public function reset()
{
$this->counter = 1;
$this->placeholders = [];
return $this;
}
/**
* @param $value
*
* @return string
*/
public function add($value)
{
$placeholderKey = ':v'.$this->counter;
$this->placeholders[$placeholderKey] = $this->setValidSqlValue($value);
++$this->counter;
return $placeholderKey;
}
/**
* @param $value
*
* @return string
*/
protected function setValidSqlValue($value)
{
$value = $this->writeNullSqlString($value);
$value = $this->writeStringAsSqlString($value);
$value = $this->writeBooleanSqlString($value);
return $value;
}
/**
* @param $value
*
* @return string
*/
protected function writeNullSqlString($value)
{
if (\is_null($value) || (\is_string($value) && empty($value))) {
$value = $this->writeNull();
}
return $value;
}
/**
* @return string
*/
protected function writeNull()
{
return 'NULL';
}
/**
* @param string $value
*
* @return string
*/
protected function writeStringAsSqlString($value)
{
if (\is_string($value)) {
$value = $this->writeString($value);
}
return $value;
}
/**
* @param string $value
*
* @return string
*/
protected function writeString($value)
{
return $value;
}
/**
* @param string $value
*
* @return string
*/
protected function writeBooleanSqlString($value)
{
if (\is_bool($value)) {
$value = $this->writeBoolean($value);
}
return $value;
}
/**
* @param bool $value
*
* @return string
*/
protected function writeBoolean($value)
{
$value = \filter_var($value, FILTER_VALIDATE_BOOLEAN);
return ($value) ? '1' : '0';
}
}

View File

@ -0,0 +1,397 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/11/14
* Time: 1:50 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
use NilPortugues\Sql\QueryBuilder\Manipulation\Select;
use NilPortugues\Sql\QueryBuilder\Syntax\Column;
use NilPortugues\Sql\QueryBuilder\Syntax\OrderBy;
use NilPortugues\Sql\QueryBuilder\Syntax\SyntaxFactory;
/**
* Class SelectWriter.
*/
class SelectWriter extends AbstractBaseWriter
{
/**
* @param $alias
* @param Select $select
*
* @return Column
*/
public function selectToColumn($alias, Select $select)
{
$selectAsColumn = $this->write($select);
if (!empty($selectAsColumn)) {
$selectAsColumn = '('.$selectAsColumn.')';
}
$column = array($alias => $selectAsColumn);
return SyntaxFactory::createColumn($column, null);
}
/**
* @param Select $select
*
* @return string
*/
public function write(Select $select)
{
if ($select->isJoinSelect()) {
return $this->writer->writeJoin($select);
}
return $this->writeSelectQuery($select);
}
/**
* @param Select $select
*
* @return string
*/
protected function writeSelectQuery(Select $select)
{
$parts = ['SELECT'];
if ($select->isDistinct()) {
$parts[] = 'DISTINCT';
}
$this->writeSelectColumns($select, $parts);
$this->writeSelectFrom($select, $parts);
$this->writeSelectJoins($select, $parts);
$this->writeSelectWhere($select, $parts);
$this->writeSelectGroupBy($select, $parts);
$this->writeSelectHaving($select, $parts);
$this->writeSelectOrderBy($select, $parts);
$this->writeSelectLimit($select, $parts);
return AbstractBaseWriter::writeQueryComment($select).implode(' ', \array_filter($parts));
}
/**
* @param Select $select
* @param string[] $parts
*
* @return $this
*/
public function writeSelectColumns(Select $select, array &$parts)
{
if ($select->isCount() === false) {
$columns = $this->writeColumnAlias(
$select->getAllColumns(),
$this->columnWriter->writeSelectsAsColumns($select),
$this->columnWriter->writeValueAsColumns($select),
$this->columnWriter->writeFuncAsColumns($select)
);
$parts = \array_merge($parts, [implode(', ', $columns)]);
return $this;
}
$columns = $select->getColumns();
$column = \array_pop($columns);
$columnList = $column->getName();
$parts = \array_merge($parts, [$columnList]);
return $this;
}
/**
* @param $tableColumns
* @param $selectAsColumns
* @param $valueAsColumns
* @param $funcAsColumns
*
* @return array
*/
protected function writeColumnAlias($tableColumns, $selectAsColumns, $valueAsColumns, $funcAsColumns)
{
$columns = \array_merge($tableColumns, $selectAsColumns, $valueAsColumns, $funcAsColumns);
\array_walk(
$columns,
function (&$column) {
$column = $this->columnWriter->writeColumnWithAlias($column);
}
);
return $columns;
}
/**
* @param Select $select
* @param string[] $parts
*
* @return $this
*/
public function writeSelectFrom(Select $select, array &$parts)
{
$parts = \array_merge(
$parts,
['FROM '.$this->writer->writeTableWithAlias($select->getTable())]
);
return $this;
}
/**
* @param Select $select
* @param array $parts
*
* @return $this
*/
public function writeSelectJoins(Select $select, array &$parts)
{
$parts = \array_merge(
$parts,
[$this->writeSelectAggrupation($select, $this->writer, 'getAllJoins', 'writeJoin', ' ')]
);
return $this;
}
/**
* @param Select $select
* @param $writer
* @param string $getMethod
* @param string $writeMethod
* @param string $glue
* @param string $prepend
*
* @return string
*/
protected function writeSelectAggrupation(Select $select, $writer, $getMethod, $writeMethod, $glue, $prepend = '')
{
$str = '';
$joins = $select->$getMethod();
if (!empty($joins)) {
\array_walk(
$joins,
function (&$join) use ($writer, $writeMethod) {
$join = $writer->$writeMethod($join);
}
);
$str = $prepend.implode($glue, $joins);
}
return $str;
}
/**
* @param Select $select
* @param array $parts
*
* @return $this
*/
public function writeSelectWhere(Select $select, array &$parts)
{
$str = '';
$wheres = $this->writeSelectWheres($select->getAllWheres());
$wheres = \array_filter($wheres);
if (\count($wheres) > 0) {
$str = 'WHERE ';
$separator = ' '.$this->writer->writeConjunction($select->getWhereOperator()).' ';
$str .= \implode($separator, $wheres);
}
$parts = \array_merge($parts, [$str]);
return $this;
}
/**
* @param array $wheres
*
* @return array
*/
protected function writeSelectWheres(array $wheres)
{
$whereWriter = WriterFactory::createWhereWriter($this->writer, $this->placeholderWriter);
\array_walk(
$wheres,
function (&$where) use (&$whereWriter) {
$where = $whereWriter->writeWhere($where);
}
);
return $wheres;
}
/**
* @param Select $select
* @param array $parts
*
* @return $this
*/
public function writeSelectGroupBy(Select $select, array &$parts)
{
$groupBy = $this->writeSelectAggrupation(
$select,
$this->columnWriter,
'getGroupBy',
'writeColumn',
', ',
'GROUP BY '
);
$parts = \array_merge($parts, [$groupBy]);
return $this;
}
/**
* @param Select $select
* @param array $parts
*
* @return $this
*/
public function writeSelectHaving(Select $select, array &$parts)
{
$str = '';
$havingArray = $select->getAllHavings();
if (\count($havingArray) > 0) {
$placeholder = $this->placeholderWriter;
$writer = $this->writer;
$str = 'HAVING ';
$separator = ' '.$select->getHavingOperator().' ';
$havingArray = $this->getHavingConditions($havingArray, $select, $writer, $placeholder);
$str .= \implode($separator, $havingArray);
}
$parts = \array_merge($parts, [$str]);
return $this;
}
/**
* @param array $havingArray
* @param Select $select
* @param GenericBuilder $writer
* @param PlaceholderWriter $placeholder
*
* @return mixed
*/
protected function getHavingConditions(
array &$havingArray,
Select $select,
GenericBuilder $writer,
PlaceholderWriter $placeholder
) {
\array_walk(
$havingArray,
function (&$having) use ($select, $writer, $placeholder) {
$whereWriter = WriterFactory::createWhereWriter($writer, $placeholder);
$clauses = $whereWriter->writeWhereClauses($having);
$having = \implode($this->writer->writeConjunction($select->getHavingOperator()), $clauses);
}
);
return $havingArray;
}
/**
* @param Select $select
* @param array $parts
*
* @return $this
*/
protected function writeSelectOrderBy(Select $select, array &$parts)
{
$str = '';
if (\count($select->getAllOrderBy())) {
$orderByArray = $select->getAllOrderBy();
\array_walk(
$orderByArray,
function (&$orderBy) {
$orderBy = $this->writeOrderBy($orderBy);
}
);
$str = 'ORDER BY ';
$str .= \implode(', ', $orderByArray);
}
$parts = \array_merge($parts, [$str]);
return $this;
}
/**
* @param OrderBy $orderBy
*
* @return string
*/
public function writeOrderBy(OrderBy $orderBy)
{
$column = $this->columnWriter->writeColumn($orderBy->getColumn());
return $column.' '.$orderBy->getDirection();
}
/**
* @param Select $select
* @param array $parts
*
* @return $this
*/
protected function writeSelectLimit(Select $select, array &$parts)
{
$mask = $this->getStartingLimit($select).$this->getLimitCount($select);
$limit = '';
if ($mask !== '00') {
$start = $this->placeholderWriter->add($select->getLimitStart());
$count = $this->placeholderWriter->add($select->getLimitCount());
$limit = "LIMIT {$start}, {$count}";
}
$parts = \array_merge($parts, [$limit]);
return $this;
}
/**
* @param Select $select
*
* @return string
*/
protected function getStartingLimit(Select $select)
{
return (null === $select->getLimitStart() || 0 == $select->getLimitStart()) ? '0' : '1';
}
/**
* @param Select $select
*
* @return string
*/
protected function getLimitCount(Select $select)
{
return (null === $select->getLimitCount()) ? '0' : '1';
}
}

View File

@ -0,0 +1,29 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/12/14
* Time: 7:15 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Manipulation\UnionAll;
/**
* Class UnionAllWriter.
*/
class UnionAllWriter extends AbstractSetWriter
{
/**
* @param UnionAll $unionAll
*
* @return string
*/
public function write(UnionAll $unionAll)
{
return $this->abstractWrite($unionAll, 'getUnions', UnionAll::UNION_ALL);
}
}

View File

@ -0,0 +1,29 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/12/14
* Time: 7:15 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Manipulation\Union;
/**
* Class UnionWriter.
*/
class UnionWriter extends AbstractSetWriter
{
/**
* @param Union $union
*
* @return string
*/
public function write(Union $union)
{
return $this->abstractWrite($union, 'getUnions', Union::UNION);
}
}

View File

@ -0,0 +1,67 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/11/14
* Time: 1:51 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Manipulation\QueryException;
use NilPortugues\Sql\QueryBuilder\Manipulation\Update;
use NilPortugues\Sql\QueryBuilder\Syntax\SyntaxFactory;
/**
* Class UpdateWriter.
*/
class UpdateWriter extends AbstractBaseWriter
{
/**
* @param Update $update
*
* @throws QueryException
*
* @return string
*/
public function write(Update $update)
{
$values = $update->getValues();
if (empty($values)) {
throw new QueryException('No values to update in Update query.');
}
$parts = array(
'UPDATE '.$this->writer->writeTable($update->getTable()).' SET ',
$this->writeUpdateValues($update),
);
AbstractBaseWriter::writeWhereCondition($update, $this->writer, $this->placeholderWriter, $parts);
AbstractBaseWriter::writeLimitCondition($update, $this->placeholderWriter, $parts);
$comment = AbstractBaseWriter::writeQueryComment($update);
return $comment.implode(' ', $parts);
}
/**
* @param Update $update
*
* @return string
*/
protected function writeUpdateValues(Update $update)
{
$assigns = [];
foreach ($update->getValues() as $column => $value) {
$newColumn = array($column);
$column = $this->columnWriter->writeColumn(SyntaxFactory::createColumn($newColumn, $update->getTable()));
$value = $this->writer->writePlaceholderValue($value);
$assigns[] = "$column = $value";
}
return \implode(', ', $assigns);
}
}

View File

@ -0,0 +1,400 @@
<?php
namespace NilPortugues\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Manipulation\Select;
use NilPortugues\Sql\QueryBuilder\Syntax\Column;
use NilPortugues\Sql\QueryBuilder\Syntax\SyntaxFactory;
use NilPortugues\Sql\QueryBuilder\Syntax\Where;
/**
* Class WhereWriter.
*/
class WhereWriter extends AbstractBaseWriter
{
/**
* @var array
*/
protected $matchMode = [
'natural' => '(MATCH({{columnNames}}) AGAINST({{columnValues}}))',
'boolean' => '(MATCH({{columnNames}}) AGAINST({{columnValues}} IN BOOLEAN MODE))',
'query_expansion' => '(MATCH({{columnNames}}) AGAINST({{columnValues}} WITH QUERY EXPANSION))',
];
/**
* @param Where $where
*
* @return string
*/
public function writeWhere(Where $where)
{
$clauses = $this->writeWhereClauses($where);
$clauses = \array_filter($clauses);
if (empty($clauses)) {
return '';
}
return \implode($this->writer->writeConjunction($where->getConjunction()), $clauses);
}
/**
* @param Where $where
*
* @return array
*/
public function writeWhereClauses(Where $where)
{
$whereArray = [];
$this->writeWhereMatches($where, $whereArray);
$this->writeWhereIns($where, $whereArray);
$this->writeWhereNotIns($where, $whereArray);
$this->writeWhereBetweens($where, $whereArray);
$this->writeWhereNotBetweens($where, $whereArray);
$this->writeWhereComparisons($where, $whereArray);
$this->writeWhereIsNulls($where, $whereArray);
$this->writeWhereIsNotNulls($where, $whereArray);
$this->writeWhereBooleans($where, $whereArray);
$this->writeExists($where, $whereArray);
$this->writeNotExists($where, $whereArray);
$this->writeSubWheres($where, $whereArray);
return $whereArray;
}
/**
* @param Where $where
* @param array $whereArray
*
* @return array
*/
protected function writeWhereMatches(Where $where, array &$whereArray)
{
$matches = [];
foreach ($where->getMatches() as $values) {
$columns = SyntaxFactory::createColumns($values['columns'], $where->getTable());
$columnNames = $this->getColumnNames($columns);
$columnValues = array(\implode(' ', $values['values']));
$columnValues = \implode(', ', $this->writer->writeValues($columnValues));
$matches[] = \str_replace(
['{{columnNames}}', '{{columnValues}}'],
[$columnNames, $columnValues],
$this->matchMode[$values['mode']]
);
}
$whereArray = \array_merge($whereArray, $matches);
}
/**
* @param $columns
*
* @return string
*/
protected function getColumnNames($columns)
{
$columnNames = [];
foreach ($columns as &$column) {
$columnNames[] = $this->columnWriter->writeColumn($column);
}
return \implode(', ', $columnNames);
}
/**
* @param Where $where
* @param array $whereArray
*
* @return array
*/
protected function writeWhereIns(Where $where, array &$whereArray)
{
$whereArray = \array_merge(
$whereArray,
$this->writeWhereIn($where, 'getIns', 'IN')
);
}
/**
* @param Where $where
* @param string $method
* @param string $operation
*
* @return array
*/
protected function writeWhereIn(Where $where, $method, $operation)
{
$collection = [];
foreach ($where->$method() as $column => $values) {
$newColumn = array($column);
$column = SyntaxFactory::createColumn($newColumn, $where->getTable());
$column = $this->columnWriter->writeColumn($column);
$values = $this->writer->writeValues($values);
$values = \implode(', ', $values);
$collection[] = "({$column} $operation ({$values}))";
}
return $collection;
}
/**
* @param Where $where
* @param array $whereArray
*
* @return array
*/
protected function writeWhereNotIns(Where $where, array &$whereArray)
{
$whereArray = \array_merge(
$whereArray,
$this->writeWhereIn($where, 'getNotIns', 'NOT IN')
);
}
/**
* @param Where $where
* @param array $whereArray
*
* @return array
*/
protected function writeWhereBetweens(Where $where, array &$whereArray)
{
$between = $where->getBetweens();
\array_walk(
$between,
function (&$between) {
$between = '('
.$this->columnWriter->writeColumn($between['subject'])
.' BETWEEN '
.$this->writer->writePlaceholderValue($between['a'])
.' AND '
.$this->writer->writePlaceholderValue($between['b'])
.')';
}
);
$whereArray = \array_merge($whereArray, $between);
}
/**
* @param Where $where
* @param array $whereArray
*
* @return array
*/
protected function writeWhereNotBetweens(Where $where, array &$whereArray)
{
$between = $where->getNotBetweens();
\array_walk(
$between,
function (&$between) {
$between = '('
.$this->columnWriter->writeColumn($between['subject'])
.' NOT BETWEEN '
.$this->writer->writePlaceholderValue($between['a'])
.' AND '
.$this->writer->writePlaceholderValue($between['b'])
.')';
}
);
$whereArray = \array_merge($whereArray, $between);
}
/**
* @param Where $where
* @param array $whereArray
*
* @return array
*/
protected function writeWhereComparisons(Where $where, array &$whereArray)
{
$comparisons = $where->getComparisons();
\array_walk(
$comparisons,
function (&$comparison) {
if (!is_array($comparison)) {
return;
}
$str = $this->writeWherePartialCondition($comparison['subject']);
$str .= $this->writer->writeConjunction($comparison['conjunction']);
$str .= $this->writeWherePartialCondition($comparison['target']);
$comparison = "($str)";
}
);
$whereArray = \array_merge($whereArray, $comparisons);
}
/**
* @param $subject
*
* @return string
*/
protected function writeWherePartialCondition(&$subject)
{
if ($subject instanceof Column) {
$str = $this->columnWriter->writeColumn($subject);
} elseif ($subject instanceof Select) {
$selectWriter = WriterFactory::createSelectWriter($this->writer, $this->placeholderWriter);
$str = '('.$selectWriter->write($subject).')';
} else {
$str = $this->writer->writePlaceholderValue($subject);
}
return $str;
}
/**
* @param Where $where
* @param array $whereArray
*
* @return array
*/
protected function writeWhereIsNulls(Where $where, array &$whereArray)
{
$whereArray = \array_merge(
$whereArray,
$this->writeWhereIsNullable($where, 'getNull', 'writeIsNull')
);
}
/**
* @param Where $where
* @param string $getMethod
* @param string $writeMethod
*
* @return array
*/
protected function writeWhereIsNullable(Where $where, $getMethod, $writeMethod)
{
$collection = $where->$getMethod();
\array_walk(
$collection,
function (&$collection) use ($writeMethod) {
$collection =
'('.$this->columnWriter->writeColumn($collection['subject'])
.$this->writer->$writeMethod().')';
}
);
return $collection;
}
/**
* @param Where $where
* @param array $whereArray
*
* @return array
*/
protected function writeWhereIsNotNulls(Where $where, array &$whereArray)
{
$whereArray = \array_merge(
$whereArray,
$this->writeWhereIsNullable($where, 'getNotNull', 'writeIsNotNull')
);
}
/**
* @param Where $where
* @param array $whereArray
*
* @return array
*/
protected function writeWhereBooleans(Where $where, array &$whereArray)
{
$booleans = $where->getBooleans();
$placeholderWriter = $this->placeholderWriter;
\array_walk(
$booleans,
function (&$boolean) use (&$placeholderWriter) {
$column = $this->columnWriter->writeColumn($boolean['subject']);
$value = $this->placeholderWriter->add($boolean['value']);
$boolean = '(ISNULL('.$column.', 0) = '.$value.')';
}
);
$whereArray = \array_merge($whereArray, $booleans);
}
/**
* @param Where $where
* @param array $whereArray
*
* @return array
*/
protected function writeExists(Where $where, array &$whereArray)
{
$whereArray = \array_merge(
$whereArray,
$this->writeExistence($where, 'getExists', 'EXISTS')
);
}
/**
* @param Where $where
* @param string $method
* @param string $operation
*
* @return array
*/
protected function writeExistence(Where $where, $method, $operation)
{
$exists = [];
foreach ($where->$method() as $select) {
$exists[] = "$operation (".$this->writer->write($select, false).')';
}
return $exists;
}
/**
* @param Where $where
* @param array $whereArray
*
* @return array
*/
protected function writeNotExists(Where $where, array &$whereArray)
{
$whereArray = \array_merge(
$whereArray,
$this->writeExistence($where, 'getNotExists', 'NOT EXISTS')
);
}
/**
* @param Where $where
* @param array $whereArray
*
* @return array
*/
protected function writeSubWheres(Where $where, array &$whereArray)
{
$subWheres = $where->getSubWheres();
\array_walk(
$subWheres,
function (&$subWhere) {
$subWhere = "({$this->writeWhere($subWhere)})";
}
);
$whereArray = \array_merge($whereArray, $subWheres);
}
}

View File

@ -0,0 +1,133 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/12/14
* Time: 2:11 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
/**
* Class WriterFactory.
*/
final class WriterFactory
{
/**
* @param GenericBuilder $writer
* @param PlaceholderWriter $placeholderWriter
*
* @return ColumnWriter
*/
public static function createColumnWriter(GenericBuilder $writer, PlaceholderWriter $placeholderWriter)
{
return new ColumnWriter($writer, $placeholderWriter);
}
/**
* @param GenericBuilder $writer
* @param PlaceholderWriter $placeholderWriter
*
* @return WhereWriter
*/
public static function createWhereWriter(GenericBuilder $writer, PlaceholderWriter $placeholderWriter)
{
return new WhereWriter($writer, $placeholderWriter);
}
/**
* @param GenericBuilder $writer
* @param PlaceholderWriter $placeholderWriter
*
* @return SelectWriter
*/
public static function createSelectWriter(GenericBuilder $writer, PlaceholderWriter $placeholderWriter)
{
return new SelectWriter($writer, $placeholderWriter);
}
/**
* @param GenericBuilder $writer
* @param PlaceholderWriter $placeholderWriter
*
* @return InsertWriter
*/
public static function createInsertWriter(GenericBuilder $writer, PlaceholderWriter $placeholderWriter)
{
return new InsertWriter($writer, $placeholderWriter);
}
/**
* @param GenericBuilder $writer
* @param PlaceholderWriter $placeholderWriter
*
* @return UpdateWriter
*/
public static function createUpdateWriter(GenericBuilder $writer, PlaceholderWriter $placeholderWriter)
{
return new UpdateWriter($writer, $placeholderWriter);
}
/**
* @param GenericBuilder $writer
* @param PlaceholderWriter $placeholderWriter
*
* @return DeleteWriter
*/
public static function createDeleteWriter(GenericBuilder $writer, PlaceholderWriter $placeholderWriter)
{
return new DeleteWriter($writer, $placeholderWriter);
}
/**
* @return PlaceholderWriter
*/
public static function createPlaceholderWriter()
{
return new PlaceholderWriter();
}
/**
* @param GenericBuilder $writer
*
* @return IntersectWriter
*/
public static function createIntersectWriter(GenericBuilder $writer)
{
return new IntersectWriter($writer);
}
/**
* @param GenericBuilder $writer
*
* @return MinusWriter
*/
public static function createMinusWriter(GenericBuilder $writer)
{
return new MinusWriter($writer);
}
/**
* @param GenericBuilder $writer
*
* @return UnionWriter
*/
public static function createUnionWriter(GenericBuilder $writer)
{
return new UnionWriter($writer);
}
/**
* @param GenericBuilder $writer
*
* @return UnionAllWriter
*/
public static function createUnionAllWriter(GenericBuilder $writer)
{
return new UnionAllWriter($writer);
}
}

View File

@ -0,0 +1,277 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/3/14
* Time: 12:07 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Manipulation;
use NilPortugues\Sql\QueryBuilder\Syntax\OrderBy;
use NilPortugues\Sql\QueryBuilder\Syntax\QueryPartInterface;
use NilPortugues\Sql\QueryBuilder\Syntax\SyntaxFactory;
use NilPortugues\Sql\QueryBuilder\Syntax\Table;
use NilPortugues\Sql\QueryBuilder\Syntax\Where;
// Builder injects itself into query for convestion to SQL string.
use NilPortugues\Sql\QueryBuilder\Builder\BuilderInterface;
/**
* Class AbstractBaseQuery.
*/
abstract class AbstractBaseQuery implements QueryInterface, QueryPartInterface
{
/**
* @var string
*/
protected $comment = '';
/**
* @var \NilPortugues\Sql\QueryBuilder\Builder\BuilderInterface
*/
protected $builder;
/**
* @var string
*/
protected $table;
/**
* @var string
*/
protected $whereOperator = 'AND';
/**
* @var Where
*/
protected $where;
/**
* @var array
*/
protected $joins = [];
/**
* @var int
*/
protected $limitStart;
/**
* @var int
*/
protected $limitCount;
/**
* @var array
*/
protected $orderBy = [];
/**
* @return Where
*/
protected function filter()
{
if (!isset($this->where)) {
$this->where = QueryFactory::createWhere($this);
}
return $this->where;
}
/**
* Stores the builder that created this query.
*
* @param BuilderInterface $builder
*
* @return $this
*/
final public function setBuilder(BuilderInterface $builder)
{
$this->builder = $builder;
return $this;
}
/**
* @return BuilderInterface
*
* @throws \RuntimeException when builder has not been injected
*/
final public function getBuilder()
{
if (!$this->builder) {
throw new \RuntimeException('Query builder has not been injected with setBuilder');
}
return $this->builder;
}
/**
* Converts this query into an SQL string by using the injected builder.
*
* @return string
*/
public function __toString()
{
try {
return $this->getSql();
} catch (\Exception $e) {
return \sprintf('[%s] %s', \get_class($e), $e->getMessage());
}
}
/**
* Converts this query into an SQL string by using the injected builder.
* Optionally can return the SQL with formatted structure.
*
* @param bool $formatted
*
* @return string
*/
public function getSql($formatted = false)
{
if ($formatted) {
return $this->getBuilder()->writeFormatted($this);
}
return $this->getBuilder()->write($this);
}
/**
* @return string
*/
abstract public function partName();
/**
* @return Where
*/
public function getWhere()
{
return $this->where;
}
/**
* @param Where $where
*
* @return $this
*/
public function setWhere(Where $where)
{
$this->where = $where;
return $this;
}
/**
* @return Table
*/
public function getTable()
{
$newTable = array($this->table);
return \is_null($this->table) ? null : SyntaxFactory::createTable($newTable);
}
/**
* @param string $table
*
* @return $this
*/
public function setTable($table)
{
$this->table = (string) $table;
return $this;
}
/**
* @param string $whereOperator
*
* @return Where
*/
public function where($whereOperator = 'AND')
{
if (!isset($this->where)) {
$this->where = $this->filter();
}
$this->where->conjunction($whereOperator);
return $this->where;
}
/**
* @return string
*/
public function getWhereOperator()
{
if (!isset($this->where)) {
$this->where = $this->filter();
}
return $this->where->getConjunction();
}
/**
* @param string $column
* @param string $direction
* @param null $table
*
* @return $this
*/
public function orderBy($column, $direction = OrderBy::ASC, $table = null)
{
$newColumn = array($column);
$column = SyntaxFactory::createColumn($newColumn, \is_null($table) ? $this->getTable() : $table);
$this->orderBy[] = new OrderBy($column, $direction);
return $this;
}
/**
* @return int
*/
public function getLimitCount()
{
return $this->limitCount;
}
/**
* @return int
*/
public function getLimitStart()
{
return $this->limitStart;
}
/**
* @param string $comment
*
* @return $this
*/
public function setComment($comment)
{
// Make each line of the comment prefixed with "--",
// and remove any trailing whitespace.
$comment = '-- '.str_replace("\n", "\n-- ", \rtrim($comment));
// Trim off any trailing "-- ", to ensure that the comment is valid.
$this->comment = \rtrim($comment, '- ');
if ($this->comment) {
$this->comment .= "\n";
}
return $this;
}
/**
* @return string
*/
public function getComment()
{
return $this->comment;
}
}

View File

@ -0,0 +1,57 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 12/24/14
* Time: 12:30 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Manipulation;
/**
* Class AbstractCreationalQuery.
*/
abstract class AbstractCreationalQuery extends AbstractBaseQuery
{
/**
* @var array
*/
protected $values = [];
/**
* @param string $table
* @param array $values
*/
public function __construct($table = null, array $values = null)
{
if (isset($table)) {
$this->setTable($table);
}
if (!empty($values)) {
$this->setValues($values);
}
}
/**
* @return array
*/
public function getValues()
{
return $this->values;
}
/**
* @param array $values
*
* @return $this
*/
public function setValues(array $values)
{
$this->values = $values;
return $this;
}
}

View File

@ -0,0 +1,80 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 12/24/14
* Time: 12:30 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Manipulation;
use NilPortugues\Sql\QueryBuilder\Syntax\QueryPartInterface;
/**
* Class AbstractSetQuery.
*/
abstract class AbstractSetQuery implements QueryInterface, QueryPartInterface
{
/**
* @var array
*/
protected $union = [];
/**
* @param Select $select
*
* @return $this
*/
public function add(Select $select)
{
$this->union[] = $select;
return $this;
}
/**
* @return array
*/
public function getUnions()
{
return $this->union;
}
/**
* @throws QueryException
*
* @return \NilPortugues\Sql\QueryBuilder\Syntax\Table
*/
public function getTable()
{
throw new QueryException(
\sprintf('%s does not support tables', $this->partName())
);
}
/**
* @throws QueryException
*
* @return \NilPortugues\Sql\QueryBuilder\Syntax\Where
*/
public function getWhere()
{
throw new QueryException(
\sprintf('%s does not support WHERE.', $this->partName())
);
}
/**
* @throws QueryException
*
* @return \NilPortugues\Sql\QueryBuilder\Syntax\Where
*/
public function where()
{
throw new QueryException(
\sprintf('%s does not support the WHERE statement.', $this->partName())
);
}
}

View File

@ -0,0 +1,263 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 12/25/14
* Time: 12:12 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Manipulation;
use NilPortugues\Sql\QueryBuilder\Syntax\Column;
use NilPortugues\Sql\QueryBuilder\Syntax\OrderBy;
use NilPortugues\Sql\QueryBuilder\Syntax\SyntaxFactory;
/**
* Class ColumnQuery.
*/
class ColumnQuery
{
/**
* @var array
*/
protected $columns = [];
/**
* @var array
*/
protected $columnSelects = [];
/**
* @var array
*/
protected $columnValues = [];
/**
* @var array
*/
protected $columnFuncs = [];
/**
* @var bool
*/
protected $isCount = false;
/**
* @var Select
*/
protected $select;
/**
* @var JoinQuery
*/
protected $joinQuery;
/**
* @param Select $select
* @param JoinQuery $joinQuery
* @param array $columns
*/
public function __construct(Select $select, JoinQuery $joinQuery, array $columns = null)
{
$this->select = $select;
$this->joinQuery = $joinQuery;
if (!isset($columns)) {
$columns = array(Column::ALL);
}
if (\count($columns)) {
$this->setColumns($columns);
}
}
/**
* @param $start
* @param int $count
*
* @return Select
*/
public function limit($start, $count = 0)
{
return $this->select->limit($start, $count);
}
/**
* @param string $whereOperator
*
* @return \NilPortugues\Sql\QueryBuilder\Syntax\Where
*/
public function where($whereOperator = 'AND')
{
return $this->select->where($whereOperator);
}
/**
* @param string $column
* @param string $direction
* @param null $table
*
* @return Select
*/
public function orderBy($column, $direction = OrderBy::ASC, $table = null)
{
return $this->select->orderBy($column, $direction, $table);
}
/**
* @param string[] $columns
*
* @return Select
*/
public function groupBy(array $columns)
{
return $this->select->groupBy($columns);
}
/**
* Allows setting a Select query as a column value.
*
* @param array $column
*
* @return $this
*/
public function setSelectAsColumn(array $column)
{
$this->columnSelects[] = $column;
return $this;
}
/**
* @return array
*/
public function getColumnSelects()
{
return $this->columnSelects;
}
/**
* Allows setting a value to the select statement.
*
* @param string $value
* @param string $alias
*
* @return $this
*/
public function setValueAsColumn($value, $alias)
{
$this->columnValues[$alias] = $value;
return $this;
}
/**
* @return array
*/
public function getColumnValues()
{
return $this->columnValues;
}
/**
* Allows calculation on columns using predefined SQL functions.
*
* @param string $funcName
* @param string[] $arguments
* @param string $alias
*
* @return $this
*/
public function setFunctionAsColumn($funcName, array $arguments, $alias)
{
$this->columnFuncs[$alias] = ['func' => $funcName, 'args' => $arguments];
return $this;
}
/**
* @return array
*/
public function getColumnFuncs()
{
return $this->columnFuncs;
}
/**
* @param string $columnName
* @param string $alias
*
* @return $this
*/
public function count($columnName = '*', $alias = '')
{
$table = $this->select->getTable();
$count = 'COUNT(';
$count .= ($columnName !== '*') ? "$table.{$columnName}" : '*';
$count .= ')';
if (isset($alias) && \strlen($alias) > 0) {
$count .= ' AS "'.$alias.'"';
}
$this->columns = array($count);
$this->isCount = true;
return $this;
}
/**
* @return bool
*/
public function isCount()
{
return $this->isCount;
}
/**
* @return array
*/
public function getAllColumns()
{
$columns = $this->getColumns();
foreach ($this->joinQuery->getJoins() as $join) {
$joinCols = $join->getAllColumns();
$columns = \array_merge($columns, $joinCols);
}
return $columns;
}
/**
* @return \NilPortugues\Sql\QueryBuilder\Syntax\Column
*
* @throws QueryException
*/
public function getColumns()
{
if (\is_null($this->select->getTable())) {
throw new QueryException('No table specified for the Select instance');
}
return SyntaxFactory::createColumns($this->columns, $this->select->getTable());
}
/**
* Sets the column names used to write the SELECT statement.
* If key is set, key is the column's alias. Value is always the column names.
*
* @param array $columns
*
* @return $this
*/
public function setColumns(array $columns)
{
$this->columns = $columns;
return $this;
}
}

View File

@ -0,0 +1,60 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/3/14
* Time: 12:07 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Manipulation;
/**
* Class Delete.
*/
class Delete extends AbstractBaseQuery
{
/**
* @var int
*/
protected $limitStart;
/**
* @param string $table
*/
public function __construct($table = null)
{
if (isset($table)) {
$this->setTable($table);
}
}
/**
* @return string
*/
public function partName()
{
return 'DELETE';
}
/**
* @return int
*/
public function getLimitStart()
{
return $this->limitStart;
}
/**
* @param int $start
*
* @return $this
*/
public function limit($start)
{
$this->limitStart = $start;
return $this;
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/3/14
* Time: 12:07 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Manipulation;
use NilPortugues\Sql\QueryBuilder\Syntax\SyntaxFactory;
/**
* Class Insert.
*/
class Insert extends AbstractCreationalQuery
{
/**
* @return string
*/
public function partName()
{
return 'INSERT';
}
/**
* @return array
*/
public function getColumns()
{
$columns = \array_keys($this->values);
return SyntaxFactory::createColumns($columns, $this->getTable());
}
}

View File

@ -0,0 +1,84 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/12/14
* Time: 7:11 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Manipulation;
use NilPortugues\Sql\QueryBuilder\Syntax\QueryPartInterface;
/**
* Class Intersect.
*/
class Intersect implements QueryInterface, QueryPartInterface
{
const INTERSECT = 'INTERSECT';
/**
* @var array
*/
protected $intersect = [];
/**
* @return string
*/
public function partName()
{
return 'INTERSECT';
}
/**
* @param Select $select
*
* @return $this
*/
public function add(Select $select)
{
$this->intersect[] = $select;
return $this;
}
/**
* @return array
*/
public function getIntersects()
{
return $this->intersect;
}
/**
* @throws QueryException
*
* @return \NilPortugues\Sql\QueryBuilder\Syntax\Table
*/
public function getTable()
{
throw new QueryException('INTERSECT does not support tables');
}
/**
* @throws QueryException
*
* @return \NilPortugues\Sql\QueryBuilder\Syntax\Where
*/
public function getWhere()
{
throw new QueryException('INTERSECT does not support WHERE.');
}
/**
* @throws QueryException
*
* @return \NilPortugues\Sql\QueryBuilder\Syntax\Where
*/
public function where()
{
throw new QueryException('INTERSECT does not support the WHERE statement.');
}
}

View File

@ -0,0 +1,308 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 12/25/14
* Time: 11:41 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Manipulation;
use NilPortugues\Sql\QueryBuilder\Syntax\Where;
use NilPortugues\Sql\QueryBuilder\Syntax\Column;
use NilPortugues\Sql\QueryBuilder\Syntax\SyntaxFactory;
/**
* Class JoinQuery.
*/
class JoinQuery
{
const JOIN_LEFT = 'LEFT';
const JOIN_RIGHT = 'RIGHT';
const JOIN_INNER = 'INNER';
const JOIN_CROSS = 'CROSS';
/**
* @var Where
*/
protected $joinCondition;
/**
* @var bool
*/
protected $isJoin = false;
/**
* @var string
*/
protected $joinType;
/**
* @var array
*/
protected $joins = [];
/**
* @var Select
*/
protected $select;
/**
* @param Select $select
*/
public function __construct(Select $select)
{
$this->select = $select;
}
/**
* @param string $table
*
* @return $this
*/
public function setTable($table)
{
$this->select->setTable($table);
return $this;
}
/**
* @param string $table
* @param mixed $selfColumn
* @param mixed $refColumn
* @param string[] $columns
*
* @return Select
*/
public function leftJoin($table, $selfColumn = null, $refColumn = null, $columns = [])
{
return $this->join($table, $selfColumn, $refColumn, $columns, self::JOIN_LEFT);
}
/**
* @param string $table
* @param mixed $selfColumn
* @param mixed $refColumn
* @param string[] $columns
* @param string $joinType
*
* @return Select
*/
public function join(
$table,
$selfColumn = null,
$refColumn = null,
$columns = [],
$joinType = null
) {
if (!isset($this->joins[$table])) {
$select = QueryFactory::createSelect($table);
$select->setColumns($columns);
$select->setJoinType($joinType);
$select->setParentQuery($this->select);
$this->addJoin($select, $selfColumn, $refColumn);
}
return $this->joins[$table];
}
/**
* @param Select $select
* @param mixed $selfColumn
* @param mixed $refColumn
*
* @return Select
*/
public function addJoin(Select $select, $selfColumn, $refColumn)
{
$select->isJoin(true);
$table = $select->getTable()->getName();
if (!isset($this->joins[$table])) {
if (!$selfColumn instanceof Column) {
$newColumn = array($selfColumn);
$selfColumn = SyntaxFactory::createColumn(
$newColumn,
$this->select->getTable()
);
}
$select->joinCondition()->equals($refColumn, $selfColumn);
$this->joins[$table] = $select;
}
return $this->joins[$table];
}
/**
* Transforms Select in a joint.
*
* @param bool $isJoin
*
* @return $this
*/
public function setJoin($isJoin = true)
{
$this->isJoin = $isJoin;
return $this;
}
/**
* @param string $table
* @param mixed $selfColumn
* @param mixed $refColumn
* @param string[] $columns
*
* @internal param null $selectClass
*
* @return Select
*/
public function rightJoin($table, $selfColumn = null, $refColumn = null, $columns = [])
{
return $this->join($table, $selfColumn, $refColumn, $columns, self::JOIN_RIGHT);
}
/**
* @param string $table
* @param mixed $selfColumn
* @param mixed $refColumn
* @param string[] $columns
*
* @return Select
*/
public function crossJoin($table, $selfColumn = null, $refColumn = null, $columns = [])
{
return $this->join($table, $selfColumn, $refColumn, $columns, self::JOIN_CROSS);
}
/**
* @param string $table
* @param mixed $selfColumn
* @param mixed $refColumn
* @param string[] $columns
*
* @return Select
*/
public function innerJoin($table, $selfColumn = null, $refColumn = null, $columns = [])
{
return $this->join($table, $selfColumn, $refColumn, $columns, self::JOIN_INNER);
}
/**
* Alias to joinCondition.
*
* @return Where
*/
public function on()
{
return $this->joinCondition();
}
/**
* WHERE constrains used for the ON clause of a (LEFT/RIGHT/INNER/CROSS) JOIN.
*
* @return Where
*/
public function joinCondition()
{
if (!isset($this->joinCondition)) {
$this->joinCondition = QueryFactory::createWhere($this->select);
}
return $this->joinCondition;
}
/**
* @return bool
*/
public function isJoinSelect()
{
return $this->isJoin;
}
/**
* @return bool
*/
public function isJoin()
{
return $this->isJoin;
}
/**
* @return \NilPortugues\Sql\QueryBuilder\Syntax\Where
*/
public function getJoinCondition()
{
return $this->joinCondition;
}
/**
* @param \NilPortugues\Sql\QueryBuilder\Syntax\Where $joinCondition
*
* @return $this
*/
public function setJoinCondition($joinCondition)
{
$this->joinCondition = $joinCondition;
return $this;
}
/**
* @return string
*/
public function getJoinType()
{
return $this->joinType;
}
/**
* @param string $joinType
*
* @return $this
*/
public function setJoinType($joinType)
{
$this->joinType = $joinType;
return $this;
}
/**
* @return array
*/
public function getJoins()
{
return $this->joins;
}
/**
* @param array $joins
*
* @return $this
*/
public function setJoins($joins)
{
$this->joins = $joins;
return $this;
}
/**
* @return array
*/
public function getAllJoins()
{
$joins = $this->joins;
foreach ($this->joins as $join) {
$joins = \array_merge($joins, $join->getAllJoins());
}
return $joins;
}
}

View File

@ -0,0 +1,95 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/12/14
* Time: 7:11 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Manipulation;
use NilPortugues\Sql\QueryBuilder\Syntax\QueryPartInterface;
/**
* Class Minus.
*/
class Minus implements QueryInterface, QueryPartInterface
{
const MINUS = 'MINUS';
/**
* @var Select
*/
protected $first;
/**
* @var Select
*/
protected $second;
/**
* @return string
*/
public function partName()
{
return 'MINUS';
}
/***
* @param Select $first
* @param Select $second
*/
public function __construct(Select $first, Select $second)
{
$this->first = $first;
$this->second = $second;
}
/**
* @return \NilPortugues\Sql\QueryBuilder\Manipulation\Select
*/
public function getFirst()
{
return $this->first;
}
/**
* @return \NilPortugues\Sql\QueryBuilder\Manipulation\Select
*/
public function getSecond()
{
return $this->second;
}
/**
* @throws QueryException
*
* @return \NilPortugues\Sql\QueryBuilder\Syntax\Table
*/
public function getTable()
{
throw new QueryException('MINUS does not support tables');
}
/**
* @throws QueryException
*
* @return \NilPortugues\Sql\QueryBuilder\Syntax\Where
*/
public function getWhere()
{
throw new QueryException('MINUS does not support WHERE.');
}
/**
* @throws QueryException
*
* @return \NilPortugues\Sql\QueryBuilder\Syntax\Where
*/
public function where()
{
throw new QueryException('MINUS does not support the WHERE statement.');
}
}

View File

@ -0,0 +1,18 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/3/14
* Time: 12:07 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Manipulation;
/**
* Class QueryException.
*/
final class QueryException extends \Exception
{
}

View File

@ -0,0 +1,107 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/3/14
* Time: 12:07 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Manipulation;
use NilPortugues\Sql\QueryBuilder\Syntax\Where;
/**
* Class QueryFactory.
*/
final class QueryFactory
{
/**
* @param string $table
* @param array $columns
*
* @return Select
*/
public static function createSelect($table = null, array $columns = null)
{
return new Select($table, $columns);
}
/**
* @param string $table
* @param array $values
*
* @return Insert
*/
public static function createInsert($table = null, array $values = null)
{
return new Insert($table, $values);
}
/**
* @param string $table
* @param array $values
*
* @return Update
*/
public static function createUpdate($table = null, array $values = null)
{
return new Update($table, $values);
}
/**
* @param string $table
*
* @return Delete
*/
public static function createDelete($table = null)
{
return new Delete($table);
}
/**
* @param QueryInterface $query
*
* @return Where
*/
public static function createWhere(QueryInterface $query)
{
return new Where($query);
}
/**
* @return Intersect
*/
public static function createIntersect()
{
return new Intersect();
}
/**
* @param Select $first
* @param Select $second
*
* @return Minus
*/
public static function createMinus(Select $first, Select $second)
{
return new Minus($first, $second);
}
/**
* @return Union
*/
public static function createUnion()
{
return new Union();
}
/**
* @return UnionAll
*/
public static function createUnionAll()
{
return new UnionAll();
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/3/14
* Time: 12:07 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Manipulation;
/**
* Interface QueryInterface.
*/
interface QueryInterface
{
/**
* @return string
*/
public function partName();
/**
* @return \NilPortugues\Sql\QueryBuilder\Syntax\Table
*/
public function getTable();
/**
* @return \NilPortugues\Sql\QueryBuilder\Syntax\Where
*/
public function getWhere();
/**
* @return \NilPortugues\Sql\QueryBuilder\Syntax\Where
*/
public function where();
}

View File

@ -0,0 +1,546 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/3/14
* Time: 12:07 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Manipulation;
use NilPortugues\Sql\QueryBuilder\Syntax\SyntaxFactory;
use NilPortugues\Sql\QueryBuilder\Syntax\Table;
use NilPortugues\Sql\QueryBuilder\Syntax\Where;
use NilPortugues\Sql\QueryBuilder\Syntax\OrderBy;
/**
* Class Select.
*/
class Select extends AbstractBaseQuery
{
/**
* @var Table
*/
protected $table;
/**
* @var array
*/
protected $groupBy = [];
/**
* @var string
*/
protected $camelCaseTableName = '';
/**
* @var Where
*/
protected $having;
/**
* @var string
*/
protected $havingOperator = 'AND';
/**
* @var bool
*/
protected $isDistinct = false;
/**
* @var Where
*/
protected $where;
/**
* @var JoinQuery
*/
protected $joinQuery;
/**
* @var ColumnQuery
*/
protected $columnQuery;
/**
* @var ParentQuery
*/
protected $parentQuery;
/**
* @param string $table
* @param array $columns
*/
public function __construct($table = null, array $columns = null)
{
if (isset($table)) {
$this->setTable($table);
}
$this->joinQuery = new JoinQuery($this);
$this->columnQuery = new ColumnQuery($this, $this->joinQuery, $columns);
}
/**
* This __clone method will create an exact clone but without the object references due to the fact these
* are lost in the process of serialization and un-serialization.
*
* @return Select
*/
public function __clone()
{
return \unserialize(\serialize($this));
}
/**
* @return string
*/
public function partName()
{
return 'SELECT';
}
/**
* @param string $table
* @param string $selfColumn
* @param string $refColumn
* @param string[] $columns
*
* @return Select
*/
public function leftJoin($table, $selfColumn = null, $refColumn = null, $columns = [])
{
return $this->joinQuery->leftJoin($table, $selfColumn, $refColumn, $columns);
}
/**
* @param string $table
* @param string $selfColumn
* @param string $refColumn
* @param string[] $columns
* @param string $joinType
*
* @return Select
*/
public function join(
$table,
$selfColumn = null,
$refColumn = null,
$columns = [],
$joinType = null
) {
return $this->joinQuery->join($table, $selfColumn, $refColumn, $columns, $joinType);
}
/**
* WHERE constrains used for the ON clause of a (LEFT/RIGHT/INNER/CROSS) JOIN.
*
* @return Where
*/
public function joinCondition()
{
return $this->joinQuery->joinCondition();
}
/**
* @param Select $select
* @param string $selfColumn
* @param string $refColumn
*
* @return Select
*/
public function addJoin(Select $select, $selfColumn, $refColumn)
{
return $this->joinQuery->addJoin($select, $selfColumn, $refColumn);
}
/**
* Transforms Select in a joint.
*
* @param bool $isJoin
*
* @return JoinQuery
*/
public function isJoin($isJoin = true)
{
return $this->joinQuery->setJoin($isJoin);
}
/**
* @param string $table
* @param string $selfColumn
* @param string $refColumn
* @param string[] $columns
*
* @internal param null $selectClass
*
* @return Select
*/
public function rightJoin($table, $selfColumn = null, $refColumn = null, $columns = [])
{
return $this->joinQuery->rightJoin($table, $selfColumn, $refColumn, $columns);
}
/**
* @param string $table
* @param string $selfColumn
* @param string $refColumn
* @param string[] $columns
*
* @return Select
*/
public function crossJoin($table, $selfColumn = null, $refColumn = null, $columns = [])
{
return $this->joinQuery->crossJoin($table, $selfColumn, $refColumn, $columns);
}
/**
* @param string $table
* @param string $selfColumn
* @param string $refColumn
* @param string[] $columns
*
* @return Select
*/
public function innerJoin($table, $selfColumn = null, $refColumn = null, $columns = [])
{
return $this->joinQuery->innerJoin($table, $selfColumn, $refColumn, $columns);
}
/**
* Alias to joinCondition.
*
* @return Where
*/
public function on()
{
return $this->joinQuery->joinCondition();
}
/**
* @return bool
*/
public function isJoinSelect()
{
return $this->joinQuery->isJoin();
}
/**
* @return array
*/
public function getAllColumns()
{
return $this->columnQuery->getAllColumns();
}
/**
* @return \NilPortugues\Sql\QueryBuilder\Syntax\Column
*
* @throws QueryException
*/
public function getColumns()
{
return $this->columnQuery->getColumns();
}
/**
* Sets the column names used to write the SELECT statement.
* If key is set, key is the column's alias. Value is always the column names.
*
* @param string[] $columns
*
* @return ColumnQuery
*/
public function setColumns(array $columns)
{
return $this->columnQuery->setColumns($columns);
}
/**
* Allows setting a Select query as a column value.
*
* @param array $column
*
* @return ColumnQuery
*/
public function setSelectAsColumn(array $column)
{
return $this->columnQuery->setSelectAsColumn($column);
}
/**
* @return array
*/
public function getColumnSelects()
{
return $this->columnQuery->getColumnSelects();
}
/**
* Allows setting a value to the select statement.
*
* @param string $value
* @param string $alias
*
* @return ColumnQuery
*/
public function setValueAsColumn($value, $alias)
{
return $this->columnQuery->setValueAsColumn($value, $alias);
}
/**
* @return array
*/
public function getColumnValues()
{
return $this->columnQuery->getColumnValues();
}
/**
* Allows calculation on columns using predefined SQL functions.
*
* @param string $funcName
* @param string[] $arguments
* @param string $alias
*
* @return ColumnQuery
*/
public function setFunctionAsColumn($funcName, array $arguments, $alias)
{
return $this->columnQuery->setFunctionAsColumn($funcName, $arguments, $alias);
}
/**
* @return array
*/
public function getColumnFuncs()
{
return $this->columnQuery->getColumnFuncs();
}
/**
* Returns all the Where conditions to the BuilderInterface class in order to write the SQL WHERE statement.
*
* @return array
*/
public function getAllWheres()
{
return $this->getAllOperation($this->where, 'getAllWheres');
}
/**
* @param null|Where $data
* @param string $operation
*
* @return array
*/
protected function getAllOperation($data, $operation)
{
$collection = [];
if (!is_null($data)) {
$collection[] = $data;
}
foreach ($this->joinQuery->getJoins() as $join) {
$collection = \array_merge($collection, $join->$operation());
}
return $collection;
}
/**
* @return array
*/
public function getAllHavings()
{
return $this->getAllOperation($this->having, 'getAllHavings');
}
/**
* @param string $columnName
* @param string $alias
*
* @return ColumnQuery
*/
public function count($columnName = '*', $alias = '')
{
return $this->columnQuery->count($columnName, $alias);
}
/**
* @return bool
*/
public function isCount()
{
return $this->columnQuery->isCount();
}
/**
* @param int $start
* @param $count
*
* @return $this
*/
public function limit($start, $count = 0)
{
$this->limitStart = $start;
$this->limitCount = $count;
return $this;
}
/**
* @return array
*/
public function getAllJoins()
{
return $this->joinQuery->getAllJoins();
}
/**
* @return array
*/
public function getGroupBy()
{
return SyntaxFactory::createColumns($this->groupBy, $this->getTable());
}
/**
* @param string[] $columns
*
* @return $this
*/
public function groupBy(array $columns)
{
$this->groupBy = $columns;
return $this;
}
/**
* @return Where
*/
public function getJoinCondition()
{
return $this->joinQuery->getJoinCondition();
}
/**
* @return string
*/
public function getJoinType()
{
return $this->joinQuery->getJoinType();
}
/**
* @param string|null $joinType
*
* @return $this
*/
public function setJoinType($joinType)
{
$this->joinQuery->setJoinType($joinType);
return $this;
}
/**
* @param $havingOperator
*
* @throws QueryException
*
* @return Where
*/
public function having($havingOperator = 'AND')
{
if (!isset($this->having)) {
$this->having = QueryFactory::createWhere($this);
}
if (!in_array($havingOperator, array(Where::CONJUNCTION_AND, Where::CONJUNCTION_OR))) {
throw new QueryException(
"Invalid conjunction specified, must be one of AND or OR, but '".$havingOperator."' was found."
);
}
$this->havingOperator = $havingOperator;
return $this->having;
}
/**
* @return string
*/
public function getHavingOperator()
{
return $this->havingOperator;
}
/**
* @return $this
*/
public function distinct()
{
$this->isDistinct = true;
return $this;
}
/**
* @return bool
*/
public function isDistinct()
{
return $this->isDistinct;
}
/**
* @return array
*/
public function getAllOrderBy()
{
return $this->orderBy;
}
/**
* @return ParentQuery
*/
public function getParentQuery()
{
return $this->parentQuery;
}
/**
* @param Select $parentQuery
*
* @return $this
*/
public function setParentQuery(Select $parentQuery)
{
$this->parentQuery = $parentQuery;
return $this;
}
/**
* @param string $column
* @param string $direction
* @param null $table
*
* @return $this
*/
public function orderBy($column, $direction = OrderBy::ASC, $table = null)
{
$current = parent::orderBy($column, $direction, $table);
if ($this->getParentQuery() != null) {
$this->getParentQuery()->orderBy($column, $direction, \is_null($table) ? $this->getTable() : $table);
}
return $current;
}
}

View File

@ -0,0 +1,27 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/12/14
* Time: 7:11 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Manipulation;
/**
* Class Union.
*/
class Union extends AbstractSetQuery
{
const UNION = 'UNION';
/**
* @return string
*/
public function partName()
{
return 'UNION';
}
}

View File

@ -0,0 +1,27 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/12/14
* Time: 7:11 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Manipulation;
/**
* Class UnionAll.
*/
class UnionAll extends AbstractSetQuery
{
const UNION_ALL = 'UNION ALL';
/**
* @return string
*/
public function partName()
{
return 'UNION ALL';
}
}

View File

@ -0,0 +1,55 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/3/14
* Time: 12:07 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Manipulation;
/**
* Class Update.
*/
class Update extends AbstractCreationalQuery
{
/**
* @var int
*/
protected $limitStart;
/**
* @var array
*/
protected $orderBy = [];
/**
* @return string
*/
public function partName()
{
return 'UPDATE';
}
/**
* @return int
*/
public function getLimitStart()
{
return $this->limitStart;
}
/**
* @param int $start
*
* @return $this
*/
public function limit($start)
{
$this->limitStart = $start;
return $this;
}
}

View File

@ -0,0 +1,139 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/3/14
* Time: 12:07 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Syntax;
use NilPortugues\Sql\QueryBuilder\Manipulation\QueryException;
/**
* Class Column.
*/
class Column implements QueryPartInterface
{
const ALL = '*';
/**
* @var Table
*/
protected $table;
/**
* @var string
*/
protected $name;
/**
* @var string
*/
protected $alias;
/**
* @param string $name
* @param string $table
* @param string $alias
*/
public function __construct($name, $table, $alias = '')
{
$this->setName($name);
$this->setTable($table);
$this->setAlias($alias);
}
/**
* @return string
*/
public function partName()
{
return 'COLUMN';
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @param string $name
*
* @return $this
*/
public function setName($name)
{
$this->name = (string) $name;
return $this;
}
/**
* @return Table
*/
public function getTable()
{
return $this->table;
}
/**
* @param string $table
*
* @return $this
*/
public function setTable($table)
{
$newTable = array($table);
$this->table = SyntaxFactory::createTable($newTable);
return $this;
}
/**
* @return string
*/
public function getAlias()
{
return $this->alias;
}
/**
* @param null|string $alias
*
* @return $this
*
* @throws QueryException
*/
public function setAlias($alias)
{
if (0 == \strlen($alias)) {
$this->alias = null;
return $this;
}
if ($this->isAll()) {
throw new QueryException("Can't use alias because column name is ALL (*)");
}
$this->alias = (string) $alias;
return $this;
}
/**
* Check whether column name is '*' or not.
*
* @return bool
*/
public function isAll()
{
return $this->getName() == self::ALL;
}
}

View File

@ -0,0 +1,92 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/3/14
* Time: 12:07 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Syntax;
/**
* Class OrderBy.
*/
class OrderBy
{
const ASC = 'ASC';
const DESC = 'DESC';
/**
* @var Column
*/
protected $column;
/**
* @var string
*/
protected $direction;
/**
* @var bool
*/
protected $useAlias;
/**
* @param Column $column
* @param string $direction
*/
public function __construct(Column $column, $direction)
{
$this->setColumn($column);
$this->setDirection($direction);
}
/**
* @return Column
*/
public function getColumn()
{
return $this->column;
}
/**
* @param Column $column
*
* @return $this
*/
public function setColumn($column)
{
$this->column = $column;
return $this;
}
/**
* @return string
*/
public function getDirection()
{
return $this->direction;
}
/**
* @param string $direction
*
* @throws \InvalidArgumentException
*
* @return $this
*/
public function setDirection($direction)
{
if (!in_array($direction, array(self::ASC, self::DESC))) {
throw new \InvalidArgumentException(
"Specified direction '$direction' is not allowed. Only ASC or DESC are allowed."
);
}
$this->direction = $direction;
return $this;
}
}

View File

@ -0,0 +1,22 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/8/14
* Time: 5:32 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Syntax;
/**
* Interface QueryPartInterface.
*/
interface QueryPartInterface
{
/**
* @return string
*/
public function partName();
}

View File

@ -0,0 +1,93 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/3/14
* Time: 12:07 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Syntax;
/**
* Class SyntaxFactory.
*/
final class SyntaxFactory
{
/**
* Creates a collection of Column objects.
*
* @param array $arguments
* @param Table|null $table
*
* @return array
*/
public static function createColumns(array &$arguments, $table = null)
{
$createdColumns = [];
foreach ($arguments as $index => $column) {
if (!is_object($column)) {
$newColumn = array($column);
$column = self::createColumn($newColumn, $table);
if (!is_numeric($index)) {
$column->setAlias($index);
}
$createdColumns[] = $column;
} else if ($column instanceof Column) {
$createdColumns[] = $column;
}
}
return \array_filter($createdColumns);
}
/**
* Creates a Column object.
*
* @param array $argument
* @param null|Table $table
*
* @return Column
*/
public static function createColumn(array &$argument, $table = null)
{
$columnName = \array_values($argument);
$columnName = $columnName[0];
$columnAlias = \array_keys($argument);
$columnAlias = $columnAlias[0];
if (\is_numeric($columnAlias) || \strpos($columnName, '*') !== false) {
$columnAlias = null;
}
return new Column($columnName, (string) $table, $columnAlias);
}
/**
* Creates a Table object.
*
* @param string[] $table
*
* @return Table
*/
public static function createTable($table)
{
$tableName = $table;
if (\is_array($table)) {
$tableName = \current($table);
$tableAlias = \key($table);
}
$newTable = new Table($tableName);
if (isset($tableAlias) && !is_numeric($tableAlias)) {
$newTable->setAlias($tableAlias);
}
return $newTable;
}
}

View File

@ -0,0 +1,138 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/3/14
* Time: 12:07 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Syntax;
/**
* Class Table.
*/
class Table
{
/**
* @var string
*/
protected $name;
/**
* @var string
*/
protected $alias;
/**
* @var string
*/
protected $schema;
/**
* @var bool
*/
protected $view = false;
/**
* @param $name
* @param string $schema
*/
public function __construct($name, $schema = null)
{
$this->name = $name;
if (!is_null($schema)) {
$this->schema = $schema;
}
}
/**
* @return string
*/
public function __toString()
{
return (string) $this->name;
}
/**
* @param bool $view
*
* @return $this
*/
public function setView($view)
{
$this->view = $view;
return $this;
}
/**
* @return bool
*/
public function isView()
{
return $this->view;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @return string
*/
public function getAlias()
{
return $this->alias;
}
/**
* @return string
*/
public function getCompleteName()
{
$alias = ($this->alias) ? " AS {$this->alias}" : '';
$schema = ($this->schema) ? "{$this->schema}." : '';
return $schema.$this->name.$alias;
}
/**
* @param string $alias
*
* @return $this
*/
public function setAlias($alias)
{
$this->alias = $alias;
return $this;
}
/**
* @return string
*/
public function getSchema()
{
return $this->schema;
}
/**
* @param string
* @param string $schema
*
* @return $this
*/
public function setSchema($schema)
{
$this->schema = $schema;
return $this;
}
}

View File

@ -0,0 +1,646 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/3/14
* Time: 12:07 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Sql\QueryBuilder\Syntax;
use NilPortugues\Sql\QueryBuilder\Manipulation\QueryException;
use NilPortugues\Sql\QueryBuilder\Manipulation\QueryFactory;
use NilPortugues\Sql\QueryBuilder\Manipulation\QueryInterface;
use NilPortugues\Sql\QueryBuilder\Manipulation\Select;
/**
* Class Where.
*/
class Where
{
const OPERATOR_GREATER_THAN_OR_EQUAL = '>=';
const OPERATOR_GREATER_THAN = '>';
const OPERATOR_LESS_THAN_OR_EQUAL = '<=';
const OPERATOR_LESS_THAN = '<';
const OPERATOR_LIKE = 'LIKE';
const OPERATOR_NOT_LIKE = 'NOT LIKE';
const OPERATOR_EQUAL = '=';
const OPERATOR_NOT_EQUAL = '<>';
const CONJUNCTION_AND = 'AND';
const CONJUNCTION_AND_NOT = 'AND NOT';
const CONJUNCTION_OR = 'OR';
const CONJUNCTION_OR_NOT = 'OR NOT';
const CONJUNCTION_EXISTS = 'EXISTS';
const CONJUNCTION_NOT_EXISTS = 'NOT EXISTS';
/**
* @var array
*/
protected $comparisons = [];
/**
* @var array
*/
protected $betweens = [];
/**
* @var array
*/
protected $isNull = [];
/**
* @var array
*/
protected $isNotNull = [];
/**
* @var array
*/
protected $booleans = [];
/**
* @var array
*/
protected $match = [];
/**
* @var array
*/
protected $ins = [];
/**
* @var array
*/
protected $notIns = [];
/**
* @var array
*/
protected $subWheres = [];
/**
* @var string
*/
protected $conjunction = self::CONJUNCTION_AND;
/**
* @var QueryInterface
*/
protected $query;
/**
* @var Table
*/
protected $table;
/**
* @var array
*/
protected $exists = [];
/**
* @var array
*/
protected $notExists = [];
/**
* @var array
*/
protected $notBetweens = [];
/**
* @param QueryInterface $query
*/
public function __construct(QueryInterface $query)
{
$this->query = $query;
}
/**
* Deep copy for nested references.
*
* @return mixed
*/
public function __clone()
{
return \unserialize(\serialize($this));
}
/**
* @return bool
*/
public function isEmpty()
{
$empty = \array_merge(
$this->comparisons,
$this->booleans,
$this->betweens,
$this->isNotNull,
$this->isNull,
$this->ins,
$this->notIns,
$this->subWheres,
$this->exists
);
return 0 == \count($empty);
}
/**
* @return string
*/
public function getConjunction()
{
return $this->conjunction;
}
/**
* @param string $operator
*
* @return $this
*
* @throws QueryException
*/
public function conjunction($operator)
{
if (false === \in_array(
$operator,
[self::CONJUNCTION_AND, self::CONJUNCTION_OR, self::CONJUNCTION_OR_NOT, self::CONJUNCTION_AND_NOT]
)
) {
throw new QueryException(
"Invalid conjunction specified, must be one of AND or OR, but '".$operator."' was found."
);
}
$this->conjunction = $operator;
return $this;
}
/**
* @return array
*/
public function getSubWheres()
{
return $this->subWheres;
}
/**
* @param $operator
*
* @return Where
*/
public function subWhere($operator = 'OR')
{
/** @var Where $filter */
$filter = QueryFactory::createWhere($this->query);
$filter->conjunction($operator);
$filter->setTable($this->getTable());
$this->subWheres[] = $filter;
return $filter;
}
/**
* @return Table
*/
public function getTable()
{
return $this->query->getTable();
}
/**
* Used for subWhere query building.
*
* @param Table $table string
*
* @return $this
*/
public function setTable($table)
{
$this->table = $table;
return $this;
}
/**
* equals alias.
*
* @param $column
* @param int $value
*
* @return static
*/
public function eq($column, $value)
{
return $this->equals($column, $value);
}
/**
* @param $column
* @param $value
*
* @return static
*/
public function equals($column, $value)
{
return $this->compare($column, $value, self::OPERATOR_EQUAL);
}
/**
* @param $column
* @param $value
* @param string $operator
*
* @return $this
*/
protected function compare($column, $value, $operator)
{
$column = $this->prepareColumn($column);
$this->comparisons[] = [
'subject' => $column,
'conjunction' => $operator,
'target' => $value,
];
return $this;
}
/**
* @param $column
*
* @return Column|Select
*/
protected function prepareColumn($column)
{
//This condition handles the "Select as a a column" special case.
//or when compare column is customized.
if ($column instanceof Select || $column instanceof Column) {
return $column;
}
$newColumn = [$column];
return SyntaxFactory::createColumn($newColumn, $this->getTable());
}
/**
* @param string $column
* @param int $value
*
* @return static
*/
public function notEquals($column, $value)
{
return $this->compare($column, $value, self::OPERATOR_NOT_EQUAL);
}
/**
* @param string $column
* @param int $value
*
* @return static
*/
public function greaterThan($column, $value)
{
return $this->compare($column, $value, self::OPERATOR_GREATER_THAN);
}
/**
* @param string $column
* @param int $value
*
* @return static
*/
public function greaterThanOrEqual($column, $value)
{
return $this->compare($column, $value, self::OPERATOR_GREATER_THAN_OR_EQUAL);
}
/**
* @param string $column
* @param int $value
*
* @return static
*/
public function lessThan($column, $value)
{
return $this->compare($column, $value, self::OPERATOR_LESS_THAN);
}
/**
* @param string $column
* @param int $value
*
* @return static
*/
public function lessThanOrEqual($column, $value)
{
return $this->compare($column, $value, self::OPERATOR_LESS_THAN_OR_EQUAL);
}
/**
* @param string $column
* @param $value
*
* @return static
*/
public function like($column, $value)
{
return $this->compare($column, $value, self::OPERATOR_LIKE);
}
/**
* @param string $column
* @param int $value
*
* @return static
*/
public function notLike($column, $value)
{
return $this->compare($column, $value, self::OPERATOR_NOT_LIKE);
}
/**
* @param string[] $columns
* @param mixed[] $values
*
* @return static
*/
public function match(array $columns, array $values)
{
return $this->genericMatch($columns, $values, 'natural');
}
/**
* @param string[] $columns
* @param mixed[] $values
* @param string $mode
*
* @return $this
*/
protected function genericMatch(array &$columns, array &$values, $mode)
{
$this->match[] = [
'columns' => $columns,
'values' => $values,
'mode' => $mode,
];
return $this;
}
/**
* @param string $literal
*
* @return $this
*/
public function asLiteral($literal)
{
$this->comparisons[] = $literal;
return $this;
}
/**
* @param string[] $columns
* @param mixed[] $values
*
* @return $this
*/
public function matchBoolean(array $columns, array $values)
{
return $this->genericMatch($columns, $values, 'boolean');
}
/**
* @param string[] $columns
* @param mixed[] $values
*
* @return $this
*/
public function matchWithQueryExpansion(array $columns, array $values)
{
return $this->genericMatch($columns, $values, 'query_expansion');
}
/**
* @param string $column
* @param int[] $values
*
* @return $this
*/
public function in($column, array $values)
{
$this->ins[$column] = $values;
return $this;
}
/**
* @param string $column
* @param int[] $values
*
* @return $this
*/
public function notIn($column, array $values)
{
$this->notIns[$column] = $values;
return $this;
}
/**
* @param string $column
* @param int $a
* @param int $b
*
* @return $this
*/
public function between($column, $a, $b)
{
$column = $this->prepareColumn($column);
$this->betweens[] = ['subject' => $column, 'a' => $a, 'b' => $b];
return $this;
}
/**
* @param string $column
* @param int $a
* @param int $b
*
* @return $this
*/
public function notBetween($column, $a, $b)
{
$column = $this->prepareColumn($column);
$this->notBetweens[] = ['subject' => $column, 'a' => $a, 'b' => $b];
return $this;
}
/**
* @param string $column
*
* @return static
*/
public function isNull($column)
{
$column = $this->prepareColumn($column);
$this->isNull[] = ['subject' => $column];
return $this;
}
/**
* @param string $column
*
* @return $this
*/
public function isNotNull($column)
{
$column = $this->prepareColumn($column);
$this->isNotNull[] = ['subject' => $column];
return $this;
}
/**
* @param string $column
* @param int $value
*
* @return $this
*/
public function addBitClause($column, $value)
{
$column = $this->prepareColumn($column);
$this->booleans[] = ['subject' => $column, 'value' => $value];
return $this;
}
/**
* @param Select $select
*
* @return $this
*/
public function exists(Select $select)
{
$this->exists[] = $select;
return $this;
}
/**
* @return array
*/
public function getExists()
{
return $this->exists;
}
/**
* @param Select $select
*
* @return $this
*/
public function notExists(Select $select)
{
$this->notExists[] = $select;
return $this;
}
/**
* @return array
*/
public function getNotExists()
{
return $this->notExists;
}
/**
* @return array
*/
public function getMatches()
{
return $this->match;
}
/**
* @return array
*/
public function getIns()
{
return $this->ins;
}
/**
* @return array
*/
public function getNotIns()
{
return $this->notIns;
}
/**
* @return array
*/
public function getBetweens()
{
return $this->betweens;
}
/**
* @return array
*/
public function getNotBetweens()
{
return $this->notBetweens;
}
/**
* @return array
*/
public function getBooleans()
{
return $this->booleans;
}
/**
* @return array
*/
public function getComparisons()
{
return $this->comparisons;
}
/**
* @return array
*/
public function getNotNull()
{
return $this->isNotNull;
}
/**
* @return array
*/
public function getNull()
{
return $this->isNull;
}
/**
* @return QueryInterface
*/
public function end()
{
return $this->query;
}
}

View File

@ -0,0 +1,284 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/16/14
* Time: 8:56 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Builder;
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
use NilPortugues\Sql\QueryBuilder\Manipulation\Select;
class GenericBuilderTest extends \PHPUnit_Framework_TestCase
{
/**
* @var GenericBuilder
*/
private $writer;
/**
*
*/
public function setUp()
{
$this->writer = new GenericBuilder();
}
/**
* @test
*/
public function itShouldCreateSelectObject()
{
$className = '\NilPortugues\Sql\QueryBuilder\Manipulation\Select';
$this->assertInstanceOf($className, $this->writer->select());
}
/**
* @test
*/
public function itShouldCreateInsertObject()
{
$className = '\NilPortugues\Sql\QueryBuilder\Manipulation\Insert';
$this->assertInstanceOf($className, $this->writer->insert());
}
/**
* @test
*/
public function itShouldCreateUpdateObject()
{
$className = '\NilPortugues\Sql\QueryBuilder\Manipulation\Update';
$this->assertInstanceOf($className, $this->writer->update());
}
/**
* @test
*/
public function itShouldCreateDeleteObject()
{
$className = '\NilPortugues\Sql\QueryBuilder\Manipulation\Delete';
$this->assertInstanceOf($className, $this->writer->delete());
}
/**
* @test
*/
public function itShouldCreateIntersectObject()
{
$className = '\NilPortugues\Sql\QueryBuilder\Manipulation\Intersect';
$this->assertInstanceOf($className, $this->writer->intersect());
}
/**
* @test
*/
public function itShouldCreateMinusObject()
{
$className = '\NilPortugues\Sql\QueryBuilder\Manipulation\Minus';
$this->assertInstanceOf($className, $this->writer->minus(new Select('table1'), new Select('table2')));
}
/**
* @test
*/
public function itShouldCreateUnionObject()
{
$className = '\NilPortugues\Sql\QueryBuilder\Manipulation\Union';
$this->assertInstanceOf($className, $this->writer->union());
}
/**
* @test
*/
public function itShouldCreateUnionAllObject()
{
$className = '\NilPortugues\Sql\QueryBuilder\Manipulation\UnionAll';
$this->assertInstanceOf($className, $this->writer->unionAll());
}
/**
* @test
*/
public function itCanAcceptATableNameForSelectInsertUpdateDeleteQueries()
{
$table = 'user';
$queries = [
'select' => $this->writer->select($table),
'insert' => $this->writer->insert($table),
'update' => $this->writer->update($table),
'delete' => $this->writer->delete($table),
];
foreach ($queries as $type => $query) {
$this->assertEquals($table, $query->getTable()->getName(), "Checking table in $type query");
}
}
/**
* @test
*/
public function itCanAcceptATableAndColumnsForSelect()
{
$table = 'user';
$columns = ['id', 'role'];
$expected = <<<QUERY
SELECT
user.id,
user.role
FROM
user
QUERY;
$select = $this->writer->select($table, $columns);
$this->assertSame($expected, $this->writer->writeFormatted($select));
}
/**
* @test
*/
public function itCanAcceptATableAndValuesForInsert()
{
$table = 'user';
$values = ['id' => 1, 'role' => 'admin'];
$expected = <<<QUERY
INSERT INTO user (user.id, user.role)
VALUES
(:v1, :v2)
QUERY;
$insert = $this->writer->insert($table, $values);
$this->assertSame($expected, $this->writer->writeFormatted($insert));
}
/**
* @test
*/
public function itCanAcceptATableAndValuesForUpdate()
{
$table = 'user';
$values = ['id' => 1, 'role' => 'super-admin'];
$expected = <<<QUERY
UPDATE
user
SET
user.id = :v1,
user.role = :v2
QUERY;
$update = $this->writer->update($table, $values);
$this->assertSame($expected, $this->writer->writeFormatted($update));
}
/**
* @test
*/
public function itShouldOutputHumanReadableQuery()
{
$selectRole = $this->writer->select();
$selectRole
->setTable('role')
->setColumns(array('role_name'))
->limit(1)
->where()
->equals('role_id', 3);
$select = $this->writer->select();
$select->setTable('user')
->setColumns(array('user_id', 'username'))
->setSelectAsColumn(array('user_role' => $selectRole))
->setSelectAsColumn(array($selectRole))
->where()
->equals('user_id', 4);
$expected = <<<QUERY
SELECT
user.user_id,
user.username,
(
SELECT
role.role_name
FROM
role
WHERE
(role.role_id = :v1)
LIMIT
:v2,
:v3
) AS "user_role",
(
SELECT
role.role_name
FROM
role
WHERE
(role.role_id = :v4)
LIMIT
:v5,
:v6
) AS "role"
FROM
user
WHERE
(user.user_id = :v7)
QUERY;
$this->assertSame($expected, $this->writer->writeFormatted($select));
}
/**
* @test
*/
public function it_should_inject_the_builder()
{
$query = $this->writer->select();
$this->assertSame($this->writer, $query->getBuilder());
}
/**
* @test
*/
public function itShouldWriteWhenGettingSql()
{
$query = $this->writer->select()
->setTable('user');
$expected = $this->writer->write($query);
$this->assertSame($expected, $query->getSql());
}
/**
* @test
*/
public function itShouldWriteFormattedWhenGettingFormattedSql()
{
$query = $this->writer->select()
->setTable('user');
$formatted = true;
$expected = $this->writer->writeFormatted($query);
$this->assertSame($expected, $query->getSql($formatted));
}
/**
* @test
*/
public function itShouldWriteSqlWhenCastToString()
{
$query = $this->writer->select()
->setTable('user');
$expected = $this->writer->write($query);
$this->assertSame($expected, (string) $query);
}
}

View File

@ -0,0 +1,74 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/4/14
* Time: 12:40 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Builder;
use NilPortugues\Sql\QueryBuilder\Builder\MySqlBuilder;
use NilPortugues\Sql\QueryBuilder\Manipulation\Select;
/**
* Class MySqlBuilderTest.
*/
class MySqlBuilderTest extends \PHPUnit_Framework_TestCase
{
/**
* @var MySqlBuilder
*/
protected $writer;
/**
*
*/
protected function setUp()
{
$this->writer = new MySqlBuilder();
}
/**
*
*/
protected function tearDown()
{
$this->writer = null;
}
/**
* @test
*/
public function itShouldWrapTableNames()
{
$query = new Select('user');
$expected = 'SELECT `user`.* FROM `user`';
$this->assertSame($expected, $this->writer->write($query));
}
/**
* @test
*/
public function itShouldWrapColumnNames()
{
$query = new Select('user', array('user_id', 'name'));
$expected = 'SELECT `user`.`user_id`, `user`.`name` FROM `user`';
$this->assertSame($expected, $this->writer->write($query));
}
/**
* @test
*/
public function itShouldWrapColumnAlias()
{
$query = new Select('user', array('userId' => 'user_id', 'name' => 'name'));
$expected = 'SELECT `user`.`user_id` AS `userId`, `user`.`name` AS `name` FROM `user`';
$this->assertSame($expected, $this->writer->write($query));
}
}

View File

@ -0,0 +1,187 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/12/14
* Time: 10:45 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
use NilPortugues\Sql\QueryBuilder\Builder\Syntax\ColumnWriter;
use NilPortugues\Sql\QueryBuilder\Builder\Syntax\PlaceholderWriter;
use NilPortugues\Sql\QueryBuilder\Manipulation\Select;
use NilPortugues\Sql\QueryBuilder\Syntax\Column;
/**
* Class ColumnWriterTest.
*/
class ColumnWriterTest extends \PHPUnit_Framework_TestCase
{
/**
* @var ColumnWriter
*/
private $columnWriter;
/**
* @var GenericBuilder
*/
private $writer;
/**
* @var Select
*/
private $query;
/**
*
*/
protected function setUp()
{
$this->writer = new GenericBuilder();
$this->query = new Select();
$this->columnWriter = new ColumnWriter(new GenericBuilder(), new PlaceholderWriter());
}
/**
* @test
*/
public function itShouldWriteColumn()
{
$column = new Column('user_id', 'user');
$result = $this->columnWriter->writeColumn($column);
$this->assertSame('user.user_id', $result);
}
/**
* @test
*/
public function itShouldWriteValueAsColumns()
{
$select = new Select('user');
$select->setValueAsColumn('1', 'user_id');
$result = $this->columnWriter->writeValueAsColumns($select);
$this->assertInstanceOf('NilPortugues\Sql\QueryBuilder\Syntax\Column', $result[0]);
}
/**
* @test
*/
public function itShouldWriteFuncAsColumns()
{
$select = new Select('user');
$select->setFunctionAsColumn('MAX', ['user_id'], 'max_value');
$result = $this->columnWriter->writeFuncAsColumns($select);
$this->assertInstanceOf('NilPortugues\Sql\QueryBuilder\Syntax\Column', $result[0]);
}
/**
* @test
*/
public function itShouldWriteColumnWithAlias()
{
$column = new Column('user_id', 'user', 'userId');
$result = $this->columnWriter->writeColumnWithAlias($column);
$this->assertSame('user.user_id AS "userId"', $result);
}
/**
* @test
*/
public function itShouldBeAbleToWriteColumnAsASelectStatement()
{
$selectRole = new Select();
$selectRole
->setTable('role')
->setColumns(array('role_name'))
->limit(1)
->where()
->equals('role_id', 3);
$this->query
->setTable('user')
->setColumns(array('user_id', 'username'))
->setSelectAsColumn(array('user_role' => $selectRole))
->setSelectAsColumn(array($selectRole))
->where()
->equals('user_id', 4);
$expected = 'SELECT user.user_id, user.username, '.
'(SELECT role.role_name FROM role WHERE (role.role_id = :v1) LIMIT :v2, :v3) AS "user_role", '.
'(SELECT role.role_name FROM role WHERE (role.role_id = :v4) LIMIT :v5, :v6) AS "role" '.
'FROM user WHERE (user.user_id = :v7)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 3, ':v2' => 1, ':v3' => 0, ':v4' => 3, ':v5' => 1, ':v6' => 0, ':v7' => 4);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToWriteColumnAsAValueStatement()
{
$this->query
->setTable('user')
->setColumns(array('user_id', 'username'))
->setValueAsColumn('10', 'priority')
->where()
->equals('user_id', 1);
$expected = 'SELECT user.user_id, user.username, :v1 AS "priority" FROM user WHERE (user.user_id = :v2)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 10, ':v2' => 1);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToWriteColumnAsAFuncWithBracketsStatement()
{
$this->query
->setTable('user')
->setColumns(array('user_id', 'username'))
->setFunctionAsColumn('MAX', array('user_id'), 'max_id')
->where()
->equals('user_id', 1);
$expected = 'SELECT user.user_id, user.username, MAX(user_id) AS "max_id" FROM user WHERE (user.user_id = :v1)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToWriteColumnAsAFuncWithoutBracketsStatement()
{
$this->query
->setTable('user')
->setColumns(array('user_id', 'username'))
->setFunctionAsColumn('CURRENT_TIMESTAMP', array(), 'server_time')
->where()
->equals('user_id', 1);
$expected = 'SELECT user.user_id, user.username, CURRENT_TIMESTAMP AS "server_time" FROM user WHERE (user.user_id = :v1)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1);
$this->assertEquals($expected, $this->writer->getValues());
}
}

View File

@ -0,0 +1,106 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/12/14
* Time: 10:45 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
use NilPortugues\Sql\QueryBuilder\Manipulation\Delete;
/**
* Class DeleteWriterTest.
*/
class DeleteWriterTest extends \PHPUnit_Framework_TestCase
{
/**
* @var GenericBuilder
*/
private $writer;
/**
* @var Delete
*/
private $query;
/**
*
*/
protected function setUp()
{
$this->writer = new GenericBuilder();
$this->query = new Delete();
}
/**
* @test
*/
public function itShouldWriteDeleteAllTableContentsQuery()
{
$this->query->setTable('user');
$expected = 'DELETE FROM user';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldWriteDeleteRowLimit1()
{
$this->query
->setTable('user')
->limit(1);
$expected = 'DELETE FROM user LIMIT :v1';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToWriteCommentInQuery()
{
$this->query
->setTable('user')
->setComment('This is a comment');
$expected = <<<SQL
-- This is a comment
DELETE FROM user
SQL;
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldWriteDeleteRowWithWhereConditionAndLimit1()
{
$this->query->setTable('user');
$conditions = $this->query->where();
$conditions
->equals('user_id', 10)
->equals('user_id', 20)
->equals('user_id', 30);
$this->query->limit(1);
$expected = <<<SQL
DELETE FROM user WHERE (user.user_id = :v1) AND (user.user_id = :v2) AND (user.user_id = :v3) LIMIT :v4
SQL;
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 10, ':v2' => 20, ':v3' => 30, ':v4' => 1);
$this->assertEquals($expected, $this->writer->getValues());
}
}

View File

@ -0,0 +1,104 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/12/14
* Time: 10:45 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
use NilPortugues\Sql\QueryBuilder\Manipulation\Insert;
/**
* Class InsertWriterTest.
*/
class InsertWriterTest extends \PHPUnit_Framework_TestCase
{
/**
* @var GenericBuilder
*/
private $writer;
/**
* @var Insert
*/
private $query;
/**
* @var string
*/
private $exceptionClass = '\NilPortugues\Sql\QueryBuilder\Manipulation\QueryException';
/**
*
*/
protected function setUp()
{
$this->writer = new GenericBuilder();
$this->query = new Insert();
}
/**
* @test
*/
public function itShouldThrowQueryExceptionBecauseNoColumnsWereDefined()
{
$this->setExpectedException($this->exceptionClass, 'No columns were defined for the current schema.');
$this->query->setTable('user');
$this->writer->write($this->query);
}
/**
* @test
*/
public function itShouldWriteInsertQuery()
{
$valueArray = array(
'user_id' => 1,
'name' => 'Nil',
'contact' => 'contact@nilportugues.com',
);
$this->query
->setTable('user')
->setValues($valueArray);
$expected = 'INSERT INTO user (user.user_id, user.name, user.contact) VALUES (:v1, :v2, :v3)';
$this->assertSame($expected, $this->writer->write($this->query));
$this->assertEquals(\array_values($valueArray), \array_values($this->query->getValues()));
$expected = array(':v1' => 1, ':v2' => 'Nil', ':v3' => 'contact@nilportugues.com');
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToWriteCommentInQuery()
{
$valueArray = array(
'user_id' => 1,
'name' => 'Nil',
'contact' => 'contact@nilportugues.com',
);
$this->query
->setTable('user')
->setComment('This is a comment')
->setValues($valueArray);
$expected = "-- This is a comment\n".'INSERT INTO user (user.user_id, user.name, user.contact) VALUES (:v1, :v2, :v3)';
$this->assertSame($expected, $this->writer->write($this->query));
$this->assertEquals(\array_values($valueArray), \array_values($this->query->getValues()));
$expected = array(':v1' => 1, ':v2' => 'Nil', ':v3' => 'contact@nilportugues.com');
$this->assertEquals($expected, $this->writer->getValues());
}
}

View File

@ -0,0 +1,118 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/12/14
* Time: 7:34 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
use NilPortugues\Sql\QueryBuilder\Builder\Syntax\IntersectWriter;
use NilPortugues\Sql\QueryBuilder\Manipulation\Intersect;
use NilPortugues\Sql\QueryBuilder\Manipulation\Select;
/**
* Class IntersectWriterTest.
*/
class IntersectWriterTest extends \PHPUnit_Framework_TestCase
{
/**
* @var GenericBuilder
*/
private $writer;
/**
* @var IntersectWriter
*/
private $intersectWriter;
/**
*
*/
public function setUp()
{
$this->intersectWriter = new IntersectWriter(new GenericBuilder());
$this->writer = new GenericBuilder();
}
public function tearDown()
{
$this->intersectWriter = null;
$this->writer = null;
}
/**
* @test
*/
public function itShouldWriteIntersect()
{
$intersect = new Intersect();
$intersect->add(new Select('user'));
$intersect->add(new Select('user_email'));
$expected = <<<SQL
SELECT user.* FROM user
INTERSECT
SELECT user_email.* FROM user_email
SQL;
$this->assertEquals($expected, $this->intersectWriter->write($intersect));
}
/**
* @test
*/
public function itShouldWriteIntersectFromGenericBuilder()
{
$intersect = $this->writer->intersect();
$intersect->add(new Select('user'));
$intersect->add(new Select('user_email'));
$expected = <<<SQL
SELECT user.* FROM user
INTERSECT
SELECT user_email.* FROM user_email
SQL;
$this->assertEquals($expected, $this->writer->write($intersect));
}
/**
* @test
*/
public function itShouldNotResetPlaceholders()
{
$select1 = (new Select('table1'))
->where()
->between('column', 1, 2)
->end();
$select2 = (new Select('table2'))
->where()
->between('column', 3, 4)
->end();
$union = (new Intersect())
->add($select1)
->add($select2);
$expectedSql = <<<SQL
SELECT table1.* FROM table1 WHERE (table1.column BETWEEN :v1 AND :v2)
INTERSECT
SELECT table2.* FROM table2 WHERE (table2.column BETWEEN :v3 AND :v4)
SQL;
$expectedParams = [
':v1' => 1,
':v2' => 2,
':v3' => 3,
':v4' => 4,
];
$this->assertEquals($expectedSql, $this->writer->write($union));
$this->assertEquals($expectedParams, $this->writer->getValues());
}
}

View File

@ -0,0 +1,77 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/12/14
* Time: 7:34 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
use NilPortugues\Sql\QueryBuilder\Builder\Syntax\MinusWriter;
use NilPortugues\Sql\QueryBuilder\Manipulation\Minus;
use NilPortugues\Sql\QueryBuilder\Manipulation\Select;
/**
* Class MinusWriterTest.
*/
class MinusWriterTest extends \PHPUnit_Framework_TestCase
{
/**
* @var MinusWriter
*/
private $minusWriter;
/**
* @var GenericBuilder
*/
private $writer;
/**
*
*/
public function setUp()
{
$this->minusWriter = new MinusWriter(new GenericBuilder());
$this->writer = new GenericBuilder();
}
public function tearDown()
{
$this->minusWriter = null;
$this->writer = null;
}
/**
* @test
*/
public function itShouldWriteMinus()
{
$minus = new Minus(new Select('user'), new Select('user_email'));
$expected = <<<SQL
SELECT user.* FROM user
MINUS
SELECT user_email.* FROM user_email
SQL;
$this->assertEquals($expected, $this->minusWriter->write($minus));
}
/**
* @test
*/
public function itShouldWriteUnionAllFromGenericBuilder()
{
$minus = $this->writer->minus(new Select('user'), new Select('user_email'));
$expected = <<<SQL
SELECT user.* FROM user
MINUS
SELECT user_email.* FROM user_email
SQL;
$this->assertEquals($expected, $this->writer->write($minus));
}
}

View File

@ -0,0 +1,72 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/12/14
* Time: 10:46 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Builder\Syntax\PlaceholderWriter;
/**
* Class PlaceholderWriterTest.
*/
class PlaceholderWriterTest extends \PHPUnit_Framework_TestCase
{
/**
* @var PlaceholderWriter
*/
private $writer;
/**
*
*/
protected function setUp()
{
$this->writer = new PlaceholderWriter();
}
/**
* @test
*/
public function itShouldAddValueAndReturnPlaceholder()
{
$result = $this->writer->add(1);
$this->assertEquals(':v1', $result);
}
/**
* @test
*/
public function itShouldAddValueAndGetReturnsArrayHoldingPlaceholderData()
{
$this->writer->add(1);
$this->assertEquals(array(':v1' => 1), $this->writer->get());
}
/**
* @test
*/
public function itShouldTranslatePhpNullToSqlNullValue()
{
$this->writer->add('');
$this->writer->add(null);
$this->assertEquals(array(':v1' => 'NULL', ':v2' => 'NULL'), $this->writer->get());
}
/**
* @test
*/
public function itShouldTranslatePhpBoolToSqlBoolValue()
{
$this->writer->add(true);
$this->writer->add(false);
$this->assertEquals(array(':v1' => 1, ':v2' => 0), $this->writer->get());
}
}

View File

@ -0,0 +1,625 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/12/14
* Time: 10:46 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Syntax\Column;
use NilPortugues\Sql\QueryBuilder\Syntax\OrderBy;
use NilPortugues\Sql\QueryBuilder\Manipulation\Select;
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
/**
* Class SelectWriterTest.
*/
class SelectWriterTest extends \PHPUnit_Framework_TestCase
{
/**
* @var GenericBuilder
*/
private $writer;
/**
* @var Select
*/
private $query;
/**
* @var string
*/
private $exceptionClass = '\NilPortugues\Sql\QueryBuilder\Manipulation\QueryException';
/**
*
*/
protected function setUp()
{
$this->writer = new GenericBuilder();
$this->query = new Select();
}
/**
* @test
*/
public function itShouldBeCloneableWithoutKeepingReferences()
{
$query1 = new Select('user');
$query2 = clone $query1;
$query2->setTable('users');
$this->assertFalse($query1->getTable() == $query2->getTable());
}
/**
* @test
*/
public function itShouldBeConstructedWithConstructor()
{
$this->query = new Select('user');
$expected = 'SELECT user.* FROM user';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldBeAbleToWriteCommentInQuery()
{
$this->query = new Select('user');
$this->query->setComment('This is a comment');
$expected = <<<SQL
-- This is a comment
SELECT user.* FROM user
SQL;
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldThrowExceptionWhenGettingColumnsButNoTableIsSet()
{
$this->setExpectedException($this->exceptionClass);
$this->query = new Select();
$this->query->getColumns();
}
/**
* @test
*/
public function itShouldBeConstructedWithConstructorWithColumns()
{
$this->query = new Select('user', array('user_id', 'name'));
$expected = 'SELECT user.user_id, user.name FROM user';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldSelectAll()
{
$this->query->setTable('user');
$expected = 'SELECT user.* FROM user';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldSelectAllDistinct()
{
$this->query->setTable('user')->distinct();
$expected = 'SELECT DISTINCT user.* FROM user';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldSelectAllWithLimit1()
{
$this->query->setTable('user')->limit(1);
$expected = 'SELECT user.* FROM user LIMIT :v1, :v2';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 0);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldSelectAllWithLimit1Offset2()
{
$this->query->setTable('user')->limit(1, 2);
$expected = 'SELECT user.* FROM user LIMIT :v1, :v2';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 2);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldSelectAllGetFirst20()
{
$this->query->setTable('user')->limit(0, 20);
$expected = 'SELECT user.* FROM user LIMIT :v1, :v2';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 0, ':v2' => 20);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldAllowColumnAlias()
{
$this->query
->setTable('user')
->setColumns(
array(
'userId' => 'user_id', // Alias -> column name
'username' => 'name',
'email' => 'email',
)
);
$expected = 'SELECT user.user_id AS "userId", user.name AS "username", user.email AS "email" FROM user';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldAllowColumnOrder()
{
$this->query
->setTable('user')
->orderBy('user_id', OrderBy::ASC);
$expected = 'SELECT user.* FROM user ORDER BY user.user_id ASC';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldAllowColumnOrderUsingColumnAlias()
{
$tableName = 'user';
$this->query
->setTable($tableName)
->setColumns(
array(
'userId' => 'user_id', // Alias -> column name
'username' => 'name',
'email' => 'email',
)
)
->orderBy('user_id', OrderBy::ASC)
->orderBy('email', OrderBy::DESC);
$expected =
'SELECT user.user_id AS "userId", user.name AS "username", user.email AS "email" FROM '.
'user ORDER BY user.user_id ASC, user.email DESC';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldBeAbleToDoALeftJoin()
{
$this->query
->setTable('user')
->leftJoin('news', 'user_id', 'author_id', array('title', 'body', 'created_at', 'updated_at'));
$expected = 'SELECT user.*, news.title, news.body, news.created_at, news.updated_at FROM user LEFT JOIN '.
'news ON (news.author_id = user.user_id)';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldBeAbleToDoARightJoin()
{
$this->query
->setTable('user')
->rightJoin('news', 'user_id', 'author_id', array('title', 'body', 'created_at', 'updated_at'));
$expected = 'SELECT user.*, news.title, news.body, news.created_at, news.updated_at FROM user RIGHT JOIN '.
'news ON (news.author_id = user.user_id)';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldBeAbleToDoAInnerJoin()
{
$this->query
->setTable('user')
->innerJoin('news', 'user_id', 'author_id', array('title', 'body', 'created_at', 'updated_at'));
$expected = 'SELECT user.*, news.title, news.body, news.created_at, news.updated_at FROM user INNER JOIN '.
'news ON (news.author_id = user.user_id)';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldBeAbleToDoACrossJoin()
{
$this->query
->setTable('user')
->crossJoin('news', 'user_id', 'author_id', array('title', 'body', 'created_at', 'updated_at'));
$expected = 'SELECT user.*, news.title, news.body, news.created_at, news.updated_at FROM user CROSS JOIN '.
'news ON (news.author_id = user.user_id)';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldBeAbleToDoALeftJoinWithOrderByOnJoinedTable()
{
$this->query
->setTable('user')
->setColumns(
array(
'userId' => 'user_id',
'username' => 'name',
'email' => 'email',
'created_at',
)
)
->orderBy('user_id', OrderBy::DESC)
->leftJoin('news', 'user_id', 'author_id', array('title', 'body', 'created_at', 'updated_at'))
->orderBy('created_at', OrderBy::DESC);
$expected = 'SELECT user.user_id AS "userId", user.name AS "username", user.email AS "email", user.created_at,'.
' news.title, news.body, news.created_at, news.updated_at FROM user LEFT JOIN news ON (news.author_id '.
'= user.user_id) ORDER BY user.user_id DESC, news.created_at DESC';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldBeAbleToDoAJoin()
{
$this->query
->setTable('user')
->join('news', 'user_id', 'author_id', array('title', 'body', 'created_at', 'updated_at'));
$expected = 'SELECT user.*, news.title, news.body, news.created_at, news.updated_at FROM user JOIN '.
'news ON (news.author_id = user.user_id)';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldBeAbleToDoAJoinWithOrderByOnJoinedTable()
{
$this->query
->setTable('user')
->setColumns(
array(
'userId' => 'user_id',
'username' => 'name',
'email' => 'email',
'created_at',
)
)
->orderBy('user_id', OrderBy::DESC)
->join('news', 'user_id', 'author_id', array('title', 'body', 'created_at', 'updated_at'))
->orderBy('created_at', OrderBy::DESC);
$expected = 'SELECT user.user_id AS "userId", user.name AS "username", user.email AS "email", user.created_at,'.
' news.title, news.body, news.created_at, news.updated_at FROM user JOIN news ON (news.author_id ='.
' user.user_id) ORDER BY user.user_id DESC, news.created_at DESC';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldBeAbleToDoAJoinWithCustomColumns()
{
$this->query
->setTable('user')
->setColumns(
array(
'userId' => 'user_id',
'username' => 'name',
'email' => 'email',
'created_at',
)
)
->orderBy('user_id', OrderBy::DESC)
->join('news', 'user_id', 'author_id', array('title', 'body', 'created_at', 'updated_at'))
->orderBy('created_at', OrderBy::DESC)
->join('articles', new Column('news_id', 'article'), new Column('id', 'news'));
$expected = 'SELECT user.user_id AS "userId", user.name AS "username", user.email AS "email", user.created_at,'.
' news.title, news.body, news.created_at, news.updated_at FROM user JOIN news ON (news.author_id ='.
' user.user_id) JOIN articles ON (news.id = article.news_id) ORDER BY user.user_id DESC, news.created_at DESC';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldBeAbleToDoAnAddWithMultipleJoins()
{
$this->query->setTable('user');
for ($i = 1; $i <= 5; ++$i) {
//Select QueryInterface for "news" table
$select = new Select();
$select
->setTable('news'.$i)
->setColumns(array('title'.$i));
//Select query for user table, being joined with "newsX" select.
$this->query->addJoin($select, 'user_id', 'author_id'.$i);
}
$expected = 'SELECT user.*, news1.title1, news2.title2, news3.title3, news4.title4, news5.title5 '.
'FROM user JOIN news1 ON (news1.author_id1 = user.user_id) JOIN news2 ON (news2.author_id2 = user.user_id)'.
' JOIN news3 ON (news3.author_id3 = user.user_id) JOIN news4 ON (news4.author_id4 = user.user_id) '.
'JOIN news5 ON (news5.author_id5 = user.user_id)';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldBeAbleToOn()
{
$this->query
->setTable('user')
->setColumns(
array(
'userId' => 'user_id',
'username' => 'name',
'email' => 'email',
'created_at',
)
)
->orderBy('user_id', OrderBy::DESC)
->join('news', 'user_id', 'author_id', array('title', 'body', 'created_at', 'updated_at'))
->orderBy('created_at', OrderBy::DESC)
->on()
->eq('author_id', 1);
$this->query->limit(1, 10);
$expected = 'SELECT user.user_id AS "userId", user.name AS "username", user.email AS "email", user.created_at,'.
' news.title, news.body, news.created_at, news.updated_at FROM user JOIN news ON '.
'(news.author_id = user.user_id) AND (news.author_id = :v1) ORDER BY '.
'user.user_id DESC, news.created_at DESC LIMIT :v2, :v3';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 1, ':v3' => 10);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToCountTotalRows()
{
$this->query
->setTable('user')
->count()
->groupBy(array('user_id', 'name'))
->having()
->equals('user_id', 1)
->equals('user_id', 2);
$expected = 'SELECT COUNT(*) FROM user GROUP BY user.user_id, user.name HAVING (user.user_id = :v1) AND (user.user_id = :v2)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 2);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToCountTotalRowsSettingDefaultColumn()
{
$this->query
->setTable('user')
->count('user_id')
->groupBy(array('user_id', 'name'))
->having()
->equals('user_id', 1)
->equals('user_id', 2);
$expected = 'SELECT COUNT(user.user_id) FROM user GROUP BY user.user_id, user.name HAVING (user.user_id = :v1) AND (user.user_id = :v2)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 2);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToCountTotalRowsSettingDefaultColumnWithAlias()
{
$this->query
->setTable('user')
->count('user_id', 'total_users')
->groupBy(array('user_id', 'name'))
->having()
->equals('user_id', 1)
->equals('user_id', 2);
$expected = 'SELECT COUNT(user.user_id) AS "total_users" FROM user GROUP BY user.user_id, user.name HAVING (user.user_id = :v1) AND (user.user_id = :v2)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 2);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToGroupByOperator()
{
$this->query
->setTable('user')
->setColumns(
array(
'userId' => 'user_id',
'username' => 'name',
'email' => 'email',
'created_at',
)
)
->groupBy(array('user_id', 'name'))
->having()
->equals('user_id', 1)
->equals('user_id', 2);
$expected = 'SELECT user.user_id AS "userId", user.name AS "username", user.email AS "email", user.created_at'.
' FROM user GROUP BY user.user_id, user.name HAVING (user.user_id = :v1) AND (user.user_id = :v2)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 2);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldThrowExceptionInvalidHavingConjunction()
{
$this->setExpectedException($this->exceptionClass);
$this->query
->setTable('user')
->setColumns(
array(
'userId' => 'user_id',
'username' => 'name',
'email' => 'email',
'created_at',
)
)
->groupBy(array('user_id', 'name'))
->having('AAAAAAAAAAAAAAAA');
}
/**
* @test
*/
public function itShouldBeAbleToSetHavingOperatorToOr()
{
$this->query
->setTable('user')
->setColumns(
array(
'userId' => 'user_id',
'username' => 'name',
'email' => 'email',
'created_at',
)
)
->groupBy(array('user_id', 'name'))
->having('OR')
->equals('user_id', 1)
->equals('user_id', 2);
$expected = 'SELECT user.user_id AS "userId", user.name AS "username", user.email AS "email", user.created_at'.
' FROM user GROUP BY user.user_id, user.name HAVING (user.user_id = :v1) OR (user.user_id = :v2)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 2);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldAllowSelectQueryToActAsAColumn()
{
$table1 = new Select('Table1');
$table1
->where()
->equals('table1_id', 1);
$table2 = new Select('Table2');
$table2
->where()
->eq($table1, 2);
$expected = 'SELECT Table2.* FROM Table2 WHERE ((SELECT Table1.* FROM Table1 '.
'WHERE (Table1.table1_id = :v1)) = :v2)';
$this->assertSame($expected, $this->writer->write($table2));
$expected = array(':v1' => 1, ':v2' => 2);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldWriteJoin()
{
$this->query
->isJoin(true)
->setTable('user')
->on()
->equals('user_id', 1);
$expected = 'JOIN user ON (user.user_id = :v1)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1);
$this->assertEquals($expected, $this->writer->getValues());
}
}

View File

@ -0,0 +1,118 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/12/14
* Time: 7:34 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
use NilPortugues\Sql\QueryBuilder\Builder\Syntax\UnionAllWriter;
use NilPortugues\Sql\QueryBuilder\Manipulation\UnionAll;
use NilPortugues\Sql\QueryBuilder\Manipulation\Select;
/**
* Class UnionAllWriterTest.
*/
class UnionAllWriterTest extends \PHPUnit_Framework_TestCase
{
/**
* @var UnionAllWriter
*/
private $unionAllWriter;
/**
* @var GenericBuilder
*/
private $writer;
/**
*
*/
public function setUp()
{
$this->unionAllWriter = new UnionAllWriter(new GenericBuilder());
$this->writer = new GenericBuilder();
}
public function tearDown()
{
$this->unionAllWriter = null;
$this->writer = null;
}
/**
* @test
*/
public function itShouldWriteUnionAll()
{
$union = new UnionAll();
$union->add(new Select('user'));
$union->add(new Select('user_email'));
$expected = <<<SQL
SELECT user.* FROM user
UNION ALL
SELECT user_email.* FROM user_email
SQL;
$this->assertEquals($expected, $this->unionAllWriter->write($union));
}
/**
* @test
*/
public function itShouldWriteUnionAllFromGenericBuilder()
{
$unionAll = $this->writer->unionAll();
$unionAll->add(new Select('user'));
$unionAll->add(new Select('user_email'));
$expected = <<<SQL
SELECT user.* FROM user
UNION ALL
SELECT user_email.* FROM user_email
SQL;
$this->assertEquals($expected, $this->writer->write($unionAll));
}
/**
* @test
*/
public function itShouldNotResetPlaceholders()
{
$select1 = (new Select('table1'))
->where()
->between('column', 1, 2)
->end();
$select2 = (new Select('table2'))
->where()
->between('column', 3, 4)
->end();
$union = (new UnionAll())
->add($select1)
->add($select2);
$expectedSql = <<<SQL
SELECT table1.* FROM table1 WHERE (table1.column BETWEEN :v1 AND :v2)
UNION ALL
SELECT table2.* FROM table2 WHERE (table2.column BETWEEN :v3 AND :v4)
SQL;
$expectedParams = [
':v1' => 1,
':v2' => 2,
':v3' => 3,
':v4' => 4,
];
$this->assertEquals($expectedSql, $this->writer->write($union));
$this->assertEquals($expectedParams, $this->writer->getValues());
}
}

View File

@ -0,0 +1,118 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/12/14
* Time: 7:34 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
use NilPortugues\Sql\QueryBuilder\Builder\Syntax\UnionWriter;
use NilPortugues\Sql\QueryBuilder\Manipulation\Union;
use NilPortugues\Sql\QueryBuilder\Manipulation\Select;
/**
* Class UnionWriterTest.
*/
class UnionWriterTest extends \PHPUnit_Framework_TestCase
{
/**
* @var UnionWriter
*/
private $unionWriter;
/**
* @var GenericBuilder
*/
private $writer;
/**
*
*/
public function setUp()
{
$this->unionWriter = new UnionWriter(new GenericBuilder());
$this->writer = new GenericBuilder();
}
public function tearDown()
{
$this->unionWriter = null;
$this->writer = null;
}
/**
* @test
*/
public function itShouldWriteUnion()
{
$union = new Union();
$union->add(new Select('user'));
$union->add(new Select('user_email'));
$expected = <<<SQL
SELECT user.* FROM user
UNION
SELECT user_email.* FROM user_email
SQL;
$this->assertEquals($expected, $this->unionWriter->write($union));
}
/**
* @test
*/
public function itShouldWriteUnionFromGenericBuilder()
{
$unionAll = $this->writer->union();
$unionAll->add(new Select('user'));
$unionAll->add(new Select('user_email'));
$expected = <<<SQL
SELECT user.* FROM user
UNION
SELECT user_email.* FROM user_email
SQL;
$this->assertEquals($expected, $this->writer->write($unionAll));
}
/**
* @test
*/
public function itShouldNotResetPlaceholders()
{
$select1 = (new Select('table1'))
->where()
->between('column', 1, 2)
->end();
$select2 = (new Select('table2'))
->where()
->between('column', 3, 4)
->end();
$union = (new Union())
->add($select1)
->add($select2);
$expectedSql = <<<SQL
SELECT table1.* FROM table1 WHERE (table1.column BETWEEN :v1 AND :v2)
UNION
SELECT table2.* FROM table2 WHERE (table2.column BETWEEN :v3 AND :v4)
SQL;
$expectedParams = [
':v1' => 1,
':v2' => 2,
':v3' => 3,
':v4' => 4,
];
$this->assertEquals($expectedSql, $this->writer->write($union));
$this->assertEquals($expectedParams, $this->writer->getValues());
}
}

View File

@ -0,0 +1,140 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/12/14
* Time: 10:47 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
use NilPortugues\Sql\QueryBuilder\Manipulation\Update;
/**
* Class UpdateWriterTest.
*/
class UpdateWriterTest extends \PHPUnit_Framework_TestCase
{
/**
* @var array
*/
private $valueArray = array();
/**
* @var GenericBuilder
*/
private $writer;
/**
* @var Update
*/
private $query;
/**
* @var string
*/
private $exceptionClass = '\NilPortugues\Sql\QueryBuilder\Manipulation\QueryException';
/**
*
*/
protected function setUp()
{
$this->writer = new GenericBuilder();
$this->query = new Update();
$this->valueArray = array(
'user_id' => 1,
'name' => 'Nil',
'contact' => 'contact@nilportugues.com',
);
}
/**
* @test
*/
public function itShouldThrowQueryException()
{
$this->setExpectedException($this->exceptionClass);
$this->query->setTable('user');
$this->writer->write($this->query);
}
/**
* @test
*/
public function itShouldWriteUpdateQuery()
{
$this->query
->setTable('user')
->setValues($this->valueArray);
$expected = 'UPDATE user SET user.user_id = :v1, user.name = :v2, user.contact = :v3';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 'Nil', ':v3' => 'contact@nilportugues.com');
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToWriteCommentInQuery()
{
$this->query
->setTable('user')
->setValues($this->valueArray)
->setComment('This is a comment');
$expected = <<<SQL
-- This is a comment
UPDATE user SET user.user_id = :v1, user.name = :v2, user.contact = :v3
SQL;
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 'Nil', ':v3' => 'contact@nilportugues.com');
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldWriteUpdateQueryWithWhereConstrain()
{
$this->query
->setTable('user')
->setValues($this->valueArray)
->where()
->equals('user_id', 1);
$expected = 'UPDATE user SET user.user_id = :v1, user.name = :v2, user.contact = :v3 WHERE (user.user_id = :v4)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 'Nil', ':v3' => 'contact@nilportugues.com', ':v4' => 1);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldWriteUpdateQueryWithWhereConstrainAndLimit1()
{
$this->query
->setTable('user')
->setValues($this->valueArray)
->where()
->equals('user_id', 1);
$this->query->limit(1);
$expected = 'UPDATE user SET user.user_id = :v1, user.name = :v2, user.contact = :v3 WHERE (user.user_id = :v4) LIMIT :v5';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 'Nil', ':v3' => 'contact@nilportugues.com', ':v4' => 1, ':v5' => 1);
$this->assertEquals($expected, $this->writer->getValues());
}
}

View File

@ -0,0 +1,561 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/13/14
* Time: 12:46 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
use NilPortugues\Sql\QueryBuilder\Manipulation\Select;
/**
* Class WhereWriterTest.
*/
class WhereWriterTest extends \PHPUnit_Framework_TestCase
{
/**
* @var GenericBuilder
*/
private $writer;
/**
* @var Select
*/
private $query;
/**
*
*/
protected function setUp()
{
$this->writer = new GenericBuilder();
$this->query = new Select();
}
/**
* @test
*/
public function itShouldAllowWhereConditions()
{
$this->query
->setTable('user')
->where()
->equals('user_id', 1)
->like('name', '%N%');
$expected = 'SELECT user.* FROM user WHERE (user.user_id = :v1) AND (user.name LIKE :v2)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => '%N%');
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldAllowWhereOrConditions()
{
$this->query
->setTable('user')
->where('OR')
->equals('user_id', 1)
->like('name', '%N%');
$this->assertSame('OR', $this->query->getWhereOperator());
$expected = 'SELECT user.* FROM user WHERE (user.user_id = :v1) OR (user.name LIKE :v2)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => '%N%');
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToLetWhereStatementNotBeEqualTo()
{
$column = 'user_id';
$value = 1;
$this->query
->setTable('user')
->where()
->notEquals($column, $value);
$expected = 'SELECT user.* FROM user WHERE (user.user_id <> :v1)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToLetWhereStatementBeGreaterThan()
{
$column = 'user_id';
$value = 1;
$this->query
->setTable('user')
->where()
->greaterThan($column, $value);
$expected = 'SELECT user.* FROM user WHERE (user.user_id > :v1)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToLetWhereStatementBeGreaterThanOrEqual()
{
$column = 'user_id';
$value = 1;
$this->query
->setTable('user')
->where()
->greaterThanOrEqual($column, $value);
$expected = 'SELECT user.* FROM user WHERE (user.user_id >= :v1)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToLetWhereStatementBeLessThan()
{
$column = 'user_id';
$value = 1;
$this->query
->setTable('user')
->where()
->lessThan($column, $value);
$expected = 'SELECT user.* FROM user WHERE (user.user_id < :v1)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToLetWhereStatementBeLessThanOrEqual()
{
$column = 'user_id';
$value = 1;
$this->query
->setTable('user')
->where()
->lessThanOrEqual($column, $value);
$expected = 'SELECT user.* FROM user WHERE (user.user_id <= :v1)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToLetWhereStatementBeLike()
{
$column = 'user_id';
$value = 1;
$this->query
->setTable('user')
->where()
->like($column, $value);
$expected = 'SELECT user.* FROM user WHERE (user.user_id LIKE :v1)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToLetWhereStatementBeNotLike()
{
$column = 'user_id';
$value = 1;
$this->query
->setTable('user')
->where()
->notLike($column, $value);
$expected = 'SELECT user.* FROM user WHERE (user.user_id NOT LIKE :v1)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToLetWhereStatementAccumulateInConditions()
{
$column = 'user_id';
$this->query
->setTable('user')
->where()
->in($column, array(1, 2, 3));
$expected = 'SELECT user.* FROM user WHERE (user.user_id IN (:v1, :v2, :v3))';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 2, ':v3' => 3);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToLetWhereStatementAccumulateNotInConditions()
{
$column = 'user_id';
$this->query
->setTable('user')
->where()
->notIn($column, array(1, 2, 3));
$expected = 'SELECT user.* FROM user WHERE (user.user_id NOT IN (:v1, :v2, :v3))';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 2, ':v3' => 3);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToLetWhereStatementWriteBetweenConditions()
{
$column = 'user_id';
$this->query
->setTable('user')
->where()
->between($column, 1, 2);
$expected = 'SELECT user.* FROM user WHERE (user.user_id BETWEEN :v1 AND :v2)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 2);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToLetWhereStatementWriteNotBetweenConditions()
{
$column = 'user_id';
$this->query
->setTable('user')
->where()
->notBetween($column, 1, 2);
$expected = 'SELECT user.* FROM user WHERE (user.user_id NOT BETWEEN :v1 AND :v2)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 2);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToLetWhereStatementSetNullValueCondition()
{
$column = 'user_id';
$this->query
->setTable('user')
->where()
->isNull($column);
$expected = 'SELECT user.* FROM user WHERE (user.user_id IS NULL)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array();
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToLetWhereStatementSetIsNotNullValueCondition()
{
$column = 'user_id';
$this->query
->setTable('user')
->where()
->isNotNull($column);
$expected = 'SELECT user.* FROM user WHERE (user.user_id IS NOT NULL)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array();
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToLetWhereStatementSetBitClauseValueCondition()
{
$column = 'user_id';
$this->query
->setTable('user')
->where()
->addBitClause($column, 1);
$expected = 'SELECT user.* FROM user WHERE (ISNULL(user.user_id, 0) = :v1)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToLetWhereStatementSubconditions()
{
$column = 'user_id';
$this->query
->setTable('user')
->where()
->equals($column, 1)
->equals($column, 2)
->subWhere('OR')
->lessThan($column, 10)
->greaterThan($column, 100);
$expected = 'SELECT user.* FROM user WHERE (user.user_id = :v1) AND (user.user_id = :v2) '.
'AND ((user.user_id < :v3) OR (user.user_id > :v4))';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 2, ':v3' => 10, ':v4' => 100);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldAllowSelectWhereButNotWriteCondition()
{
$table1 = new Select('Table1');
$table1
->where();
$expected = 'SELECT Table1.* FROM Table1';
$this->assertSame($expected, $this->writer->write($table1));
}
/**
* @test
*/
public function itShouldAllowHavingConditions()
{
$this->query
->setTable('user')
->having()
->greaterThan('user_id', 1)
->like('name', '%N%');
$expected = 'SELECT user.* FROM user HAVING (user.user_id > :v1) AND (user.name LIKE :v2)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => '%N%');
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToUseSelectStatementsInWhere()
{
$selectRole = new Select();
$selectRole
->setTable('role')
->setColumns(array('role_name'))
->limit(1)
->where()
->equals('role_id', 3);
$this->query
->setTable('user')
->setColumns(array('user_id', 'role_id'))
->where()
->equals('role_id', $selectRole);
$expected = 'SELECT user.user_id, user.role_id FROM user WHERE '.
'(user.role_id = (SELECT role.role_name FROM role WHERE (role.role_id = :v1) LIMIT :v2, :v3))';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 3, ':v2' => 1, ':v3' => 0);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToSelectWithFullMatchSearchUsingMatchInNaturalMode()
{
$this->query
->setTable('user')
->setColumns(array('user_id', 'role_id'))
->where()
->match(array('username', 'email'), array('Nil'));
$expected = 'SELECT user.user_id, user.role_id FROM user '.
'WHERE (MATCH(user.username, user.email) AGAINST(:v1))';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 'Nil');
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToSelectWithFullMatchSearchUsingMatchInBooleanMode()
{
$this->query
->setTable('user')
->setColumns(array('user_id', 'role_id'))
->where()
->matchBoolean(array('username', 'email'), array('Nil'));
$expected = 'SELECT user.user_id, user.role_id FROM user '.
'WHERE (MATCH(user.username, user.email) AGAINST(:v1 IN BOOLEAN MODE))';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 'Nil');
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToSelectWithFullMatchSearchUsingMatchInQueryExpansionMode()
{
$this->query
->setTable('user')
->setColumns(array('user_id', 'role_id'))
->where()
->matchWithQueryExpansion(array('username', 'email'), array('Nil'));
$expected = 'SELECT user.user_id, user.role_id FROM user '.
'WHERE (MATCH(user.username, user.email) AGAINST(:v1 WITH QUERY EXPANSION))';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 'Nil');
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToDoWhereExists()
{
$select = new Select('banned_user');
$select->where()->equals('user_id', 1);
$this->query
->setTable('user')
->setColumns(array('user_id', 'role_id'))
->where()
->exists($select)
->equals('user', 'Nil');
$expected = 'SELECT user.user_id, user.role_id FROM user WHERE (user.user = :v1) AND '.
'EXISTS (SELECT banned_user.* FROM banned_user WHERE (banned_user.user_id = :v2))';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 'Nil', ':v2' => 1);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToDoWhereNotExists()
{
$select = new Select('banned_user');
$select->where()->equals('user_id', 1);
$this->query
->setTable('user')
->setColumns(array('user_id', 'role_id'))
->where()
->notExists($select)
->equals('user', 'Nil');
$expected = 'SELECT user.user_id, user.role_id FROM user WHERE (user.user = :v1) AND '.
'NOT EXISTS (SELECT banned_user.* FROM banned_user WHERE (banned_user.user_id = :v2))';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 'Nil', ':v2' => 1);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldAllowWhereConditionAsLiteral()
{
$this->query
->setTable('user')
->where()
->asLiteral('(username is not null and status=:status)')
->notEquals('name', '%N%');
$expected = 'SELECT user.* FROM user WHERE (username is not null and status=:status) AND (user.name <> :v1)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => '%N%');
$this->assertEquals($expected, $this->writer->getValues());
}
}

View File

@ -0,0 +1,150 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/12/14
* Time: 10:47 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
use NilPortugues\Sql\QueryBuilder\Builder\Syntax\PlaceholderWriter;
use NilPortugues\Sql\QueryBuilder\Builder\Syntax\WriterFactory;
/**
* Class WriterFactoryTest.
*/
class WriterFactoryTest extends \PHPUnit_Framework_TestCase
{
/**
* @var PlaceholderWriter
*/
private $placeholder;
/**
* @var GenericBuilder
*/
private $writer;
/**
*
*/
public function setUp()
{
$this->writer = new GenericBuilder();
$this->placeholder = new PlaceholderWriter();
}
/**
* @test
*/
public function itShouldCreateColumnWriter()
{
$writer = WriterFactory::createColumnWriter($this->writer, $this->placeholder);
$this->assertSame('NilPortugues\Sql\QueryBuilder\Builder\Syntax\ColumnWriter', \get_class($writer));
}
/**
* @test
*/
public function itShouldCreateWhereWriter()
{
$writer = WriterFactory::createWhereWriter($this->writer, $this->placeholder);
$this->assertSame('NilPortugues\Sql\QueryBuilder\Builder\Syntax\WhereWriter', \get_class($writer));
}
/**
* @test
*/
public function itShouldCreateSelectWriter()
{
$writer = WriterFactory::createSelectWriter($this->writer, $this->placeholder);
$this->assertSame('NilPortugues\Sql\QueryBuilder\Builder\Syntax\SelectWriter', \get_class($writer));
}
/**
* @test
*/
public function itShouldCreateInsertWriter()
{
$writer = WriterFactory::createInsertWriter($this->writer, $this->placeholder);
$this->assertSame('NilPortugues\Sql\QueryBuilder\Builder\Syntax\InsertWriter', \get_class($writer));
}
/**
* @test
*/
public function itShouldCreateUpdateWriter()
{
$writer = WriterFactory::createUpdateWriter($this->writer, $this->placeholder);
$this->assertSame('NilPortugues\Sql\QueryBuilder\Builder\Syntax\UpdateWriter', \get_class($writer));
}
/**
* @test
*/
public function itShouldCreateDeleteWriter()
{
$writer = WriterFactory::createDeleteWriter($this->writer, $this->placeholder);
$this->assertSame('NilPortugues\Sql\QueryBuilder\Builder\Syntax\DeleteWriter', \get_class($writer));
}
/**
* @test
*/
public function itShouldCreatePlaceholderWriter()
{
$writer = WriterFactory::createPlaceholderWriter();
$this->assertSame('NilPortugues\Sql\QueryBuilder\Builder\Syntax\PlaceholderWriter', \get_class($writer));
}
/**
* @test
*/
public function itShouldCreateIntersectWriter()
{
$writer = WriterFactory::createIntersectWriter($this->writer);
$this->assertSame('NilPortugues\Sql\QueryBuilder\Builder\Syntax\IntersectWriter', \get_class($writer));
}
/**
* @test
*/
public function itShouldCreateMinusWriter()
{
$writer = WriterFactory::createMinusWriter($this->writer);
$this->assertSame('NilPortugues\Sql\QueryBuilder\Builder\Syntax\MinusWriter', \get_class($writer));
}
/**
* @test
*/
public function itShouldCreateUnion()
{
$writer = WriterFactory::createUnionWriter($this->writer);
$this->assertSame('NilPortugues\Sql\QueryBuilder\Builder\Syntax\UnionWriter', \get_class($writer));
}
/**
* @test
*/
public function itShouldCreateUnionAll()
{
$writer = WriterFactory::createUnionAllWriter($this->writer);
$this->assertSame('NilPortugues\Sql\QueryBuilder\Builder\Syntax\UnionAllWriter', \get_class($writer));
}
}

View File

@ -0,0 +1,74 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/7/14
* Time: 11:44 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Manipulation;
/**
* Class BaseQueryTest.
*/
class BaseQueryTest extends \PHPUnit_Framework_TestCase
{
/**
* @var \NilPortugues\Tests\Sql\QueryBuilder\Manipulation\Resources\DummyQuery
*/
private $query;
/**
* @var string
*/
private $whereClass = '\NilPortugues\Sql\QueryBuilder\Syntax\Where';
/**
*
*/
protected function setUp()
{
$this->query = new Resources\DummyQuery();
$this->query->setTable('tablename');
}
/**
*
*/
protected function tearDown()
{
$this->query = null;
}
/**
* @test
*/
public function itShouldBeAbleToSetTableName()
{
$this->assertSame('tablename', $this->query->getTable()->getName());
}
/**
* @test
*/
public function itShouldGetWhere()
{
$this->assertNull($this->query->getWhere());
$this->query->where();
$this->assertInstanceOf($this->whereClass, $this->query->getWhere());
}
/**
* @test
*/
public function itShouldGetWhereOperator()
{
$this->assertSame('AND', $this->query->getWhereOperator());
$this->query->where('OR');
$this->assertSame('OR', $this->query->getWhereOperator());
}
}

View File

@ -0,0 +1,56 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/3/14
* Time: 1:37 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Manipulation;
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
use NilPortugues\Sql\QueryBuilder\Manipulation\Delete;
/**
* Class DeleteTest.
*/
class DeleteTest extends \PHPUnit_Framework_TestCase
{
/**
* @var GenericBuilder
*/
private $writer;
/**
* @var Delete
*/
private $query;
/**
*
*/
protected function setUp()
{
$this->query = new Delete();
}
/**
* @test
*/
public function itShouldGetPartName()
{
$this->assertSame('DELETE', $this->query->partName());
}
/**
* @test
*/
public function itShouldReturnLimit1()
{
$this->query->limit(1);
$this->assertSame(1, $this->query->getLimitStart());
}
}

View File

@ -0,0 +1,77 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/3/14
* Time: 1:37 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Manipulation;
use NilPortugues\Sql\QueryBuilder\Manipulation\Insert;
/**
* Class InsertTest.
*/
class InsertTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Insert
*/
private $query;
/**
*
*/
protected function setUp()
{
$this->query = new Insert();
}
/**
* @test
*/
public function itShouldGetPartName()
{
$this->assertSame('INSERT', $this->query->partName());
}
/**
* @test
*/
public function itShouldSetValues()
{
$values = ['user_id' => 1, 'username' => 'nilportugues'];
$this->query->setValues($values);
$this->assertSame($values, $this->query->getValues());
}
/**
* @test
*/
public function itShouldGetColumns()
{
$values = ['user_id' => 1, 'username' => 'nilportugues'];
$this->query->setValues($values);
$columns = $this->query->getColumns();
$this->assertInstanceOf('NilPortugues\Sql\QueryBuilder\Syntax\Column', $columns[0]);
}
/**
* @test
*/
public function itShouldSetNullableValues()
{
$values = ['user_id' => 1, 'description' => null, 'isVisible' => false];
$this->query->setValues($values);
$this->assertSame($values, $this->query->getValues());
}
}

View File

@ -0,0 +1,89 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/12/14
* Time: 7:26 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Manipulation;
use NilPortugues\Sql\QueryBuilder\Manipulation\Intersect;
use NilPortugues\Sql\QueryBuilder\Manipulation\Select;
/**
* Class IntersectTest.
*/
class IntersectTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Intersect
*/
private $query;
/**
* @var string
*/
private $exceptionClass = '\NilPortugues\Sql\QueryBuilder\Manipulation\QueryException';
/**
*
*/
protected function setUp()
{
$this->query = new Intersect();
}
/**
* @test
*/
public function itShouldGetPartName()
{
$this->assertSame('INTERSECT', $this->query->partName());
}
/**
* @test
*/
public function itShouldThrowExceptionForUnsupportedGetTable()
{
$this->setExpectedException($this->exceptionClass);
$this->query->getTable();
}
/**
* @test
*/
public function itShouldThrowExceptionForUnsupportedGetWhere()
{
$this->setExpectedException($this->exceptionClass);
$this->query->getWhere();
}
/**
* @test
*/
public function itShouldThrowExceptionForUnsupportedWhere()
{
$this->setExpectedException($this->exceptionClass);
$this->query->where();
}
/**
* @test
*/
public function itShouldGetIntersectSelects()
{
$this->assertEquals(array(), $this->query->getIntersects());
$select1 = new Select('user');
$select2 = new Select('user_email');
$this->query->add($select1);
$this->query->add($select2);
$this->assertEquals(array($select1, $select2), $this->query->getIntersects());
}
}

View File

@ -0,0 +1,82 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/12/14
* Time: 7:26 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Manipulation;
use NilPortugues\Sql\QueryBuilder\Manipulation\Minus;
use NilPortugues\Sql\QueryBuilder\Manipulation\Select;
/**
* Class MinusTest.
*/
class MinusTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Minus
*/
private $query;
/**
* @var string
*/
private $exceptionClass = '\NilPortugues\Sql\QueryBuilder\Manipulation\QueryException';
/**
*
*/
protected function setUp()
{
$this->query = new Minus(new Select('user'), new Select('user_email'));
}
/**
* @test
*/
public function itShouldGetPartName()
{
$this->assertSame('MINUS', $this->query->partName());
}
/**
* @test
*/
public function itShouldThrowExceptionForUnsupportedGetTable()
{
$this->setExpectedException($this->exceptionClass);
$this->query->getTable();
}
/**
* @test
*/
public function itShouldThrowExceptionForUnsupportedGetWhere()
{
$this->setExpectedException($this->exceptionClass);
$this->query->getWhere();
}
/**
* @test
*/
public function itShouldThrowExceptionForUnsupportedWhere()
{
$this->setExpectedException($this->exceptionClass);
$this->query->where();
}
/**
* @test
*/
public function itShouldGetMinusSelects()
{
$this->assertEquals(new Select('user'), $this->query->getFirst());
$this->assertEquals(new Select('user_email'), $this->query->getSecond());
}
}

View File

@ -0,0 +1,98 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/16/14
* Time: 8:50 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Manipulation;
use NilPortugues\Sql\QueryBuilder\Manipulation\QueryFactory;
use NilPortugues\Sql\QueryBuilder\Manipulation\Select;
/**
* Class QueryFactoryTest.
*/
class QueryFactoryTest extends \PHPUnit_Framework_TestCase
{
/**
* @test
*/
public function itShouldCreateSelectObject()
{
$className = '\NilPortugues\Sql\QueryBuilder\Manipulation\Select';
$this->assertInstanceOf($className, QueryFactory::createSelect());
}
/**
* @test
*/
public function itShouldCreateInsertObject()
{
$className = '\NilPortugues\Sql\QueryBuilder\Manipulation\Insert';
$this->assertInstanceOf($className, QueryFactory::createInsert());
}
/**
* @test
*/
public function itShouldCreateUpdateObject()
{
$className = '\NilPortugues\Sql\QueryBuilder\Manipulation\Update';
$this->assertInstanceOf($className, QueryFactory::createUpdate());
}
/**
* @test
*/
public function itShouldCreateDeleteObject()
{
$className = '\NilPortugues\Sql\QueryBuilder\Manipulation\Delete';
$this->assertInstanceOf($className, QueryFactory::createDelete());
}
/**
* @test
*/
public function itShouldCreateMinusObject()
{
$className = '\NilPortugues\Sql\QueryBuilder\Manipulation\Minus';
$this->assertInstanceOf($className, QueryFactory::createMinus(new Select('table1'), new Select('table2')));
}
/**
* @test
*/
public function itShouldCreateUnionObject()
{
$className = '\NilPortugues\Sql\QueryBuilder\Manipulation\Union';
$this->assertInstanceOf($className, QueryFactory::createUnion());
}
/**
* @test
*/
public function itShouldCreateUnionAllObject()
{
$className = '\NilPortugues\Sql\QueryBuilder\Manipulation\UnionAll';
$this->assertInstanceOf($className, QueryFactory::createUnionAll());
}
/**
* @test
*/
public function itShouldCreateWhereObject()
{
$mockClass = '\NilPortugues\Sql\QueryBuilder\Manipulation\QueryInterface';
$query = $this->getMockBuilder($mockClass)
->disableOriginalConstructor()
->getMock();
$className = '\NilPortugues\Sql\QueryBuilder\Syntax\Where';
$this->assertInstanceOf($className, QueryFactory::createWhere($query));
}
}

View File

@ -0,0 +1,27 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/3/14
* Time: 12:58 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Manipulation\Resources;
use NilPortugues\Sql\QueryBuilder\Manipulation\AbstractBaseQuery;
/**
* Class DummyQuery.
*/
class DummyQuery extends AbstractBaseQuery
{
/**
* @return string
*/
public function partName()
{
return 'DUMMY';
}
}

View File

@ -0,0 +1,101 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/3/14
* Time: 1:36 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Manipulation;
use NilPortugues\Sql\QueryBuilder\Manipulation\Select;
use NilPortugues\Sql\QueryBuilder\Syntax\OrderBy;
/**
* Class SelectTest.
*/
class SelectTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Select
*/
private $query;
/**
*
*/
protected function setUp()
{
$this->query = new Select();
}
/**
* @test
*/
public function itShouldGetPartName()
{
$this->assertSame('SELECT', $this->query->partName());
}
/**
* @test
*/
public function itShouldSetParentOrderByAlso()
{
$columns = [
'id',
'phase_id',
'league_id',
'date',
];
$parentTable = 'events';
$this->query->setTable($parentTable);
$this->query->setColumns($columns);
$sorts = [
[
'field' => 'league_id',
'direction' => 1,
],
[
'field' => 'start_date',
'direction' => 0,
'table' => 'phases',
'joinBy' => 'phase_id',
'joinWith' => 'id',
],
[
'field' => 'date',
'direction' => 1,
],
];
if (is_array($sorts)) {
foreach ($sorts as $sort) {
$order = (int)$sort['direction'] > 0 ? OrderBy::ASC : OrderBy::DESC;
if (count($sort) == 5) {
$this->query->leftJoin(
$sort['table'],
$sort['joinBy'],
$sort['joinWith']
)->orderBy($sort['field'], $order);
} else {
$this->query->orderBy($sort['field'], $order);
}
}
}
$returnedOrders = $this->query->getAllOrderBy();
foreach ($returnedOrders as $id => $orderByObject) {
$column = $orderByObject->getColumn();
$table = $column->getTable();
$expectedColumn = $sorts[$id]['field'];
$expectedTable = array_key_exists('table', $sorts[$id]) ? $sorts[$id]['table'] : $parentTable;
$expectedDirection = (int)$sorts[$id]['direction'] > 0 ? OrderBy::ASC : OrderBy::DESC;
$this->assertSame($expectedColumn, $column->getName());
$this->assertSame($expectedTable, $table->getName());
$this->assertSame($expectedDirection, $orderByObject->getDirection());
}
$this->assertCount(count($sorts), $returnedOrders);
}
}

View File

@ -0,0 +1,89 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/12/14
* Time: 7:26 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Manipulation;
use NilPortugues\Sql\QueryBuilder\Manipulation\UnionAll;
use NilPortugues\Sql\QueryBuilder\Manipulation\Select;
/**
* Class UnionAllTest.
*/
class UnionAllTest extends \PHPUnit_Framework_TestCase
{
/**
* @var UnionAll
*/
private $query;
/**
* @var string
*/
private $exceptionClass = '\NilPortugues\Sql\QueryBuilder\Manipulation\QueryException';
/**
*
*/
protected function setUp()
{
$this->query = new UnionAll();
}
/**
* @test
*/
public function itShouldGetPartName()
{
$this->assertSame('UNION ALL', $this->query->partName());
}
/**
* @test
*/
public function itShouldThrowExceptionForUnsupportedGetTable()
{
$this->setExpectedException($this->exceptionClass);
$this->query->getTable();
}
/**
* @test
*/
public function itShouldThrowExceptionForUnsupportedGetWhere()
{
$this->setExpectedException($this->exceptionClass);
$this->query->getWhere();
}
/**
* @test
*/
public function itShouldThrowExceptionForUnsupportedWhere()
{
$this->setExpectedException($this->exceptionClass);
$this->query->where();
}
/**
* @test
*/
public function itShouldGetIntersectSelects()
{
$this->assertEquals(array(), $this->query->getUnions());
$select1 = new Select('user');
$select2 = new Select('user_email');
$this->query->add($select1);
$this->query->add($select2);
$this->assertEquals(array($select1, $select2), $this->query->getUnions());
}
}

View File

@ -0,0 +1,89 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/12/14
* Time: 7:26 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Manipulation;
use NilPortugues\Sql\QueryBuilder\Manipulation\Union;
use NilPortugues\Sql\QueryBuilder\Manipulation\Select;
/**
* Class UnionTest.
*/
class UnionTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Union
*/
private $query;
/**
* @var string
*/
private $exceptionClass = '\NilPortugues\Sql\QueryBuilder\Manipulation\QueryException';
/**
*
*/
protected function setUp()
{
$this->query = new Union();
}
/**
* @test
*/
public function itShouldGetPartName()
{
$this->assertSame('UNION', $this->query->partName());
}
/**
* @test
*/
public function itShouldThrowExceptionForUnsupportedGetTable()
{
$this->setExpectedException($this->exceptionClass);
$this->query->getTable();
}
/**
* @test
*/
public function itShouldThrowExceptionForUnsupportedGetWhere()
{
$this->setExpectedException($this->exceptionClass);
$this->query->getWhere();
}
/**
* @test
*/
public function itShouldThrowExceptionForUnsupportedWhere()
{
$this->setExpectedException($this->exceptionClass);
$this->query->where();
}
/**
* @test
*/
public function itShouldGetIntersectSelects()
{
$this->assertEquals(array(), $this->query->getUnions());
$select1 = new Select('user');
$select2 = new Select('user_email');
$this->query->add($select1);
$this->query->add($select2);
$this->assertEquals(array($select1, $select2), $this->query->getUnions());
}
}

View File

@ -0,0 +1,73 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/3/14
* Time: 1:37 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Manipulation;
use NilPortugues\Sql\QueryBuilder\Manipulation\Update;
/**
* Class UpdateTest.
*/
class UpdateTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Update
*/
private $query;
/**
*
*/
protected function setUp()
{
$this->query = new Update();
}
/**
* @test
*/
public function itShouldGetPartName()
{
$this->assertSame('UPDATE', $this->query->partName());
}
/**
* @test
*/
public function itShouldReturnLimit1()
{
$this->query->limit(1);
$this->assertSame(1, $this->query->getLimitStart());
}
/**
* @test
*/
public function itShouldReturnValues()
{
$values = ['user_id' => 1];
$this->query->setValues($values);
$this->assertSame($values, $this->query->getValues());
}
/**
* @test
*/
public function itShouldSetNullableValues()
{
$values = ['user_id' => 1, 'description' => null, 'isVisible' => false];
$this->query->setValues($values);
$this->assertSame($values, $this->query->getValues());
}
}

View File

@ -0,0 +1,96 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/2/14
* Time: 11:54 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Syntax;
use NilPortugues\Sql\QueryBuilder\Syntax\Column;
use NilPortugues\Sql\QueryBuilder\Syntax\Table;
/**
* Class ColumnTest.
*/
class ColumnTest extends \PHPUnit_Framework_TestCase
{
/**
* @var string
*/
protected $tableClass = '\NilPortugues\Sql\QueryBuilder\Syntax\Table';
/**
* @var string
*/
protected $queryException = '\NilPortugues\Sql\QueryBuilder\Manipulation\QueryException';
/**
* @test
*/
public function itShouldReturnPartName()
{
$column = new Column('id', 'user');
$this->assertSame('COLUMN', $column->partName());
}
/**
* @test
*/
public function itShouldConstruct()
{
$column = new Column('id', 'user');
$this->assertEquals('id', $column->getName());
$this->assertInstanceOf($this->tableClass, $column->getTable());
$this->assertEquals('user', $column->getTable()->getName());
}
/**
* @test
*/
public function itShouldSetColumnName()
{
$column = new Column('id', 'user');
$column->setName('user_id');
$this->assertEquals('user_id', $column->getName());
}
/**
* @test
*/
public function itShouldSetTableName()
{
$tableName = 'user';
$column = new Column('id', $tableName);
$column->setTable(new Table($tableName));
$this->assertInstanceOf($this->tableClass, $column->getTable());
$this->assertEquals($tableName, $column->getTable()->getName());
}
/**
* @test
*/
public function itShouldSetAliasName()
{
$column = new Column('user_id', 'user', 'userId');
$this->assertEquals('userId', $column->getAlias());
}
/**
* @test
*/
public function itShouldThrowExceptionIfAliasOnAllSelection()
{
$this->setExpectedException($this->queryException);
new Column('*', 'user', 'userId');
}
}

View File

@ -0,0 +1,63 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/3/14
* Time: 12:07 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Syntax;
use NilPortugues\Sql\QueryBuilder\Syntax\Column;
use NilPortugues\Sql\QueryBuilder\Syntax\OrderBy;
/**
* Class OrderByTest.
*/
class OrderByTest extends \PHPUnit_Framework_TestCase
{
/**
* @var string
*/
protected $columnClass = '\NilPortugues\Sql\QueryBuilder\Syntax\Column';
/**
* @test
*/
public function itShouldConstructOrderBy()
{
$column = new Column('registration_date', 'user');
$order = new OrderBy($column, OrderBy::ASC);
$this->assertInstanceOf($this->columnClass, $order->getColumn());
$this->assertEquals(OrderBy::ASC, $order->getDirection());
}
/**
* @test
*/
public function itShouldGetOrderByDirection()
{
$column = new Column('registration_date', 'user');
$order = new OrderBy($column, OrderBy::ASC);
$this->assertEquals(OrderBy::ASC, $order->getDirection());
$order->setDirection(OrderBy::DESC);
$this->assertEquals(OrderBy::DESC, $order->getDirection());
}
/**
* @test
*/
public function itShouldThrowExceptionIfDirectionNotValid()
{
$column = new Column('registration_date', 'user');
$order = new OrderBy($column, OrderBy::ASC);
$this->setExpectedException('\InvalidArgumentException');
$order->setDirection('this is not a valid direction');
}
}

View File

@ -0,0 +1,97 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/2/14
* Time: 11:34 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Syntax;
use NilPortugues\Sql\QueryBuilder\Syntax\Table;
/**
* Class TableTest.
*/
class TableTest extends \PHPUnit_Framework_TestCase
{
/**
* @test
*/
public function testConstruct()
{
$table = new Table('user');
$this->assertEquals('user', $table->getName());
}
/**
* @test
*/
public function itShouldReturnNullIfTableNameHasNoAlias()
{
$table = new Table('user');
$this->assertNull($table->getAlias());
}
/**
* @test
*/
public function itShouldReturnAliasIfTableNameAliasHasBeenSet()
{
$table = new Table('user');
$table->setAlias('u');
$this->assertEquals('u', $table->getAlias());
}
/**
* @test
*/
public function itShouldReturnNullIfSchemaNotSet()
{
$table = new Table('user');
$this->assertNull($table->getSchema());
}
/**
* @test
*/
public function itShouldReturnSchemaIfSchemaHasValue()
{
$table = new Table('user', 'website');
$this->assertEquals('website', $table->getSchema());
}
/**
* @test
*/
public function itShouldReturnTheCompleteName()
{
$table = new Table('user');
$table->setAlias('p');
$table->setSchema('website');
$this->assertEquals('website.user AS p', $table->getCompleteName());
}
/**
* @test
*/
public function itShouldReturnFalseOnIsView()
{
$table = new Table('user_status');
$this->assertFalse($table->isView());
}
/**
* @test
*/
public function itShouldReturnTrueOnIsView()
{
$table = new Table('user_status');
$table->setView(true);
$this->assertTrue($table->isView());
}
}

View File

@ -0,0 +1,419 @@
<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 6/3/14
* Time: 12:31 AM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Syntax;
use NilPortugues\Sql\QueryBuilder\Manipulation\Select;
use NilPortugues\Sql\QueryBuilder\Syntax\Where;
use NilPortugues\Tests\Sql\QueryBuilder\Manipulation\Resources\DummyQuery;
/**
* Class WhereTest.
*/
class WhereTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Where
*/
protected $where;
/**
* @var string
*/
protected $whereClass = '\NilPortugues\Sql\QueryBuilder\Syntax\Where';
/**
* @var string
*/
protected $columnClass = '\NilPortugues\Sql\QueryBuilder\Syntax\Column';
/**
* @var string
*/
protected $queryException = '\NilPortugues\Sql\QueryBuilder\Manipulation\QueryException';
/**
*
*/
protected function setUp()
{
$query = new DummyQuery();
$query->setTable('users');
$this->where = new Where($query);
}
/**
* @test
*/
public function itShouldBeCloneable()
{
$this->assertEquals($this->where, clone $this->where);
}
/**
* @test
*/
public function itShouldBeEmptyOnConstruct()
{
$this->assertTrue($this->where->isEmpty());
}
/**
* @test
*/
public function itShouldReturnDefaultConjuctionAnd()
{
$this->assertSame('AND', $this->where->getConjunction());
}
/**
* @test
*/
public function itShouldReturnDefaultSubWhere()
{
$this->assertSame(array(), $this->where->getSubWheres());
}
/**
* @test
*/
public function itShouldReturnSubFilter()
{
$filter = $this->where->subWhere();
$this->assertSame(array(), $filter->getSubWheres());
$this->assertInstanceOf($this->whereClass, $filter);
}
/**
* @test
*/
public function itShouldReturnTheSameEqAndEqual()
{
$column = 'user_id';
$value = 1;
$this->assertSame(
$this->where->equals($column, $value),
$this->where->eq($column, $value)
);
}
/**
* @test
*/
public function itShouldNotBeEqualTo()
{
$column = 'user_id';
$value = 1;
$result = $this->where->notEquals($column, $value)->getComparisons();
$this->assertSame('<>', $result[0]['conjunction']);
$this->assertSame($column, $result[0]['subject']->getName());
$this->assertSame($value, $result[0]['target']);
}
/**
* @test
*/
public function itShouldBeGreaterThan()
{
$column = 'user_id';
$value = 1;
$result = $this->where->greaterThan($column, $value)->getComparisons();
$this->assertSame('>', $result[0]['conjunction']);
$this->assertSame($column, $result[0]['subject']->getName());
$this->assertSame($value, $result[0]['target']);
}
/**
* @test
*/
public function itShouldBeGreaterThanOrEqual()
{
$column = 'user_id';
$value = 1;
$result = $this->where->greaterThanOrEqual($column, $value)->getComparisons();
$this->assertSame('>=', $result[0]['conjunction']);
$this->assertSame($column, $result[0]['subject']->getName());
$this->assertSame($value, $result[0]['target']);
}
/**
* @test
*/
public function itShouldBeLessThan()
{
$column = 'user_id';
$value = 1;
$result = $this->where->lessThan($column, $value)->getComparisons();
$this->assertSame('<', $result[0]['conjunction']);
$this->assertSame($column, $result[0]['subject']->getName());
$this->assertSame($value, $result[0]['target']);
}
/**
* @test
*/
public function itShouldBeLessThanOrEqual()
{
$column = 'user_id';
$value = 1;
$result = $this->where->lessThanOrEqual($column, $value)->getComparisons();
$this->assertSame('<=', $result[0]['conjunction']);
$this->assertSame($column, $result[0]['subject']->getName());
$this->assertSame($value, $result[0]['target']);
}
/**
* @test
*/
public function itShouldBeLike()
{
$column = 'user_id';
$value = 1;
$result = $this->where->like($column, $value)->getComparisons();
$this->assertSame('LIKE', $result[0]['conjunction']);
$this->assertSame($column, $result[0]['subject']->getName());
$this->assertSame($value, $result[0]['target']);
}
/**
* @test
*/
public function itShouldBeNotLike()
{
$column = 'user_id';
$value = 1;
$result = $this->where->notLike($column, $value)->getComparisons();
$this->assertSame('NOT LIKE', $result[0]['conjunction']);
$this->assertSame($column, $result[0]['subject']->getName());
$this->assertSame($value, $result[0]['target']);
}
/**
* @test
*/
public function itShouldAccumulateMatchConditions()
{
$column = array('user_id');
$result = $this->where
->match($column, array(1, 2, 3))
->getMatches();
$expected = array(
0 => array(
'columns' => array('user_id'),
'values' => array(1, 2, 3),
'mode' => 'natural',
),
);
$this->assertEquals($expected, $result);
}
/**
* @test
*/
public function itShouldAccumulateMatchBooleanConditions()
{
$column = array('user_id');
$result = $this->where
->matchBoolean($column, array(1, 2, 3))
->getMatches();
$expected = array(
0 => array(
'columns' => array('user_id'),
'values' => array(1, 2, 3),
'mode' => 'boolean',
),
);
$this->assertEquals($expected, $result);
}
/**
* @test
*/
public function itShouldAccumulateMatchQueryExpansionConditions()
{
$column = array('user_id');
$result = $this->where
->matchWithQueryExpansion($column, array(1, 2, 3))
->getMatches();
$expected = array(
0 => array(
'columns' => array('user_id'),
'values' => array(1, 2, 3),
'mode' => 'query_expansion',
),
);
$this->assertEquals($expected, $result);
}
/**
* @test
*/
public function itShouldAccumulateInConditions()
{
$column = 'user_id';
$result = $this->where
->in($column, array(1, 2, 3))
->getIns();
$expected = array($column => array(1, 2, 3));
$this->assertEquals($expected, $result);
}
/**
* @test
*/
public function itShouldAccumulateNotInConditions()
{
$column = 'user_id';
$result = $this->where
->notIn($column, array(1, 2, 3))
->getNotIns();
$expected = array($column => array(1, 2, 3));
$this->assertEquals($expected, $result);
}
/**
* @test
*/
public function itShouldWriteBetweenConditions()
{
$column = 'user_id';
$result = $this->where
->between($column, 1, 2)
->getBetweens();
$this->assertInstanceOf($this->columnClass, $result[0]['subject']);
$this->assertEquals(1, $result[0]['a']);
$this->assertEquals(2, $result[0]['b']);
}
/**
* @test
*/
public function itShouldSetNullValueCondition()
{
$column = 'user_id';
$result = $this->where
->isNull($column)
->getNull();
$this->assertInstanceOf($this->columnClass, $result[0]['subject']);
}
/**
* @test
*/
public function itShouldSetIsNotNullValueCondition()
{
$column = 'user_id';
$result = $this->where
->isNotNull($column)
->getNotNull();
$this->assertInstanceOf($this->columnClass, $result[0]['subject']);
}
/**
* @test
*/
public function itShouldSetBitClauseValueCondition()
{
$column = 'user_id';
$result = $this->where
->addBitClause($column, 1)
->getBooleans();
$this->assertEquals(1, $result[0]['value']);
$this->assertInstanceOf($this->columnClass, $result[0]['subject']);
}
/**
* @test
*/
public function ItShouldChangeAndToOrOperator()
{
$result = $this->where->conjunction('OR');
$this->assertEquals('OR', $result->getConjunction());
}
/**
* @test
*/
public function itShouldThrowExceptionOnUnknownConjunction()
{
$this->setExpectedException($this->queryException);
$this->where->conjunction('NOT_VALID_CONJUNCTION');
}
/**
* @test
*/
public function itShouldSetExistsCondition()
{
$select1 = new Select('user');
$select1->where()->equals('user_id', 10);
$result = $this->where->exists($select1)->getExists();
$this->assertEquals(array($select1), $result);
}
/**
* @test
*/
public function itShouldSetNotExistsCondition()
{
$select1 = new Select('user');
$select1->where()->equals('user_id', 10);
$result = $this->where->notExists($select1)->getNotExists();
$this->assertEquals(array($select1), $result);
}
/**
* @test
*/
public function itShouldReturnLiterals()
{
$result = $this->where->asLiteral('(username is not null and status=:status)')->getComparisons();
$this->assertSame('(username is not null and status=:status)', $result[0]);
}
}