New #1152: Add UuidValue expression for DBMS-independent UUID values - #1199
New #1152: Add UuidValue expression for DBMS-independent UUID values#1199KalimeroMK wants to merge 2 commits into
UuidValue expression for DBMS-independent UUID values#1199Conversation
…values `ColumnBuilder::uuidPrimaryKey()` and `uuid()` already produce the right DDL on every DBMS, but inserting a UUID required knowing which representation the current connection expects: MySQL, MariaDB, SQLite and Oracle store a UUID as 16 raw bytes, while PostgreSQL and MSSQL expect the canonical string. The official guide had to document the difference (yiisoft/docs#324) and `CommonCommandTest::testUuid()` works around it with a per-driver `match`. `UuidValue` carries the intent in the value instead of relying on the loaded table schema. That matters because a UUID column reads back as `binary(16)` on MySQL and `blob(16)` on SQLite, so a schema-driven typecast cannot tell it apart from an ordinary binary column. The value is normalized to the canonical lowercase form on construction, so the canonical string, 32 hexadecimal characters, 16 raw bytes and any `Stringable` returning one of those are all accepted — including `Ramsey\Uuid\UuidInterface` itself. `UuidValueBuilder` binds the canonical string, which is correct for PostgreSQL and MSSQL. It is left non-final with a single `prepareValue()` seam so drivers storing raw bytes override one method and reuse `DbUuidHelper::uuidToBlob()`, which until now was unused by `src/`. No behaviour changes for existing code: passing raw bytes or a raw string keeps working exactly as before.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1199 +/- ##
=========================================
Coverage 98.62% 98.62%
- Complexity 1641 1645 +4
=========================================
Files 120 122 +2
Lines 4283 4293 +10
=========================================
+ Hits 4224 4234 +10
Misses 59 59 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
|
||
| public function build(ExpressionInterface $expression, array &$params = []): string | ||
| { | ||
| return $this->queryBuilder->buildValue($this->prepareValue($expression), $params); |
There was a problem hiding this comment.
If UUID is binary value, should it be built as binary?
There was a problem hiding this comment.
Fixed in 6795ad2. prepareValue() now returns a Param, so DBMS that store a UUID as raw bytes can bind it as DataType::LOB instead of letting buildValue() infer DataType::STRING.
| try { | ||
| $this->value = strtolower(DbUuidHelper::toUuid((string) $value)); | ||
| } catch (InvalidArgumentException $e) { | ||
| throw new InvalidArgumentException( | ||
| 'Value is not a valid UUID. Expected the canonical form, 32 hexadecimal characters or 16 raw bytes.', | ||
| previous: $e, | ||
| ); | ||
| } |
There was a problem hiding this comment.
Suggest to change the message of current exception instead adding one more try-catch.
db/src/Helper/DbUuidHelper.php
Line 28 in 11032c2
There was a problem hiding this comment.
Fixed in 6795ad2. Reworded the exception in DbUuidHelper::toUuid() and dropped the extra try/catch in UuidValue.
Return a `Param` from `UuidValueBuilder::prepareValue()` so DBMS that store a UUID as raw bytes can bind it as `DataType::LOB` instead of letting `buildValue()` infer `DataType::STRING` from the PHP type. Reword the exception in `DbUuidHelper::toUuid()` and drop the extra try/catch that wrapped it in `UuidValue`.
|
@Tigrov correct, this is only the core half — the default builder covers PostgreSQL and MSSQL, while MySQL/MariaDB/SQLite/Oracle override Correction to what I wrote earlier about CI: no tag is needed. |
SQLite stores a UUID as 16 raw bytes in a `blob(16)` column, so `prepareValue()` converts the canonical form with `DbUuidHelper::uuidToBlob()` and binds it as `DataType::LOB`. Requires yiisoft/db#1199.
MySQL and MariaDB store a UUID as 16 raw bytes in a `binary(16)` column, so `prepareValue()` converts the canonical form with `DbUuidHelper::uuidToBlob()` and binds it as `DataType::LOB`. Requires yiisoft/db#1199.
Oracle stores a UUID as 16 raw bytes in a `raw(16)` column, so `prepareValue()` converts the canonical form with `DbUuidHelper::uuidToBlob()` and binds it as `DataType::LOB`. Requires yiisoft/db#1199.
|
@Tigrov driver PRs are up, green against this branch on real databases:
Oracle could not use the Correction to my earlier note about CI: |
Adds
UuidValue, an expression that carries a UUID and is bound in the representation the current DBMS expects — raw bytes for MySQL, MariaDB, SQLite and Oracle, canonical string for PostgreSQL and MSSQL:It accepts the canonical form, 32 hexadecimal characters, 16 raw bytes or any
Stringable. Passing raw bytes or a raw string directly keeps working as before.