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
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ enum_entry,
enum_schema,
float_entry,
float_schema,
html_entry,
html_schema,
int_entry,
int_schema,
json_entry,
Expand Down Expand Up @@ -72,6 +74,7 @@ public function test_normalization_nullable_entries() : void
),
enum_entry('enum', null),
xml_entry('xml', null),
html_entry('html', null),
)
);
$schema = schema(
Expand Down Expand Up @@ -101,6 +104,7 @@ enum_entry('enum', null),
),
enum_schema('enum', BackedStringEnum::class, true),
xml_schema('xml', true),
html_schema('html', true),
);

self::assertEquals(
Expand All @@ -119,6 +123,7 @@ enum_schema('enum', BackedStringEnum::class, true),
'struct' => null,
'enum' => null,
'xml' => null,
'html' => null,
],
],
(new RowsNormalizer())->normalize($rows, $schema)
Expand Down
10 changes: 10 additions & 0 deletions src/core/etl/src/Flow/ETL/DSL/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@
use Flow\ETL\Retry\RetryStrategy\{AnyThrowable, OnExceptionTypes};
use Flow\ETL\Row\{Entries, EntryFactory, SortOrder};
use Flow\ETL\Row\Entry\{BooleanEntry, DateEntry, DateTimeEntry, EnumEntry, FloatEntry, IntegerEntry, JsonEntry, ListEntry, MapEntry, StringEntry, StructureEntry, TimeEntry, UuidEntry, XMLElementEntry, XMLEntry};
use Flow\ETL\Row\Entry\HTMLEntry;
use Flow\ETL\Row\{Entry, EntryReference, Reference, References};
use Flow\ETL\Row\Formatter\ASCIISchemaFormatter;
use Flow\ETL\Schema\{Definition, Formatter\PHPFormatter\TypeFormatter, Formatter\PHPFormatter\ValueFormatter};
Expand Down Expand Up @@ -627,6 +628,15 @@ function xml_element_entry(string $name, \DOMElement|string|null $value, ?Metada
return new XMLElementEntry($name, $value, $metadata);
}

/**
* @return Entry<?HTMLDocument>
*/
#[DocumentationDSL(module: Module::CORE, type: DSLType::ENTRY)]
function html_entry(string $name, HTMLDocument|string|null $value, ?Metadata $metadata = null) : Entry
{
return new HTMLEntry($name, $value, $metadata);
}

/**
* @param Entry<mixed> ...$entries
*/
Expand Down
119 changes: 119 additions & 0 deletions src/core/etl/src/Flow/ETL/Row/Entry/HTMLEntry.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
<?php

declare(strict_types=1);

namespace Flow\ETL\Row\Entry;

use function Flow\Types\DSL\{type_equals, type_html, type_optional};
use Flow\ETL\Row\{Entry, Reference};
use Flow\ETL\Schema\{Definition, Metadata};
use Flow\Types\Type;
use Flow\Types\Value\HTMLDocument;

/**
* @implements Entry<?HTMLDocument>
*/
final class HTMLEntry implements Entry
{
use EntryRef;

private Metadata $metadata;

/**
* @var Type<HTMLDocument>
*/
private readonly Type $type;

private ?HTMLDocument $value;

public function __construct(
private readonly string $name,
HTMLDocument|string|null $value,
?Metadata $metadata = null,
) {
if (\is_string($value)) {
$this->value = HTMLDocument::fromString($value);
} else {
$this->value = $value;
}

$this->metadata = $metadata ?: Metadata::empty();
$this->type = type_html();
}

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

public function definition() : Definition
{
return new Definition($this->name, $this->type, null === $this->value, $this->metadata);
}

public function duplicate() : self
{
return new self($this->name, $this->value ? clone $this->value : null, $this->metadata);
}

public function is(Reference|string $name) : bool
{
if ($name instanceof Reference) {
return $this->name === $name->name();
}

return $this->name === $name;
}

public function isEqual(Entry $entry) : bool
{
if (!$entry instanceof self || !$this->is($entry->name())) {
return false;
}

if (!type_equals($this->type, $entry->type)) {
return false;
}

return $entry->value()?->toString() === $this->value?->toString();
}

public function map(callable $mapper) : self
{
return new self($this->name, $mapper($this->value));
}

public function name() : string
{
return $this->name;
}

public function rename(string $name) : self
{
return new self($name, $this->value);
}

public function toString() : string
{
if (null === $this->value) {
return '';
}

return $this->value->toString();
}

public function type() : Type
{
return $this->type;
}

public function value() : ?HTMLDocument
{
return $this->value;
}

public function withValue(mixed $value) : self
{
return new self($this->name, type_optional($this->type())->assert($value), $this->metadata);
}
}
7 changes: 7 additions & 0 deletions src/core/etl/src/Flow/ETL/Row/EntryFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
datetime_entry,
enum_entry,
float_entry,
html_entry,
int_entry,
json_entry,
json_object_entry,
Expand Down Expand Up @@ -51,6 +52,7 @@ enum_entry,
UuidType,
XMLElementType,
XMLType};
use Flow\Types\Type\Logical\HTMLType;
use Flow\Types\Type\Native\{
ArrayType,
BooleanType,
Expand Down Expand Up @@ -171,6 +173,7 @@ public function createAs(string $entryName, mixed $value, Definition|Type $defin
NullType::class => StringEntry::fromNull($entryName, $metadata),
XMLType::class => xml_entry($entryName, null, $metadata),
XMLElementType::class => xml_element_entry($entryName, null, $metadata),
HTMLType::class => html_entry($entryName, null, $metadata),
default => throw new InvalidArgumentException("Can't convert value into type \"{$type->toString()}\""),
};
}
Expand Down Expand Up @@ -234,6 +237,10 @@ public function createAs(string $entryName, mixed $value, Definition|Type $defin
}
}

if ($type instanceof HTMLType) {
return html_entry($entryName, type_optional($type)->cast($value), $metadata);
}

if ($type instanceof XMLType) {
return xml_entry($entryName, type_optional($type)->cast($value), $metadata);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ enum_entry,
float_entry,
from_array,
from_rows,
html_entry,
int_entry,
json_entry,
list_entry,
Expand Down Expand Up @@ -75,6 +76,7 @@ public function extract(FlowContext $context) : \Generator
),
enum_entry('enum', BackedStringEnum::three),
xml_entry('xml', '<xml><node id="123">test<foo>bar</foo></node></xml>'),
html_entry('html', '<!DOCTYPE html><html lang="en"><head></head><body></body></html>'),
),
);
}
Expand All @@ -84,15 +86,15 @@ enum_entry('enum', BackedStringEnum::three),

self::assertCommandOutputIdentical(
<<<'ASCIITABLE'
+------+------------+-----+---------+----------------------+-------+----------------------+---------+-------------------+----------------------+-------+----------------------+
| id | price | 100 | deleted | created-at | phase | array | list | map | items | enum | xml |
+------+------------+-----+---------+----------------------+-------+----------------------+---------+-------------------+----------------------+-------+----------------------+
| 1234 | 123.450000 | 100 | false | 2020-07-13T15:00:00+ | | [{"id":1,"status":"N | [1,2,3] | ["NEW","PENDING"] | {"item-id":"1","name | three | <xml><node id="123"> |
| 1234 | 123.450000 | 100 | false | 2020-07-13T15:00:00+ | | [{"id":1,"status":"N | [1,2,3] | ["NEW","PENDING"] | {"item-id":"1","name | three | <xml><node id="123"> |
| 1234 | 123.450000 | 100 | false | 2020-07-13T15:00:00+ | | [{"id":1,"status":"N | [1,2,3] | ["NEW","PENDING"] | {"item-id":"1","name | three | <xml><node id="123"> |
| 1234 | 123.450000 | 100 | false | 2020-07-13T15:00:00+ | | [{"id":1,"status":"N | [1,2,3] | ["NEW","PENDING"] | {"item-id":"1","name | three | <xml><node id="123"> |
| 1234 | 123.450000 | 100 | false | 2020-07-13T15:00:00+ | | [{"id":1,"status":"N | [1,2,3] | ["NEW","PENDING"] | {"item-id":"1","name | three | <xml><node id="123"> |
+------+------------+-----+---------+----------------------+-------+----------------------+---------+-------------------+----------------------+-------+----------------------+
+------+------------+-----+---------+----------------------+-------+----------------------+---------+-------------------+----------------------+-------+----------------------+----------------------+
| id | price | 100 | deleted | created-at | phase | array | list | map | items | enum | xml | html |
+------+------------+-----+---------+----------------------+-------+----------------------+---------+-------------------+----------------------+-------+----------------------+----------------------+
| 1234 | 123.450000 | 100 | false | 2020-07-13T15:00:00+ | | [{"id":1,"status":"N | [1,2,3] | ["NEW","PENDING"] | {"item-id":"1","name | three | <xml><node id="123"> | <!DOCTYPE html><html |
| 1234 | 123.450000 | 100 | false | 2020-07-13T15:00:00+ | | [{"id":1,"status":"N | [1,2,3] | ["NEW","PENDING"] | {"item-id":"1","name | three | <xml><node id="123"> | <!DOCTYPE html><html |
| 1234 | 123.450000 | 100 | false | 2020-07-13T15:00:00+ | | [{"id":1,"status":"N | [1,2,3] | ["NEW","PENDING"] | {"item-id":"1","name | three | <xml><node id="123"> | <!DOCTYPE html><html |
| 1234 | 123.450000 | 100 | false | 2020-07-13T15:00:00+ | | [{"id":1,"status":"N | [1,2,3] | ["NEW","PENDING"] | {"item-id":"1","name | three | <xml><node id="123"> | <!DOCTYPE html><html |
| 1234 | 123.450000 | 100 | false | 2020-07-13T15:00:00+ | | [{"id":1,"status":"N | [1,2,3] | ["NEW","PENDING"] | {"item-id":"1","name | three | <xml><node id="123"> | <!DOCTYPE html><html |
+------+------------+-----+---------+----------------------+-------+----------------------+---------+-------------------+----------------------+-------+----------------------+----------------------+
5 rows

ASCIITABLE,
Expand Down
Loading
Loading