Skip to content

Commit b027a1d

Browse files
authored
Merge pull request #41 from kitloong/feature/collation
Feature/collation
2 parents 764a304 + dd5a468 commit b027a1d

File tree

62 files changed

+2457
-1879
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+2457
-1879
lines changed

.env.action

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
MYSQL57_HOST=127.0.0.1
2+
MYSQL57_PORT=3306
3+
MYSQL57_DATABASE=migration
4+
MYSQL57_USERNAME=root
5+
MYSQL57_PASSWORD=
6+
7+
MYSQL8_HOST=127.0.0.1
8+
MYSQL8_PORT=33062
9+
MYSQL8_DATABASE=migration
10+
MYSQL8_USERNAME=root
11+
MYSQL8_PASSWORD=
12+
13+
POSTGRES_HOST=127.0.0.1
14+
POSTGRES_PORT=5432
15+
POSTGRES_DATABASE=migration
16+
POSTGRES_USERNAME=root
17+
POSTGRES_PASSWORD=!QAZ2wsx
18+
19+
SQLSRV_HOST=127.0.0.1
20+
SQLSRV_PORT=1433
21+
SQLSRV_DATABASE=migration
22+
SQLSRV_USERNAME=sa
23+
SQLSRV_PASSWORD=!QAZ2wsx

.env.example

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
MYSQL57_HOST=mysql57
2+
MYSQL57_PORT=3306
3+
MYSQL57_DATABASE=migration
4+
MYSQL57_USERNAME=
5+
MYSQL57_PASSWORD=
6+
7+
MYSQL8_HOST=mysql8
8+
MYSQL8_PORT=3306
9+
MYSQL8_DATABASE=migration
10+
MYSQL8_USERNAME=
11+
MYSQL8_PASSWORD=
12+
13+
POSTGRES_HOST=pgsql
14+
POSTGRES_PORT=5432
15+
POSTGRES_DATABASE=migration
16+
POSTGRES_USERNAME=
17+
POSTGRES_PASSWORD=

.gitattributes

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,7 @@
66
/.gitattributes export-ignore
77
/.gitignore export-ignore
88
/.travis.yml export-ignore
9-
/phpunit.xml.dist export-ignore
9+
/phpunit.xml export-ignore
1010
/tests export-ignore
11+
/.env.* export-ignore
12+
/phpcs.xml export-ignore

.github/workflows/tests.yml

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,60 @@ jobs:
1212
image: mysql:5.7
1313
env:
1414
MYSQL_ALLOW_EMPTY_PASSWORD: yes
15-
MYSQL_DATABASE: forge
15+
MYSQL_DATABASE: migration
1616
ports:
17-
- 33306:3306
17+
- 3306:3306
1818
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
1919

20+
mysql8:
21+
image: mysql:8
22+
env:
23+
MYSQL_ALLOW_EMPTY_PASSWORD: yes
24+
MYSQL_DATABASE: migration
25+
ports:
26+
- 33062:3306
27+
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
28+
29+
postgres:
30+
image: mdillon/postgis:11
31+
env:
32+
POSTGRES_DB: migration
33+
POSTGRES_USER: root
34+
POSTGRES_PASSWORD: "!QAZ2wsx"
35+
ports:
36+
- 5432:5432
37+
options: >-
38+
--health-cmd pg_isready
39+
--health-interval 10s
40+
--health-timeout 5s
41+
--health-retries 5
42+
43+
sqlsrv:
44+
image: mcr.microsoft.com/mssql/server:2019-latest
45+
env:
46+
SA_PASSWORD: "!QAZ2wsx"
47+
ACCEPT_EULA: "Y"
48+
ports:
49+
- 1433:1433
50+
2051
strategy:
2152
matrix:
2253
php: [ 7.3, 7.4 ]
2354
laravel: [ 8.*, 7.*, 6.*, 5.8.*, 5.7.*, 5.6.* ]
55+
dbal: [ 2.* ]
2456
stability: [ prefer-stable ]
2557
include:
2658
- laravel: 8.*
2759
php: 8.0
60+
dbal: 3.*
2861
stability: prefer-stable
2962
- laravel: 7.*
3063
php: 8.0
64+
dbal: 2.*
3165
stability: prefer-stable
3266
- laravel: 6.*
3367
php: 8.0
68+
dbal: 2.*
3469
stability: prefer-stable
3570

3671
name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }}
@@ -39,18 +74,37 @@ jobs:
3974
- name: Checkout code
4075
uses: actions/checkout@v2
4176

77+
- name: Alter MySQL 8 root plugin
78+
run: |
79+
mysql --version
80+
mysql --host 127.0.0.1 --port ${{ job.services.mysql8.ports['3306'] }} -u root -e "ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY ''"
81+
82+
- name: SQL Server Create Database
83+
run: |
84+
sleep 5s
85+
86+
# Test connection
87+
sqlcmd -S 127.0.0.1 -U sa -P '!QAZ2wsx' -Q 'SELECT 1' -b
88+
89+
# Create DB
90+
sqlcmd -S 127.0.0.1 -U sa -P '!QAZ2wsx' -Q 'CREATE DATABASE migration' -b
91+
4292
- name: Setup PHP
4393
uses: shivammathur/setup-php@v2
4494
with:
4595
php-version: ${{ matrix.php }}
46-
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, gd, redis, memcached
96+
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, gd, redis, memcached, pdo_sqlsrv
4797
tools: composer:v2
4898
coverage: none
4999

