Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions documentation/upgrading.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,109 @@ Please follow the instructions for your specific version to ensure a smooth upgr

---

## Upgrading from 0.27.x to 0.28.x

### 1) JsonType now uses Json value object instead of string

The `JsonType` has been refactored to use a dedicated `Json` value object (similar to `Uuid`/`UuidType` pattern).
This allows static analysis tools to distinguish between regular strings and JSON strings.

**Breaking Changes:**

- `JsonType::assert()` now returns `Json` instance instead of `string`
- `JsonType::cast()` now returns `Json` instance instead of `string`
- `JsonType::isValid()` now checks for `Json` instance (plain strings are no longer valid)
- `Cast::cast('json', $value)` function now returns `Json` object instead of string
- `type_json()` return type annotation changed from `Type<string>` to `Type<Json>`
- `JsonEntry::value()` now returns `?Json` instead of `?array` (consistent with `UuidEntry::value()` returning `?Uuid`)
- `JsonEntry::json()` method removed (use `value()` instead)

**Migration:**

If you were using `type_json()->cast($value)` and expected a string, use `->toString()`:

Before:
```php
$jsonString = type_json()->cast($array); // was string
```

After:
```php
$json = type_json()->cast($array); // now Json object
$jsonString = $json->toString(); // get the string
$jsonArray = $json->toArray(); // get as array
```

If you were using `JsonEntry::value()` and edxpected an array:

Before:
```php
$entry = json_entry('data', ['key' => 'value']);
$array = $entry->value(); // was array
```

After:
```php
$entry = json_entry('data', ['key' => 'value']);
$json = $entry->value(); // now Json object
$array = $json?->toArray(); // get as array
$string = $json?->toString(); // get as string
```

If you were using `JsonEntry::json()`:

Before:
```php
$json = $entry->json();
```

After:
```php
$json = $entry->value(); // json() method removed, use value() instead
```

**New Json value object features:**

```php
use Flow\Types\Value\Json;

// Create from string
$json = new Json('{"key": "value"}');

// Create from array
$json = Json::fromArray(['key' => 'value']);

// Check if valid JSON
Json::isValid('{"key": "value"}'); // true

// Convert to string/array
$json->toString(); // '{"key":"value"}'
$json->toArray(); // ['key' => 'value']

// Json implements Stringable
(string) $json; // '{"key":"value"}'

// Json implements JsonSerializable
json_encode($json); // '{"key":"value"}'
```

**Note:** `JsonEntry::value()` now returns `?Json` for consistency with `UuidEntry::value()` returning `?Uuid`. Use `->toArray()` or `->toString()` on the Json object to get the underlying data.

**Row methods behavior:**

```php
// Row::toArray() converts Json to array automatically (for convenient serialization)
$row->toArray(); // Returns ['data' => ['key' => 'value']] not ['data' => Json(...)]

// Row::valueOf() returns the raw value (Json object for json entries)
$row->valueOf('data'); // Returns Json object (use ->toArray() if you need array)

// Entry value() returns the typed value
$row->get('data')->value(); // Returns Json object (use ->toArray() if you need array)
```

---

## Upgrading from 0.26.x to 0.27.x

### 1) Force `EntryFactory $entryFactory` to be required on `array_to_row` & `array_to_row(s)`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace Flow\ETL\Adapter\CSV\RowsNormalizer;

use function Flow\ETL\DSL\date_interval_to_microseconds;
use function Flow\Types\DSL\type_json;
use Flow\ETL\Row\Entry;
use Flow\ETL\Row\Entry\{DateEntry, DateTimeEntry, EnumEntry, JsonEntry, ListEntry, MapEntry, StructureEntry, TimeEntry, UuidEntry, XMLElementEntry, XMLEntry};

Expand All @@ -32,8 +31,8 @@ public function normalize(Entry $entry) : string|float|int|bool|null
EnumEntry::class => $entry->value()?->name,
ListEntry::class,
MapEntry::class,
StructureEntry::class,
JsonEntry::class => type_json()->cast($entry->value()),
StructureEntry::class => \json_encode($entry->value(), \JSON_THROW_ON_ERROR),
JsonEntry::class => $entry->toString(),
default => $entry->value(),
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use function Flow\ETL\DSL\{config, flow_context};
use Flow\ETL\Adapter\Http\DynamicExtractor\NextRequestFactory;
use Flow\ETL\Tests\FlowTestCase;
use Flow\Types\Value\Json;
use Http\Mock\Client;
use Nyholm\Psr7\Factory\Psr17Factory;
use Nyholm\Psr7\Response;
Expand Down Expand Up @@ -59,8 +60,9 @@ public function create(?ResponseInterface $previousResponse = null) : ?RequestIn
self::assertSame('flow-php', $body['login'], \json_encode($body, JSON_THROW_ON_ERROR));
self::assertSame(73_495_297, $body['id'], \json_encode($body, JSON_THROW_ON_ERROR));

