diff --git a/.travis.yml b/.travis.yml
index 883da78..49767e9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,23 +1,117 @@
language: php
+sudo: false
+dist: trusty
-php:
- - 7.2
+cache:
+ directories:
+ - vendor
+ - $HOME/.composer/cache
-services:
- - postgresql
-
-matrix:
- fast_finish: true
+before_install:
+ - phpenv config-rm xdebug.ini || true
+ - |
+ if [ "x$COVERAGE" == "xyes" ]; then
+ pecl install pcov-1.0.0
+ fi
install:
- - composer install
-
-before_script:
- - psql -c 'create database testing;' -U postgres
+ - rm composer.lock
+ - travis_retry composer -n update --prefer-dist
script:
- vendor/bin/ecs check --config=ecs.yml .
- - phpdbg -qrr vendor/bin/phpunit --coverage-clover build/logs/clover.xml
+ - |
+ if [ "x$DOCKER_POSTGRES" == "xyes" ]; then
+ sudo docker exec -ti postgres11 psql postgres -U postgres -c "CREATE DATABASE testing"
+ else
+ psql -c 'CREATE DATABASE testing;' -U postgres
+ fi
+ - |
+ if [ "x$COVERAGE" == "xyes" ]; then
+ ./vendor/bin/phpunit --configuration phpunit.travis.xml --coverage-clover build/logs/clover.xml
+ else
+ ./vendor/bin/phpunit --configuration phpunit.travis.xml
+ fi
after_success:
- - travis_retry vendor/bin/php-coveralls -v
+ - |
+ if [ "x$COVERAGE" == "xyes" ]; then
+ travis_retry vendor/bin/php-coveralls -v
+ fi
+
+matrix:
+ fast_finish: true
+ allow_failures:
+ - php: "7.4snapshot"
+ include:
+ - stage: Test
+ php: "7.2"
+ env: DB=pgsql POSTGRESQL_VERSION=11.0
+ sudo: required
+ services:
+ - docker
+ - stage: Test
+ php: "7.3"
+ env: DB=pgsql POSTGRESQL_VERSION=9.2 COVERAGE=yes
+ services:
+ - postgresql
+ addons:
+ postgresql: "9.2"
+ - stage: Test
+ php: "7.3"
+ env: DB=pgsql POSTGRESQL_VERSION=9.3 COVERAGE=yes
+ services:
+ - postgresql
+ addons:
+ postgresql: "9.3"
+ - stage: Test
+ php: "7.3"
+ env: DB=pgsql POSTGRESQL_VERSION=9.4 COVERAGE=yes
+ services:
+ - postgresql
+ addons:
+ postgresql: "9.4"
+ - stage: Test
+ php: "7.3"
+ env: DB=pgsql POSTGRESQL_VERSION=9.5 COVERAGE=yes
+ services:
+ - postgresql
+ addons:
+ postgresql: "9.5"
+ - stage: Test
+ php: "7.3"
+ env: DB=pgsql POSTGRESQL_VERSION=9.6 COVERAGE=yes
+ services:
+ - postgresql
+ addons:
+ postgresql: "9.6"
+ - stage: Test
+ php: "7.3"
+ env: DB=pgsql POSTGRESQL_VERSION=10.0 COVERAGE=yes
+ sudo: required
+ services:
+ - postgresql
+ addons:
+ postgresql: "9.6"
+ before_script:
+ - bash ./tests/travis/install-postgres-10.sh
+ - stage: Test
+ php: "7.3"
+ env: DB=pgsql DOCKER_POSTGRES=yes POSTGRESQL_VERSION=11.0 COVERAGE=yes
+ sudo: required
+ services:
+ - docker
+ - postgresql
+ addons:
+ postgresql: "9.6"
+ before_script:
+ - bash ./tests/travis/install-postgres-11.sh
+ - stage: Test
+ php: "7.4snapshot"
+ env: DB=pgsql DOCKER_POSTGRES=yes POSTGRESQL_VERSION=11.0
+ sudo: required
+ services:
+ - docker
+ - postgresql
+ before_script:
+ - bash ./tests/travis/install-postgres-11.sh
diff --git a/README.md b/README.md
index 0712d0f..b33eb8b 100644
--- a/README.md
+++ b/README.md
@@ -16,6 +16,7 @@ php composer.phar require umbrellio/laravel-pg-extensions
- [Extended `Schema::create()`](#extended-table-creation)
- [Extended `Schema` with GIST/GIN indexes](#create-gist/gin-indexes)
+ - [Extended `Schema` with USING](#extended-schema-using)
- [Working with unique indexes](#extended-unique-indexes-creation)
- [Working with partitions](#partitions)
- [Check existing index before manipulation](#check-existing-index)
@@ -30,6 +31,24 @@ Schema::create('table', function (Blueprint $table) {
});
```
+### Extended Schema USING
+
+Example:
+```php
+Schema::create('table', function (Blueprint $table) {
+ $table->integer('number');
+});
+
+//modifications with data...
+
+Schema::table('table', function (Blueprint $table) {
+ $table
+ ->string('number')
+ ->using("('[' || number || ']')::character varyiing")
+ ->change();
+});
+```
+
### Create gist/gin indexes
```php
diff --git a/composer.json b/composer.json
index dce9b12..49ee59b 100644
--- a/composer.json
+++ b/composer.json
@@ -1,5 +1,6 @@
{
"name": "umbrellio/laravel-pg-extensions",
+ "description": "",
"type": "library",
"minimum-stability": "stable",
"authors": [
@@ -10,6 +11,7 @@
],
"require": {
"php": "^7.2",
+ "doctrine/dbal": "^2.9",
"laravel/framework": "^5.8"
},
"require-dev": {
diff --git a/composer.lock b/composer.lock
index f8b1d94..4d6cc35 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "806be43cfecda6994cd0335061c2ad39",
+ "content-hash": "a9b56c70136605e96d824acfe6f3ab54",
"packages": [
{
"name": "doctrine/cache",
@@ -83,31 +83,31 @@
},
{
"name": "doctrine/dbal",
- "version": "v2.9.2",
+ "version": "v2.10.4",
"source": {
"type": "git",
- "url": "https://github.com/doctrine/dbal.git",
- "reference": "22800bd651c1d8d2a9719e2a3dc46d5108ebfcc9"
+ "url": "https://github.com/pvsaintpe/dbal.git",
+ "reference": "59aedf521cca50af294bdbbc14337ea3a0293d86"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/dbal/zipball/22800bd651c1d8d2a9719e2a3dc46d5108ebfcc9",
- "reference": "22800bd651c1d8d2a9719e2a3dc46d5108ebfcc9",
+ "url": "https://api.github.com/repos/pvsaintpe/dbal/zipball/59aedf521cca50af294bdbbc14337ea3a0293d86",
+ "reference": "59aedf521cca50af294bdbbc14337ea3a0293d86",
"shasum": ""
},
"require": {
"doctrine/cache": "^1.0",
"doctrine/event-manager": "^1.0",
"ext-pdo": "*",
- "php": "^7.1"
+ "php": "^7.2"
},
"require-dev": {
- "doctrine/coding-standard": "^5.0",
- "jetbrains/phpstorm-stubs": "^2018.1.2",
- "phpstan/phpstan": "^0.10.1",
- "phpunit/phpunit": "^7.4",
- "symfony/console": "^2.0.5|^3.0|^4.0",
- "symfony/phpunit-bridge": "^3.4.5|^4.0.5"
+ "doctrine/coding-standard": "^6.0",
+ "jetbrains/phpstorm-stubs": "^2019.1",
+ "phpstan/phpstan": "^0.11.3",
+ "phpunit/phpunit": "^8.2.1",
+ "symfony/console": "^2.0.5|^3.0|^4.0|^5.0",
+ "symfony/phpunit-bridge": "^3.4.5|^4.0.5|^5.0"
},
"suggest": {
"symfony/console": "For helpful console commands such as SQL execution and import of files."
@@ -118,7 +118,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.9.x-dev",
+ "dev-master": "2.10.x-dev",
"dev-develop": "3.0.x-dev"
}
},
@@ -127,11 +127,19 @@
"Doctrine\\DBAL\\": "lib/Doctrine/DBAL"
}
},
- "notification-url": "https://packagist.org/downloads/",
+ "autoload-dev": {
+ "psr-4": {
+ "Doctrine\\Tests\\": "tests/Doctrine/Tests"
+ }
+ },
"license": [
"MIT"
],
"authors": [
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com"
+ },
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
@@ -140,10 +148,6 @@
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
- {
- "name": "Guilherme Blanco",
- "email": "guilhermeblanco@gmail.com"
- },
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
@@ -154,14 +158,28 @@
"keywords": [
"abstraction",
"database",
+ "db2",
"dbal",
+ "mariadb",
+ "mssql",
"mysql",
- "persistence",
+ "oci8",
+ "oracle",
+ "pdo",
"pgsql",
- "php",
- "queryobject"
- ],
- "time": "2018-12-31T03:27:51+00:00"
+ "postgresql",
+ "queryobject",
+ "sasql",
+ "sql",
+ "sqlanywhere",
+ "sqlite",
+ "sqlserver",
+ "sqlsrv"
+ ],
+ "support": {
+ "source": "https://github.com/pvsaintpe/dbal/tree/bug/default-expression"
+ },
+ "time": "2019-07-11T16:39:36+00:00"
},
{
"name": "doctrine/event-manager",
@@ -523,16 +541,16 @@
},
{
"name": "laravel/framework",
- "version": "v5.8.27",
+ "version": "v5.8.29",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
- "reference": "f1dccffb96f614895393e27e4667105a05407af5"
+ "reference": "489ae2218c7eb138caac780de584d8df9fe8160b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/framework/zipball/f1dccffb96f614895393e27e4667105a05407af5",
- "reference": "f1dccffb96f614895393e27e4667105a05407af5",
+ "url": "https://api.github.com/repos/laravel/framework/zipball/489ae2218c7eb138caac780de584d8df9fe8160b",
+ "reference": "489ae2218c7eb138caac780de584d8df9fe8160b",
"shasum": ""
},
"require": {
@@ -666,7 +684,7 @@
"framework",
"laravel"
],
- "time": "2019-07-02T13:43:47+00:00"
+ "time": "2019-07-16T14:05:28+00:00"
},
{
"name": "league/flysystem",
@@ -832,16 +850,16 @@
},
{
"name": "nesbot/carbon",
- "version": "2.20.0",
+ "version": "2.21.3",
"source": {
"type": "git",
"url": "https://github.com/briannesbitt/Carbon.git",
- "reference": "bc671b896c276795fad8426b0aa24e8ade0f2498"
+ "reference": "58bdbbfab17ccd2ec7347b99e997f18232def4dc"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/bc671b896c276795fad8426b0aa24e8ade0f2498",
- "reference": "bc671b896c276795fad8426b0aa24e8ade0f2498",
+ "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/58bdbbfab17ccd2ec7347b99e997f18232def4dc",
+ "reference": "58bdbbfab17ccd2ec7347b99e997f18232def4dc",
"shasum": ""
},
"require": {
@@ -857,6 +875,9 @@
"phpunit/phpunit": "^7.5 || ^8.0",
"squizlabs/php_codesniffer": "^3.4"
},
+ "bin": [
+ "bin/carbon"
+ ],
"type": "library",
"extra": {
"laravel": {
@@ -879,6 +900,10 @@
"name": "Brian Nesbitt",
"email": "brian@nesbot.com",
"homepage": "http://nesbot.com"
+ },
+ {
+ "name": "kylekatarnls",
+ "homepage": "http://github.com/kylekatarnls"
}
],
"description": "A simple API extension for DateTime.",
@@ -888,20 +913,20 @@
"datetime",
"time"
],
- "time": "2019-06-25T10:00:57+00:00"
+ "time": "2019-07-18T18:47:28+00:00"
},
{
"name": "opis/closure",
- "version": "3.3.0",
+ "version": "3.3.1",
"source": {
"type": "git",
"url": "https://github.com/opis/closure.git",
- "reference": "f846725591203098246276b2e7b9e8b7814c4965"
+ "reference": "92927e26d7fc3f271efe1f55bdbb073fbb2f0722"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/opis/closure/zipball/f846725591203098246276b2e7b9e8b7814c4965",
- "reference": "f846725591203098246276b2e7b9e8b7814c4965",
+ "url": "https://api.github.com/repos/opis/closure/zipball/92927e26d7fc3f271efe1f55bdbb073fbb2f0722",
+ "reference": "92927e26d7fc3f271efe1f55bdbb073fbb2f0722",
"shasum": ""
},
"require": {
@@ -949,7 +974,7 @@
"serialization",
"serialize"
],
- "time": "2019-05-31T20:04:32+00:00"
+ "time": "2019-07-09T21:58:11+00:00"
},
{
"name": "paragonie/random_compat",
@@ -3723,34 +3748,35 @@
},
{
"name": "ocramius/package-versions",
- "version": "1.4.0",
+ "version": "1.5.1",
"source": {
"type": "git",
"url": "https://github.com/Ocramius/PackageVersions.git",
- "reference": "a4d4b60d0e60da2487bd21a2c6ac089f85570dbb"
+ "reference": "1d32342b8c1eb27353c8887c366147b4c2da673c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/a4d4b60d0e60da2487bd21a2c6ac089f85570dbb",
- "reference": "a4d4b60d0e60da2487bd21a2c6ac089f85570dbb",
+ "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/1d32342b8c1eb27353c8887c366147b4c2da673c",
+ "reference": "1d32342b8c1eb27353c8887c366147b4c2da673c",
"shasum": ""
},
"require": {
"composer-plugin-api": "^1.0.0",
- "php": "^7.1.0"
+ "php": "^7.3.0"
},
"require-dev": {
- "composer/composer": "^1.6.3",
- "doctrine/coding-standard": "^5.0.1",
+ "composer/composer": "^1.8.6",
+ "doctrine/coding-standard": "^6.0.0",
"ext-zip": "*",
- "infection/infection": "^0.7.1",
- "phpunit/phpunit": "^7.0.0"
+ "infection/infection": "^0.13.4",
+ "phpunit/phpunit": "^8.2.5",
+ "vimeo/psalm": "^3.4.9"
},
"type": "composer-plugin",
"extra": {
"class": "PackageVersions\\Installer",
"branch-alias": {
- "dev-master": "2.0.x-dev"
+ "dev-master": "1.6.x-dev"
}
},
"autoload": {
@@ -3769,7 +3795,7 @@
}
],
"description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)",
- "time": "2019-02-21T12:16:21+00:00"
+ "time": "2019-07-17T15:49:50+00:00"
},
{
"name": "orchestra/testbench",
@@ -4386,16 +4412,16 @@
},
{
"name": "phpunit/php-code-coverage",
- "version": "7.0.5",
+ "version": "7.0.6",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "aed67b57d459dcab93e84a5c9703d3deb5025dff"
+ "reference": "d471d0d2b529a67c6a722dd446c4ec90881ac315"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/aed67b57d459dcab93e84a5c9703d3deb5025dff",
- "reference": "aed67b57d459dcab93e84a5c9703d3deb5025dff",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d471d0d2b529a67c6a722dd446c4ec90881ac315",
+ "reference": "d471d0d2b529a67c6a722dd446c4ec90881ac315",
"shasum": ""
},
"require": {
@@ -4404,17 +4430,17 @@
"php": "^7.2",
"phpunit/php-file-iterator": "^2.0.2",
"phpunit/php-text-template": "^1.2.1",
- "phpunit/php-token-stream": "^3.0.1",
+ "phpunit/php-token-stream": "^3.0.2",
"sebastian/code-unit-reverse-lookup": "^1.0.1",
- "sebastian/environment": "^4.1",
+ "sebastian/environment": "^4.2.2",
"sebastian/version": "^2.0.1",
- "theseer/tokenizer": "^1.1"
+ "theseer/tokenizer": "^1.1.3"
},
"require-dev": {
- "phpunit/phpunit": "^8.0"
+ "phpunit/phpunit": "^8.2.2"
},
"suggest": {
- "ext-xdebug": "^2.6.1"
+ "ext-xdebug": "^2.7.2"
},
"type": "library",
"extra": {
@@ -4445,7 +4471,7 @@
"testing",
"xunit"
],
- "time": "2019-06-06T12:28:18+00:00"
+ "time": "2019-07-08T05:29:42+00:00"
},
{
"name": "phpunit/php-file-iterator",
@@ -4589,16 +4615,16 @@
},
{
"name": "phpunit/php-token-stream",
- "version": "3.0.1",
+ "version": "3.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
- "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18"
+ "reference": "c4a66b97f040e3e20b3aa2a243230a1c3a9f7c8c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/c99e3be9d3e85f60646f152f9002d46ed7770d18",
- "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/c4a66b97f040e3e20b3aa2a243230a1c3a9f7c8c",
+ "reference": "c4a66b97f040e3e20b3aa2a243230a1c3a9f7c8c",
"shasum": ""
},
"require": {
@@ -4634,20 +4660,20 @@
"keywords": [
"tokenizer"
],
- "time": "2018-10-30T05:52:18+00:00"
+ "time": "2019-07-08T05:24:54+00:00"
},
{
"name": "phpunit/phpunit",
- "version": "8.2.3",
+ "version": "8.2.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "f67ca36860ebca7224d4573f107f79bd8ed0ba03"
+ "reference": "c1b8534b3730f20f58600124129197bf1183dc92"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f67ca36860ebca7224d4573f107f79bd8ed0ba03",
- "reference": "f67ca36860ebca7224d4573f107f79bd8ed0ba03",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c1b8534b3730f20f58600124129197bf1183dc92",
+ "reference": "c1b8534b3730f20f58600124129197bf1183dc92",
"shasum": ""
},
"require": {
@@ -4674,7 +4700,7 @@
"sebastian/global-state": "^3.0.0",
"sebastian/object-enumerator": "^3.0.3",
"sebastian/resource-operations": "^2.0.1",
- "sebastian/type": "^1.1.0",
+ "sebastian/type": "^1.1.3",
"sebastian/version": "^2.0.1"
},
"require-dev": {
@@ -4717,7 +4743,7 @@
"testing",
"xunit"
],
- "time": "2019-06-19T12:03:56+00:00"
+ "time": "2019-07-15T06:26:24+00:00"
},
{
"name": "psr/cache",
@@ -6550,7 +6576,7 @@
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
- "php": "^7.1.3"
+ "php": "^7.2"
},
"platform-dev": []
}
diff --git a/ecs.yml b/ecs.yml
index 768e555..5028a93 100644
--- a/ecs.yml
+++ b/ecs.yml
@@ -14,3 +14,5 @@ parameters:
skip:
Symplify\CodingStandard\Sniffs\CleanCode\CognitiveComplexitySniff:
- src/Schema/Blueprint.php
+ Symplify\CodingStandard\Sniffs\CleanCode\ForbiddenReferenceSniff:
+ - src/Schema/Traits/AlterTableChangeColumnTrait.php
diff --git a/phpunit.travis.xml b/phpunit.travis.xml
new file mode 100644
index 0000000..22ab00f
--- /dev/null
+++ b/phpunit.travis.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./tests
+
+
+
+
+ ./src
+
+ ./src/.meta.php
+
+
+
+
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 1dc3aef..1e2c087 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -1,19 +1,24 @@
-
+ stopOnFailure="true">
+
+
+
+
+
+
+
+
./src
./src/.meta.php
- ./src/Commands
diff --git a/src/.meta.php b/src/.meta.php
index 1fdb06a..9f6ba6d 100644
--- a/src/.meta.php
+++ b/src/.meta.php
@@ -15,8 +15,19 @@
* @method UniqueDefinition uniquePartial($columns, ?string $index = null, ?string $algorithm = null)
* @method Fluent gin($columns, ?string $name = null)
* @method Fluent gist($columns, ?string $name = null)
+ * @method ColumnDefinition tsRange(string $name)
+ * @method ColumnDefinition tsVector(string $name)
*/
class Blueprint
{
}
+
+ /**
+ * @method ColumnDefinition using($expression)
+ * @method ColumnDefinition gist()
+ * @method ColumnDefinition gin()
+ */
+ class ColumnDefinition
+ {
+ }
}
diff --git a/src/Doctrine/RangeExtension.php b/src/Doctrine/RangeExtension.php
new file mode 100644
index 0000000..9fc6c45
--- /dev/null
+++ b/src/Doctrine/RangeExtension.php
@@ -0,0 +1,37 @@
+ RangeBlueprint::class,
+ PostgresGrammar::class => RangeGrammar::class,
+ ];
+ }
+
+ public static function getName(): string
+ {
+ return static::NAME;
+ }
+
+ public static function getTypes(): array
+ {
+ return array_merge(parent::getTypes(), [
+ TsRangeType::TYPE_NAME => TsRangeType::class,
+ ]);
+ }
+}
diff --git a/src/Doctrine/Schema/Grammars/RangeGrammar.php b/src/Doctrine/Schema/Grammars/RangeGrammar.php
new file mode 100644
index 0000000..b43ceab
--- /dev/null
+++ b/src/Doctrine/Schema/Grammars/RangeGrammar.php
@@ -0,0 +1,18 @@
+addColumn(TsRangeType::TYPE_NAME, $column);
+ };
+ }
+}
diff --git a/src/Doctrine/Schema/VectorBlueprint.php b/src/Doctrine/Schema/VectorBlueprint.php
new file mode 100644
index 0000000..f3477a4
--- /dev/null
+++ b/src/Doctrine/Schema/VectorBlueprint.php
@@ -0,0 +1,19 @@
+addColumn(TsVectorType::TYPE_NAME, $column);
+ };
+ }
+}
diff --git a/src/Doctrine/Types/TsRangeType.php b/src/Doctrine/Types/TsRangeType.php
new file mode 100644
index 0000000..d572a45
--- /dev/null
+++ b/src/Doctrine/Types/TsRangeType.php
@@ -0,0 +1,41 @@
+ VectorBlueprint::class,
+ PostgresGrammar::class => VectorGrammar::class,
+ ];
+ }
+
+ public static function getName(): string
+ {
+ return static::NAME;
+ }
+
+ public static function getTypes(): array
+ {
+ return array_merge(parent::getTypes(), [
+ TsVectorType::TYPE_NAME => TsVectorType::class,
+ ]);
+ }
+}
diff --git a/src/Extensions/AbstractComponent.php b/src/Extensions/AbstractComponent.php
index 3eb63a7..b03f5a4 100644
--- a/src/Extensions/AbstractComponent.php
+++ b/src/Extensions/AbstractComponent.php
@@ -4,9 +4,6 @@
namespace Umbrellio\Postgres\Extensions;
-/**
- * @codeCoverageIgnore
- */
abstract class AbstractComponent
{
final public function __construct()
diff --git a/src/Extensions/AbstractExtension.php b/src/Extensions/AbstractExtension.php
index 04acb44..b66b9d1 100644
--- a/src/Extensions/AbstractExtension.php
+++ b/src/Extensions/AbstractExtension.php
@@ -8,9 +8,6 @@
use Umbrellio\Postgres\Extensions\Exceptions\MacroableMissedException;
use Umbrellio\Postgres\Extensions\Exceptions\MixinInvalidException;
-/**
- * @codeCoverageIgnore
- */
abstract class AbstractExtension extends AbstractComponent
{
abstract public static function getMixins(): array;
diff --git a/src/PostgresConnection.php b/src/PostgresConnection.php
index d1818d1..eddfacf 100644
--- a/src/PostgresConnection.php
+++ b/src/PostgresConnection.php
@@ -4,12 +4,15 @@
namespace Umbrellio\Postgres;
+use Doctrine\DBAL\Connection;
+use Doctrine\DBAL\Events;
use Illuminate\Database\PostgresConnection as BasePostgresConnection;
use Illuminate\Support\Traits\Macroable;
use Umbrellio\Postgres\Extensions\AbstractExtension;
use Umbrellio\Postgres\Extensions\Exceptions\ExtensionInvalidException;
use Umbrellio\Postgres\Schema\Builder;
use Umbrellio\Postgres\Schema\Grammars\PostgresGrammar;
+use Umbrellio\Postgres\Schema\Listeners\SchemaAlterTableChangeColumnListener;
class PostgresConnection extends BasePostgresConnection
{
@@ -19,6 +22,7 @@ class PostgresConnection extends BasePostgresConnection
/**
* @param AbstractExtension|string $extension
+ * @throws ExtensionInvalidException
* @codeCoverageIgnore
*/
final public static function registerExtension(string $extension): void
@@ -41,23 +45,27 @@ public function getSchemaBuilder()
return new Builder($this);
}
- public function useDefaultPostProcessor()
+ public function useDefaultPostProcessor(): void
{
parent::useDefaultPostProcessor();
$this->registerExtensions();
}
+ public function getDoctrineConnection(): Connection
+ {
+ $doctrineConnection = parent::getDoctrineConnection();
+ $this->overrideDoctrineBehavior($doctrineConnection);
+ return $doctrineConnection;
+ }
+
protected function getDefaultSchemaGrammar()
{
return $this->withTablePrefix(new PostgresGrammar());
}
- /**
- * @codeCoverageIgnore
- */
- final private function registerExtensions(): void
+ private function registerExtensions(): void
{
- collect(self::$extensions)->each(function ($extension, $key) {
+ collect(self::$extensions)->each(function ($extension) {
/** @var AbstractExtension $extension */
$extension::register();
foreach ($extension::getTypes() as $type => $typeClass) {
@@ -65,4 +73,17 @@ final private function registerExtensions(): void
}
});
}
+
+ private function overrideDoctrineBehavior(Connection $connection): Connection
+ {
+ $eventManager = $connection->getEventManager();
+ if (!$eventManager->hasListeners(Events::onSchemaAlterTableChangeColumn)) {
+ $eventManager->addEventListener(
+ Events::onSchemaAlterTableChangeColumn,
+ new SchemaAlterTableChangeColumnListener()
+ );
+ }
+ $connection->getDatabasePlatform()->setEventManager($eventManager);
+ return $connection;
+ }
}
diff --git a/src/Schema/Grammars/PostgresGrammar.php b/src/Schema/Grammars/PostgresGrammar.php
index 088a14e..6236d6e 100644
--- a/src/Schema/Grammars/PostgresGrammar.php
+++ b/src/Schema/Grammars/PostgresGrammar.php
@@ -60,7 +60,6 @@ public function compileGin(Blueprint $blueprint, Fluent $command): string
);
}
-
public function compileGist(Blueprint $blueprint, Fluent $command): string
{
return sprintf(
diff --git a/src/Schema/Listeners/SchemaAlterTableChangeColumnListener.php b/src/Schema/Listeners/SchemaAlterTableChangeColumnListener.php
new file mode 100644
index 0000000..d65fed9
--- /dev/null
+++ b/src/Schema/Listeners/SchemaAlterTableChangeColumnListener.php
@@ -0,0 +1,26 @@
+preventDefault();
+
+ $event->addSql(
+ $this->getAlterTableChangeColumnSQL(
+ $event->getPlatform(),
+ $event->getTableDiff(),
+ $event->getColumnDiff()
+ )
+ );
+ }
+}
diff --git a/src/Schema/Traits/AlterTableChangeColumnTrait.php b/src/Schema/Traits/AlterTableChangeColumnTrait.php
new file mode 100644
index 0000000..245ec9b
--- /dev/null
+++ b/src/Schema/Traits/AlterTableChangeColumnTrait.php
@@ -0,0 +1,208 @@
+quoteName($platform, $diff);
+
+ $oldColumnName = $columnDiff->getOldColumnName()->getQuotedName($platform);
+ $column = $columnDiff->column;
+
+ $this->compileAlterColumnType($platform, $columnDiff, $column, $quoteName, $oldColumnName, $sql);
+
+ $this->compileAlterColumnDefault($platform, $columnDiff, $column, $quoteName, $oldColumnName, $sql);
+
+ $this->compileAlterColumnNull($columnDiff, $column, $quoteName, $oldColumnName, $sql);
+
+ $this->compileAlterColumnSequence($platform, $columnDiff, $diff, $column, $quoteName, $oldColumnName, $sql);
+
+ $this->compileAlterColumnComment($platform, $columnDiff, $column, $quoteName, $sql);
+
+ if (!$columnDiff->hasChanged('length')) {
+ return $sql;
+ }
+
+ $sql[] = sprintf(
+ 'ALTER TABLE %s ALTER %s TYPE %s',
+ $quoteName,
+ $oldColumnName,
+ $column->getType()->getSQLDeclaration($column->toArray(), $platform)
+ );
+
+ return $sql;
+ }
+
+ private function compileAlterColumnComment(
+ AbstractPlatform $platform,
+ ColumnDiff $columnDiff,
+ Column $column,
+ string $quoteName,
+ &$sql
+ ): void {
+ $newComment = $this->getColumnComment($column);
+ $oldComment = $this->getOldColumnComment($columnDiff);
+
+ if (($columnDiff->fromColumn !== null && $oldComment !== $newComment)
+ || $columnDiff->hasChanged('comment')
+ ) {
+ $sql[] = $platform->getCommentOnColumnSQL($quoteName, $column->getQuotedName($platform), $newComment);
+ }
+ }
+
+ private function compileAlterColumnNull(
+ ColumnDiff $columnDiff,
+ Column $column,
+ string $quoteName,
+ string $oldColumnName,
+ &$sql
+ ): void {
+ if ($columnDiff->hasChanged('notnull')) {
+ $sql[] = sprintf(
+ 'ALTER TABLE %s ALTER %s %s NOT NULL',
+ $quoteName,
+ $oldColumnName,
+ ($column->getNotnull() ? 'SET' : 'DROP')
+ );
+ }
+ }
+
+ private function compileAlterColumnDefault(
+ AbstractPlatform $platform,
+ ColumnDiff $columnDiff,
+ Column $column,
+ string $quoteName,
+ string $oldColumnName,
+ &$sql
+ ): void {
+ if ($columnDiff->hasChanged('default') || $this->typeChangeBreaksDefaultValue($columnDiff)) {
+ $defaultClause = $column->getDefault() === null
+ ? ' DROP DEFAULT'
+ : ' SET' . $this->getDefaultValueDeclarationSQL($platform, $column);
+ $sql[] = sprintf('ALTER TABLE %s ALTER %s %s', $quoteName, $oldColumnName, trim($defaultClause));
+ }
+ }
+
+ private function compileAlterColumnSequence(
+ AbstractPlatform $platform,
+ ColumnDiff $columnDiff,
+ TableDiff $diff,
+ Column $column,
+ string $quoteName,
+ string $oldColumnName,
+ &$sql
+ ): void {
+ if (!$columnDiff->hasChanged('autoincrement')) {
+ return;
+ }
+
+ if (!$column->getAutoincrement()) {
+ $sql[] = sprintf('ALTER TABLE %s ALTER %s DROP DEFAULT', $quoteName, $oldColumnName);
+ return;
+ }
+
+ $seqName = $platform->getIdentitySequenceName($diff->name, $oldColumnName);
+
+ $sql[] = sprintf('CREATE SEQUENCE %s', $seqName);
+ $sql[] = sprintf("SELECT setval('%s', (SELECT MAX(%s) FROM %s))", $seqName, $oldColumnName, $quoteName);
+ $sql[] = sprintf("ALTER TABLE %s ALTER %s SET DEFAULT nextval('%s')", $quoteName, $oldColumnName, $seqName);
+ }
+
+ private function compileAlterColumnType(
+ AbstractPlatform $platform,
+ ColumnDiff $columnDiff,
+ Column $column,
+ string $quoteName,
+ string $oldColumnName,
+ &$sql
+ ): void {
+ if ($columnDiff->hasChanged('type')
+ || $columnDiff->hasChanged('precision')
+ || $columnDiff->hasChanged('scale')
+ || $columnDiff->hasChanged('fixed')
+ ) {
+ $type = $column->getType();
+
+ $columnDefinition = $column->toArray();
+ $columnDefinition['autoincrement'] = false;
+
+ if ($this->typeChangeBreaksDefaultValue($columnDiff)) {
+ $sql[] = sprintf('ALTER TABLE %s ALTER %s DROP DEFAULT', $quoteName, $oldColumnName);
+ }
+
+ $typeName = $type->getSQLDeclaration($columnDefinition, $platform);
+
+ if ($columnDiff->hasChanged('type')) {
+ $using = sprintf('USING %s::%s', $oldColumnName, $typeName);
+
+ if ($columnDefinition['using'] ?? false) {
+ $using = 'USING ' . $columnDefinition['using'];
+ }
+ }
+
+ $sql[] = trim(sprintf(
+ 'ALTER TABLE %s ALTER %s TYPE %s %s',
+ $quoteName,
+ $oldColumnName,
+ $typeName,
+ $using ?? ''
+ ));
+ }
+ }
+
+ private function getDefaultValueDeclarationSQL(AbstractPlatform $platform, Column $column): string
+ {
+ if ($column->getDefault() instanceof Expression) {
+ return ' DEFAULT ' . $column->getDefault();
+ }
+
+ return $platform->getDefaultValueDeclarationSQL($column->toArray());
+ }
+
+ private function typeChangeBreaksDefaultValue(ColumnDiff $columnDiff): bool
+ {
+ $oldTypeIsNumeric = $this->isNumericType($columnDiff->fromColumn->getType());
+ $newTypeIsNumeric = $this->isNumericType($columnDiff->column->getType());
+
+ return $columnDiff->hasChanged('type')
+ && !($oldTypeIsNumeric && $newTypeIsNumeric && $columnDiff->column->getAutoincrement());
+ }
+
+ private function isNumericType(Type $type): bool
+ {
+ return $type instanceof IntegerType || $type instanceof BigIntType;
+ }
+
+ private function quoteName(AbstractPlatform $platform, TableDiff $diff): string
+ {
+ return $diff->getName($platform)->getQuotedName($platform);
+ }
+
+ private function getOldColumnComment(ColumnDiff $columnDiff): ?string
+ {
+ return $columnDiff->fromColumn ? $this->getColumnComment($columnDiff->fromColumn) : null;
+ }
+
+ private function getColumnComment(Column $column): ?string
+ {
+ return $column->getComment();
+ }
+}
diff --git a/src/UmbrellioPostgresProvider.php b/src/UmbrellioPostgresProvider.php
index 2da00c4..1e4f57e 100644
--- a/src/UmbrellioPostgresProvider.php
+++ b/src/UmbrellioPostgresProvider.php
@@ -7,9 +7,18 @@
use Illuminate\Database\DatabaseManager;
use Illuminate\Database\DatabaseServiceProvider;
use Umbrellio\Postgres\Connectors\ConnectionFactory;
+use Umbrellio\Postgres\Doctrine\RangeExtension;
+use Umbrellio\Postgres\Doctrine\VectorExtension;
class UmbrellioPostgresProvider extends DatabaseServiceProvider
{
+ public function register()
+ {
+ parent::register();
+ PostgresConnection::registerExtension(RangeExtension::class);
+ PostgresConnection::registerExtension(VectorExtension::class);
+ }
+
/**
* @codeCoverageIgnore
*/
diff --git a/tests.sh b/tests.sh
new file mode 100755
index 0000000..c4ce18c
--- /dev/null
+++ b/tests.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+psql postgres -U user -tc "SELECT 1 FROM pg_database WHERE datname = 'testing'" | grep -q 1 || psql postgres -U user -c "CREATE DATABASE testing"
+composer lint
+php -d pcov.directory='.' vendor/bin/phpunit --coverage-html build
diff --git a/tests/Functional/FunctionalTestCase.php b/tests/Functional/FunctionalTestCase.php
deleted file mode 100644
index af522b6..0000000
--- a/tests/Functional/FunctionalTestCase.php
+++ /dev/null
@@ -1,31 +0,0 @@
-set('database.default', 'testing');
- $app['config']->set('database.connections.testing', [
- 'driver' => 'pgsql',
- 'host' => env('TEST_DB_HOST', 'localhost'),
- 'port' => env('TEST_DB_PORT', 5432),
- 'database' => env('TEST_DB', 'testing'),
- 'username' => env('TEST_DB_USER', 'postgres'),
- 'password' => env('TEST_DB_PASSWORD', ''),
- 'charset' => 'utf8',
- 'prefix' => '',
- 'schema' => 'public',
- ]);
- }
-}
diff --git a/tests/Functional/HasIndexTest.php b/tests/Functional/HasIndexTest.php
deleted file mode 100644
index 811ef37..0000000
--- a/tests/Functional/HasIndexTest.php
+++ /dev/null
@@ -1,42 +0,0 @@
-increments('id');
- $table->string('name');
-
- if (!$table->hasIndex(['name'], true)) {
- $table->unique(['name']);
- }
- });
-
- $this->assertTrue(Schema::hasTable('test_table'));
-
- $indexes = $this->getIndexByName('test_table_name_unique');
-
- Schema::table('test_table', function (Blueprint $table) {
- if (!$table->hasIndex(['name'], true)) {
- $table->unique(['name']);
- }
- });
-
- $this->assertTrue(isset($indexes->indexdef));
- }
-
- protected function getIndexByName($name)
- {
- return collect(DB::select("SELECT indexdef FROM pg_indexes WHERE indexname = '{$name}'"))->first();
- }
-}
diff --git a/tests/Functional/Helpers/ColumnAssertions.php b/tests/Functional/Helpers/ColumnAssertions.php
new file mode 100644
index 0000000..dc7e68a
--- /dev/null
+++ b/tests/Functional/Helpers/ColumnAssertions.php
@@ -0,0 +1,72 @@
+getCommentListing($table, $column);
+
+ if ($expected === null) {
+ $this->assertNull($comment);
+ }
+
+ $this->assertSame($expected, $comment);
+ }
+
+ protected function assertDefaultOnColumn(string $table, string $column, ?string $expected = null): void
+ {
+ $defaultValue = $this->getDefaultListing($table, $column);
+
+ if ($expected === null) {
+ $this->assertNull($defaultValue);
+ }
+
+ $this->assertSame($expected, $defaultValue);
+ }
+
+ protected function assertTypeColumn(string $table, string $column, string $expected): void
+ {
+ $this->assertSame($expected, Schema::getColumnType($table, $column));
+ }
+ private function getCommentListing(string $table, string $column)
+ {
+ $definition = DB::selectOne(
+ '
+ SELECT pgd.description
+ FROM pg_catalog.pg_statio_all_tables AS st
+ INNER JOIN pg_catalog.pg_description pgd ON (pgd.objoid = st.relid)
+ INNER JOIN information_schema.columns c ON pgd.objsubid = c.ordinal_position
+ AND c.table_schema = st.schemaname AND c.table_name = st.relname
+ WHERE c.table_name = ? AND c.column_name = ?
+ ',
+ [$table, $column]
+ );
+
+ return $definition ? $definition->description : null;
+ }
+
+ private function getDefaultListing(string $table, string $column)
+ {
+ $definition = DB::selectOne(
+ '
+ SELECT column_default
+ FROM information_schema.columns c
+ WHERE c.table_name = ? and c.column_name = ?
+ ',
+ [$table, $column]
+ );
+
+ return $definition ? $definition->column_default : null;
+ }
+}
diff --git a/tests/Functional/Helpers/IndexAssertions.php b/tests/Functional/Helpers/IndexAssertions.php
new file mode 100644
index 0000000..07d23d0
--- /dev/null
+++ b/tests/Functional/Helpers/IndexAssertions.php
@@ -0,0 +1,41 @@
+assertNotNull($this->getIndexListing($index));
+ }
+
+ protected function assertSameIndex(string $index, string $expectedDef): void
+ {
+ $definition = $this->getIndexListing($index);
+
+ $this->seeIndex($index);
+ $this->assertSame($expectedDef, $definition);
+ }
+
+ protected function assertRegExpIndex(string $index, string $expectedDef): void
+ {
+ $definition = $this->getIndexListing($index);
+
+ $this->seeIndex($index);
+ $this->assertRegExp($expectedDef, $definition);
+ }
+ private function getIndexListing($index): ?string
+ {
+ $definition = DB::selectOne('SELECT indexdef FROM pg_indexes WHERE indexname = ?', [$index]);
+
+ return $definition ? $definition->indexdef : null;
+ }
+}
diff --git a/tests/Functional/Helpers/TableAssertions.php b/tests/Functional/Helpers/TableAssertions.php
new file mode 100644
index 0000000..c3a2c90
--- /dev/null
+++ b/tests/Functional/Helpers/TableAssertions.php
@@ -0,0 +1,36 @@
+assertSame($this->getTableDefinition($sourceTable), $this->getTableDefinition($destinationTable));
+ }
+
+ protected function assertSameTable(array $expectedDef, string $table): void
+ {
+ $definition = $this->getTableDefinition($table);
+
+ $this->assertSame($expectedDef, $definition);
+ }
+
+ protected function seeTable(string $table): void
+ {
+ $this->assertTrue(Schema::hasTable($table));
+ }
+
+ private function getTableDefinition(string $table): array
+ {
+ return Schema::getColumnListing($table);
+ }
+}
diff --git a/tests/Functional/Schema/AddColumnsTest.php b/tests/Functional/Schema/AddColumnsTest.php
new file mode 100644
index 0000000..c58b326
--- /dev/null
+++ b/tests/Functional/Schema/AddColumnsTest.php
@@ -0,0 +1,40 @@
+assertTypeColumn('test_table', 'field_range', $type);
+ }
+
+ public function provideRangeTypes(): Generator
+ {
+ yield ['tsrange', function (Blueprint $table, string $column) {
+ $table->tsRange($column);
+ }];
+ yield ['text', function (Blueprint $table, string $column) {
+ $table->tsVector($column);
+ }];
+ }
+}
diff --git a/tests/Functional/Schema/AlterColumnsTest.php b/tests/Functional/Schema/AlterColumnsTest.php
new file mode 100644
index 0000000..dcb7deb
--- /dev/null
+++ b/tests/Functional/Schema/AlterColumnsTest.php
@@ -0,0 +1,246 @@
+string('code')->default('1');
+ });
+
+ $this->assertDefaultOnColumn('test_table', 'code', "'1'::character varying");
+
+ Schema::table('test_table', function (Blueprint $table) {
+ $table->string('code')->comment('some comment')->change();
+ });
+
+ $this->assertCommentOnColumn('test_table', 'code', 'some comment');
+ $this->assertDefaultOnColumn('test_table', 'code', "'1'::character varying");
+ }
+
+ /** @test */
+ public function alterTableJsonSetComment(): void
+ {
+ Schema::create('test_table', function (Blueprint $table) {
+ $table->string('json_field');
+ });
+
+ $this->assertCommentOnColumn('test_table', 'json_field');
+
+ Schema::table('test_table', function (Blueprint $table) {
+ $table->json('json_field')->comment('(DC2Type:json_array)')->change();
+ });
+
+ $this->assertCommentOnColumn('test_table', 'json_field', '(DC2Type:json_array)');
+ }
+
+ /** @test */
+ public function alterTableSetDCComment(): void
+ {
+ Schema::create('test_table', function (Blueprint $table) {
+ $table->string('code')->default('1');
+ });
+
+ $this->assertDefaultOnColumn('test_table', 'code', "'1'::character varying");
+ $this->assertCommentOnColumn('test_table', 'code');
+
+ Schema::table('test_table', function (Blueprint $table) {
+ $table->string('code')->comment('(DC2Type:string)')->change();
+ });
+
+ $this->assertDefaultOnColumn('test_table', 'code', "'1'::character varying");
+ $this->assertCommentOnColumn('test_table', 'code', '(DC2Type:string)');
+ }
+
+ /** @test */
+ public function alterTableDropDCComment(): void
+ {
+ Schema::create('test_table', function (Blueprint $table) {
+ $table->integer('number')->comment('(DC2Type:integer)')->default(1);
+ });
+
+ $this->assertCommentOnColumn('test_table', 'number', '(DC2Type:integer)');
+
+ Schema::table('test_table', function (Blueprint $table) {
+ $table->integer('number')->comment('test')->change();
+ });
+
+ $this->assertCommentOnColumn('test_table', 'number', 'test');
+ }
+
+ /** @test */
+ public function alterTableChangeSimpleComment(): void
+ {
+ Schema::create('test_table', function (Blueprint $table) {
+ $table->integer('number')->comment('(DC2Type:integer)')->default(1);
+ });
+
+ $this->assertDefaultOnColumn('test_table', 'number', '1');
+
+ Schema::table('test_table', function (Blueprint $table) {
+ $table->string('number')->comment('some comment')->change();
+ });
+
+ $this->assertCommentOnColumn('test_table', 'number', 'some comment');
+ $this->assertDefaultOnColumn('test_table', 'number', "'1'::character varying");
+ }
+
+ /** @test */
+ public function alterTableUsingByDefault(): void
+ {
+ Schema::create('test_table', function (Blueprint $table) {
+ $table->string('code')->default('1');
+ });
+
+ $this->assertDefaultOnColumn('test_table', 'code', "'1'::character varying");
+
+ Schema::table('test_table', function (Blueprint $table) {
+ $table->integer('code')->default(null)->change();
+ });
+
+ $this->assertTypeColumn('test_table', 'code', 'integer');
+ $this->assertDefaultOnColumn('test_table', 'code');
+ }
+
+ /** @test */
+ public function alterTableUsingWithExpression(): void
+ {
+ Schema::create('test_table', function (Blueprint $table) {
+ $table->integer('id')->primary();
+ $table->integer('number')->default('1')->nullable();
+ });
+
+ $this->assertDefaultOnColumn('test_table', 'number', '1');
+
+ DB::table('test_table')->insert([['id' => 1]]);
+
+ $this->assertDatabaseHas('test_table', ['id' => 1]);
+ $this->assertTypeColumn('test_table', 'number', 'integer');
+
+ Schema::table('test_table', function (Blueprint $table) {
+ $table->string('number')
+ ->using("('[' || number || ']')::character varying")
+ ->change();
+ });
+
+ $this->assertDefaultOnColumn('test_table', 'number', "'1'::character varying");
+ $this->assertTypeColumn('test_table', 'number', 'string');
+ $this->assertDatabaseHas('test_table', [
+ 'id' => 1,
+ 'number' => '[1]',
+ ]);
+ }
+
+ /** @test */
+ public function alterTableSetDefault(): void
+ {
+ Schema::create('test_table', function (Blueprint $table) {
+ $table->integer('code')->nullable();
+ });
+
+ $this->assertTypeColumn('test_table', 'code', 'integer');
+ $this->assertDefaultOnColumn('test_table', 'code');
+
+ Schema::table('test_table', function (Blueprint $table) {
+ $table->string('code')->default('test_string')->change();
+ });
+
+ $this->assertTypeColumn('test_table', 'code', 'string');
+ $this->assertDefaultOnColumn('test_table', 'code', "'test_string'::character varying");
+ }
+
+ /** @test */
+ public function alterTableChangeDefault(): void
+ {
+ Schema::create('test_table', function (Blueprint $table) {
+ $table->string('description')->default('default1');
+ });
+
+ $this->assertDefaultOnColumn('test_table', 'description', "'default1'::character varying");
+
+ Schema::table('test_table', function (Blueprint $table) {
+ $table->text('description')->default('default2')->change();
+ });
+
+ $this->assertDefaultOnColumn('test_table', 'description', "'default2'::text");
+ }
+
+ /** @test */
+ public function alterTableDropDefault(): void
+ {
+ Schema::create('test_table', function (Blueprint $table) {
+ $table->string('description')->default('default_value');
+ });
+
+ $this->assertDefaultOnColumn('test_table', 'description', "'default_value'::character varying");
+
+ Schema::table('test_table', function (Blueprint $table) {
+ $table->string('description')->nullable()->default(null)->change();
+ });
+
+ $this->assertDefaultOnColumn('test_table', 'description');
+ }
+
+ /** @test */
+ public function alterTableSetDefaultExpression(): void
+ {
+ Schema::create('test_table', function (Blueprint $table) {
+ $table->string('code')->nullable();
+ });
+
+ $this->assertDefaultOnColumn('test_table', 'code');
+
+ Schema::table('test_table', function (Blueprint $table) {
+ $table->string('code')->default(new Expression("''::character varying"))->change();
+ });
+
+ $this->assertDefaultOnColumn('test_table', 'code', "''::character varying");
+ }
+
+ /** @test */
+ public function alterTableCreateSequence(): void
+ {
+ Schema::create('test_table', function (Blueprint $table) {
+ $table->integer('id')->default(1);
+ });
+
+ $this->assertDefaultOnColumn('test_table', 'id', '1');
+
+ Schema::table('test_table', function (Blueprint $table) {
+ $table->increments('id')->change();
+ });
+
+ $this->assertDefaultOnColumn('test_table', 'id', "nextval('test_table_id_seq'::regclass)");
+ }
+
+ /** @test */
+ public function alterTableDropSequence(): void
+ {
+ Schema::create('test_table', function (Blueprint $table) {
+ $table->increments('id');
+ });
+
+ $this->assertDefaultOnColumn('test_table', 'id', "nextval('test_table_id_seq'::regclass)");
+
+ Schema::table('test_table', function (Blueprint $table) {
+ $table->integer('id')->change();
+ });
+
+ $this->assertDefaultOnColumn('test_table', 'id');
+ }
+}
diff --git a/tests/Functional/Schema/CreateIndexTest.php b/tests/Functional/Schema/CreateIndexTest.php
new file mode 100644
index 0000000..938dff0
--- /dev/null
+++ b/tests/Functional/Schema/CreateIndexTest.php
@@ -0,0 +1,202 @@
+tsRange('code')->gist();
+ });
+
+ $this->seeIndex('test_table_code_gist');
+
+ Schema::table('test_table', function (Blueprint $table) {
+ $table->tsRange('some_id');
+ $table->tsRange('some_key');
+ $table->gist('some_key', 'specify_gist_key');
+ $table->gist('some_id');
+ });
+
+ $this->seeIndex('specify_gist_key');
+ $this->seeIndex('test_table_some_id_gist');
+ }
+
+ /** @test */
+ public function createGinIndex(): void
+ {
+ Schema::create('test_table', function (Blueprint $table) {
+ $table->tsVector('id')->gin();
+ });
+
+ $this->seeIndex('test_table_id_gin');
+
+ Schema::table('test_table', function (Blueprint $table) {
+ $table->tsVector('some_id');
+ $table->tsVector('some_key');
+ $table->gin('some_key', 'specify_gin_key');
+ $table->gin('some_id');
+ });
+
+ $this->seeIndex('specify_gin_key');
+ $this->seeIndex('test_table_some_id_gin');
+ }
+
+ /** @test */
+ public function createIndexIfNotExists(): void
+ {
+ Schema::create('test_table', function (Blueprint $table) {
+ $table->increments('id');
+ $table->string('name');
+
+ if (!$table->hasIndex(['name'], true)) {
+ $table->unique(['name']);
+ }
+ });
+
+ $this->assertTrue(Schema::hasTable('test_table'));
+
+ Schema::table('test_table', function (Blueprint $table) {
+ if (!$table->hasIndex(['name'], true)) {
+ $table->unique(['name']);
+ }
+ });
+
+ $this->seeIndex('test_table_name_unique');
+ }
+
+ /**
+ * @test
+ * @dataProvider provideIndexes
+ */
+ public function createPartialUniqueWithNull(string $expected, Closure $callback): void
+ {
+ Schema::create('test_table', function (Blueprint $table) use ($callback) {
+ $table->increments('id');
+ $table->string('name');
+ $table->string('code');
+ $table->integer('phone');
+ $table->boolean('enabled');
+ $table->integer('icq');
+ $table->softDeletes();
+
+ $callback($table);
+ });
+
+ $this->assertTrue(Schema::hasTable('test_table'));
+ $this->assertRegExpIndex('test_table_name_unique', '/' . $this->getDummyIndex() . $expected . '/');
+ }
+
+ /** @test */
+ public function createSpecifyIndex(): void
+ {
+ Schema::create('test_table', function (Blueprint $table) {
+ $table->string('name')->index('specify_index_name');
+ });
+
+ $this->assertTrue(Schema::hasTable('test_table'));
+
+ $this->assertRegExpIndex(
+ 'specify_index_name',
+ '/CREATE INDEX specify_index_name ON (public.)?test_table USING btree \(name\)/'
+ );
+ }
+
+ public function provideIndexes(): Generator
+ {
+ yield ['', function (Blueprint $table) {
+ $table->uniquePartial('name');
+ }];
+ yield [
+ ' WHERE \(deleted_at IS NULL\)',
+ function (Blueprint $table) {
+ $table->uniquePartial('name')->whereNull('deleted_at');
+ },
+ ];
+ yield [
+ ' WHERE \(deleted_at IS NOT NULL\)',
+ function (Blueprint $table) {
+ $table->uniquePartial('name')->whereNotNull('deleted_at');
+ },
+ ];
+ yield [
+ ' WHERE \(phone = 1234\)',
+ function (Blueprint $table) {
+ $table->uniquePartial('name')->where('phone', '=', 1234);
+ },
+ ];
+ yield [
+ " WHERE \(\(code\)::text = 'test'::text\)",
+ function (Blueprint $table) {
+ $table->uniquePartial('name')->where('code', '=', 'test');
+ },
+ ];
+ yield [
+ ' WHERE \(\(phone >= 1\) AND \(phone <= 2\)\)',
+ function (Blueprint $table) {
+ $table->uniquePartial('name')->whereBetween('phone', [1, 2]);
+ },
+ ];
+ yield [
+ ' WHERE \(\(phone < 1\) OR \(phone > 2\)\)',
+ function (Blueprint $table) {
+ $table->uniquePartial('name')->whereNotBetween('phone', [1, 2]);
+ },
+ ];
+ yield [
+ ' WHERE \(phone <> icq\)',
+ function (Blueprint $table) {
+ $table->uniquePartial('name')->whereColumn('phone', '<>', 'icq');
+ },
+ ];
+ yield [
+ ' WHERE \(\(phone = 1\) AND \(icq < 2\)\)',
+ function (Blueprint $table) {
+ $table->uniquePartial('name')->whereRaw('phone = ? and icq < ?', [1, 2]);
+ },
+ ];
+ yield [
+ ' WHERE \(phone = ANY \(ARRAY\[1, 2, 4\]\)\)',
+ function (Blueprint $table) {
+ $table->uniquePartial('name')->whereIn('phone', [1, 2, 4]);
+ },
+ ];
+ yield [
+ ' WHERE \(0 = 1\)',
+ function (Blueprint $table) {
+ $table->uniquePartial('name')->whereIn('phone', []);
+ },
+ ];
+ yield [
+ ' WHERE \(phone <> ALL \(ARRAY\[1, 2, 4\]\)\)',
+ function (Blueprint $table) {
+ $table->uniquePartial('name')->whereNotIn('phone', [1, 2, 4]);
+ },
+ ];
+ yield [
+ ' WHERE \(1 = 1\)',
+ function (Blueprint $table) {
+ $table->uniquePartial('name')->whereNotIn('phone', []);
+ },
+ ];
+ }
+
+ protected function getDummyIndex(): string
+ {
+ return 'CREATE UNIQUE INDEX test_table_name_unique ON (public.)?test_table USING btree \(name\)';
+ }
+}
diff --git a/tests/Functional/SchemaTest.php b/tests/Functional/Schema/CreateTableTest.php
similarity index 53%
rename from tests/Functional/SchemaTest.php
rename to tests/Functional/Schema/CreateTableTest.php
index 3e9f825..ce234a0 100644
--- a/tests/Functional/SchemaTest.php
+++ b/tests/Functional/Schema/CreateTableTest.php
@@ -2,27 +2,32 @@
declare(strict_types=1);
-namespace Umbrellio\Postgres\Tests\Functional;
+namespace Umbrellio\Postgres\Tests\Functional\Schema;
+use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Schema;
use Umbrellio\Postgres\Schema\Blueprint;
+use Umbrellio\Postgres\Tests\Functional\Helpers\TableAssertions;
+use Umbrellio\Postgres\Tests\FunctionalTestCase;
-class SchemaTest extends FunctionalTestCase
+class CreateTableTest extends FunctionalTestCase
{
+ use DatabaseTransactions, TableAssertions;
+
/** @test */
- public function create(): void
+ public function createSimple(): void
{
Schema::create('test_table', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
});
- $this->assertTrue(Schema::hasTable('test_table'));
- $this->assertSame(['id', 'name'], Schema::getColumnListing('test_table'));
+ $this->seeTable('test_table');
+ $this->assertSameTable(['id', 'name'], 'test_table');
}
/** @test */
- public function createLikeSimple(): void
+ public function createViaLike(): void
{
Schema::create('test_table', function (Blueprint $table) {
$table->increments('id');
@@ -33,14 +38,13 @@ public function createLikeSimple(): void
$table->like('test_table');
});
- $this->assertTrue(Schema::hasTable('test_table'));
- $this->assertTrue(Schema::hasTable('test_table2'));
-
- $this->assertSame(Schema::getColumnListing('test_table'), Schema::getColumnListing('test_table2'));
+ $this->seeTable('test_table');
+ $this->seeTable('test_table2');
+ $this->assertCompareTables('test_table', 'test_table2');
}
/** @test */
- public function createLikeFull(): void
+ public function createViaLikeIncludingAll(): void
{
Schema::create('test_table', function (Blueprint $table) {
$table->increments('id');
@@ -52,8 +56,8 @@ public function createLikeFull(): void
$table->ifNotExists();
});
- $this->assertTrue(Schema::hasTable('test_table'));
- $this->assertTrue(Schema::hasTable('test_table2'));
- $this->assertSame(Schema::getColumnListing('test_table'), Schema::getColumnListing('test_table2'));
+ $this->seeTable('test_table');
+ $this->seeTable('test_table2');
+ $this->assertCompareTables('test_table', 'test_table2');
}
}
diff --git a/tests/Functional/UniqueIndexTest.php b/tests/Functional/UniqueIndexTest.php
deleted file mode 100644
index 8de9265..0000000
--- a/tests/Functional/UniqueIndexTest.php
+++ /dev/null
@@ -1,142 +0,0 @@
-increments('id');
- $table->string('name');
- $table->string('code');
- $table->integer('phone');
- $table->boolean('enabled');
- $table->integer('icq');
- $table->softDeletes();
- $callback($table);
- });
-
- $this->assertTrue(Schema::hasTable('test_table'));
-
- $indexes = $this->getIndexByName('test_table_name_unique');
-
- $this->assertTrue(isset($indexes->indexdef));
- $this->assertSame($this->getDummyIndex() . $expected, $indexes->indexdef);
- }
-
- /** @test */
- public function createSpecifyIndex(): void
- {
- Schema::create('test_table', function (Blueprint $table) {
- $table->string('name')->index('specify_index_name');
- });
-
- $this->assertTrue(Schema::hasTable('test_table'));
-
- $this->assertSame(
- 'CREATE INDEX specify_index_name ON public.test_table USING btree (name)',
- $this->getIndexByName('specify_index_name')->indexdef
- );
- }
-
- public function provideIndexes(): Generator
- {
- yield ['', function (Blueprint $table) {
- $table->uniquePartial('name');
- }];
- yield [
- ' WHERE (deleted_at IS NULL)',
- function (Blueprint $table) {
- $table->uniquePartial('name')->whereNull('deleted_at');
- },
- ];
- yield [
- ' WHERE (deleted_at IS NOT NULL)',
- function (Blueprint $table) {
- $table->uniquePartial('name')->whereNotNull('deleted_at');
- },
- ];
- yield [
- ' WHERE (phone = 1234)',
- function (Blueprint $table) {
- $table->uniquePartial('name')->where('phone', '=', 1234);
- },
- ];
- yield [
- " WHERE ((code)::text = 'test'::text)",
- function (Blueprint $table) {
- $table->uniquePartial('name')->where('code', '=', 'test');
- },
- ];
- yield [
- ' WHERE ((phone >= 1) AND (phone <= 2))',
- function (Blueprint $table) {
- $table->uniquePartial('name')->whereBetween('phone', [1, 2]);
- },
- ];
- yield [
- ' WHERE ((phone < 1) OR (phone > 2))',
- function (Blueprint $table) {
- $table->uniquePartial('name')->whereNotBetween('phone', [1, 2]);
- },
- ];
- yield [
- ' WHERE (phone <> icq)',
- function (Blueprint $table) {
- $table->uniquePartial('name')->whereColumn('phone', '<>', 'icq');
- },
- ];
- yield [
- ' WHERE ((phone = 1) AND (icq < 2))',
- function (Blueprint $table) {
- $table->uniquePartial('name')->whereRaw('phone = ? and icq < ?', [1, 2]);
- },
- ];
- yield [
- ' WHERE (phone = ANY (ARRAY[1, 2, 4]))',
- function (Blueprint $table) {
- $table->uniquePartial('name')->whereIn('phone', [1, 2, 4]);
- },
- ];
- yield [
- ' WHERE (0 = 1)',
- function (Blueprint $table) {
- $table->uniquePartial('name')->whereIn('phone', []);
- },
- ];
- yield [
- ' WHERE (phone <> ALL (ARRAY[1, 2, 4]))',
- function (Blueprint $table) {
- $table->uniquePartial('name')->whereNotIn('phone', [1, 2, 4]);
- },
- ];
- yield [
- ' WHERE (1 = 1)',
- function (Blueprint $table) {
- $table->uniquePartial('name')->whereNotIn('phone', []);
- },
- ];
- }
-
- protected function getDummyIndex()
- {
- return 'CREATE UNIQUE INDEX test_table_name_unique ON public.test_table USING btree (name)';
- }
-
- protected function getIndexByName($name)
- {
- return collect(DB::select("SELECT indexdef FROM pg_indexes WHERE indexname = '{$name}'"))->first();
- }
-}
diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php
new file mode 100644
index 0000000..ecf2691
--- /dev/null
+++ b/tests/FunctionalTestCase.php
@@ -0,0 +1,49 @@
+getConnectionParams();
+
+ $app['config']->set('database.default', 'main');
+ $app['config']->set('database.connections.main', [
+ 'driver' => 'pgsql',
+ 'host' => $params['host'],
+ 'port' => (int) $params['port'],
+ 'database' => $params['database'],
+ 'username' => $params['user'],
+ 'password' => $params['password'],
+ 'charset' => 'utf8',
+ 'prefix' => '',
+ 'schema' => 'public',
+ ]);
+ }
+
+ private function getConnectionParams(): array
+ {
+ return [
+ 'driver' => $GLOBALS['db_type'] ?? 'pdo_pgsql',
+ 'user' => $GLOBALS['db_username'],
+ 'password' => $GLOBALS['db_password'],
+ 'host' => $GLOBALS['db_host'],
+ 'database' => $GLOBALS['db_database'],
+ 'port' => $GLOBALS['db_port'],
+ ];
+ }
+}
diff --git a/tests/TestCase.php b/tests/TestCase.php
index 2467719..67c8ab0 100644
--- a/tests/TestCase.php
+++ b/tests/TestCase.php
@@ -9,7 +9,7 @@
abstract class TestCase extends BaseTestCase
{
- protected function getPackageProviders($app)
+ protected function getPackageProviders($app): array
{
return [UmbrellioPostgresProvider::class];
}
diff --git a/tests/Unit/Doctrine/Types/TsRangeTypeTest.php b/tests/Unit/Doctrine/Types/TsRangeTypeTest.php
new file mode 100644
index 0000000..375908d
--- /dev/null
+++ b/tests/Unit/Doctrine/Types/TsRangeTypeTest.php
@@ -0,0 +1,74 @@
+type = $this
+ ->getMockBuilder(TsRangeType::class)
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+
+ $this->abstractPlatform = $this->getMockForAbstractClass(AbstractPlatform::class);
+ }
+
+ /** @test */
+ public function getSQLDeclaration(): void
+ {
+ $this->assertSame(TsRangeType::TYPE_NAME, $this->type->getSQLDeclaration([], $this->abstractPlatform));
+ }
+
+ /**
+ * @dataProvider providePHPValues
+ * @test
+ */
+ public function convertToPHPValue($value, $expected): void
+ {
+ $this->assertSame($expected, $this->type->convertToDatabaseValue($value, $this->abstractPlatform));
+ }
+
+ public function provideDatabaseValues(): Generator
+ {
+ yield [null, null];
+ yield ['[1352302322,1352302356]', '[1352302322,1352302356]'];
+ }
+
+ /**
+ * @dataProvider provideDatabaseValues
+ * @test
+ */
+ public function convertToDatabaseValue($value, $expected): void
+ {
+ $this->assertSame($expected, $this->type->convertToPHPValue($value, $this->abstractPlatform));
+ }
+
+ public function providePHPValues(): Generator
+ {
+ yield [null, null];
+ yield ['[1352302322,1352302356]', '[1352302322,1352302356]'];
+ }
+
+ /** @test */
+ public function getTypeName(): void
+ {
+ $this->assertSame(TsRangeType::TYPE_NAME, $this->type->getName());
+ }
+}
diff --git a/tests/Unit/Doctrine/Types/TsVectorTypeTest.php b/tests/Unit/Doctrine/Types/TsVectorTypeTest.php
new file mode 100644
index 0000000..10ba52b
--- /dev/null
+++ b/tests/Unit/Doctrine/Types/TsVectorTypeTest.php
@@ -0,0 +1,74 @@
+type = $this
+ ->getMockBuilder(TsVectorType::class)
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+
+ $this->abstractPlatform = $this->getMockForAbstractClass(AbstractPlatform::class);
+ }
+
+ /** @test */
+ public function getSQLDeclaration(): void
+ {
+ $this->assertSame(TsVectorType::TYPE_NAME, $this->type->getSQLDeclaration([], $this->abstractPlatform));
+ }
+
+ /**
+ * @dataProvider providePHPValues
+ * @test
+ */
+ public function convertToPHPValue($value, $expected): void
+ {
+ $this->assertSame($expected, $this->type->convertToDatabaseValue($value, $this->abstractPlatform));
+ }
+
+ public function provideDatabaseValues(): Generator
+ {
+ yield [null, null];
+ yield ['key:2, key:2,3', 'key:2, key:2,3'];
+ }
+
+ /**
+ * @dataProvider provideDatabaseValues
+ * @test
+ */
+ public function convertToDatabaseValue($value, $expected): void
+ {
+ $this->assertSame($expected, $this->type->convertToPHPValue($value, $this->abstractPlatform));
+ }
+
+ public function providePHPValues(): Generator
+ {
+ yield [null, null];
+ yield ['key:2, key:2,3', 'key:2, key:2,3'];
+ }
+
+ /** @test */
+ public function getTypeName(): void
+ {
+ $this->assertSame(TsVectorType::TYPE_NAME, $this->type->getName());
+ }
+}
diff --git a/tests/Unit/Extensions/AbstractExtensionTest.php b/tests/Unit/Extensions/AbstractExtensionTest.php
new file mode 100644
index 0000000..24c1ee9
--- /dev/null
+++ b/tests/Unit/Extensions/AbstractExtensionTest.php
@@ -0,0 +1,65 @@
+ new class() extends Model {
+ },
+ ];
+ }
+ };
+
+ $this->expectException(MixinInvalidException::class);
+
+ /** @var AbstractExtension $abstractExtension */
+ $abstractExtension::register();
+ }
+
+ /** @test */
+ public function registerWithInvalidMixin(): void
+ {
+ $abstractExtension = new class() extends AbstractExtension {
+ public static function getName(): string
+ {
+ return 'extension';
+ }
+
+ public static function getMixins(): array
+ {
+ return [
+ ServiceProvider::class => new class() extends AbstractComponent {
+ },
+ ];
+ }
+ };
+
+ $this->expectException(MacroableMissedException::class);
+
+ /** @var AbstractExtension $abstractExtension */
+ $abstractExtension::register();
+ }
+}
diff --git a/tests/Unit/Helpers/BlueprintAssertions.php b/tests/Unit/Helpers/BlueprintAssertions.php
new file mode 100644
index 0000000..be7de4b
--- /dev/null
+++ b/tests/Unit/Helpers/BlueprintAssertions.php
@@ -0,0 +1,51 @@
+blueprint = new Blueprint($table);
+ $this->postgresConnection = $this->createMock(PostgresConnection::class);
+ $this->postgresGrammar = new PostgresGrammar();
+ }
+
+ /**
+ * @param string|array $sql
+ */
+ protected function assertSameSql($sql): void
+ {
+ $this->assertSame((array) $sql, $this->runToSql());
+ }
+
+ protected function assertRegExpSql(string $regexpExpected): void
+ {
+ foreach ($this->runToSql() as $sql) {
+ $this->assertRegExp($regexpExpected, $sql);
+ }
+ }
+
+ private function runToSql(): array
+ {
+ return $this->blueprint->toSql($this->postgresConnection, $this->postgresGrammar);
+ }
+}
diff --git a/tests/Unit/Schema/BlueprintTest.php b/tests/Unit/Schema/Blueprint/PartitionTest.php
similarity index 64%
rename from tests/Unit/Schema/BlueprintTest.php
rename to tests/Unit/Schema/Blueprint/PartitionTest.php
index e70633f..e748882 100644
--- a/tests/Unit/Schema/BlueprintTest.php
+++ b/tests/Unit/Schema/Blueprint/PartitionTest.php
@@ -2,32 +2,29 @@
declare(strict_types=1);
-namespace Umbrellio\Postgres\Unit\Schema;
+namespace Umbrellio\Postgres\Unit\Schema\Blueprint;
use Illuminate\Support\Carbon;
use InvalidArgumentException;
-use Umbrellio\Postgres\PostgresConnection;
-use Umbrellio\Postgres\Schema\Blueprint;
-use Umbrellio\Postgres\Schema\Grammars\PostgresGrammar;
use Umbrellio\Postgres\Tests\TestCase;
+use Umbrellio\Postgres\Tests\Unit\Helpers\BlueprintAssertions;
-class BlueprintTest extends TestCase
+class PartitionTest extends TestCase
{
- /** @var Blueprint */
- private $blueprint;
+ use BlueprintAssertions;
+
+ private const TABLE = 'test_table';
protected function setUp(): void
{
parent::setUp();
-
- $this->blueprint = new Blueprint('test_table');
+ $this->initializeMock(static::TABLE);
}
/** @test */
public function detachPartition(): void
{
$this->blueprint->detachPartition('some_partition');
-
$this->assertSameSql('alter table "test_table" detach partition some_partition');
}
@@ -38,7 +35,6 @@ public function attachPartitionRangeInt(): void
'from' => 10,
'to' => 100,
]);
-
$this->assertSameSql('alter table "test_table" attach partition some_partition for values from (10) to (100)');
}
@@ -46,7 +42,6 @@ public function attachPartitionRangeInt(): void
public function attachPartitionFailedWithoutForValuesPart(): void
{
$this->blueprint->attachPartition('some_partition');
-
$this->expectException(InvalidArgumentException::class);
$this->runToSql();
}
@@ -61,18 +56,10 @@ public function attachPartitionRangeDates(): void
'to' => $tomorrow,
]);
- $this->assertSameSql(
- 'alter table "test_table" attach partition some_partition '
- . "for values from ('{$today->toDateTimeString()}') to ('{$tomorrow->toDateTimeString()}')");
- }
-
- private function assertSameSql(string $sql): void
- {
- $this->assertSame([$sql], $this->runToSql());
- }
-
- private function runToSql(): array
- {
- return $this->blueprint->toSql($this->createMock(PostgresConnection::class), new PostgresGrammar());
+ $this->assertSameSql(sprintf(
+ 'alter table "test_table" attach partition some_partition for values from (\'%s\') to (\'%s\')',
+ $today->toDateTimeString(),
+ $tomorrow->toDateTimeString()
+ ));
}
}
diff --git a/tests/Unit/Schema/Grammars/GrammarTest.php b/tests/Unit/Schema/Grammars/GrammarTest.php
index 808628b..2a87d54 100644
--- a/tests/Unit/Schema/Grammars/GrammarTest.php
+++ b/tests/Unit/Schema/Grammars/GrammarTest.php
@@ -4,43 +4,33 @@
namespace Umbrellio\Postgres\Tests\Unit\Schema\Grammars;
-use Mockery;
-use Umbrellio\Postgres\PostgresConnection;
-use Umbrellio\Postgres\Schema\Blueprint;
-use Umbrellio\Postgres\Schema\Grammars\PostgresGrammar;
use Umbrellio\Postgres\Tests\TestCase;
+use Umbrellio\Postgres\Tests\Unit\Helpers\BlueprintAssertions;
class GrammarTest extends TestCase
{
- /** @test */
- public function addingGinIndex()
- {
- $blueprint = new Blueprint('test');
- $blueprint->gin('foo');
- $statements = $blueprint->toSql($this->getConnectionMock(), $this->getGrammar());
- $this->assertCount(1, $statements);
- $this->assertStringContainsString('CREATE INDEX', $statements[0]);
- $this->assertStringContainsString('GIN("foo")', $statements[0]);
- }
+ use BlueprintAssertions;
- /** @test */
- public function addingGistIndex()
+ private const TABLE = 'test_table';
+
+ protected function setUp(): void
{
- $blueprint = new Blueprint('test');
- $blueprint->gist('foo');
- $statements = $blueprint->toSql($this->getConnectionMock(), $this->getGrammar());
- $this->assertCount(1, $statements);
- $this->assertStringContainsString('CREATE INDEX', $statements[0]);
- $this->assertStringContainsString('GIST("foo")', $statements[0]);
+ parent::setUp();
+
+ $this->initializeMock(static::TABLE);
}
- protected function getConnectionMock()
+ /** @test */
+ public function addingGinIndex(): void
{
- return Mockery::mock(PostgresConnection::class);
+ $this->blueprint->gin('foo');
+ $this->assertRegExpSql('/CREATE INDEX test_table_foo_gin ON (public.)?"test_table" USING GIN\("foo"\)/');
}
- protected function getGrammar()
+ /** @test */
+ public function addingGistIndex(): void
{
- return new PostgresGrammar();
+ $this->blueprint->gist('foo');
+ $this->assertRegExpSql('/CREATE INDEX test_table_foo_gist ON (public.)?"test_table" USING GIST\("foo"\)/');
}
}
diff --git a/tests/Unit/Schema/IndexTest.php b/tests/Unit/Schema/IndexTest.php
deleted file mode 100644
index 1b05de6..0000000
--- a/tests/Unit/Schema/IndexTest.php
+++ /dev/null
@@ -1,42 +0,0 @@
-blueprint = Mockery::mock(Blueprint::class)
- ->makePartial()
- ->shouldAllowMockingProtectedMethods();
- }
-
- /** @test */
- public function ginIndex()
- {
- $this->blueprint
- ->shouldReceive('indexCommand')
- ->with('gin', 'col', 'myName');
- $this->blueprint->gin('col', 'myName');
- }
-
- /** @test */
- public function gistIndex()
- {
- $this->blueprint
- ->shouldReceive('indexCommand')
- ->with('gist', 'col', 'myName');
- $this->blueprint->gist('col', 'myName');
- }
-}
diff --git a/tests/travis/install-postgres-10.sh b/tests/travis/install-postgres-10.sh
new file mode 100755
index 0000000..8804124
--- /dev/null
+++ b/tests/travis/install-postgres-10.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+
+set -ex
+
+echo "Installing Postgres 10"
+sudo service postgresql stop
+sudo apt-get remove -q 'postgresql-*'
+sudo apt-get update -q
+sudo apt-get install -q postgresql-10 postgresql-client-10
+sudo cp /etc/postgresql/{9.6,10}/main/pg_hba.conf
+
+echo "Restarting Postgres 10"
+sudo service postgresql restart
diff --git a/tests/travis/install-postgres-11.sh b/tests/travis/install-postgres-11.sh
new file mode 100755
index 0000000..2ef1aab
--- /dev/null
+++ b/tests/travis/install-postgres-11.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+set -ex
+
+echo "Preparing Postgres 11"
+
+sudo service postgresql stop || true
+
+sudo docker run -d --name postgres11 -p 5432:5432 postgres:11.1
+sudo docker exec -i postgres11 bash <<< 'until pg_isready -U postgres > /dev/null 2>&1 ; do sleep 1; done'
+
+echo "Postgres 11 ready"