50100
- name: Install dependencies
51101
run: |
52-
composer require "laravel/framework:${{ matrix.laravel }}" --no-interaction --no-update
102+
php -m
103+
composer require "laravel/framework:${{ matrix.laravel }}" "doctrine/dbal:${{ matrix.dbal }}" --no-interaction --no-update
53104
composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress
54105
106+
- name: Setup .env
107+
run: composer run action-env-setup
108+
55109
- name: Execute tests
56110
run: vendor/bin/phpunit

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,7 @@ report
33
composer.lock
44
build
55
.idea
6-
.phpunit.result.cache
6+
.phpunit.result.cache
7+
storage
8+
.env
9+
.phpstorm.meta.php

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ Run `php artisan help migrate:generate` for a list of options.
8787
|-t, --tables[=TABLES]|A list of Tables you wish to Generate Migrations for separated by a comma: users,posts,comments|
8888
|-i, --ignore[=IGNORE]|A list of Tables you wish to ignore, separated by a comma: users,posts,comments|
8989
|-p, --path[=PATH]|Where should the file be created?|
90+
| --useDBCollation|Follow db collations for migrations|
9091
| --defaultIndexNames|Don't use db index names for migrations|
9192
| --defaultFKNames|Don't use db foreign key names for migrations|
9293
|-tp, --templatePath[=TEMPLATEPATH]|The location of the template for this generator|

composer.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"require-dev": {
1818
"orchestra/testbench": "^3.6|^4.0|^5.0|^6.0",
1919
"squizlabs/php_codesniffer": "^3.5",
20-
"mockery/mockery": "^1.0"
20+
"mockery/mockery": "^1.0",
21+
"ext-pdo": "*"
2122
},
2223
"autoload": {
2324
"psr-4": {
@@ -37,5 +38,12 @@
3738
"KitLoong\\MigrationsGenerator\\MigrationsGeneratorServiceProvider"
3839
]
3940
}
40-
}
41+
},
42+
"minimum-stability": "dev",
43+
"prefer-stable": true,
44+
"scripts": {
45+
"action-env-setup": [
46+
"@php -r \"file_exists('.env') || copy('.env.action', '.env');\""
47+
]
48+
}
4149
}

phpcs.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@
88
<file>tests</file>
99

1010
<exclude-pattern>features/bootstrap/FeatureContext.php</exclude-pattern>
11+
<exclude-pattern>tests/KitLoong/resources/database/migrations/*.php</exclude-pattern>
1112
</ruleset>

src/KitLoong/MigrationsGenerator/Generators/DatetimeField.php

Lines changed: 106 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,51 @@
11
<?php
2-
/**
3-
* Created by PhpStorm.
4-
* User: liow.kitloong
5-
* Date: 2020/03/29
6-
*/
72

83
namespace KitLoong\MigrationsGenerator\Generators;
94

105
use Doctrine\DBAL\Schema\Column;
6+
use Doctrine\DBAL\Types\DateTimeImmutableType;
7+
use Doctrine\DBAL\Types\DateTimeType;
8+
use Doctrine\DBAL\Types\DateTimeTzImmutableType;
9+
use Doctrine\DBAL\Types\DateTimeTzType;
1110
use KitLoong\MigrationsGenerator\MigrationMethod\ColumnModifier;
1211
use KitLoong\MigrationsGenerator\MigrationMethod\ColumnName;
1312
use KitLoong\MigrationsGenerator\MigrationMethod\ColumnType;
13+
use KitLoong\MigrationsGenerator\MigrationsGeneratorSetting;
14+
use KitLoong\MigrationsGenerator\Repositories\MySQLRepository;
15+
use KitLoong\MigrationsGenerator\Repositories\PgSQLRepository;
16+
use KitLoong\MigrationsGenerator\Repositories\SQLSrvRepository;
17+
use KitLoong\MigrationsGenerator\Support\Regex;
18+
use KitLoong\MigrationsGenerator\Types\DBALTypes;
1419

