1
0
mirror of https://github.com/dg/dibi.git synced 2025-08-31 01:39:46 +02:00

Compare commits

...

23 Commits

Author SHA1 Message Date
David Grudl
95c3f72a17 Released version 4.2.2 2021-04-21 13:56:00 +02:00
David Grudl
d71caf0c75 Row: fixed ?? usage 2021-04-21 13:54:59 +02:00
Miloslav Hůla
3066fea2aa Connection: begin(), commit() & rollback() calls are forbidden in transaction() 2021-04-05 16:50:15 +02:00
Miloslav Hůla
b00e556289 Connection::transtaction() call can be nested 2021-04-05 16:50:15 +02:00
Miloslav Hůla
877dffd460 tests: use test() helper 2021-04-05 13:37:16 +02:00
Miloslav Hůla
7049949b14 Connection::transaction(): pass self as a callback argument 2021-04-05 13:37:16 +02:00
Miloslav Hůla
771e846a62 tests: Sqlite3 driver fix 2021-04-05 13:37:16 +02:00
David Grudl
4e056c52dd updated appveyor.yml 2021-03-10 16:53:34 +01:00
David Grudl
40ad77cf5f SqlsrvDriver: workaround for "Driver's SQLSetConnectAttr failed on ODBC <=13" bug 2021-03-10 16:42:33 +01:00
David Grudl
d09b462eef Released version 4.2.1 2021-03-01 15:17:15 +01:00
David Grudl
4c796a0e0f readme: added support me 2021-02-05 21:53:00 +01:00
Jan Kuchař
304af5185d PostgreSQL driver: escaping of save point name (#383) 2021-02-05 21:52:45 +01:00
David Grudl
e046935137 Strict: refactoring 2020-12-30 12:44:04 +01:00
Jan Kuchař
1a77048225 PostgreReflector: removed version check (#381) 2020-12-23 10:31:03 +01:00
David Grudl
ca74488636 Released version 4.2.0 2020-11-25 21:02:22 +01:00
David Grudl
07f994a0b5 added Connection::transaction() 2020-11-25 20:59:58 +01:00
David Grudl
5fa5acb724 Connection: added option [result][formatTimeInterval] that sets time-interval column decoding 2020-11-02 15:28:28 +01:00
David Grudl
98563d8165 Connection: added option [result][normalize] [Closes #367] 2020-11-02 15:28:28 +01:00
David Grudl
c464960239 Connection, Result: added format 'native' 2020-11-02 15:28:28 +01:00
David Grudl
a9e90d0b22 Connection, Results: refactorings, added Result::setFormats() 2020-11-02 15:28:28 +01:00
David Grudl
decb30de1e Connection::translateArg() removed (BC break) 2020-11-02 15:28:28 +01:00
David Grudl
f4e71e8855 requires PHP 7.2 2020-11-02 15:28:28 +01:00
David Grudl
39f59e0f08 opened 4.2-dev 2020-11-02 15:28:28 +01:00
17 changed files with 244 additions and 81 deletions

View File

@@ -1,6 +1,5 @@
language: php language: php
php: php:
- 7.1
- 7.2 - 7.2
- 7.3 - 7.3
- 7.4 - 7.4

View File

@@ -15,17 +15,17 @@ init:
- SET ANSICON=121x90 (121x90) - SET ANSICON=121x90 (121x90)
install: install:
# Install PHP 7.1 # Install PHP 7.2
- IF EXIST c:\php7 (SET PHP=0) ELSE (SET PHP=1) - IF EXIST c:\php7 (SET PHP=0) ELSE (SET PHP=1)
- IF %PHP%==1 mkdir c:\php7 - IF %PHP%==1 mkdir c:\php7
- IF %PHP%==1 cd c:\php7 - IF %PHP%==1 cd c:\php7
- IF %PHP%==1 curl https://windows.php.net/downloads/releases/archives/php-7.1.5-Win32-VC14-x64.zip --output php.zip - IF %PHP%==1 curl https://windows.php.net/downloads/releases/archives/php-7.2.18-Win32-VC15-x64.zip --output php.zip
- IF %PHP%==1 7z x php.zip >nul - IF %PHP%==1 7z x php.zip >nul
- IF %PHP%==1 echo extension_dir=ext >> php.ini - IF %PHP%==1 echo extension_dir=ext >> php.ini
- IF %PHP%==1 echo extension=php_openssl.dll >> php.ini - IF %PHP%==1 echo extension=php_openssl.dll >> php.ini
- IF %PHP%==1 appveyor DownloadFile https://files.nette.org/misc/php-sqlsrv.zip - IF %PHP%==1 curl https://github.com/microsoft/msphpsql/releases/download/v5.8.0/Windows-7.2.zip -L --output sqlsrv.zip
- IF %PHP%==1 7z x php-sqlsrv.zip >nul - IF %PHP%==1 7z x sqlsrv.zip >nul
- IF %PHP%==1 copy SQLSRV\php_sqlsrv_71_ts.dll ext\php_sqlsrv_71_ts.dll - IF %PHP%==1 copy Windows-7.2\x64\php_sqlsrv_72_ts.dll ext\php_sqlsrv_ts.dll
- IF %PHP%==1 del /Q *.zip - IF %PHP%==1 del /Q *.zip
# Install Microsoft Access Database Engine x64 # Install Microsoft Access Database Engine x64

View File

@@ -11,7 +11,7 @@
} }
], ],
"require": { "require": {
"php": ">=7.1" "php": ">=7.2"
}, },
"require-dev": { "require-dev": {
"tracy/tracy": "~2.2", "tracy/tracy": "~2.2",
@@ -31,7 +31,7 @@
}, },
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "4.1-dev" "dev-master": "4.2-dev"
} }
} }
} }

