README
parent
33f9eb64f8
commit
796abb1837
|
@ -0,0 +1,183 @@
|
|||
### Зачем?
|
||||
|
||||
Зачем очередная обёртка, спросите вы? А вот зачем:
|
||||
|
||||
* Удобный select builder по мотивам MediaWiki-овского - не то, чтобы он был везде нужен,
|
||||
да и параметры экранировать, в принципе, можно и через голое PDO...
|
||||
...Но! Запросы часто нужно собирать по частям - и вот тут select builder на голых
|
||||
PHP-шных массивах очень удобен. Ну и в целом - синтаксис более краток, чем PDO.
|
||||
Но если не хочется - можно его и не использовать.
|
||||
* Удобные функции для изменения данных - insert, upsert, update, delete,
|
||||
просто по имени таблицы и переданному массиву записей
|
||||
* Автоматическое переподключение
|
||||
* Вложенные транзакции на SAVEPOINT'ах
|
||||
* Лог запросов
|
||||
|
||||
Я это использую во всех проектах примерно с момента знакомства с MediaWiki.
|
||||
|
||||
### Лицензия и автор
|
||||
|
||||
Лицензия - GPL 3.0 или более новой версии
|
||||
|
||||
Автор - Виталий Филиппов, 2012-2017
|
||||
|
||||
### Создание соединения
|
||||
|
||||
```
|
||||
$db = new DatabasePdoPgsql([
|
||||
'host' => 'localhost',
|
||||
'port' => 5432,
|
||||
'socket' => '/var/run/postgresql',
|
||||
'dbname' => '',
|
||||
'username' => '',
|
||||
'password' => '',
|
||||
'reconnect' => true,
|
||||
'tableNames' => [],
|
||||
'queryLogFile' => '',
|
||||
'autoBegin' => false,
|
||||
'ondestroy' => 'commit',
|
||||
'init' => [],
|
||||
]);
|
||||
```
|
||||
|
||||
Опции в основном говорят сами за себя. Неочевидные:
|
||||
|
||||
* tableNames - маппинг имён таблиц (поддерживается замена имён таблиц на уровне обёртки).
|
||||
* queryLogFile - путь к файлу с логом запросов
|
||||
* autoBegin - начинать ли транзакцию автоматически при первом запросе
|
||||
* ondestroy - что делать при уничтожении объекта с активной транзакцией:
|
||||
применить ("commit") или откатить ("rollback").
|
||||
|
||||
### "SELECT BUILDER"
|
||||
|
||||
`$db->select($tables, $fields, $where, $options, $format)`
|
||||
|
||||
Пример:
|
||||
|
||||
```
|
||||
$db->select(
|
||||
[
|
||||
'u' => 'users',
|
||||
'i' => [ 'INNER', 'instances', [ 'i.id=u.instance_id' ] ]
|
||||
],
|
||||
'u.*, i.name instance_name',
|
||||
[
|
||||
'u.reg_timestamp > ?' => time(),
|
||||
'u.reg_timestamp < date_part(\'epoch\', now())',
|
||||
'u.key' => [ 'A', 'B', 'C' ], // превратится в условие: u.key IN ('A', 'B', 'C')
|
||||
],
|
||||
[
|
||||
'FOR UPDATE', // или 'FOR SHARE' или 'LOCK IN SHARE MODE'
|
||||
'GROUP BY' => 'u.id',
|
||||
'ORDER BY' => [ 'u.reg_timestamp' => 'ASC' ],
|
||||
'LIMIT' => 10,
|
||||
'OFFSET' => 10,
|
||||
],
|
||||
MS_HASH
|
||||
);
|
||||
```
|
||||
|
||||
По сути - это весь базовый синтаксис select builder'а. JOIN'ы могут быть LEFT, могут быть вложенными.
|
||||
|
||||
MS_* - формат возврата. По умолчанию возвращает массив записей БД в ассоциативном формате. MS_HASH -
|
||||
значение по умолчанию, его как 4-й параметр можно не указывать, либо вместо MS_HASH можно указать:
|
||||
|
||||
- MS_VALUE - тогда вернётся только 1-е значение 1-й строки (скаляр)
|
||||
- MS_ROW - вернётся только 1-я строка (в ассоциативном формате)
|
||||
- MS_COL - вернётся только 1-я колонка (массив скаляров)
|
||||
- MS_RESULT - вернётся объект результата (mysqli/PDO) для ручной обработки, результат при этом не буферизуется
|
||||
|
||||
Можно вызвать `$db->select("SELECT * FROM users", MS_HASH)` - это просто выполнит текстовый запрос.
|
||||
В этом случае вторым параметром обязатело передать одну из констант MS_*.
|
||||
|
||||
Также вместо `$db->select($tables, $fields, $where, $options)` можно вызвать с теми же параметрами
|
||||
`$db->select_builder($tables, $fields, $where, $options)` - он вернёт текст запроса.
|
||||
|
||||
### UPSERT
|
||||
|
||||
`$db->upsert('users', [ [ 'email' => 'vasya@pupkin.ru', 'name' => 'vasya', 'surname' => 'pupkin' ] ], [ 'email' ])` - UPSERT.
|
||||
|
||||
Для тех, кто знает PostgreSQL - это INSERT ... ON CONFLICT (email) DO UPDATE ...
|
||||
|
||||
Третий параметр - список полей уникального ключа, по которым проверяет конфликт.
|
||||
|
||||
Для тех, кто знает MySQL - аналог REPLACE или точнее INSERT ... ON DUPLICATE KEY UPDATE ...
|
||||
|
||||
### Другие функции
|
||||
|
||||
`$db->quote($value)` - экранирование значения
|
||||
|
||||
`$db->query("TRUNCATE users")` - выполнение произвольных запросов без чтения результата (только true/false)
|
||||
|
||||
`$db->insert_row('users', [ 'name' => 'vasya', 'surname' => 'pupkin' ])` - вставка одной строки, вернёт ID
|
||||
|
||||
`$db->insert('users', [ [ 'name' => 'vasya', 'surname' => 'pupkin' ], ... ])` - вставка множества строк
|
||||
|
||||
`$db->update('users', [ 'name' => 'vasya' ], [ 'id' => 1 ])` - эквивалентно UPDATE users SET name='vasya' WHERE id=1
|
||||
|
||||
Плюшка: в качестве первого параметра можно передавать JOIN'енные таблицы, в PostgreSQL
|
||||
это будет корректно превращено в конструкцию UPDATE table FROM ...
|
||||
|
||||
Например:
|
||||
|
||||
```
|
||||
$db->update(
|
||||
[ 'u' => 'users', 'i' => [ 'INNER', 'instances', [ 'i.id=u.instance_id'] ] ],
|
||||
'name' => 'vasya',
|
||||
[ 'i.domain' => 'pupkin.ru' ]
|
||||
);
|
||||
```
|
||||
|
||||
`$db->delete('users', [ 'id' => [ 1, 2, 3 ] ])` - удаление по условию
|
||||
|
||||
В качестве первого параметра, как и в update(), можно передавать JOIN'енные таблицы, в PostgreSQL
|
||||
это будет корректно превращено в конструкцию DELETE ... USING.
|
||||
|
||||
### Транзакции
|
||||
|
||||
`$db->begin(), $db->commit(), $db->rollback(), $db->commitAll(), $db->rollbackAll()`
|
||||
|
||||
Транзакции. Могут быть вложенные, т.е. можно несколько раз подряд сделать begin и commit/rollback.
|
||||
Вложенные транзакции превращаются в SAVEPOINT'ы.
|
||||
|
||||
`$db->commitAll()` коммитит транзакцию со всеми активными SAVEPOINT'ами,
|
||||
|
||||
`$db->rollbackAll()` откатывает транзакцию со всеми активными SAVEPOINT'ами.
|
||||
|
||||
### VALUES
|
||||
|
||||
Дополнительная плюшка: обёртка для синтаксиса "inline таблиц" PostgreSQL.
|
||||
|
||||
```
|
||||
$users = $db->select(
|
||||
[
|
||||
'd' => $db->values_table([
|
||||
[ 'social_network' => 'vk.com', 'date' => '2017-01-01' ],
|
||||
[ 'social_network' => 'facebook.com', 'date' => '2017-01-02' ],
|
||||
]),
|
||||
'u' => [ 'INNER', 'users', [ 'u.social_network=d.social_network', 'u.reg_date=d.date' ] ],
|
||||
],
|
||||
'u.*',
|
||||
[]
|
||||
);
|
||||
```
|
||||
|
||||
Эквивалентно
|
||||
|
||||
```
|
||||
SELECT u.*
|
||||
FROM (VALUES ('vk.com','2017-01-01'),('facebook.com','2017-01-02')) AS d ("social_network","date")
|
||||
INNER JOIN users u ON (u.social_network=d.social_network) AND (u.reg_date=d.date)
|
||||
```
|
||||
|
||||
### MySQL
|
||||
|
||||
Всё вышеописанное, кроме VALUES, актуально и для MySQL - синтаксис точно такой же.
|
||||
|
||||
Дополнительная плюшка в MySQL - это CALC_FOUND_ROWS и функция $db->found_rows(), возвращающая
|
||||
количество найденных строк. Фактически эту опцию можно использоать и в PdoPgsql-драйвере - он пробует
|
||||
эмулировать её через COUNT(*) OVER() - но это не очень красивое решение.
|
||||
|
||||
И ещё одна плюшка - возможность использования той же самой обёртки для общения с SphinxSearch,
|
||||
работающему по протоколу SphinxQL - в ней есть поддержка sphinx-специфичных опций (но за описаниями
|
||||
лучше залезьте в код).
|
Loading…
Reference in New Issue