From b5e96eb7e0e8d348e7dd0742a2dd3a3640251d33 Mon Sep 17 00:00:00 2001 From: Dave Mc Nicoll Date: Mon, 16 Dec 2024 18:46:24 +0000 Subject: [PATCH] - WIP on Collation --- src/Adapter/MySQL.php | 1 + src/Adapter/SQLite.php | 34 +++++++++++++++++++++- src/Attribute/Obj/Collation.php | 4 ++- src/Attribute/Property/Collation.php | 10 +++++++ src/Common/Sql.php | 10 +++++-- src/Query/OrderBy.php | 5 ++-- src/QueryBuilder/Sql/MysqlQueryBuilder.php | 4 +-- src/Repository.php | 4 +-- 8 files changed, 61 insertions(+), 11 deletions(-) create mode 100644 src/Attribute/Property/Collation.php diff --git a/src/Adapter/MySQL.php b/src/Adapter/MySQL.php index d698c9e..7344da2 100644 --- a/src/Adapter/MySQL.php +++ b/src/Adapter/MySQL.php @@ -150,6 +150,7 @@ class MySQL implements AdapterInterface, MigrateInterface, SqlAdapterInterface { public static function escapeIdentifier(string $segment, int $type) : string { switch($type) { + default: case static::IDENTIFIER_DATABASE: case static::IDENTIFIER_TABLE: case static::IDENTIFIER_FIELD: diff --git a/src/Adapter/SQLite.php b/src/Adapter/SQLite.php index 29d16b7..7433c58 100644 --- a/src/Adapter/SQLite.php +++ b/src/Adapter/SQLite.php @@ -2,9 +2,9 @@ namespace Ulmus\Adapter; +use Collator; use Ulmus\Common\PdoObject; use Ulmus\ConnectionAdapter; - use Ulmus\Entity; use Ulmus\Migration\FieldDefinition; use Ulmus\{Migration\MigrateInterface, Repository, QueryBuilder}; @@ -37,6 +37,7 @@ class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface }; $this->exportFunctions($pdo); + $this->exportCollations($pdo); $this->registerPragma($pdo, $this->pragmaBegin); } catch(\PDOException $ex){ @@ -196,6 +197,37 @@ class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface $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 { $builder = new QueryBuilder\Sql\SqliteQueryBuilder(); diff --git a/src/Attribute/Obj/Collation.php b/src/Attribute/Obj/Collation.php index ab0540b..fdff980 100644 --- a/src/Attribute/Obj/Collation.php +++ b/src/Attribute/Obj/Collation.php @@ -4,5 +4,7 @@ namespace Ulmus\Attribute\Obj; #[\Attribute(\Attribute::TARGET_CLASS)] class Collation { - + public function __construct( + public string $name = "" + ) {} } diff --git a/src/Attribute/Property/Collation.php b/src/Attribute/Property/Collation.php new file mode 100644 index 0000000..a19a4fe --- /dev/null +++ b/src/Attribute/Property/Collation.php @@ -0,0 +1,10 @@ +validateFieldType($field); @@ -30,7 +31,7 @@ class OrderBy extends Fragment { $list = array_map(function($item) { list($field, $direction) = $item; - return $field . ( $direction ? " $direction" : "" ); + return implode(' ', array_filter([ $field , $direction ?? null ] )); }, $this->orderBy); return $this->renderSegments([ diff --git a/src/QueryBuilder/Sql/MysqlQueryBuilder.php b/src/QueryBuilder/Sql/MysqlQueryBuilder.php index afa8f0e..b4caf10 100644 --- a/src/QueryBuilder/Sql/MysqlQueryBuilder.php +++ b/src/QueryBuilder/Sql/MysqlQueryBuilder.php @@ -260,7 +260,7 @@ class MysqlQueryBuilder extends SqlQueryBuilder 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) ) { $orderBy = new Query\OrderBy(); @@ -272,7 +272,7 @@ class MysqlQueryBuilder extends SqlQueryBuilder return $this; } - public function groupBy(string|object $field) : self + public function groupBy(string|\Stringable $field) : self { if ( null === $groupBy = $this->getFragment(Query\GroupBy::class) ) { $groupBy = new Query\GroupBy(); diff --git a/src/Repository.php b/src/Repository.php index aa0bb9f..7e9b97b 100644 --- a/src/Repository.php +++ b/src/Repository.php @@ -548,7 +548,7 @@ class Repository implements RepositoryInterface 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); @@ -558,7 +558,7 @@ class Repository implements RepositoryInterface # @UNTESTED 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; }