View File

@@ -15,12 +15,14 @@ Database access functions in PHP are not standardised. This library
hides the differences between them, and above all, it gives you a very handy interface. hides the differences between them, and above all, it gives you a very handy interface.
Support Project Support Me
--------------- ----------
Do you like Dibi? Are you looking forward to the new features? Do you like Dibi? Are you looking forward to the new features?
[![Donate](https://files.nette.org/icons/donation-1.svg?)](https://nette.org/make-donation?to=dibi) [![Buy me a coffee](https://files.nette.org/icons/donation-3.svg)](https://github.com/sponsors/dg)
Thank you!
Installation Installation
@@ -32,7 +34,7 @@ Install Dibi via Composer:
composer require dibi/dibi composer require dibi/dibi
``` ```
The Dibi 4.1 requires PHP version 7.1 and supports PHP up to 8.0. The Dibi 4.2 requires PHP version 7.2 and supports PHP up to 8.0.
Usage Usage

View File

@@ -28,6 +28,9 @@ class Connection implements IConnection
/** @var array Current connection configuration */ /** @var array Current connection configuration */
private $config; private $config;
/** @var string[] resultset formats */
private $formats;
/** @var Driver|null */ /** @var Driver|null */
private $driver; private $driver;
@@ -37,17 +40,26 @@ class Connection implements IConnection
/** @var HashMap Substitutes for identifiers */ /** @var HashMap Substitutes for identifiers */
private $substitutes; private $substitutes;
private $transactionDepth = 0;
/** /**
* Connection options: (see driver-specific options too) * Connection options: (see driver-specific options too)
* - lazy (bool) => if true, connection will be established only when required * - lazy (bool) => if true, connection will be established only when required
* - result (array) => result set options * - result (array) => result set options
* - formatDateTime => date-time format (if empty, DateTime objects will be returned) * - normalize => normalizes result fields (default: true)
* - formatJson => json format ( * - formatDateTime => date-time format
* "string" for leaving value as is, * empty for decoding as Dibi\DateTime (default)
* "object" for decoding json as \stdClass, * "..." formatted according to given format, see https://www.php.net/manual/en/datetime.format.php
* "array" for decoding json as an array - default * "native" for leaving value as is
* ) * - formatTimeInterval => time-interval format
* empty for decoding as DateInterval (default)
* "..." formatted according to given format, see https://www.php.net/manual/en/dateinterval.format.php
* "native" for leaving value as is
* - formatJson => json format
* "array" for decoding json as an array (default)
* "object" for decoding json as \stdClass
* "native" for leaving value as is
* - profiler (array) * - profiler (array)
* - run (bool) => enable profiler? * - run (bool) => enable profiler?
* - file => file to log * - file => file to log
@@ -65,9 +77,15 @@ class Connection implements IConnection
Helpers::alias($config, 'result|formatDateTime', 'resultDateTime'); Helpers::alias($config, 'result|formatDateTime', 'resultDateTime');
$config['driver'] = $config['driver'] ?? 'mysqli'; $config['driver'] = $config['driver'] ?? 'mysqli';
$config['name'] = $name; $config['name'] = $name;
$config['result']['formatJson'] = $config['result']['formatJson'] ?? 'array';
$this->config = $config; $this->config = $config;
$this->formats = [
Type::DATE => $this->config['result']['formatDate'],
Type::DATETIME => $this->config['result']['formatDateTime'],
Type::JSON => $this->config['result']['formatJson'] ?? 'array',
Type::TIME_INTERVAL => $this->config['result']['formatTimeInterval'] ?? null,
];
// profiler // profiler
if (isset($config['profiler']['file']) && (!isset($config['profiler']['run']) || $config['profiler']['run'])) { if (isset($config['profiler']['file']) && (!isset($config['profiler']['run']) || $config['profiler']['run'])) {
$filter = $config['profiler']['filter'] ?? Event::QUERY; $filter = $config['profiler']['filter'] ?? Event::QUERY;
@@ -200,7 +218,7 @@ class Connection implements IConnection
*/ */
final public function query(...$args): Result final public function query(...$args): Result
{ {
return $this->nativeQuery($this->translateArgs($args)); return $this->nativeQuery($this->translate(...$args));
} }
@@ -211,7 +229,10 @@ class Connection implements IConnection
*/ */
final public function translate(...$args): string final public function translate(...$args): string
{ {
return $this->translateArgs($args); if (!$this->driver) {
$this->connect();
}
return (clone $this->translator)->translate($args);
} }
@@ -222,7 +243,7 @@ class Connection implements IConnection
final public function test(...$args): bool final public function test(...$args): bool
{ {
try { try {
Helpers::dump($this->translateArgs($args)); Helpers::dump($this->translate(...$args));
return true; return true;
} catch (Exception $e) { } catch (Exception $e) {
@@ -243,19 +264,7 @@ class Connection implements IConnection
*/ */
final public function dataSource(...$args): DataSource final public function dataSource(...$args): DataSource
{ {
return new DataSource($this->translateArgs($args), $this); return new DataSource($this->translate(...$args), $this);
}
/**
* Generates SQL query.
*/
protected function translateArgs(array $args): string
{
if (!$this->driver) {
$this->connect();
}
return (clone $this->translator)->translate($args);
} }
@@ -328,6 +337,10 @@ class Connection implements IConnection
*/ */
public function begin(string $savepoint = null): void public function begin(string $savepoint = null): void
{ {
if ($this->transactionDepth !== 0) {
throw new \LogicException(__METHOD__ . '() call is forbidden inside a transaction() callback');
}
if (!$this->driver) { if (!$this->driver) {
$this->connect(); $this->connect();
} }
@@ -352,6 +365,10 @@ class Connection implements IConnection
*/ */
public function commit(string $savepoint = null): void public function commit(string $savepoint = null): void
{ {
if ($this->transactionDepth !== 0) {
throw new \LogicException(__METHOD__ . '() call is forbidden inside a transaction() callback');
}
if (!$this->driver) { if (!$this->driver) {
$this->connect(); $this->connect();
} }
@@ -376,6 +393,10 @@ class Connection implements IConnection
*/ */
public function rollback(string $savepoint = null): void public function rollback(string $savepoint = null): void
{ {
if ($this->transactionDepth !== 0) {
throw new \LogicException(__METHOD__ . '() call is forbidden inside a transaction() callback');
}
if (!$this->driver) { if (!$this->driver) {
$this->connect(); $this->connect();
} }
@@ -395,15 +416,42 @@ class Connection implements IConnection
} }
/**
* @return mixed
*/
public function transaction(callable $callback)
{
if ($this->transactionDepth === 0) {
$this->begin();
}
$this->transactionDepth++;
try {
$res = $callback($this);
} catch (\Throwable $e) {
$this->transactionDepth--;
if ($this->transactionDepth === 0) {
$this->rollback();
}
throw $e;
}
$this->transactionDepth--;
if ($this->transactionDepth === 0) {
$this->commit();
}
return $res;
}
/** /**
* Result set factory. * Result set factory.
*/ */
public function createResultSet(ResultDriver $resultDriver): Result public function createResultSet(ResultDriver $resultDriver): Result
{ {
$res = new Result($resultDriver); return (new Result($resultDriver, $this->config['result']['normalize'] ?? true))
return $res->setFormat(Type::DATE, $this->config['result']['formatDate']) ->setFormats($this->formats);
->setFormat(Type::DATETIME, $this->config['result']['formatDateTime'])
->setFormat(Type::JSON, $this->config['result']['formatJson']);
} }

View File

@@ -188,7 +188,7 @@ class PostgreDriver implements Dibi\Driver
*/ */
public function begin(string $savepoint = null): void public function begin(string $savepoint = null): void
{ {
$this->query($savepoint ? "SAVEPOINT $savepoint" : 'START TRANSACTION'); $this->query($savepoint ? "SAVEPOINT {$this->escapeIdentifier($savepoint)}" : 'START TRANSACTION');
} }
@@ -198,7 +198,7 @@ class PostgreDriver implements Dibi\Driver
*/ */
public function commit(string $savepoint = null): void public function commit(string $savepoint = null): void
{ {
$this->query($savepoint ? "RELEASE SAVEPOINT $savepoint" : 'COMMIT'); $this->query($savepoint ? "RELEASE SAVEPOINT {$this->escapeIdentifier($savepoint)}" : 'COMMIT');
} }
@@ -208,7 +208,7 @@ class PostgreDriver implements Dibi\Driver
*/ */
public function rollback(string $savepoint = null): void public function rollback(string $savepoint = null): void
{ {
$this->query($savepoint ? "ROLLBACK TO SAVEPOINT $savepoint" : 'ROLLBACK'); $this->query($savepoint ? "ROLLBACK TO SAVEPOINT {$this->escapeIdentifier($savepoint)}" : 'ROLLBACK');
} }

View File

@@ -28,9 +28,6 @@ class PostgreReflector implements Dibi\Reflector
public function __construct(Dibi\Driver $driver, string $version) public function __construct(Dibi\Driver $driver, string $version)
{ {
if ($version < 7.4) {
throw new Dibi\DriverException('Reflection requires PostgreSQL 7.4 and newer.');
}
$this->driver = $driver; $this->driver = $driver;
$this->version = $version; $this->version = $version;
} }

View File

@@ -63,11 +63,13 @@ class SqlsrvDriver implements Dibi\Driver
$options['UID'] = (string) $options['UID']; $options['UID'] = (string) $options['UID'];
$options['Database'] = (string) $options['Database']; $options['Database'] = (string) $options['Database'];
sqlsrv_configure('WarningsReturnAsErrors', 0);
$this->connection = sqlsrv_connect($config['host'], $options); $this->connection = sqlsrv_connect($config['host'], $options);
sqlsrv_configure('WarningsReturnAsErrors', 1);
} }
if (!is_resource($this->connection)) { if (!is_resource($this->connection)) {
$info = sqlsrv_errors(); $info = sqlsrv_errors(SQLSRV_ERR_ERRORS);
throw new Dibi\DriverException($info[0]['message'], $info[0]['code']); throw new Dibi\DriverException($info[0]['message'], $info[0]['code']);
} }
$this->version = sqlsrv_server_info($this->connection)['SQLServerVersion']; $this->version = sqlsrv_server_info($this->connection)['SQLServerVersion'];

View File

@@ -41,11 +41,13 @@ class Result implements IDataSource
private $formats = []; private $formats = [];
public function __construct(ResultDriver $driver) public function __construct(ResultDriver $driver, bool $normalize = true)
{ {
$this->driver = $driver; $this->driver = $driver;
if ($normalize) {
$this->detectTypes(); $this->detectTypes();
} }
}
/** /**
@@ -454,8 +456,12 @@ class Result implements IDataSource
continue; continue;
} }
$value = $row[$key]; $value = $row[$key];
$format = $this->formats[$type] ?? null;
if ($type === Type::TEXT) { if ($type === null || $format === 'native') {
$row[$key] = $value;
} elseif ($type === Type::TEXT) {
$row[$key] = (string) $value; $row[$key] = (string) $value;
} elseif ($type === Type::INTEGER) { } elseif ($type === Type::INTEGER) {
@@ -485,17 +491,16 @@ class Result implements IDataSource
} elseif ($type === Type::DATETIME || $type === Type::DATE || $type === Type::TIME) { } elseif ($type === Type::DATETIME || $type === Type::DATE || $type === Type::TIME) {
if ($value && substr((string) $value, 0, 3) !== '000') { // '', null, false, '0000-00-00', ... if ($value && substr((string) $value, 0, 3) !== '000') { // '', null, false, '0000-00-00', ...
$value = new DateTime($value); $value = new DateTime($value);
$row[$key] = empty($this->formats[$type]) $row[$key] = $format ? $value->format($format) : $value;
? $value
: $value->format($this->formats[$type]);
} else { } else {
$row[$key] = null; $row[$key] = null;
} }
} elseif ($type === Type::TIME_INTERVAL) { } elseif ($type === Type::TIME_INTERVAL) {
preg_match('#^(-?)(\d+)\D(\d+)\D(\d+)\z#', $value, $m); preg_match('#^(-?)(\d+)\D(\d+)\D(\d+)\z#', $value, $m);
$row[$key] = new \DateInterval("PT$m[2]H$m[3]M$m[4]S"); $value = new \DateInterval("PT$m[2]H$m[3]M$m[4]S");
$row[$key]->invert = (int) (bool) $m[1]; $value->invert = (int) (bool) $m[1];
$row[$key] = $format ? $value->format($format) : $value;
} elseif ($type === Type::BINARY) { } elseif ($type === Type::BINARY) {
$row[$key] = is_string($value) $row[$key] = is_string($value)
@@ -503,15 +508,12 @@ class Result implements IDataSource
: $value; : $value;
} elseif ($type === Type::JSON) { } elseif ($type === Type::JSON) {
if ($this->formats[$type] === 'string') { if ($format === 'string') { // back compatibility with 'native'
$row[$key] = $value; $row[$key] = $value;
} else { } else {
$row[$key] = json_decode($value, $this->formats[$type] === 'array'); $row[$key] = json_decode($value, $format === 'array');
} }
} elseif ($type === null) {
$row[$key] = $value;
} else { } else {
throw new \RuntimeException('Unexpected type ' . $type); throw new \RuntimeException('Unexpected type ' . $type);
} }
@@ -549,7 +551,7 @@ class Result implements IDataSource
/** /**
* Sets date format. * Sets type format.
*/ */
final public function setFormat(string $type, ?string $format): self final public function setFormat(string $type, ?string $format): self
{ {
@@ -558,6 +560,16 @@ class Result implements IDataSource
} }
/**
* Sets type formats.
*/
final public function setFormats(array $formats): self
{
$this->formats = $formats;
return $this;
}
/** /**
* Returns data format. * Returns data format.
*/ */

View File

@@ -53,6 +53,12 @@ class Row implements \ArrayAccess, \IteratorAggregate, \Countable
} }
public function __isset(string $key): bool
{
return false;
}
/********************* interfaces ArrayAccess, Countable & IteratorAggregate ****************d*g**/ /********************* interfaces ArrayAccess, Countable & IteratorAggregate ****************d*g**/

View File

@@ -46,7 +46,7 @@ trait Strict
public static function __callStatic(string $name, array $args) public static function __callStatic(string $name, array $args)
{ {
$rc = new ReflectionClass(static::class); $rc = new ReflectionClass(static::class);
$items = array_intersect($rc->getMethods(ReflectionMethod::IS_PUBLIC), $rc->getMethods(ReflectionMethod::IS_STATIC)); $items = array_filter($rc->getMethods(\ReflectionMethod::IS_STATIC), function ($m) { return $m->isPublic(); });
$items = array_map(function ($item) { return $item->getName(); }, $items); $items = array_map(function ($item) { return $item->getName(); }, $items);
$hint = ($t = Helpers::getSuggestion($items, $name)) $hint = ($t = Helpers::getSuggestion($items, $name))
? ", did you mean $t()?" ? ", did you mean $t()?"
@@ -68,7 +68,7 @@ trait Strict
return $ret; return $ret;
} }
$rc = new ReflectionClass($this); $rc = new ReflectionClass($this);
$items = array_diff($rc->getProperties(ReflectionProperty::IS_PUBLIC), $rc->getProperties(ReflectionProperty::IS_STATIC)); $items = array_filter($rc->getProperties(ReflectionProperty::IS_PUBLIC), function ($p) { return !$p->isStatic(); });
$items = array_map(function ($item) { return $item->getName(); }, $items); $items = array_map(function ($item) { return $item->getName(); }, $items);
$hint = ($t = Helpers::getSuggestion($items, $name)) $hint = ($t = Helpers::getSuggestion($items, $name))
? ", did you mean $$t?" ? ", did you mean $$t?"
@@ -84,7 +84,7 @@ trait Strict
public function __set(string $name, $value) public function __set(string $name, $value)
{ {
$rc = new ReflectionClass($this); $rc = new ReflectionClass($this);
$items = array_diff($rc->getProperties(ReflectionProperty::IS_PUBLIC), $rc->getProperties(ReflectionProperty::IS_STATIC)); $items = array_filter($rc->getProperties(ReflectionProperty::IS_PUBLIC), function ($p) { return !$p->isStatic(); });
$items = array_map(function ($item) { return $item->getName(); }, $items); $items = array_map(function ($item) { return $item->getName(); }, $items);
$hint = ($t = Helpers::getSuggestion($items, $name)) $hint = ($t = Helpers::getSuggestion($items, $name))
? ", did you mean $$t?" ? ", did you mean $$t?"

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
* @method static void begin(string $savepoint = null) * @method static void begin(string $savepoint = null)
* @method static void commit(string $savepoint = null) * @method static void commit(string $savepoint = null)
* @method static void rollback(string $savepoint = null) * @method static void rollback(string $savepoint = null)
* @method static mixed transaction(callable $callback)
* @method static Dibi\Reflection\Database getDatabaseInfo() * @method static Dibi\Reflection\Database getDatabaseInfo()
* @method static Dibi\Fluent command() * @method static Dibi\Fluent command()
* @method static Dibi\Fluent select(...$args) * @method static Dibi\Fluent select(...$args)
@@ -44,7 +45,7 @@ class dibi
/** version */ /** version */
public const public const
VERSION = '4.1.3'; VERSION = '4.2.2';
/** sorting order */ /** sorting order */
public const public const

View File

@@ -30,21 +30,102 @@ Assert::exception(function () use ($conn) {
*/ */
$conn->begin(); test('begin() & rollback()', function () use ($conn) {
Assert::same(3, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle()); $conn->begin();
$conn->query('INSERT INTO [products]', [ Assert::same(3, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle());
$conn->query('INSERT INTO [products]', [
'title' => 'Test product', 'title' => 'Test product',
]); ]);
Assert::same(4, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle()); Assert::same(4, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle());
$conn->rollback(); $conn->rollback();
Assert::same(3, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle()); Assert::same(3, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle());
});
test('begin() & commit()', function () use ($conn) {
$conn->begin();
$conn->begin(); $conn->query('INSERT INTO [products]', [
$conn->query('INSERT INTO [products]', [
'title' => 'Test product', 'title' => 'Test product',
]); ]);
$conn->commit(); $conn->commit();
Assert::same(4, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle()); Assert::same(4, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle());
});
test('transaction() fail', function () use ($conn) {
Assert::exception(function () use ($conn) {
$conn->transaction(function (Dibi\Connection $connection) {
$connection->query('INSERT INTO [products]', [
'title' => 'Test product',
]);
throw new Exception('my exception');
});
}, \Throwable::class, 'my exception');
Assert::same(4, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle());
});
test('transaction() success', function () use ($conn) {
$conn->transaction(function (Dibi\Connection $connection) {
$connection->query('INSERT INTO [products]', [
'title' => 'Test product',
]);
});
Assert::same(5, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle());
});
test('nested transaction() call fail', function () use ($conn) {
Assert::exception(function () use ($conn) {
$conn->transaction(function (Dibi\Connection $connection) {
$connection->query('INSERT INTO [products]', [
'title' => 'Test product',
]);
$connection->transaction(function (Dibi\Connection $connection2) {
$connection2->query('INSERT INTO [products]', [
'title' => 'Test product',
]);
throw new Exception('my exception');
});
});
}, \Throwable::class, 'my exception');
Assert::same(5, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle());
});
test('nested transaction() call success', function () use ($conn) {
$conn->transaction(function (Dibi\Connection $connection) {
$connection->query('INSERT INTO [products]', [
'title' => 'Test product',
]);
$connection->transaction(function (Dibi\Connection $connection2) {
$connection2->query('INSERT INTO [products]', [
'title' => 'Test product',
]);
});
});
Assert::same(7, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle());
});
test('begin(), commit() & rollback() calls are forbidden in transaction()', function () use ($conn) {
Assert::exception(function () use ($conn) {
$conn->transaction(function (Dibi\Connection $connection) {
$connection->begin();
});
}, \LogicException::class, Dibi\Connection::class . '::begin() call is forbidden inside a transaction() callback');
Assert::exception(function () use ($conn) {
$conn->transaction(function (Dibi\Connection $connection) {
$connection->commit();
});
}, \LogicException::class, Dibi\Connection::class . '::commit() call is forbidden inside a transaction() callback');
Assert::exception(function () use ($conn) {
$conn->transaction(function (Dibi\Connection $connection) {
$connection->rollback();
});
}, \LogicException::class, Dibi\Connection::class . '::rollback() call is forbidden inside a transaction() callback');
});

View File

@@ -32,7 +32,7 @@ Assert::same(
); );
if (!in_array($config['driver'], ['sqlite', 'pdo', 'sqlsrv'], true)) { if (!in_array($config['driver'], ['sqlite', 'sqlite3', 'pdo', 'sqlsrv'], true)) {
Assert::same( Assert::same(
['products.product_id', 'orders.order_id', 'customers.name', 'xXx'], ['products.product_id', 'orders.order_id', 'customers.name', 'xXx'],
$info->getColumnNames(true) $info->getColumnNames(true)
@@ -43,7 +43,7 @@ if (!in_array($config['driver'], ['sqlite', 'pdo', 'sqlsrv'], true)) {
$columns = $info->getColumns(); $columns = $info->getColumns();
Assert::same('product_id', $columns[0]->getName()); Assert::same('product_id', $columns[0]->getName());
if (!in_array($config['driver'], ['sqlite', 'pdo', 'sqlsrv'], true)) { if (!in_array($config['driver'], ['sqlite', 'sqlite3', 'pdo', 'sqlsrv'], true)) {
Assert::same('products', $columns[0]->getTableName()); Assert::same('products', $columns[0]->getTableName());
} }
Assert::null($columns[0]->getVendorInfo('xxx')); Assert::null($columns[0]->getVendorInfo('xxx'));

View File

@@ -24,6 +24,17 @@ class MockResult extends Dibi\Result
} }
test('', function () {
$result = new MockResult;
$result->setType('col', Type::TEXT);
$result->setFormat(Type::TEXT, 'native');
Assert::same(['col' => null], $result->test(['col' => null]));
Assert::same(['col' => true], $result->test(['col' => true]));
Assert::same(['col' => false], $result->test(['col' => false]));
});
test('', function () { test('', function () {
$result = new MockResult; $result = new MockResult;
$result->setType('col', Type::BOOL); $result->setType('col', Type::BOOL);

View File

@@ -35,6 +35,10 @@ Assert::error(function () use ($row) {
Assert::false(isset($row->missing)); Assert::false(isset($row->missing));
Assert::false(isset($row['missing'])); Assert::false(isset($row['missing']));
// ??
Assert::same(123, $row->missing ?? 123);
Assert::same(123, $row['missing'] ?? 123);
// suggestions // suggestions
Assert::error(function () use ($row) { Assert::error(function () use ($row) {

View File

@@ -12,5 +12,5 @@ extension=php_pdo_pgsql.dll
extension=php_pdo_sqlite.dll extension=php_pdo_sqlite.dll
extension=php_pgsql.dll extension=php_pgsql.dll
extension=php_sqlite3.dll extension=php_sqlite3.dll
extension=php_sqlsrv_71_ts.dll extension=php_sqlsrv_ts.dll
extension=php_odbc.dll extension=php_odbc.dll