- A lot of work done on bug fixing. Added a new SQLite adapter
This commit is contained in:
1 parent
667df92e52
commit
c14644cdda
28 files changed
+727
-234
No files matched your search
@@ -3,6 +3,7 @@
|
||||
namespace Ulmus\Adapter;
|
||||
|
||||
use Ulmus\Common\PdoObject;
|
||||
use Ulmus\Migration\FieldDefinition;
|
||||
|
||||
interface AdapterInterface {
|
||||
public const IDENTIFIER_FIELD = 1;
|
||||
@@ -10,10 +11,16 @@ interface AdapterInterface {
|
||||
public const IDENTIFIER_DATABASE = 3;
|
||||
public const IDENTIFIER_SCHEMA = 4;
|
||||
public const IDENTIFIER_VALUE = 5;
|
||||
|
||||
|
||||
public function connect() : object /* | PdoObject|mixed */;
|
||||
public function buildDataSourceName() : string;
|
||||
public function setup(array $configuration) : void;
|
||||
public function escapeIdentifier(string $segment, int $type) : string;
|
||||
public function defaultEngine() : ? string;
|
||||
public function databaseName() : string;
|
||||
public function mapFieldType(FieldDefinition $field) : string;
|
||||
public function schemaTable(string $databaseName, string $tableName) /*: object|EntityCollection */;
|
||||
public function repositoryClass() : string;
|
||||
public function queryBuilderClass() : string;
|
||||
public function tableSyntax() : array;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Adapter;
|
||||
|
||||
use Ulmus\{Entity\InformationSchema\Table, Migration\FieldDefinition, Repository, QueryBuilder};
|
||||
|
||||
trait DefaultAdapterTrait
|
||||
{
|
||||
public function repositoryClass() : string
|
||||
{
|
||||
return Repository::class;
|
||||
}
|
||||
|
||||
public function queryBuilderClass() : string
|
||||
{
|
||||
return QueryBuilder::class;
|
||||
}
|
||||
|
||||
public function tableSyntax() : array
|
||||
{
|
||||
return [
|
||||
'ai' => "AUTO_INCREMENT",
|
||||
'pk' => "PRIMARY KEY",
|
||||
'unsigned' => "UNSIGNED",
|
||||
];
|
||||
}
|
||||
|
||||
public function databaseName() : string
|
||||
{
|
||||
return $this->database;
|
||||
}
|
||||
|
||||
public function schemaTable(string $databaseName, string $tableName) /* : ? object */
|
||||
{
|
||||
return Table::repository()->where(Table::field('schema'), $databaseName)->loadOneFromField(Table::field('name'), $tableName);
|
||||
}
|
||||
|
||||
public function mapFieldType(FieldDefinition $field, bool $typeOnly = false) : string
|
||||
{
|
||||
$type = $field->type;
|
||||
|
||||
$length = $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";
|
||||
}
|
||||
|
||||
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 . ( $length ? "($length" . ( $precision ? ",$precision" : "" ) . ")" : "" );
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,13 @@ namespace Ulmus\Adapter;
|
||||
use Ulmus\Common\PdoObject;
|
||||
|
||||
use Ulmus\Exception\AdapterConfigurationException;
|
||||
use Ulmus\Migration\FieldDefinition;
|
||||
use Ulmus\{Entity\InformationSchema\Table, Repository, QueryBuilder};
|
||||
|
||||
class MsSQL implements AdapterInterface {
|
||||
use DefaultAdapterTrait;
|
||||
|
||||
const DSN_PREFIX = "sqlsrv";
|
||||
|
||||
public int $port;
|
||||
|
||||
@@ -129,7 +134,7 @@ class MsSQL implements AdapterInterface {
|
||||
$parts[] = "WSID={$this->wsid}";
|
||||
}
|
||||
|
||||
return "sqlsrv:" . implode(';', $parts);
|
||||
return static::DSN_PREFIX . ":" . implode(';', $parts);
|
||||
}
|
||||
|
||||
public function setup(array $configuration) : void
|
||||
|
||||
+12
-2
@@ -2,11 +2,18 @@
|
||||
|
||||
namespace Ulmus\Adapter;
|
||||
|
||||
use Ulmus\Entity\InformationSchema\Table;
|
||||
use Ulmus\QueryBuilder;
|
||||
use Ulmus\Repository;
|
||||
use Ulmus\Common\PdoObject;
|
||||
|
||||
use Ulmus\Exception\AdapterConfigurationException;
|
||||
use Ulmus\Migration\FieldDefinition;
|
||||
|
||||
class MySQL implements AdapterInterface {
|
||||
use DefaultAdapterTrait;
|
||||
|
||||
const DSN_PREFIX = "mysql";
|
||||
|
||||
public string $hostname;
|
||||
|
||||
@@ -17,7 +24,7 @@ class MySQL implements AdapterInterface {
|
||||
public string $password;
|
||||
|
||||
public string $charset = "utf8mb4";
|
||||
|
||||
|
||||
public ? string $socket;
|
||||
|
||||
public int $port = 3306;
|
||||
@@ -68,6 +75,9 @@ class MySQL implements AdapterInterface {
|
||||
catch(PDOException $ex){
|
||||
throw $ex;
|
||||
}
|
||||
finally {
|
||||
$this->password = str_repeat('*', strlen($this->password));
|
||||
}
|
||||
|
||||
return $pdo;
|
||||
}
|
||||
@@ -91,7 +101,7 @@ class MySQL implements AdapterInterface {
|
||||
$parts[] = "charset={$this->charset}";
|
||||
}
|
||||
|
||||
return "mysql:" . implode(';', $parts);
|
||||
return static::DSN_PREFIX . ":" . implode(';', $parts);
|
||||
}
|
||||
|
||||
public function setup(array $configuration) : void
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Adapter;
|
||||
|
||||
use Ulmus\Common\PdoObject;
|
||||
|
||||
use Ulmus\Entity\Sqlite\Table;
|
||||
use Ulmus\Exception\AdapterConfigurationException;
|
||||
use Ulmus\Migration\FieldDefinition;
|
||||
use Ulmus\{ Repository, QueryBuilder };
|
||||
|
||||
class SQLite implements AdapterInterface {
|
||||
use DefaultAdapterTrait;
|
||||
|
||||
const DSN_PREFIX = "sqlite";
|
||||
|
||||
public string $path;
|
||||
|
||||
public array $pragma;
|
||||
|
||||
public function __construct(
|
||||
? string $path = null,
|
||||
? array $pragma = null
|
||||
) {
|
||||
if ($path !== null) {
|
||||
$this->path = $path;
|
||||
}
|
||||
|
||||
if ($pragma !== null) {
|
||||
$this->pragma = $pragma;
|
||||
}
|
||||
}
|
||||
|
||||
public function connect() : PdoObject
|
||||
{
|
||||
try {
|
||||
$pdo = new PdoObject($this->buildDataSourceName(), null, null);
|
||||
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
|
||||
$pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
|
||||
$pdo->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch(PDOException $ex){
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
return $pdo;
|
||||
}
|
||||
|
||||
public function buildDataSourceName() : string
|
||||
{
|
||||
$parts[] = $this->path;
|
||||
|
||||
return static::DSN_PREFIX . ":" . implode(';', $parts);
|
||||
}
|
||||
|
||||
public function setup(array $configuration) : void
|
||||
{
|
||||
$this->path = $configuration['path'] ?? "";
|
||||
$this->pragma = $configuration['pragma'] ?? [];
|
||||
}
|
||||
|
||||
# https://sqlite.org/lang_keywords.html
|
||||
public function escapeIdentifier(string $segment, int $type) : string
|
||||
{
|
||||
switch($type) {
|
||||
case static::IDENTIFIER_DATABASE:
|
||||
case static::IDENTIFIER_TABLE:
|
||||
case static::IDENTIFIER_FIELD:
|
||||
return '"' . trim(str_replace('"', '""', $segment), '"') . '"';
|
||||
|
||||
case static::IDENTIFIER_VALUE:
|
||||
return "'$segment'";
|
||||
}
|
||||
}
|
||||
|
||||
public function defaultEngine(): ? string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function databaseName() : string
|
||||
{
|
||||
$base = basename($this->path);
|
||||
|
||||
return substr($base, 0, strrpos($base, '.') ?: strlen($base));
|
||||
}
|
||||
|
||||
public function schemaTable(string $databaseName, string $tableName) /* : ? object */
|
||||
{
|
||||
return Table::repository()->loadOneFromField(Table::field('tableName'), $tableName);
|
||||
}
|
||||
|
||||
public function mapFieldType(FieldDefinition $field, bool $typeOnly = false) : string
|
||||
{
|
||||
$type = $field->type;
|
||||
|
||||
$length = $field->length;
|
||||
|
||||
if ( is_a($type, Entity\Field\Date::class, true) || is_a($type, Entity\Field\Time::class, true) || is_a($type, \DateTime::class, true) ) {
|
||||
$type = "TEXT";
|
||||
$length = strlen((string) $type);
|
||||
}
|
||||
else {
|
||||
switch($type) {
|
||||
case "bool":
|
||||
$check = sprintf("CHECK (%s IN (0, 1))", $field->getColumnName());
|
||||
|
||||
case "bigint":
|
||||
case "int":
|
||||
$type = "INTEGER";
|
||||
break;
|
||||
|
||||
case "array":
|
||||
case "string":
|
||||
$type = "TEXT";
|
||||
$length = null;
|
||||
break;
|
||||
|
||||
case "float":
|
||||
$type = "REAL";
|
||||
break;
|
||||
|
||||
default:
|
||||
$type = "BLOB";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $typeOnly ? $type : $type . ( $length ? "($length" . ( $precision ? ",$precision" : "" ) . ")" : "" );
|
||||
}
|
||||
|
||||
public function tableSyntax() : array
|
||||
{
|
||||
return [
|
||||
'ai' => "AUTOINCREMENT",
|
||||
'pk' => "PRIMARY KEY",
|
||||
'unsigned' => "",
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user