Skip to content

Commit

Permalink
fix: handle some edge cases with postgres and mariadb
Browse files Browse the repository at this point in the history
  • Loading branch information
WatheqAlshowaiter committed Jul 19, 2024
1 parent 72cd76d commit 1ac5f01
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 48 deletions.
10 changes: 8 additions & 2 deletions database/migrations/2024_07_13_093048_create_mothers_table.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use WatheqAlshowaiter\ModelRequiredFields\Constants;

Expand All @@ -19,7 +20,7 @@ public function up(): void

$table->enum('types', ['one', 'two'])->default('one'); // default => ignored

if ((float) App::version() >= Constants::VERSION_AFTER_UUID_SUPPORT) {
if ((float) App::version() >= Constants::VERSION_AFTER_UUID_SUPPORT && DB::connection()->getDriverName() !== 'mariadb') {
$table->uuid('uuid'); // required
} else {
$table->string('uuid');
Expand All @@ -29,7 +30,12 @@ public function up(): void
} else {
$table->string('ulid'); // required
}
$table->json('description')->nullable();

if (DB::connection()->getDriverName() === 'mariadb') {
$table->json('description')->nullable();
} else {
$table->text('description')->nullable();
}
});
}

Expand Down
3 changes: 2 additions & 1 deletion database/migrations/2024_07_13_100247_create_sons_table.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Schema;
use WatheqAlshowaiter\ModelRequiredFields\Constants;
use Illuminate\Support\Facades\DB;

