diff --git a/README.md b/README.md index d8a4e8afcbd1b0bf87dfd48b10f32af33ad7abbe..2c33677e4b381c080a40d3a87c8ff53bde005d22 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,12 @@ Idea: make statically typed what is possible and prevent typos. - do not write it twice (sync database to database-access-layer classes) - do not screw up database - support for rich types as UUID, arrays, ... (easy to add more) +# Docs + +- This library currenly missing comprehensive docs. +- [Cook book](docs/cookbook) – contains useful solutions for situations we have been facing in practise. + + ## Installation This is private repo, so you have to add repositories to you `composer.json` manually. This tells composer where to find our packages. @@ -46,3 +52,4 @@ composer require grifart/tables:dev-master # 2. install grifart/class-scaffolder for automatic defintions generation: composer require grifart/class-scaffolder ```` + diff --git a/docs/cookbook/migrate-to-composite-field.md b/docs/cookbook/migrate-to-composite-field.md new file mode 100644 index 0000000000000000000000000000000000000000..dd9b2ea2a3525b72a3023fcd20ef14dc64aabdb6 --- /dev/null +++ b/docs/cookbook/migrate-to-composite-field.md @@ -0,0 +1,52 @@ +# Migrate to composite field + +Sometimes you start with table containing values, which you then see have dependency on each other. As happened with [Stamp object](https://gitlab.grifart.cz/ivy/server/-/merge_requests/222/diffs#note_69354) (originally named `auditTrail`). + +## 1. migrating database + +```sql +-- prepare new data type in PostgreSQL +CREATE TYPE "public"."auditTrail" AS ( + "occurredAt" timestamp without time zone, + "causedBy" uuid +); + +-- Add column with default value +ALTER TABLE "clinic"."patient" + ADD COLUMN "created" "public"."auditTrail" DEFAULT NULL; + +-- migrate data from two original columns to the new composite one +UPDATE "clinic"."patient" SET + "created" = ROW("createdAt", "createdBy"); + +-- removed old one and remove DEFAULT value (as it should be required filed at the end) +ALTER TABLE "clinic"."patient" + ALTER COLUMN "created" SET NOT NULL, + ALTER COLUMN "created" DROP DEFAULT, + DROP COLUMN "createdAt", + DROP COLUMN "createdBy"; +``` + +And add mapping of new field. It is useful to use PostgreSQL tools for composite & array types. This helper class will provide you logic for (de)serializing these composite types into standard SQL query. + +```php +<?php + $phpToDatabaseMapper->addMapping( + static fn(string $dbType): ?string => $dbType === 'stamp' ? Stamp::class : null, + static fn(Stamp $trail): string => PostgreSQLTools::toPgComposite([ + (string) $trail->getOccurredAt(), + $trail->getCausedBy()->toString(), + ]), + ); + $databaseToPhpMapper->addMapping( + static fn(string $dbType): ?string => $dbType === 'stamp' ? Stamp::class : null, + static function (string $value): Stamp { + [$occurredAt, $causedBy] = PostgreSQLTools::fromPgComposite($value); + $occurredAtLocal = LocalDateTime::parse($occurredAt, ISO8601Parsers::dateTime()); + return Stamp::from( + AccountId::of($causedBy), + $occurredAtLocal->atTimeZone(TimeZone::utc())->getInstant(), + ); + }, + ); +``` \ No newline at end of file