$responseHeaders = $rows->current()->first()->valueOf('response_headers');
\assert(\is_array($responseHeaders));
$responseHeadersValue = $rows->current()->first()->valueOf('response_headers');
self::assertInstanceOf(Json::class, $responseHeadersValue);
$responseHeaders = $responseHeadersValue->toArray();
self::assertSame(['GitHub.com'], $responseHeaders['Server']);
self::assertSame(200, $rows->current()->first()->valueOf('response_status_code'));
self::assertSame('1.1', $rows->current()->first()->valueOf('response_protocol_version'));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public function normalize(Entry $entry) : string|float|int|bool|array|null
DateEntry::class => $entry->value()?->format($this->dateFormat),
TimeEntry::class => $entry->value() ? date_interval_to_microseconds($entry->value()) : null,
EnumEntry::class => $entry->value()?->name,
JsonEntry::class => $this->normalizeJsonValue($entry->value()),
JsonEntry::class => $this->normalizeJsonValue($entry->value()?->toArray()),
ListEntry::class,
MapEntry::class,
StructureEntry::class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
namespace Flow\ETL\Adapter\Parquet;

use function Flow\Types\DSL\type_string;
use Flow\ETL\Row\Entry\{UuidEntry, XMLEntry};
use Flow\ETL\Row\Entry\{JsonEntry, UuidEntry, XMLEntry};
use Flow\ETL\{Rows, Schema};
use Flow\Types\Value\Json;

final readonly class RowsNormalizer
{
Expand Down Expand Up @@ -35,11 +36,18 @@ public function normalize(Rows $rows, Schema $schema) : array
continue;
}

$columns[$entry->name()] = match ($entry::class) {
$value = match ($entry::class) {
JsonEntry::class => $entry->toString(),
UuidEntry::class => type_string()->cast($entry->value()),
XMLEntry::class => type_string()->cast($entry->value()),
default => $schema->get($entry->ref())->type()->cast($entry->value()),
};

if ($value instanceof Json) {
$value = $value->toString();
}

$columns[$entry->name()] = $value;
}

$normalizedRows[] = $columns;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ public function test_writing_with_provided_schema() : void

self::assertEquals(
[
['id' => '1', 'name' => 'test', 'uuid' => new \Flow\Types\Value\Uuid('26fd21b0-6080-4d6c-bdb4-1214f1feffef'), 'json' => [['id' => 1, 'name' => 'test'], ['id' => 2, 'name' => 'test']]],
['id' => '2', 'name' => 'test', 'uuid' => new \Flow\Types\Value\Uuid('26fd21b0-6080-4d6c-bdb4-1214f1feffef'), 'json' => [['id' => 1, 'name' => 'test'], ['id' => 2, 'name' => 'test']]],
['id' => '1', 'name' => 'test', 'uuid' => '26fd21b0-6080-4d6c-bdb4-1214f1feffef', 'json' => [['id' => 1, 'name' => 'test'], ['id' => 2, 'name' => 'test']]],
['id' => '2', 'name' => 'test', 'uuid' => '26fd21b0-6080-4d6c-bdb4-1214f1feffef', 'json' => [['id' => 1, 'name' => 'test'], ['id' => 2, 'name' => 'test']]],
],
data_frame($config)
->read(from_parquet($path))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Flow\ETL\Adapter\XML\RowsNormalizer\EntryNormalizer;

use function Flow\Types\DSL\{type_json, type_string};
use function Flow\Types\DSL\type_string;
use Flow\ETL\Adapter\XML\Abstraction\{XMLAttribute, XMLNode};
use Flow\ETL\Exception\InvalidArgumentException;
use Flow\Types\Type;
Expand Down Expand Up @@ -114,11 +114,11 @@ public function normalize(string $name, Type $type, mixed $value) : XMLNode|XMLA
IntegerType::class,
BooleanType::class,
FloatType::class => XMLNode::flatNode($name, type_string()->cast($value)),
ArrayType::class => XMLNode::flatNode($name, type_json()->cast($value)),
ArrayType::class => XMLNode::flatNode($name, \is_array($value) ? \json_encode($value, \JSON_THROW_ON_ERROR) : ''),
EnumType::class => XMLNode::flatNode($name, $value instanceof \BackedEnum ? $value->name : ''),
InstanceOfType::class => XMLNode::flatNode($name, type_string()->cast($value)),
DateTimeType::class => XMLNode::flatNode($name, type_string()->cast($value instanceof \DateTimeInterface ? $value->format($this->dateTimeFormat) : '')),
JsonType::class => XMLNode::flatNode($name, type_json()->cast($value)),
JsonType::class => XMLNode::flatNode($name, $value instanceof \Stringable ? $value->__toString() : ''),
UuidType::class => XMLNode::flatNode($name, \is_scalar($value) || $value instanceof \Stringable ? (string) $value : ''),
default => throw new InvalidArgumentException("Given type can't be converted to node, given type: {$type->toString()}"),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Flow\ETL\Adapter\XML\Abstraction\{XMLAttribute, XMLNode};
use Flow\ETL\Adapter\XML\RowsNormalizer\EntryNormalizer\PHPValueNormalizer;
use Flow\ETL\Tests\FlowTestCase;
use Flow\Types\Value\Json;

final class PHPValueNormalizerTest extends FlowTestCase
{
Expand Down Expand Up @@ -96,7 +97,7 @@ public function test_normalizing_json_type() : void

self::assertEquals(
XMLNode::flatNode('json', '{"a":"1","b":22}'),
$normalizer->normalize('json', type_json(), ['a' => '1', 'b' => 22])
$normalizer->normalize('json', type_json(), Json::fromArray(['a' => '1', 'b' => 22]))
);
}

Expand Down
Loading