class CreateSonsTable extends Migration
{
public function up(): void
{
Schema::create('sons', function (Blueprint $table) {

if ((float) App::version() >= Constants::VERSION_AFTER_UUID_SUPPORT) {
if ((float) App::version() >= Constants::VERSION_AFTER_UUID_SUPPORT && DB::connection()->getDriverName() !== 'mariadb') {
$table->uuid('id')->primary(); // primary key => ignored
} else {
$table->bigIncrements('id'); // primary key => ignored
Expand Down
5 changes: 2 additions & 3 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,11 @@
<env name="APP_MAINTENANCE_DRIVER" value="file"/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="CACHE_STORE" value="array"/>
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
<!-- <env name="DB_CONNECTION" value="sqlite"/> -->
<!-- <env name="DB_DATABASE" value=":memory:"/> -->
<env name="MAIL_MAILER" value="array"/>
<env name="PULSE_ENABLED" value="false"/>
<env name="QUEUE_CONNECTION" value="sync"/>
<env name="SESSION_DRIVER" value="array"/>
<!-- <env name="TELESCOPE_ENABLED" value="false"/>-->
</php>
</phpunit>
85 changes: 44 additions & 41 deletions src/RequiredFields.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,21 @@ public static function getRequiredFields(
->toArray();

return collect(Schema::getColumns((new self())->getTable()))
->reject(function ($column) use ($primaryIndex, $withNullables, $withDefaults, $withPrimaryKey) {
->reject(function ($column) use ($primaryIndex, $withNullables, $withDefaults) {
return
$column['nullable'] && ! $withNullables
|| $column['default'] != null && ! $withDefaults
|| in_array($column['name'], $primaryIndex) && ! $withPrimaryKey;
$column['nullable'] && !$withNullables ||
$column['default'] != null && !$withDefaults ||
(in_array($column['name'], $primaryIndex));
})
->pluck('name')
->when($withPrimaryKey, function ($collection) use ($primaryIndex) {
return $collection->prepend(...$primaryIndex);
})
->unique()
->toArray();
}

/**
* @todo convert this method to private after testing
*
* @return array|string
*/
public static function getRequiredFieldsForOlderVersions(
Expand Down Expand Up @@ -107,11 +109,12 @@ private static function getRequiredFieldsForSqlite(
return (array) $column;
}, $queryResult);


return collect($queryResult)
->reject(function ($column) use ($withNullables, $withDefaults, $withPrimaryKey) {
return $column['pk'] && ! $withPrimaryKey
|| $column['dflt_value'] != null && ! $withDefaults
|| ! $column['notnull'] && ! $withNullables;
return $column['pk'] && !$withPrimaryKey
|| $column['dflt_value'] != null && !$withDefaults
|| !$column['notnull'] && !$withNullables;
})
->pluck('name')
->toArray();
Expand Down Expand Up @@ -152,9 +155,9 @@ private static function getRequiredFieldsForMysqlAndMariaDb(

return collect($queryResult)
->reject(function ($column) use ($withNullables, $withDefaults, $withPrimaryKey) {
return $column['primary'] && ! $withPrimaryKey
|| $column['default'] != null && ! $withDefaults
|| $column['nullable'] && ! $withNullables;
return $column['primary'] && !$withPrimaryKey
|| $column['default'] != null && !$withDefaults
|| $column['nullable'] && !$withNullables;
})
->pluck('name')
->toArray();
Expand All @@ -168,18 +171,12 @@ private static function getRequiredFieldsForPostgres(
$withDefaults = false,
$withPrimaryKey = false
) {

$table = self::getTableFromThisModel();

$primaryIndex = DB::select("
SELECT
SELECT
ic.relname AS name,
string_agg(
a.attname,
','
ORDER BY
indseq.ord
) AS columns,
string_agg(a.attname, ',' ORDER BY indseq.ord) AS columns,
am.amname AS type,
i.indisunique AS unique,
i.indisprimary AS primary
Expand All @@ -193,14 +190,14 @@ private static function getRequiredFieldsForPostgres(
LEFT JOIN pg_attribute a ON a.attrelid = i.indrelid
AND a.attnum = indseq.num
WHERE
tc.relname = 'users'
tc.relname = ?
AND tn.nspname = CURRENT_SCHEMA
GROUP BY
ic.relname,
am.amname,
i.indisunique,
i.indisprimary;
");
", [$table]);

$primaryIndex = array_map(function ($column) {
return (array) $column;
Expand All @@ -216,35 +213,41 @@ private static function getRequiredFieldsForPostgres(

$queryResult = DB::select(
'
SELECT
is_nullable as nullable,
column_name as name,
column_default as default
FROM
information_schema.columns
WHERE
TABLE_NAME = ?
ORDER BY
ORDINAL_POSITION ASC',
SELECT
is_nullable AS nullable,
column_name AS name,
column_default AS default
FROM
information_schema.columns
WHERE
table_name = ?
ORDER BY
ordinal_position ASC',
[$table]
);

// convert stdClass object children to array
$queryResult = array_map(function ($column) {
return (array) $column;
}, $queryResult);

return collect($queryResult)
$result = collect($queryResult)
->reject(function ($column) use ($primaryIndex, $withPrimaryKey, $withDefaults, $withNullables) {
return
$column['default'] && ! $withDefaults
|| $column['nullable'] == 'YES' && ! $withNullables
|| in_array($column['name'], $primaryIndex) && ! $withPrimaryKey;
return ($column['default'] && !$withDefaults) ||
($column['nullable'] == 'YES' && !$withNullables) ||
(in_array($column['name'], $primaryIndex));
})
->pluck('name')
->toArray();

// Add primary key to the result if $withPrimaryKey is true
if ($withPrimaryKey) {
$result = array_unique(array_merge($primaryIndex, $result));
}

return $result;
}


/**
* Not tested yet in machine with SQL SERVER
*
Expand Down Expand Up @@ -283,9 +286,9 @@ private static function getRequiredFieldsForSqlServer(

return collect($queryResult)
->reject(function ($column) use ($withDefaults, $withNullables, $withPrimaryKey) {
return $column['primary'] && ! $withPrimaryKey
|| $column['default'] != null && ! $withDefaults
|| $column['nullable'] && ! $withNullables;
return $column['primary'] && !$withPrimaryKey
|| $column['default'] != null && !$withDefaults
|| $column['nullable'] && !$withNullables;
})
->pluck('name')
->toArray();
Expand Down
68 changes: 67 additions & 1 deletion tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,72 @@ protected function getPackageProviders($app)

public function getEnvironmentSetUp($app)
{
config()->set('database.default', 'testing');
$dbConnection = env('DB_CONNECTION', 'sqlite');

$app['config']->set('database.default', $dbConnection);

if ($dbConnection === 'mysql') {
$app['config']->set('database.connections.mysql', [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'laravel'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
]);
}

if ($dbConnection === 'mariadb') {
$app['config']->set('database.connections.mariadb', [
'driver' => 'mariadb',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'laravel'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => env('DB_CHARSET', 'utf8mb4'),
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
]);
}

if ($dbConnection === 'pgsql') {
$app['config']->set('database.connections.pgsql', [
'driver' => 'pgsql',
'host' => env('PGSQL_DB_HOST', '127.0.0.1'),
'port' => env('PGSQL_DB_PORT', '5432'),
'database' => env('PGSQL_DB_DATABASE', 'laravel'),
'username' => env('PGSQL_DB_USERNAME', 'postgres'),
'password' => env('PGSQL_DB_PASSWORD', ''),
]);
}

if ($dbConnection === 'sqlite') {
$app['config']->set('database.connections.sqlite', [
'driver' => 'sqlite',
'database' => ':memory:',
]);
}

if ($dbConnection === 'sqlsrv') {
$app['config']->set('database.connections.sqlsrv', [
'driver' => 'sqlsrv',
'host' => env('SQLSRV_DB_HOST', 'localhost'),
'port' => env('SQLSRV_DB_PORT', '1433'),
'database' => env('SQLSRV_DB_DATABASE', 'laravel'),
'username' => env('SQLSRV_DB_USERNAME', 'root'),
'password' => env('SQLSRV_DB_PASSWORD', ''),
]);
}

// if not supported above then stop the test
if (!in_array($dbConnection, ['mysql', 'mariadb', 'pgsql', 'sqlite', 'sqlsrv'])) {
echo "database {$dbConnection} is not supported";
exit;
}
}
}

0 comments on commit 1ac5f01

Please sign in to comment.