diff --git a/.github/workflows/mssql.yml b/.github/workflows/mssql.yml index 667ce8f..4341cea 100644 --- a/.github/workflows/mssql.yml +++ b/.github/workflows/mssql.yml @@ -23,7 +23,7 @@ jobs: name: PHP ${{ matrix.php }}-mssql-${{ matrix.mssql.server }} env: - extensions: pdo, pdo_sqlsrv-5.11.1 + extensions: pdo, pdo_sqlsrv-5.12 runs-on: ${{ matrix.mssql.os || 'ubuntu-latest' }} @@ -62,6 +62,11 @@ jobs: options: --name=mssql --health-cmd="/opt/mssql-tools${{ matrix.mssql.odbc-version }}/bin/sqlcmd ${{ matrix.mssql.flag }} -S localhost -U SA -P 'YourStrong!Passw0rd' -Q 'SELECT 1'" --health-interval=10s --health-timeout=5s --health-retries=3 steps: + - name: Install ODBC driver. + run: | + sudo curl https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/prod.list | sudo tee /etc/apt/sources.list.d/mssql-release.list + sudo ACCEPT_EULA=Y apt-get install -y msodbcsql18 + - name: Checkout uses: actions/checkout@v3 diff --git a/composer.json b/composer.json index a6df501..94926f7 100644 --- a/composer.json +++ b/composer.json @@ -56,7 +56,8 @@ }, "autoload-dev": { "psr-4": { - "Yiisoft\\Data\\Db\\Tests\\": "tests" + "Yiisoft\\Data\\Db\\Tests\\": "tests", + "Yiisoft\\Data\\Tests\\": "vendor/yiisoft/data/tests" }, "files": ["tests/bootstrap.php"] }, diff --git a/src/AbstractQueryDataReader.php b/src/AbstractQueryDataReader.php index 9320a3d..16644f0 100644 --- a/src/AbstractQueryDataReader.php +++ b/src/AbstractQueryDataReader.php @@ -27,6 +27,9 @@ abstract class AbstractQueryDataReader implements QueryDataReaderInterface private ?Sort $sort = null; private ?FilterInterface $filter = null; private ?FilterInterface $having = null; + /** + * @psalm-var non-negative-int|null + */ private ?int $limit = null; private int $offset = 0; diff --git a/src/Exception/NotSupportedFilterOptionException.php b/src/Exception/NotSupportedFilterOptionException.php new file mode 100644 index 0000000..27cbc36 --- /dev/null +++ b/src/Exception/NotSupportedFilterOptionException.php @@ -0,0 +1,20 @@ +getConnection(); diff --git a/tests/Base/DataTrait.php b/tests/Base/DataTrait.php new file mode 100644 index 0000000..146aeb8 --- /dev/null +++ b/tests/Base/DataTrait.php @@ -0,0 +1,115 @@ +makeConnection(); + } + + return self::$connection; + } + + protected function setUp(): void + { + $this->populateDatabase(); + } + + protected function tearDown(): void + { + $this->dropDatabase(); + } + + protected function getReader(): DataReaderInterface + { + /** @var PdoConnectionInterface $db */ + $db = $this->getConnection(); + + return new QueryDataReader((new Query($db))->from('user')); + } + + protected function assertFixtures(array $expectedFixtureIndexes, array $actualFixtures): void + { + $processedActualFixtures = []; + foreach ($actualFixtures as $fixture) { + if (is_object($fixture)) { + $fixture = json_decode(json_encode($fixture), associative: true); + } + + unset($fixture['id']); + $fixture['number'] = (int) $fixture['number']; + $fixture['balance'] = (float) $fixture['balance']; + + if ($fixture['born_at'] !== null && $this->getConnection()->getDriverName() === 'oci') { + $fixture['born_at'] = DateTime::createFromFormat('d-M-y', $fixture['born_at'])->format('Y-m-d'); + } + + $processedActualFixtures[$fixture['number'] - 1] = $fixture; + } + + parent::assertFixtures($expectedFixtureIndexes, $processedActualFixtures); + } + + protected function populateDatabase(): void + { + /** @var PdoConnectionInterface $db */ + $db = $this->getConnection(); + if ($db->getSchema()->getTableSchema('{{%user}}') !== null) { + return; + } + + $db + ->createCommand() + ->createTable( + '{{%user}}', + [ + 'id' => 'pk', + 'number' => 'integer NOT NULL', + 'email' => 'string(255) NOT NULL', + 'balance' => 'float DEFAULT 0.0 NOT NULL', + 'born_at' => 'date', + ], + ) + ->execute(); + + $db->transaction(static function (ConnectionInterface $database): void { + foreach (self::$fixtures as $fixture) { + if ($fixture['born_at'] !== null && $database->getDriverName() === 'oci') { + $fixture['born_at'] = new Expression( + "TO_DATE(:born_at, 'yyyy-mm-dd')", + [':born_at' => $fixture['born_at']], + ); + } + + $database->createCommand()->insert('{{%user}}', $fixture)->execute(); + } + }); + } + + protected function dropDatabase(): void + { + /** @var PdoConnectionInterface $db */ + $db = $this->getConnection(); + $db->createCommand()->dropTable('{{%user}}')->execute(); + } +} diff --git a/tests/Base/Reader/ReaderWithFilter/BaseReaderWithAllTestCase.php b/tests/Base/Reader/ReaderWithFilter/BaseReaderWithAllTestCase.php new file mode 100644 index 0000000..7aa5200 --- /dev/null +++ b/tests/Base/Reader/ReaderWithFilter/BaseReaderWithAllTestCase.php @@ -0,0 +1,12 @@ +charset('UTF8MB4'); $db = new Connection($pdoDriver, new SchemaCache(new ArrayCache())); diff --git a/tests/Mssql/QueryDataReaderTest.php b/tests/Mssql/QueryDataReaderTest.php index 84764d2..cc559be 100644 --- a/tests/Mssql/QueryDataReaderTest.php +++ b/tests/Mssql/QueryDataReaderTest.php @@ -4,7 +4,9 @@ namespace Yiisoft\Data\Db\Tests\Mssql; -final class QueryDataReaderTest extends \Yiisoft\Data\Db\Tests\Base\QueryDataReaderTest +use Yiisoft\Data\Db\Tests\Base\BaseQueryDataReaderTestCase; + +final class QueryDataReaderTest extends BaseQueryDataReaderTestCase { use DatabaseTrait; diff --git a/tests/Mssql/ReaderWithHandler/ReaderWithAllTest.php b/tests/Mssql/ReaderWithHandler/ReaderWithAllTest.php new file mode 100644 index 0000000..0b83314 --- /dev/null +++ b/tests/Mssql/ReaderWithHandler/ReaderWithAllTest.php @@ -0,0 +1,13 @@ +