- WIP on Collation
This commit is contained in:
parent
b601939459
commit
b5e96eb7e0
|
@ -150,6 +150,7 @@ class MySQL implements AdapterInterface, MigrateInterface, SqlAdapterInterface {
|
||||||
public static function escapeIdentifier(string $segment, int $type) : string
|
public static function escapeIdentifier(string $segment, int $type) : string
|
||||||
{
|
{
|
||||||
switch($type) {
|
switch($type) {
|
||||||
|
default:
|
||||||
case static::IDENTIFIER_DATABASE:
|
case static::IDENTIFIER_DATABASE:
|
||||||
case static::IDENTIFIER_TABLE:
|
case static::IDENTIFIER_TABLE:
|
||||||
case static::IDENTIFIER_FIELD:
|
case static::IDENTIFIER_FIELD:
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
namespace Ulmus\Adapter;
|
namespace Ulmus\Adapter;
|
||||||
|
|
||||||
|
use Collator;
|
||||||
use Ulmus\Common\PdoObject;
|
use Ulmus\Common\PdoObject;
|
||||||
use Ulmus\ConnectionAdapter;
|
use Ulmus\ConnectionAdapter;
|
||||||
|
|
||||||
use Ulmus\Entity;
|
use Ulmus\Entity;
|
||||||
use Ulmus\Migration\FieldDefinition;
|
use Ulmus\Migration\FieldDefinition;
|
||||||
use Ulmus\{Migration\MigrateInterface, Repository, QueryBuilder};
|
use Ulmus\{Migration\MigrateInterface, Repository, QueryBuilder};
|
||||||
|
@ -37,6 +37,7 @@ class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface
|
||||||
};
|
};
|
||||||
|
|
||||||
$this->exportFunctions($pdo);
|
$this->exportFunctions($pdo);
|
||||||
|
$this->exportCollations($pdo);
|
||||||
$this->registerPragma($pdo, $this->pragmaBegin);
|
$this->registerPragma($pdo, $this->pragmaBegin);
|
||||||
}
|
}
|
||||||
catch(\PDOException $ex){
|
catch(\PDOException $ex){
|
||||||
|
@ -196,6 +197,37 @@ class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface
|
||||||
$pdo->sqliteCreateFunction('year', fn($date) => ( new \DateTime($date) )->format('Y'), 1);
|
$pdo->sqliteCreateFunction('year', fn($date) => ( new \DateTime($date) )->format('Y'), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function exportCollations(PdoObject $pdo) : void
|
||||||
|
{
|
||||||
|
|
||||||
|
if ( class_exists('Locale') ) {
|
||||||
|
# @TODO debug this, case-sensitivity not working properly !!
|
||||||
|
$collator = new Collator(\Locale::getDefault());
|
||||||
|
$collator->setStrength(Collator::TERTIARY);
|
||||||
|
$collator->setAttribute(Collator::NUMERIC_COLLATION, Collator::ON);
|
||||||
|
|
||||||
|
$pdo->sqliteCreateCollation('locale_cmp', fn($e1, $e2) => $collator->compare($e1, $e2));
|
||||||
|
$pdo->sqliteCreateCollation('locale_cmp_desc', fn($e1, $e2) => $collator->compare($e2, $e1));
|
||||||
|
|
||||||
|
$collatorCi = new Collator(\Locale::getDefault());
|
||||||
|
$collatorCi->setStrength(Collator::SECONDARY);
|
||||||
|
$collatorCi->setAttribute(Collator::NUMERIC_COLLATION, Collator::ON);
|
||||||
|
|
||||||
|
$pdo->sqliteCreateCollation('locale_cmp_ci', fn($e1, $e2) => $collatorCi->compare($e1, $e2));
|
||||||
|
$pdo->sqliteCreateCollation('locale_cmp_ci_desc', fn($e1, $e2) => $collatorCi->compare($e2, $e1));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$comp = fn(string $e1, string $e2) => \iconv('UTF-8', 'ASCII//TRANSLIT', $e1) <=> \iconv('UTF-8', 'ASCII//TRANSLIT', $e2);
|
||||||
|
$pdo->sqliteCreateCollation('locale_cmp', fn($e1, $e2) => $comp);
|
||||||
|
$pdo->sqliteCreateCollation('locale_cmp_desc', fn($e2, $e1) => $comp);
|
||||||
|
|
||||||
|
$compCi = fn(string $e1, string $e2) => strtoupper(\iconv('UTF-8', 'ASCII//TRANSLIT', $e1)) <=> strtoupper(\iconv('UTF-8', 'ASCII//TRANSLIT', $e2));
|
||||||
|
$pdo->sqliteCreateCollation('locale_cmp_ci', fn($e1, $e2) => $compCi);
|
||||||
|
$pdo->sqliteCreateCollation('locale_cmp_ci_desc', fn($e2, $e1) => $compCi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static function registerPragma(PdoObject $pdo, array $pragmaList) : void
|
public static function registerPragma(PdoObject $pdo, array $pragmaList) : void
|
||||||
{
|
{
|
||||||
$builder = new QueryBuilder\Sql\SqliteQueryBuilder();
|
$builder = new QueryBuilder\Sql\SqliteQueryBuilder();
|
||||||
|
|
|
@ -4,5 +4,7 @@ namespace Ulmus\Attribute\Obj;
|
||||||
|
|
||||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||||
class Collation {
|
class Collation {
|
||||||
|
public function __construct(
|
||||||
|
public string $name = ""
|
||||||
|
) {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Collation {
|
||||||
|
public function __construct(
|
||||||
|
public string $name = ""
|
||||||
|
) {}
|
||||||
|
}
|
|
@ -62,7 +62,7 @@ abstract class Sql {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function raw(string $sql) : object
|
public static function raw(string $sql) : object
|
||||||
{
|
{
|
||||||
return static::identifier($sql);
|
return static::identifier($sql);
|
||||||
|
@ -84,8 +84,12 @@ abstract class Sql {
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function parameter($value) : string
|
public static function collate(string $name) : string
|
||||||
{
|
{
|
||||||
|
if ( ! preg_match('/^[a-z0-9$_]+$/i',$name) ) {
|
||||||
|
throw new \InvalidArgumentException(sprintf("Given identifier '%s' should contains supported characters in function name (a-Z, 0-9, $ and _)", $name));
|
||||||
|
}
|
||||||
|
|
||||||
|
return static::raw(sprintf("COLLATE %s", $name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ class OrderBy extends Fragment {
|
||||||
public array $orderBy = [];
|
public array $orderBy = [];
|
||||||
|
|
||||||
const SQL_TOKEN = "ORDER BY";
|
const SQL_TOKEN = "ORDER BY";
|
||||||
|
const SQL_COLLATE = "COLLATE";
|
||||||
|
|
||||||
public function set(array $order) : self
|
public function set(array $order) : self
|
||||||
{
|
{
|
||||||
|
@ -16,7 +17,7 @@ class OrderBy extends Fragment {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function add(object|string $field, ? string $direction = null) : self
|
public function add(string|\Stringable $field, ? string $direction = null) : self
|
||||||
{
|
{
|
||||||
$this->validateFieldType($field);
|
$this->validateFieldType($field);
|
||||||
|
|
||||||
|
@ -30,7 +31,7 @@ class OrderBy extends Fragment {
|
||||||
$list = array_map(function($item) {
|
$list = array_map(function($item) {
|
||||||
list($field, $direction) = $item;
|
list($field, $direction) = $item;
|
||||||
|
|
||||||
return $field . ( $direction ? " $direction" : "" );
|
return implode(' ', array_filter([ $field , $direction ?? null ] ));
|
||||||
}, $this->orderBy);
|
}, $this->orderBy);
|
||||||
|
|
||||||
return $this->renderSegments([
|
return $this->renderSegments([
|
||||||
|
|
|
@ -260,7 +260,7 @@ class MysqlQueryBuilder extends SqlQueryBuilder
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function orderBy(string|\Stringable $field, ? string $direction = null) : self
|
public function orderBy(string|\Stringable $field, null|string|\Stringable $direction = null) : self
|
||||||
{
|
{
|
||||||
if ( null === $orderBy = $this->getFragment(Query\OrderBy::class) ) {
|
if ( null === $orderBy = $this->getFragment(Query\OrderBy::class) ) {
|
||||||
$orderBy = new Query\OrderBy();
|
$orderBy = new Query\OrderBy();
|
||||||
|
@ -272,7 +272,7 @@ class MysqlQueryBuilder extends SqlQueryBuilder
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function groupBy(string|object $field) : self
|
public function groupBy(string|\Stringable $field) : self
|
||||||
{
|
{
|
||||||
if ( null === $groupBy = $this->getFragment(Query\GroupBy::class) ) {
|
if ( null === $groupBy = $this->getFragment(Query\GroupBy::class) ) {
|
||||||
$groupBy = new Query\GroupBy();
|
$groupBy = new Query\GroupBy();
|
||||||
|
|
|
@ -548,7 +548,7 @@ class Repository implements RepositoryInterface
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function orderBy(string|object $field, ? string $direction = null) : self
|
public function orderBy(string|\Stringable $field, null|string|\Stringable $direction = null) : self
|
||||||
{
|
{
|
||||||
$this->queryBuilder->orderBy($field, $direction);
|
$this->queryBuilder->orderBy($field, $direction);
|
||||||
|
|
||||||
|
@ -558,7 +558,7 @@ class Repository implements RepositoryInterface
|
||||||
# @UNTESTED
|
# @UNTESTED
|
||||||
public function randomizeOrder() : self
|
public function randomizeOrder() : self
|
||||||
{
|
{
|
||||||
$this->queryBuilder->orderBy(Common\Sql::function('RAND', Sql::identifier('CURDATE()+0')));
|
$this->queryBuilder->orderBy(Common\Sql::function('RAND', Common\Sql::identifier('CURDATE()+0')));
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue