New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support array columns types #59
Comments
|
Array types are not supported. @jaulz worked on it with #29, but adding it is very complicated. But I am right now working on adding For now, you can add the column by using the domain type: $query->domain('mycol', 'int[]');Can you share why you need the integer array type? What do you want to do with it? I could directly add some functionality for your use case. |
|
I would like to store the list of zipcodes on each french cities. The equivalent of : CREATE TABLE cities (
id serial primary key;
name VARCHAR(255) NOT NULL;
insee_code VARCHAR(10) NOT NULL UNIQUE;
postal_codes integer[] NOT NULL;
);I'm not sure to completely understand #29 but just add main types as following should do the job, no ? vendor/tpetry/laravel-postgresql-enhanced/src/Schema/BlueprintTypes.php /**
* Create a new integer array column on the table.
*/
public function integerArray(string $column): ColumnDefinition
{
return $this->addColumn('integerArray', $column);
}
/**
* Create a new string array column on the table.
*/
public function stringArray(string $column, ?int $length = null)
{
$length = $length ?: Builder::$defaultStringLength;
return $this->addColumn('stringArray', $column, compact('length'));
}
/**
* Create a new integer array column on the table.
*/
public function textArray(string $column): ColumnDefinition
{
return $this->addColumn('textArray', $column);
}
}vendor/tpetry/laravel-postgresql-enhanced/src/Schema/Grammars/GrammarTypes.php /**
* Create the column definition for a integer array type.
*/
protected function typeIntegerArray(Fluent $column): string
{
return 'int[]';
}
/**
* Create the column definition for a string array type.
*/
protected function typeStringArray(Fluent $column): string
{
return blank($column['length']) ? 'varchar' : "varchar({$column['length']})";
}
/**
* Create the column definition for a text array type.
*/
protected function typeTextArray(Fluent $column): string
{
return 'text[]';
} One advantage of the array type vs the jsonb type is that you have a all constraints already set from your type (ex: integer[] allows only integer inside). With a JSON you can have all types inside (object, array, integer, string, boolean, ...) even with a constraint : CREATE TABLE test (
tab jsonb NOT NULL CHECK (jsonb_typeof(tab) = 'array')
);
INSERT INTO test VALUES ('[1, "2", true, {}, null]');
select * from test;
=> [1, "2", true, {}, null]With an integer array, you can only insert integer inside (number as string are automatically converted in addition) : CREATE TABLE test (
tab integer[] NOT NULL
);
INSERT INTO test VALUES ('{1, "2", 3}');
select * from test;
=> {1,2,3}Max |
|
Ah ok I understood, the issue : doctrine don't know how to manage the integer array field : |
|
Yeah, that's the problem. I need to build doctrine types for everything. For now, you can do the I may be able to work on it sometime in the next 2 weeks. I'll need that by myself currently. |
|
It's a doctrine issue, I will try to create an issue on doctrine repo. vendor/doctrine/dbal/src/Platforms/PostgreSQLPlatform.php protected function initializeDoctrineTypeMappings()
{
$this->doctrineTypeMapping = [
'bigint' => 'bigint',
'bigserial' => 'bigint',
'bool' => 'boolean',
'boolean' => 'boolean',
'bpchar' => 'string',
'bytea' => 'blob',
'char' => 'string',
'date' => 'date',
'datetime' => 'datetime',
'decimal' => 'decimal',
'double' => 'float',
'double precision' => 'float',
'float' => 'float',
'float4' => 'float',
'float8' => 'float',
'inet' => 'string',
'int' => 'integer',
'int2' => 'smallint',
'int4' => 'integer',
'int8' => 'bigint',
'integer' => 'integer',
'interval' => 'string',
'json' => 'json',
'jsonb' => 'json',
'money' => 'decimal',
'numeric' => 'decimal',
'serial' => 'integer',
'serial4' => 'integer',
'serial8' => 'bigint',
'real' => 'float',
'smallint' => 'smallint',
'text' => 'text',
'time' => 'time',
'timestamp' => 'datetime',
'timestamptz' => 'datetimetz',
'timetz' => 'time',
'tsvector' => 'text',
'uuid' => 'guid',
'varchar' => 'string',
'year' => 'date',
'_varchar' => 'string',
// new line =>
'_int4' => 'string',
];
}With that patch integer[] are working fine (except we get a string {1, 2, 3} instead of an array in eloquent). All array are the type with underscore as prefix (even multidimensional array, for example: integer[][] => _int4) |
|
Just added a specific cast and it's working 🎉 app/Casts/PostgresArray.php (the implementation is ugly mainly for string but it's ok for integer array, it's just as demo) : <?php
namespace App\Casts;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Database\Eloquent\Model;
class PostgresArray implements CastsAttributes
{
/**
* Cast the given value.
*
* @param array<string, mixed> $attributes
*/
public function get(Model $model, string $key, mixed $value, array $attributes): mixed
{
return json_decode(str_replace(['{', '}'], ['[', ']'], $value));
}
/**
* Prepare the given value for storage.
*
* @param array<string, mixed> $attributes
*/
public function set(Model $model, string $key, mixed $value, array $attributes): mixed
{
return str_replace(['[', ']'], ['{', '}'], json_encode($value));;
}
}app/Models/City.php <?php
namespace App\Models;
use App\Casts\PostgresArray;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class City extends Model
{
use HasFactory;
protected $casts = [
'postal_codes' => PostgresArray::class,
];
}routes/web.php Route::get('/test', function () {
$city = City::first();
dump($city->postal_codes);
$city->postal_codes = [...$city->postal_codes, 12345];
$city->save();
dump($city->postal_codes);
}); |
|
For the encode/decode we can inspire from Yii implementation for example : |
|
The integer array type is now supported with |
Hello,
First, thanks for your really useful package !
I would like to add a field with the type
integer[](array of integer) but the type doesn't seems to exist in the columns types supported, I'm missing something ?Thanks in advance,
Max
The text was updated successfully, but these errors were encountered: