Skip to content

Commit

Permalink
Schema to/from Array
Browse files Browse the repository at this point in the history
  • Loading branch information
norberttech committed Jan 28, 2024
1 parent ef7d2f3 commit 590c4a5
Show file tree
Hide file tree
Showing 30 changed files with 863 additions and 19 deletions.
12 changes: 1 addition & 11 deletions docs/components/core/schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,6 @@ There is more than one way to validate the schema, built in strategies are defin

By default, ETL is initializing `StrictValidator`, but it's possible to override it by passing second argument to `DataFrame::validate()` method.

### Schema Constraints

- [all](../../../src/core/etl/src/Flow/ETL/Row/Schema/Constraint/All.php)
- [any](../../../src/core/etl/src/Flow/ETL/Row/Schema/Constraint/Any.php)
- [is instance of](../../../src/core/etl/src/Flow/ETL/Row/Schema/Constraint/IsInstanceOf.php)
- [list type](../../../src/core/etl/src/Flow/ETL/Row/Schema/Constraint/ListType.php)
- [not empty](../../../src/core/etl/src/Flow/ETL/Row/Schema/Constraint/NotEmpty.php)
- [same as](../../../src/core/etl/src/Flow/ETL/Row/Schema/Constraint/SameAs.php)
- [void](../../../src/core/etl/src/Flow/ETL/Row/Schema/Constraint/VoidConstraint.php)

## Example - schema validation

```php
Expand All @@ -46,7 +36,7 @@ data_frame()
schema(
int_schema('id', $nullable = false),
str_schema('name', $nullable = true),
bool_schema('active', $nullable = false, new SameAs(true), Metadata::empty()->add('key', 'value')),
bool_schema('active', $nullable = false, Metadata::empty()->add('key', 'value')),
)
)
->write(to_output(false, Output::rows_and_schema))
Expand Down
25 changes: 24 additions & 1 deletion src/core/etl/src/Flow/ETL/DSL/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,14 @@ function structure_type(array $elements, bool $nullable = false) : StructureType
return new StructureType($elements, $nullable);
}

/**
* @param array<string, StructureElement> $elements
*/
function type_structure(array $elements, bool $nullable = false) : StructureType
{
return new StructureType($elements, $nullable);
}

function struct_element(string $name, Type $type) : StructureElement
{
return new StructureElement($name, $type);
Expand Down Expand Up @@ -1007,6 +1015,16 @@ function schema(Definition ...$definitions) : Schema
return new Schema(...$definitions);
}

function schema_to_json(Schema $schema) : string
{
return \json_encode($schema->normalize(), JSON_THROW_ON_ERROR);
}

function schema_from_json(string $schema) : Schema
{
return Schema::fromArray(\json_decode($schema, true, 512, JSON_THROW_ON_ERROR));
}

function int_schema(string $name, bool $nullable = false, ?Schema\Metadata $metadata = null) : Definition
{
return Definition::integer($name, $nullable, $metadata);
Expand Down Expand Up @@ -1085,9 +1103,14 @@ function struct_schema(string $name, StructureType $type, ?Schema\Metadata $meta
return Definition::structure($name, $type, $metadata);
}

function structure_schema(string $name, StructureType $type, ?Schema\Metadata $metadata = null) : Definition
{
return Definition::structure($name, $type, $metadata);
}

function uuid_schema(string $name, bool $nullable = false, ?Schema\Metadata $metadata = null) : Definition
{
return Definition::uuid($name, \uuid_type($nullable), $metadata);
return Definition::uuid($name, $nullable, $metadata);
}

function execution_context(?Config $config = null) : FlowContext
Expand Down
13 changes: 13 additions & 0 deletions src/core/etl/src/Flow/ETL/PHP/Type/Logical/DateTimeType.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ public function __construct(private readonly bool $nullable = false)
{
}

public static function fromArray(array $data) : self
{
return new self($data['nullable'] ?? false);
}

public function isEqual(Type $type) : bool
{
return $type instanceof self;
Expand Down Expand Up @@ -42,6 +47,14 @@ public function merge(Type $type) : self
return new self($this->nullable || $type->nullable());
}

public function normalize() : array
{
return [
'type' => 'datetime',
'nullable' => $this->nullable,
];
}

public function nullable() : bool
{
return $this->nullable;
Expand Down
13 changes: 13 additions & 0 deletions src/core/etl/src/Flow/ETL/PHP/Type/Logical/JsonType.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ public function __construct(private readonly bool $nullable)
{
}

public static function fromArray(array $data) : self
{
return new self($data['nullable'] ?? false);
}

public function isEqual(Type $type) : bool
{
return $type instanceof self;
Expand Down Expand Up @@ -47,6 +52,14 @@ public function merge(Type $type) : self
return new self($this->nullable || $type->nullable());
}

public function normalize() : array
{
return [
'type' => 'json',
'nullable' => $this->nullable,
];
}

public function nullable() : bool
{
return $this->nullable;
Expand Down
28 changes: 23 additions & 5 deletions src/core/etl/src/Flow/ETL/PHP/Type/Logical/List/ListElement.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@
use function Flow\ETL\DSL\type_uuid;
use function Flow\ETL\DSL\type_xml;
use function Flow\ETL\DSL\type_xml_node;
use Flow\ETL\Exception\InvalidArgumentException;
use Flow\ETL\PHP\Type\Logical\ListType;
use Flow\ETL\PHP\Type\Logical\MapType;
use Flow\ETL\PHP\Type\Logical\StructureType;
use Flow\ETL\PHP\Type\Type;
use Flow\ETL\PHP\Type\TypeFactory;

final class ListElement
{
public function __construct(private readonly Type $value)
public function __construct(private readonly Type $type)
{
}

Expand All @@ -38,6 +40,15 @@ public static function float() : self
return new self(type_float(false));
}

public static function fromArray(array $data) : self
{
if (!\array_key_exists('type', $data)) {
throw new InvalidArgumentException("Missing 'type' key in list element definition");
}

return new self(TypeFactory::fromArray($data['type']));
}

public static function fromType(Type $type) : self
{
return new self($type);
Expand Down Expand Up @@ -102,21 +113,28 @@ public static function xml_node(bool $nullable = false) : self

public function isEqual(mixed $value) : bool
{
return $this->value->isEqual($value);
return $this->type->isEqual($value);
}

public function isValid(mixed $value) : bool
{
return $this->value->isValid($value);
return $this->type->isValid($value);
}

public function normalize() : array
{
return [
'type' => $this->type->normalize(),
];
}

public function toString() : string
{
return $this->value->toString();
return $this->type->toString();
}

public function type() : Type
{
return $this->value;
return $this->type;
}
}
14 changes: 14 additions & 0 deletions src/core/etl/src/Flow/ETL/PHP/Type/Logical/ListType.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ public function __construct(private readonly ListElement $element, private reado
{
}

public static function fromArray(array $data) : self
{
return new self(ListElement::fromArray($data['element']), $data['nullable'] ?? false);
}

public function element() : ListElement
{
return $this->element;
Expand Down Expand Up @@ -64,6 +69,15 @@ public function merge(Type $type) : self
return new self($this->element, $this->nullable || $type->nullable());
}

public function normalize() : array
{
return [
'type' => 'list',
'element' => $this->element->normalize(),
'nullable' => $this->nullable,
];
}

public function nullable() : bool
{
return $this->nullable;
Expand Down
24 changes: 24 additions & 0 deletions src/core/etl/src/Flow/ETL/PHP/Type/Logical/Map/MapKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
use function Flow\ETL\DSL\type_int;
use function Flow\ETL\DSL\type_string;
use function Flow\ETL\DSL\type_uuid;
use Flow\ETL\Exception\InvalidArgumentException;
use Flow\ETL\PHP\Type\Logical\LogicalType;
use Flow\ETL\PHP\Type\Native\ScalarType;
use Flow\ETL\PHP\Type\TypeFactory;

final class MapKey
{
Expand All @@ -20,6 +22,21 @@ public static function datetime() : self
return new self(type_datetime(false));
}

public static function fromArray(array $data) : self
{
if (!\array_key_exists('type', $data)) {
throw new InvalidArgumentException('Missing "type" key in ' . self::class . ' fromArray()');
}

$keyType = TypeFactory::fromArray($data['type']);

if (!$keyType instanceof ScalarType && !$keyType instanceof LogicalType) {
throw new InvalidArgumentException('Invalid "type" key in ' . self::class . ' fromArray()');
}

return new self($keyType);
}

public static function fromType(ScalarType|LogicalType $type) : self
{
return new self($type);
Expand Down Expand Up @@ -50,6 +67,13 @@ public function isValid(mixed $value) : bool
return $this->value->isValid($value);
}

public function normalize() : array
{
return [
'type' => $this->value->normalize(),
];
}

public function toString() : string
{
return $this->value->toString();
Expand Down
18 changes: 18 additions & 0 deletions src/core/etl/src/Flow/ETL/PHP/Type/Logical/Map/MapValue.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
use function Flow\ETL\DSL\type_string;
use function Flow\ETL\DSL\type_xml;
use function Flow\ETL\DSL\type_xml_node;
use Flow\ETL\Exception\InvalidArgumentException;
use Flow\ETL\PHP\Type\Logical\ListType;
use Flow\ETL\PHP\Type\Logical\MapType;
use Flow\ETL\PHP\Type\Type;
use Flow\ETL\PHP\Type\TypeFactory;

final class MapValue
{
Expand All @@ -35,6 +37,15 @@ public static function float() : self
return new self(type_float());
}

public static function fromArray(array $value) : self
{
if (!\array_key_exists('type', $value)) {
throw new InvalidArgumentException('Missing "type" key in ' . self::class . ' fromArray()');
}

return new self(TypeFactory::fromArray($value['type']));
}

public static function fromType(Type $type) : self
{
return new self($type);
Expand Down Expand Up @@ -93,6 +104,13 @@ public function isValid(mixed $value) : bool
return $this->value->isValid($value);
}

public function normalize() : array
{
return [
'type' => $this->value->normalize(),
];
}

public function toString() : string
{
return $this->value->toString();
Expand Down
15 changes: 15 additions & 0 deletions src/core/etl/src/Flow/ETL/PHP/Type/Logical/MapType.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ public function __construct(private readonly MapKey $key, private readonly MapVa
{
}

public static function fromArray(array $data) : self
{
return new self(MapKey::fromArray($data['key']), MapValue::fromArray($data['value']), $data['nullable'] ?? false);
}

public function isEqual(Type $type) : bool
{
if (!$type instanceof self) {
Expand Down Expand Up @@ -69,6 +74,16 @@ public function merge(Type $type) : self
return new self($this->key, $this->value, $this->nullable || $type->nullable());
}

public function normalize() : array
{
return [
'type' => 'map',
'key' => $this->key->normalize(),
'value' => $this->value->normalize(),
'nullable' => $this->nullable,
];
}

public function nullable() : bool
{
return $this->nullable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

use Flow\ETL\Exception\InvalidArgumentException;
use Flow\ETL\PHP\Type\Type;
use Flow\ETL\PHP\Type\TypeFactory;

final class StructureElement
{
Expand All @@ -15,6 +16,19 @@ public function __construct(private readonly string $name, private readonly Type
}
}

public static function fromArray(array $element) : self
{
if (!\array_key_exists('name', $element)) {
throw InvalidArgumentException::because('Structure element must have a name');
}

if (!\array_key_exists('type', $element)) {
throw InvalidArgumentException::because('Structure element must have a type');
}

return new self($element['name'], TypeFactory::fromArray($element['type']));
}

public function isEqual(self $element) : bool
{
return $this->name === $element->name && $this->type->isEqual($element->type());
Expand Down Expand Up @@ -44,6 +58,14 @@ public function name() : string
return $this->name;
}

public function normalize() : array
{
return [
'name' => $this->name,
'type' => $this->type->normalize(),
];
}

public function toString() : string
{
return $this->name . ': ' . $this->type->toString();
Expand Down
Loading

0 comments on commit 590c4a5

Please sign in to comment.