1520
class DatetimeField
1621
{
22+
const SQLSRV_DATETIME_DEFAULT_SCALE = 3;
23+
const SQLSRV_DATETIME_DEFAULT_LENGTH = 8;
24+
25+
const SQLSRV_DATETIME_TZ_DEFAULT_SCALE = 7;
26+
const SQLSRV_DATETIME_TZ_DEFAULT_LENGTH = 10;
27+
1728
private $decorator;
29+
private $mySQLRepository;
30+
private $pgSQLRepository;
31+
private $sqlSrvRepository;
32+
private $regex;
1833

19-
public function __construct(Decorator $decorator)
20-
{
34+
public function __construct(
35+
Decorator $decorator,
36+
MySQLRepository $mySQLRepository,
37+
PgSQLRepository $pgSQLRepository,
38+
SQLSrvRepository $sqlSrvRepository,
39+
Regex $regex
40+
) {
2141
$this->decorator = $decorator;
42+
$this->mySQLRepository = $mySQLRepository;
43+
$this->pgSQLRepository = $pgSQLRepository;
44+
$this->sqlSrvRepository = $sqlSrvRepository;
45+
$this->regex = $regex;
2246
}
2347

24-
public function makeField(array $field, Column $column, bool $useTimestamps): array
48+
public function makeField(string $table, array $field, Column $column, bool $useTimestamps): array
2549
{
2650
if ($useTimestamps) {
2751
if ($field['field'] === ColumnName::CREATED_AT) {
@@ -41,19 +65,31 @@ public function makeField(array $field, Column $column, bool $useTimestamps): ar
4165
$field['type'] = FieldGenerator::$fieldTypeMap[$field['type']];
4266
}
4367

44-
if ($column->getLength() !== null && $column->getLength() > 0) {
68+
$length = $this->getLength($table, $column);
69+
if ($length !== null && $length > 0) {
4570
if ($field['type'] === ColumnType::SOFT_DELETES) {
4671
$field['field'] = ColumnName::DELETED_AT;
4772
}
48-
$field['args'][] = $column->getLength();
73+
$field['args'][] = $length;
74+
}
75+
76+
if (app(MigrationsGeneratorSetting::class)->getPlatform() === Platform::MYSQL) {
77+
if ($column->getType()->getName() === DBALTypes::TIMESTAMP) {
78+
if ($this->mySQLRepository->useOnUpdateCurrentTimestamp($table, $column->getName())) {
79+
$field['decorators'][] = ColumnModifier::USE_CURRENT_ON_UPDATE;
80+
}
81+
}
4982
}
83+
5084
return $field;
5185
}
5286

5387
public function makeDefault(Column $column): string
5488
{
5589
if (in_array($column->getDefault(), ['CURRENT_TIMESTAMP'], true)) {
5690
return ColumnModifier::USE_CURRENT;
91+
} elseif ($column->getDefault() === 'now()') { // For PgSQL
92+
return ColumnModifier::USE_CURRENT;
5793
} else {
5894
$default = $this->decorator->columnDefaultToString($column->getDefault());
5995
return $this->decorator->decorate(ColumnModifier::DEFAULT, [$default]);
@@ -64,7 +100,7 @@ public function makeDefault(Column $column): string
64100
* @param Column[] $columns
65101
* @return bool
66102
*/
67-
public function isUseTimestamps($columns): bool
103+
public function isUseTimestamps(array $columns): bool
68104
{
69105
/** @var Column[] $timestampsColumns */
70106
$timestampsColumns = [];
@@ -86,4 +122,63 @@ public function isUseTimestamps($columns): bool
86122
}
87123
return $useTimestamps;
88124
}
125+
126+
private function getLength(string $table, Column $column): ?int
127+
{
128+
switch (app(MigrationsGeneratorSetting::class)->getPlatform()) {
129+
case Platform::POSTGRESQL:
130+
return $this->getPgSQLLength($table, $column);
131+
case Platform::SQLSERVER:
132+
return $this->getSQLSrvLength($table, $column);
133+
default:
134+
return $column->getLength();
135+
}
136+
}
137+
138+
/**
139+
* @param string $table
140+
* @param \Doctrine\DBAL\Schema\Column $column
141+
* @return int|null
142+
*/
143+
private function getPgSQLLength(string $table, Column $column): ?int
144+
{
145+
$rawType = ($this->pgSQLRepository->getTypeByColumnName($table, $column->getName()));
146+
$length = $this->regex->getTextBetween($rawType);
147+
if ($length !== null) {
148+
return (int) $length;
149+
} else {
150+
return null;
151+
}
152+
}
153+
154+
/**
155+
* @param string $table
156+
* @param \Doctrine\DBAL\Schema\Column $column
157+
* @return int|null
158+
*/
159+
private function getSQLSrvLength(string $table, Column $column): ?int
160+
{
161+
$colDef = $this->sqlSrvRepository->getColumnDefinition($table, $column->getName());
162+
163+
switch (get_class($column->getType())) {
164+
case DateTimeType::class:
165+
case DateTimeImmutableType::class:
166+
if ($colDef->getScale() === self::SQLSRV_DATETIME_DEFAULT_SCALE &&
167+
$colDef->getLength() === self::SQLSRV_DATETIME_DEFAULT_LENGTH) {
168+
return null;
169+
} else {
170+
return $column->getScale();
171+
}
172+
case DateTimeTzType::class:
173+
case DateTimeTzImmutableType::class:
174+
if ($colDef->getScale() === self::SQLSRV_DATETIME_TZ_DEFAULT_SCALE &&
175+
$colDef->getLength() === self::SQLSRV_DATETIME_TZ_DEFAULT_LENGTH) {
176+
return null;
177+
} else {
178+
return $column->getScale();
179+
}
180+
default:
181+
return $column->getScale();
182+
}
183+
}
89184
}

0 commit comments

Comments
 (0)