New #1152: Add UuidValue expression for DBMS-independent UUID values - #1199
Conversation
…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 1644 +3
=========================================
Files 120 122 +2
Lines 4283 4291 +8
=========================================
+ Hits 4224 4232 +8
Misses 59 59 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
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: |
|
@Tigrov both review comments are addressed in 6795ad2 and CI is green (82 checks, mergeable). Could you merge this and tag 2.0.2? The three driver PRs — yiisoft/db-sqlite#432, yiisoft/db-mysql#482, yiisoft/db-oracle#411 — are ready and only waiting on that tag: their |
DBMS-specific packages now implement ExpressionBuilderInterface directly instead of extending this builder, which keeps the coupling between the core and the driver packages at the interface.
* New: Add SQLite implementation of `UuidValue` expression 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. * Rename the base-class alias and guard the read-back type in the test * Cover every accepted UUID input form in the builder test * Implement ExpressionBuilderInterface directly in UuidValueBuilder The core UuidValueBuilder is final now, so this builder no longer extends it. Dropping the inheritance keeps the coupling with the core package at the interface. * Apply Rector: use null coalescing assignment * Use bindParam() instead of buildValue() in UuidValueBuilder --------- Co-authored-by: zoran <zoran.bogoevski@zitcha.com> Co-authored-by: Sergei Predvoditelev <sergei@predvoditelev.ru>
* New: Add MySQL implementation of `UuidValue` expression 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. * Rename the base-class alias and guard the read-back type in the test * Cover every accepted UUID input form in the builder test * Implement ExpressionBuilderInterface directly in UuidValueBuilder The core UuidValueBuilder is final now, so this builder no longer extends it. Dropping the inheritance keeps the coupling with the core package at the interface. * Use bindParam() instead of buildValue() in UuidValueBuilder --------- Co-authored-by: zoran <zoran.bogoevski@zitcha.com> Co-authored-by: Sergei Predvoditelev <sergei@predvoditelev.ru>
* New: Add Oracle implementation of `UuidValue` expression 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. * Fix: emit `HEXTORAW()` literal instead of binding a LOB parameter CI showed PDO_OCI inserts NULL when the raw bytes are bound as a large object, so build the `HEXTORAW()` literal directly — the representation this driver already uses for binary values. * Fix: accept both `raw` read formats in the UUID round-trip test * Fix: compare the read-back UUID case-insensitively * Rename the base-class alias and guard the read-back type in the test * Cover every accepted UUID input form in the builder test * Implement ExpressionBuilderInterface directly in UuidValueBuilder The core UuidValueBuilder is final now, so this builder no longer extends it. Dropping the inheritance keeps the coupling with the core package at the interface. --------- Co-authored-by: zoran <zoran.bogoevski@zitcha.com> Co-authored-by: Sergei Predvoditelev <sergei@predvoditelev.ru>
|
@KalimeroMK Thanks 👍 |
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.