- Field mapper is now removed from Adapters and set into it's own object
- Added a PK to Column (IS)
This commit is contained in:
parent
9977a25cf5
commit
3c2ae86653
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace Ulmus\Adapter;
|
namespace Ulmus\Adapter;
|
||||||
|
|
||||||
|
use Ulmus\Migration\FieldDefinition;
|
||||||
use Ulmus\Migration\MigrateInterface;
|
use Ulmus\Migration\MigrateInterface;
|
||||||
use Ulmus\QueryBuilder\Sql;
|
use Ulmus\QueryBuilder\Sql;
|
||||||
use Ulmus\Common\PdoObject;
|
use Ulmus\Common\PdoObject;
|
||||||
|
@ -136,7 +137,14 @@ class MySQL implements AdapterInterface, MigrateInterface, SqlAdapterInterface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function escapeIdentifier(string $segment, int $type) : string
|
public function mapFieldType(FieldDefinition $field, bool $typeOnly = false) : string
|
||||||
|
{
|
||||||
|
$mapper = new MySQLFieldMapper($field);
|
||||||
|
|
||||||
|
return $typeOnly ? $mapper->type : $mapper->render();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function escapeIdentifier(string $segment, int $type) : string
|
||||||
{
|
{
|
||||||
switch($type) {
|
switch($type) {
|
||||||
case static::IDENTIFIER_DATABASE:
|
case static::IDENTIFIER_DATABASE:
|
||||||
|
@ -158,5 +166,4 @@ class MySQL implements AdapterInterface, MigrateInterface, SqlAdapterInterface {
|
||||||
{
|
{
|
||||||
return Sql\MysqlQueryBuilder::class;
|
return Sql\MysqlQueryBuilder::class;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Adapter;
|
||||||
|
|
||||||
|
use Ulmus\Migration\FieldDefinition;
|
||||||
|
|
||||||
|
class MySQLFieldMapper extends SqlFieldMapper
|
||||||
|
{
|
||||||
|
public readonly string $type;
|
||||||
|
|
||||||
|
public readonly string $length;
|
||||||
|
|
||||||
|
public function map() : void
|
||||||
|
{
|
||||||
|
$type = $this->field->type;
|
||||||
|
$length = $this->field->length;
|
||||||
|
|
||||||
|
if ( enum_exists($type) ) {
|
||||||
|
# Haven't found a better way yet to check for BackendEnum without an instance of the object
|
||||||
|
if ( ! method_exists($type, 'tryFrom') ) {
|
||||||
|
throw new \Ulmus\Exception\BackedEnumRequired(sprintf("You must define your enum as a BackedEnum instead of an UnitEnum for field '%s'.", $this->field->getColumnName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->length = implode(',', array_map(fn($e) => MySQL::escapeIdentifier($e->value, MySQL::IDENTIFIER_VALUE) , $type::cases()));
|
||||||
|
$this->type = "ENUM";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
parent::map();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,7 +61,7 @@ class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
# https://sqlite.org/lang_keywords.html
|
# https://sqlite.org/lang_keywords.html
|
||||||
public function escapeIdentifier(string $segment, int $type) : string
|
public static function escapeIdentifier(string $segment, int $type) : string
|
||||||
{
|
{
|
||||||
switch($type) {
|
switch($type) {
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -4,6 +4,6 @@ namespace Ulmus\Adapter;
|
||||||
|
|
||||||
interface SqlAdapterInterface
|
interface SqlAdapterInterface
|
||||||
{
|
{
|
||||||
public function escapeIdentifier(string $segment, int $type) : string;
|
public static function escapeIdentifier(string $segment, int $type) : string;
|
||||||
public function defaultEngine() : ? string;
|
public function defaultEngine() : ? string;
|
||||||
}
|
}
|
|
@ -46,60 +46,9 @@ trait SqlAdapterTrait
|
||||||
|
|
||||||
public function mapFieldType(FieldDefinition $field, bool $typeOnly = false) : string
|
public function mapFieldType(FieldDefinition $field, bool $typeOnly = false) : string
|
||||||
{
|
{
|
||||||
$type = $field->type;
|
$mapper = new SqlFieldMapper($field);
|
||||||
|
|
||||||
$length = $field->length;
|
return $typeOnly ? $mapper->type : $mapper->render();
|
||||||
|
|
||||||
if ( is_a($type, Entity\Field\Date::class, true) ) {
|
|
||||||
$type = "DATE";
|
|
||||||
}
|
|
||||||
elseif ( is_a($type, Entity\Field\Time::class, true) ) {
|
|
||||||
$type = "TIME";
|
|
||||||
}
|
|
||||||
elseif ( is_a($type, \DateTime::class, true) ) {
|
|
||||||
$type = "DATETIME";
|
|
||||||
}
|
|
||||||
|
|
||||||
switch($type) {
|
|
||||||
case "bool":
|
|
||||||
$type = "TINYINT";
|
|
||||||
$length = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "array":
|
|
||||||
case "string":
|
|
||||||
if ($length && $length <= 255) {
|
|
||||||
$type = "VARCHAR";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
elseif (! $length || ( $length <= 65535 ) ) {
|
|
||||||
$type = "TEXT";
|
|
||||||
}
|
|
||||||
elseif ( $length <= 16777215 ) {
|
|
||||||
$type = "MEDIUMTEXT";
|
|
||||||
}
|
|
||||||
elseif ($length <= 4294967295) {
|
|
||||||
$type = "LONGTEXT";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new \Exception("A column with size bigger than 4GB cannot be created.");
|
|
||||||
}
|
|
||||||
|
|
||||||
# Length is unnecessary on TEXT fields
|
|
||||||
unset($length);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "float":
|
|
||||||
$type = "DOUBLE";
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
$type = strtoupper($type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $typeOnly ? $type : $type . ( isset($length) ? "($length" . ( ! empty($precision) ? ",$precision" : "" ) . ")" : "" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function whitelistAttributes(array &$parameters) : void
|
public function whitelistAttributes(array &$parameters) : void
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Adapter;
|
||||||
|
|
||||||
|
use Ulmus\Migration\FieldDefinition;
|
||||||
|
|
||||||
|
class SqlFieldMapper
|
||||||
|
{
|
||||||
|
public readonly string $type;
|
||||||
|
|
||||||
|
public readonly string $length;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
public FieldDefinition $field,
|
||||||
|
) {
|
||||||
|
$this->map();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function map() : void
|
||||||
|
{
|
||||||
|
$type = $this->field->type;
|
||||||
|
$length = $this->field->length;
|
||||||
|
|
||||||
|
if ( is_a($type, Entity\Field\Date::class, true) ) {
|
||||||
|
$type = "DATE";
|
||||||
|
}
|
||||||
|
elseif ( is_a($type, Entity\Field\Time::class, true) ) {
|
||||||
|
$type = "TIME";
|
||||||
|
}
|
||||||
|
elseif ( is_a($type, \DateTime::class, true) ) {
|
||||||
|
$type = "DATETIME";
|
||||||
|
}
|
||||||
|
elseif ( enum_exists($type) ) {
|
||||||
|
# Haven't found a better way yet to check for BackendEnum without an instance of the object
|
||||||
|
if ( ! method_exists($type, 'tryFrom') ) {
|
||||||
|
throw new \Ulmus\Exception\BackedEnumRequired(sprintf("You must define your enum as a BackedEnum instead of an UnitEnum for field '%s'.", $this->field->getColumnName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
$type = "string";
|
||||||
|
}
|
||||||
|
|
||||||
|
switch($type) {
|
||||||
|
case "bool":
|
||||||
|
$this->type = "TINYINT";
|
||||||
|
$length = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "array":
|
||||||
|
case "string":
|
||||||
|
if ($length && $length <= 255) {
|
||||||
|
$this->type = "VARCHAR";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
elseif (! $length || ( $length <= 65535 ) ) {
|
||||||
|
$this->type = "TEXT";
|
||||||
|
}
|
||||||
|
elseif ( $length <= 16777215 ) {
|
||||||
|
$this->type = "MEDIUMTEXT";
|
||||||
|
}
|
||||||
|
elseif ($length <= 4294967295) {
|
||||||
|
$this->type = "LONGTEXT";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new \Exception("A column with a length bigger than 4GB cannot be created.");
|
||||||
|
}
|
||||||
|
|
||||||
|
# Length is unnecessary on TEXT fields
|
||||||
|
unset($length);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "float":
|
||||||
|
$this->type = "DOUBLE";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
$this->type = strtoupper($type);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render() : string
|
||||||
|
{
|
||||||
|
return $this->type . ( isset($this->length) ? "($this->length)" : "" );
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace Ulmus\Entity\InformationSchema;
|
namespace Ulmus\Entity\InformationSchema;
|
||||||
|
|
||||||
|
use Notes\Common\ReflectedProperty;
|
||||||
use Ulmus\Entity\Field\Datetime;
|
use Ulmus\Entity\Field\Datetime;
|
||||||
|
|
||||||
use Ulmus\{Attribute\Obj\Table};
|
use Ulmus\{Attribute\Obj\Table};
|
||||||
|
@ -12,6 +13,9 @@ class Column
|
||||||
{
|
{
|
||||||
use \Ulmus\EntityTrait;
|
use \Ulmus\EntityTrait;
|
||||||
|
|
||||||
|
#[Field\Id]
|
||||||
|
public ? id $srs_id;
|
||||||
|
|
||||||
#[Field(name: "TABLE_CATALOG", length: 512)]
|
#[Field(name: "TABLE_CATALOG", length: 512)]
|
||||||
public string $tableCatalog;
|
public string $tableCatalog;
|
||||||
|
|
||||||
|
@ -78,4 +82,37 @@ class Column
|
||||||
#[Field(name: "GENERATION_EXPRESSION", type: "longtext")]
|
#[Field(name: "GENERATION_EXPRESSION", type: "longtext")]
|
||||||
public ? string $generationExpression;
|
public ? string $generationExpression;
|
||||||
|
|
||||||
|
public function matchFieldDefinition(ReflectedProperty $definition) : bool
|
||||||
|
{
|
||||||
|
if ($this->nullable === $definition->allowsNull()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($definition->value)) {
|
||||||
|
if ( $definition->value !== $this->defaultValue()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif (! isset($definition->value)) {
|
||||||
|
if ( ! $this->defaultValueIsNull() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function defaultValueIsNull() : bool
|
||||||
|
{
|
||||||
|
return $this->defaultValue() === null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function defaultValue() : mixed
|
||||||
|
{
|
||||||
|
if (is_numeric($this->default)) {
|
||||||
|
return (int) $this->default;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->default;
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue