Skip to content

Commit 29efaa1

Browse files
authored
#1926 - change bechawior for entry factory (#1943)
* feat: move to type narrower * feat: move to type narrower * feat: move to type narrower * fix: resolve conflicts * fix: resolve conflicts * fix: resolve conflicts * fix: after review * fix: after review * fix: tests * fix: tests * fix: after review * feat: add tests * fix: cs-fix * feat: change architecture logic * fix: cs-fix * Revert "fix: cs-fix" This reverts commit fa5a2d0. * fix: cs-fix
1 parent bbee977 commit 29efaa1

13 files changed

Lines changed: 411 additions & 276 deletions

File tree

src/cli/tests/Flow/CLI/Tests/Integration/FileSchemaCommandTest.php

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public function test_run_schema() : void
2222

2323
self::assertCommandOutputIdentical(
2424
<<<'OUTPUT'
25-
[{"ref":"order_id","type":{"type":"uuid"},"nullable":false,"metadata":[]},{"ref":"created_at","type":{"type":"string"},"nullable":false,"metadata":[]},{"ref":"updated_at","type":{"type":"string"},"nullable":false,"metadata":[]},{"ref":"discount","type":{"type":"string"},"nullable":true,"metadata":[]},{"ref":"address","type":{"type":"json"},"nullable":false,"metadata":[]},{"ref":"notes","type":{"type":"json"},"nullable":false,"metadata":[]},{"ref":"items","type":{"type":"json"},"nullable":false,"metadata":[]}]
25+
[{"ref":"order_id","type":{"type":"string"},"nullable":false,"metadata":[]},{"ref":"created_at","type":{"type":"string"},"nullable":false,"metadata":[]},{"ref":"updated_at","type":{"type":"string"},"nullable":false,"metadata":[]},{"ref":"discount","type":{"type":"string"},"nullable":true,"metadata":[]},{"ref":"address","type":{"type":"json"},"nullable":false,"metadata":[]},{"ref":"notes","type":{"type":"json"},"nullable":false,"metadata":[]},{"ref":"items","type":{"type":"json"},"nullable":false,"metadata":[]}]
2626

2727
OUTPUT,
2828
$tester->getDisplay()
@@ -40,7 +40,7 @@ public function test_run_schema_as_ascii() : void
4040
self::assertCommandOutputIdentical(
4141
<<<'OUTPUT'
4242
schema
43-
|-- order_id: uuid
43+
|-- order_id: string
4444
|-- created_at: string
4545
|-- updated_at: string
4646
|-- discount: ?string
@@ -85,7 +85,7 @@ public function test_run_schema_with_offset() : void
8585
self::assertCommandOutputIdentical(
8686
<<<'OUTPUT'
8787
schema
88-
|-- order_id: uuid
88+
|-- order_id: string
8989
|-- created_at: string
9090
|-- updated_at: string
9191
|-- discount: ?string
@@ -117,7 +117,7 @@ public function test_run_schema_with_offset_and_limit() : void
117117
+------------+--------+----------+----------+
118118
| name | type | nullable | metadata |
119119
+------------+--------+----------+----------+
120-
| order_id | uuid | false | [] |
120+
| order_id | string | false | [] |
121121
| created_at | string | false | [] |
122122
| updated_at | string | false | [] |
123123
| discount | string | false | [] |
@@ -143,7 +143,7 @@ public function test_run_schema_with_php_output() : void
143143
self::assertCommandOutputIdentical(
144144
<<<'OUTPUT'
145145
\Flow\ETL\DSL\schema(
146-
\Flow\ETL\DSL\uuid_schema("order_id", nullable: false, metadata: \Flow\ETL\DSL\schema_metadata()),
146+
\Flow\ETL\DSL\string_schema("order_id", nullable: false, metadata: \Flow\ETL\DSL\schema_metadata()),
147147
\Flow\ETL\DSL\string_schema("created_at", nullable: false, metadata: \Flow\ETL\DSL\schema_metadata()),
148148
\Flow\ETL\DSL\string_schema("updated_at", nullable: false, metadata: \Flow\ETL\DSL\schema_metadata()),
149149
\Flow\ETL\DSL\string_schema("discount", nullable: true, metadata: \Flow\ETL\DSL\schema_metadata()),
@@ -171,7 +171,7 @@ public function test_run_schema_with_pretty_output() : void
171171
{
172172
"ref": "order_id",
173173
"type": {
174-
"type": "uuid"
174+
"type": "string"
175175
},
176176
"nullable": false,
177177
"metadata": []
@@ -244,7 +244,7 @@ public function test_run_schema_with_table_output() : void
244244
+------------+--------+----------+----------+
245245
| name | type | nullable | metadata |
246246
+------------+--------+----------+----------+
247-
| order_id | uuid | false | [] |
247+
| order_id | string | false | [] |
248248
| created_at | string | false | [] |
249249
| updated_at | string | false | [] |
250250
| discount | string | true | [] |
@@ -328,7 +328,7 @@ public function test_run_schema_with_table_output_on_excel() : void
328328
+------------+--------+----------+----------+
329329
| name | type | nullable | metadata |
330330
+------------+--------+----------+----------+
331-
| order_id | uuid | false | [] |
331+
| order_id | string | false | [] |
332332
| created_at | string | false | [] |
333333
| updated_at | string | false | [] |
334334
| discount | string | true | [] |
@@ -463,7 +463,7 @@ public function test_run_schema_with_zero_offset() : void
463463
self::assertCommandOutputIdentical(
464464
<<<'OUTPUT'
465465
schema
466-
|-- order_id: uuid
466+
|-- order_id: string
467467
|-- created_at: string
468468
|-- updated_at: string
469469
|-- discount: ?string

src/core/etl/src/Flow/ETL/Row/EntryFactory.php

Lines changed: 7 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,16 @@ enum_entry,
2121
uuid_entry,
2222
xml_element_entry,
2323
xml_entry};
24-
use function Flow\Types\DSL\{type_date,
25-
type_datetime,
26-
type_html,
27-
type_json,
28-
type_optional,
29-
type_string,
30-
type_time,
31-
type_uuid,
32-
type_xml,
33-
type_xml_element};
34-
use Flow\ETL\Exception\{InvalidArgumentException,
35-
RuntimeException,
36-
SchemaDefinitionNotFoundException};
24+
use function Flow\Types\DSL\{type_optional, type_string};
25+
use Flow\ETL\Exception\{InvalidArgumentException, SchemaDefinitionNotFoundException};
3726
use Flow\ETL\Row\Entry\{ListEntry, MapEntry, StringEntry, StructureEntry};
3827
use Flow\ETL\Schema;
3928
use Flow\ETL\Schema\{Definition, Metadata};
4029
use Flow\Types\Exception\CastingException;
4130
use Flow\Types\Type;
4231
use Flow\Types\Type\Logical\{DateTimeType,
4332
DateType,
33+
HTMLType,
4434
InstanceOfType,
4535
JsonType,
4636
ListType,
@@ -52,7 +42,6 @@ enum_entry,
5242
UuidType,
5343
XMLElementType,
5444
XMLType};
55-
use Flow\Types\Type\Logical\HTMLType;
5645
use Flow\Types\Type\Native\{
5746
ArrayType,
5847
BooleanType,
@@ -63,17 +52,14 @@ enum_entry,
6352
StringType,
6453
UnionType
6554
};
66-
use Flow\Types\Type\Native\String\StringTypeChecker;
6755
use Flow\Types\Type\TypeDetector;
68-
use Flow\Types\Value\Uuid;
6956

7057
final readonly class EntryFactory
7158
{
7259
/**
7360
* @param null|Definition<mixed>|Schema $schema
7461
*
7562
* @throws InvalidArgumentException
76-
* @throws RuntimeException
7763
* @throws SchemaDefinitionNotFoundException
7864
*
7965
* @return Entry<mixed>
@@ -96,45 +82,6 @@ public function create(string $entryName, mixed $value, Schema|Definition|null $
9682

9783
$valueType = (new TypeDetector())->detectType($value);
9884

99-
if ($valueType instanceof StringType) {
100-
$value = type_string()->assert($value);
101-
$stringChecker = new StringTypeChecker($value);
102-
103-
if ($stringChecker->isJson()) {
104-
$valueType = type_json();
105-
} elseif ($stringChecker->isUuid()) {
106-
$valueType = type_uuid();
107-
} elseif ($stringChecker->isHTML()) {
108-
$valueType = type_html();
109-
} elseif ($stringChecker->isXML()) {
110-
$valueType = type_xml();
111-
}
112-
}
113-
114-
if ($valueType instanceof InstanceOfType) {
115-
if ($valueType->class === \DOMDocument::class) {
116-
$valueType = type_xml();
117-
} elseif ($valueType->class === \DOMElement::class) {
118-
$valueType = type_xml_element();
119-
} elseif ($valueType->class === \DateInterval::class) {
120-
$valueType = type_time();
121-
} elseif (\in_array($valueType->class, [\DateTimeImmutable::class, \DateTimeInterface::class, \DateTime::class], true)) {
122-
if ($value instanceof \DateTimeInterface && $value->format('H:i:s') === '00:00:00') {
123-
$valueType = type_date();
124-
} else {
125-
$valueType = type_datetime();
126-
}
127-
} else {
128-
foreach (['Ramsey\Uuid\UuidInterface', Uuid::class, 'Symfony\Component\Uid\Uuid'] as $uuidClass) {
129-
if (\is_a($valueType->class, $uuidClass, true)) {
130-
$valueType = type_uuid();
131-
132-
break;
133-
}
134-
}
135-
}
136-
}
137-
13885
return $this->createAs($entryName, $value, $valueType);
13986
}
14087

@@ -223,6 +170,10 @@ public function createAs(string $entryName, mixed $value, Definition|Type $defin
223170
return string_entry($entryName, type_optional(type_string())->cast($value), $metadata);
224171
}
225172

173+
if ($type instanceof NullType) {
174+
return StringEntry::fromNull($entryName, $metadata);
175+
}
176+
226177
if ($type instanceof EnumType) {
227178
$castValue = type_optional($type)->cast($value);
228179

src/core/etl/tests/Flow/ETL/Tests/Unit/Function/CastTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public static function cast_provider() : array
4444
'xml_to_array' => [$xml, 'array', ['root' => ['foo' => ['@attributes' => ['baz' => 'buz'], '@value' => 'bar']]]],
4545
'string_to_xml' => [$xmlString, 'xml', $xml],
4646
'xml_to_string' => [$xml, 'string', '<root><foo baz="buz">bar</foo></root>'],
47-
'full_xml_to_string' => [$fullXMLString, 'string', '<root><foo baz="buz">bar</foo></root>'],
47+
'full_xml_to_string' => [$fullXMLString, 'string', $fullXMLString],
4848
'datetime' => [new \DateTimeImmutable('2023-01-01 00:00:00 UTC'), 'string', '2023-01-01T00:00:00+00:00'],
4949
'datetime_to_date' => [new \DateTimeImmutable('2023-01-01 00:01:00 UTC'), 'date', new \DateTimeImmutable('2023-01-01T00:00:00+00:00')],
5050
'string_to_timezone' => ['UTC', 'timezone', new \DateTimeZone('UTC')],

src/core/etl/tests/Flow/ETL/Tests/Unit/Row/EntryFactoryTest.php

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ enum_entry,
1414
json_object_entry,
1515
list_entry,
1616
str_entry,
17+
string_entry,
1718
time_entry,
1819
uuid_entry,
1920
xml_entry};
@@ -35,9 +36,9 @@ enum_schema,
3536
time_schema,
3637
uuid_schema,
3738
xml_schema};
38-
use function Flow\Types\DSL\{type_datetime, type_float, type_integer, type_list, type_map, type_string, type_structure, type_time_zone};
39+
use function Flow\Types\DSL\{type_datetime, type_float, type_integer, type_list, type_map, type_null, type_string, type_structure, type_time_zone};
3940
use Flow\ETL\Exception\{InvalidArgumentException, SchemaDefinitionNotFoundException};
40-
use Flow\ETL\Row\Entry\TimeEntry;
41+
use Flow\ETL\Row\Entry\{StringEntry, TimeEntry};
4142
use Flow\ETL\Row\{Entry, EntryFactory};
4243
use Flow\ETL\Schema\Metadata;
4344
use Flow\ETL\Tests\Fixtures\Enum\BackedIntEnum;
@@ -59,17 +60,17 @@ public static function provide_recognized_data() : \Generator
5960

6061
yield 'xml' => [
6162
$xml = '<root><foo>1</foo><bar>2</bar><baz>3</baz></root>',
62-
xml_entry('e', $xml),
63+
string_entry('e', $xml),
6364
];
6465

6566
yield 'html' => [
6667
$html = '<!DOCTYPE html><html><head></head><body><div id="id">2</div><p>3</p></body></html>',
67-
html_entry('e', $html),
68+
string_entry('e', $html),
6869
];
6970

7071
yield 'uuid' => [
7172
$uuid = '00000000-0000-0000-0000-000000000000',
72-
uuid_entry('e', $uuid),
73+
string_entry('e', $uuid),
7374
];
7475
}
7576

@@ -263,7 +264,7 @@ public function test_html_from_dom_document() : void
263264
public function test_html_from_string() : void
264265
{
265266
self::assertEquals(
266-
html_entry('e', $html = '<!DOCTYPE html><html><head></head><body><div>foo</div><p>3</p></body></html>'),
267+
string_entry('e', $html = '<!DOCTYPE html><html><head></head><body><div>foo</div><p>3</p></body></html>'),
267268
$this->entryFactory->create('e', $html)
268269
);
269270
}
@@ -418,6 +419,14 @@ public function test_nested_structure() : void
418419
);
419420
}
420421

422+
public function test_null_type_handled() : void
423+
{
424+
self::assertEquals(
425+
StringEntry::fromNull('e'),
426+
$this->entryFactory->createAs('e', null, type_null())
427+
);
428+
}
429+
421430
public function test_object() : void
422431
{
423432
$this->expectExceptionMessage("e: object<ArrayIterator> can't be converted to any known Entry, please normalize that object first");
@@ -521,16 +530,17 @@ public function test_uuid_from_ramsey_uuid_library() : void
521530
self::markTestSkipped("Package 'ramsey/uuid' is required for this test.");
522531
}
523532

533+
$uuidObject = Uuid::uuid4();
524534
self::assertEquals(
525-
uuid_entry('e', $uuid = Uuid::uuid4()->toString()),
526-
$this->entryFactory->create('e', $uuid)
535+
uuid_entry('e', $uuidObject->toString()),
536+
$this->entryFactory->create('e', $uuidObject)
527537
);
528538
}
529539

530540
public function test_uuid_from_string() : void
531541
{
532542
self::assertEquals(
533-
uuid_entry('e', $uuid = '00000000-0000-0000-0000-000000000000'),
543+
string_entry('e', $uuid = '00000000-0000-0000-0000-000000000000'),
534544
$this->entryFactory->create('e', $uuid)
535545
);
536546
}
@@ -546,7 +556,7 @@ public function test_uuid_string_with_uuid_definition_provided() : void
546556
public function test_uuid_type() : void
547557
{
548558
self::assertEquals(
549-
uuid_entry('e', '00000000-0000-0000-0000-000000000000'),
559+
string_entry('e', '00000000-0000-0000-0000-000000000000'),
550560
$this->entryFactory->create('e', '00000000-0000-0000-0000-000000000000')
551561
);
552562
}
@@ -580,7 +590,7 @@ public function test_xml_from_dom_document() : void
580590
public function test_xml_from_string() : void
581591
{
582592
self::assertEquals(
583-
xml_entry('e', $xml = '<root><foo>1</foo><bar>2</bar><baz>3</baz></root>'),
593+
string_entry('e', $xml = '<root><foo>1</foo><bar>2</bar><baz>3</baz></root>'),
584594
$this->entryFactory->create('e', $xml)
585595
);
586596
}

src/lib/types/src/Flow/Types/Type/AutoCaster.php

Lines changed: 6 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,9 @@
44

55
namespace Flow\Types\Type;
66

7-
use function Flow\Types\DSL\{get_type,
8-
type_boolean,
9-
type_date,
10-
type_datetime,
11-
type_float,
12-
type_integer,
13-
type_json,
14-
type_time_zone,
15-
type_uuid};
16-
use Flow\Types\Type\Native\String\StringTypeChecker;
7+
use function Flow\Types\DSL\{get_type, type_float};
8+
use Flow\Types\Type\Native\NullType;
9+
use Flow\Types\Type\Native\String\StringTypeNarrower;
1710

1811
final readonly class AutoCaster
1912
{
@@ -62,44 +55,12 @@ private function castArray(array $value) : array
6255

6356
private function castToString(string $value) : mixed
6457
{
65-
$typeChecker = new StringTypeChecker($value);
58+
$narrowedType = (new StringTypeNarrower())->narrow($value);
6659

67-
if ($typeChecker->isNull()) {
60+
if ($narrowedType instanceof NullType) {
6861
return null;
6962
}
7063

71-
if ($typeChecker->isInteger()) {
72-
return type_integer()->cast($value);
73-
}
74-
75-
if ($typeChecker->isFloat()) {
76-
return type_float()->cast($value);
77-
}
78-
79-
if ($typeChecker->isBoolean()) {
80-
return type_boolean()->cast($value);
81-
}
82-
83-
if ($typeChecker->isJson()) {
84-
return type_json()->cast($value);
85-
}
86-
87-
if ($typeChecker->isUuid()) {
88-
return type_uuid()->cast($value);
89-
}
90-
91-
if ($typeChecker->isTimeZone()) {
92-
return type_time_zone()->cast($value);
93-
}
94-
95-
if ($typeChecker->isDate()) {
96-
return type_date()->cast($value);
97-
}
98-
99-
if ($typeChecker->isDateTime()) {
100-
return type_datetime()->cast($value);
101-
}
102-
103-
return $value;
64+
return $narrowedType->cast($value);
10465
}
10566
}

0 commit comments

Comments
 (0)