Skip to content

Commit 301ad8a

Browse files
committed
WIP
1 parent c2db368 commit 301ad8a

10 files changed

+268
-2
lines changed

src/Configuration.php

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php
2+
3+
namespace EcomDev\MySQL2JSONL;
4+
5+
use Amp\Mysql\MysqlConfig;
6+
use JsonSchema\Constraints\Constraint;
7+
use JsonSchema\Validator;
8+
use JsonException;
9+
10+
final readonly class Configuration
11+
{
12+
private function __construct(
13+
public MysqlConfig $connection,
14+
public TableCondition $includeCondition,
15+
public TableCondition $excludeCondition,
16+
)
17+
{
18+
19+
}
20+
21+
/**
22+
* Creates configuration based on JSON value supported by schema.json
23+
*
24+
* @throws ConfigurationException|JsonException
25+
*/
26+
public static function fromJSON(string $json): Configuration
27+
{
28+
$validator = new Validator();
29+
$schema = json_decode(
30+
file_get_contents(dirname(__DIR__) . DIRECTORY_SEPARATOR . 'schema.json'),
31+
flags: JSON_THROW_ON_ERROR
32+
);
33+
$data = json_decode(
34+
$json,
35+
flags: JSON_THROW_ON_ERROR
36+
);
37+
$result = $validator->validate($data, $schema, Constraint::CHECK_MODE_APPLY_DEFAULTS);
38+
39+
if (($result & Validator::ERROR_DOCUMENT_VALIDATION) === Validator::ERROR_DOCUMENT_VALIDATION) {
40+
$errors = array_reduce(
41+
$validator->getErrors(),
42+
function ($errors, $error) {
43+
$errors[$error['property']] = $error['message'];
44+
return $errors;
45+
}
46+
);
47+
48+
throw ConfigurationException::fromErrors($errors);
49+
}
50+
51+
52+
return new self(
53+
new MysqlConfig(
54+
host: $data->connection->host,
55+
port: (int) $data->connection->port,
56+
user: $data->connection->user,
57+
password: $data->connection->password,
58+
database: $data->connection->database,
59+
),
60+
StaticTableCondition::alwaysTrue(),
61+
StaticTableCondition::alwaysFalse(),
62+
);
63+
}
64+
65+
public static function fromMySQLConfig(MysqlConfig $config): self
66+
{
67+
return new self($config, StaticTableCondition::alwaysTrue(), StaticTableCondition::alwaysFalse());
68+
}
69+
70+
public function withIncludeCondition(TableCondition $condition): self
71+
{
72+
73+
}
74+
75+
public function withExcludeCondition(TableCondition $condition): self
76+
{
77+
78+
}
79+
}

src/ConfigurationException.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace EcomDev\MySQL2JSONL;
4+
5+
use JsonSchema\Exception\InvalidSchemaException;
6+
use RuntimeException;
7+
use Symfony\Component\Console\Output\OutputInterface;
8+
9+
final class ConfigurationException extends RuntimeException implements \Throwable
10+
{
11+
private function __construct(
12+
private readonly array $errors
13+
) {
14+
parent::__construct('Configuration validation failed');
15+
}
16+
17+
/**
18+
* Creates message from errors
19+
*
20+
* @param string[] $errors
21+
*/
22+
public static function fromErrors(array $errors): self
23+
{
24+
return new self($errors);
25+
}
26+
27+
public function output(OutputInterface $output): void
28+
{
29+
30+
}
31+
}

src/ExportTableFactory.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
namespace EcomDev\MySQL2JSONL;
44

5-
class ExportTableFactory
5+
final class ExportTableFactory
66
{
7+
public function __construct()
8+
{
9+
}
710
}

src/ImportProgressNotifier.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
namespace EcomDev\MySQL2JSONL;
4+
5+
use Symfony\Component\Console\Helper\ProgressBar;
6+
use Symfony\Component\Console\Output\ConsoleOutputInterface;
7+
8+
final class ImportProgressNotifier implements ProgressNotifier
9+
{
10+
/**
11+
* Progress bar per output component
12+
*
13+
* @var ProgressBar[]
14+
*/
15+
private array $progressBars = [];
16+
17+
public function __construct(private readonly ConsoleOutputInterface $output)
18+
{
19+
}
20+
21+
public function start(string $name, int $total): void
22+
{
23+
$progressBar = new ProgressBar($this->output, $total);
24+
$progressBar->setProgressCharacter('🚀');
25+
$progressBar->setBarCharacter('-');
26+
$progressBar->setEmptyBarCharacter(' ');
27+
$this->progressBars[$name] = $progressBar;
28+
29+
}
30+
31+
public function update(string $name, int $current): void
32+
{
33+
$this->progressBars[$name]->advance($current);
34+
}
35+
36+
public function finish(string $name): void
37+
{
38+
$this->progressBars[$name]->finish();
39+
}
40+
}

src/ProgressNotifier.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
namespace EcomDev\MySQL2JSONL;
4+
5+
interface ProgressNotifier
6+
{
7+
public function start(string $name, int $total): void;
8+
9+
public function update(string $name, int $current): void;
10+
11+
public function finish(string $name): void;
12+
}

src/Sql/InsertOnDuplicate.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace EcomDev\MySQL2JSONL\Sql;
44

5-
class InsertOnDuplicate
5+
final class InsertOnDuplicate
66
{
77
public function generate(string $tableName, array $columns, int $rowCount, $onUpdate = []): string
88
{

src/StaticTableCondition.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace EcomDev\MySQL2JSONL;
4+
5+
final readonly class StaticTableCondition implements TableCondition
6+
{
7+
private function __construct(private bool $result)
8+
{
9+
}
10+
11+
public static function alwaysTrue(): self
12+
{
13+
return new self(true);
14+
}
15+
16+
17+
public static function alwaysFalse(): self
18+
{
19+
return new self(false);
20+
}
21+
22+
public function isSatisfiedBy(string $tableName, int $rows): bool
23+
{
24+
return $this->result;
25+
}
26+
27+
public function withCondition(TableCondition $condition): TableCondition
28+
{
29+
return $this;
30+
}
31+
}

src/TableCondition.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace EcomDev\MySQL2JSONL;
4+
5+
interface TableCondition
6+
{
7+
public function isSatisfiedBy(string $tableName, int $rows): bool;
8+
9+
public function withCondition(TableCondition $condition): self;
10+
}

tests/ConfigurationTest.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
namespace EcomDev\MySQL2JSONL;
4+
5+
use Amp\Mysql\MysqlConfig;
6+
use PHPUnit\Framework\Attributes\Test;
7+
use PHPUnit\Framework\TestCase;
8+
9+
class ConfigurationTest extends TestCase
10+
{
11+
#[Test]
12+
public function createsConfigurationWithOnlyHostAndDatabase()
13+
{
14+
$this->assertEquals(
15+
Configuration::fromMysqlConfig(
16+
MysqlConfig::fromAuthority("db", "root", "", "magento")
17+
),
18+
Configuration::fromJSON(
19+
<<<JSON
20+
{
21+
"connection": {
22+
"host": "db",
23+
"database": "magento"
24+
}
25+
}
26+
JSON
27+
)
28+
);
29+
}
30+
31+
#[Test]
32+
public function reportsErrorOnJsonValidation()
33+
{
34+
$this->assertConfigException(
35+
<<<JSON
36+
{
37+
"connection": {
38+
"database": "magento"
39+
}
40+
}
41+
JSON,
42+
ConfigurationException::fromErrors([
43+
'connection.host' => 'The property host is required'
44+
])
45+
);
46+
}
47+
48+
private function assertConfigException(string $json, ConfigurationException $error): void
49+
{
50+
$this->expectException(ConfigurationException::class);
51+
52+
try {
53+
Configuration::fromJSON($json);
54+
} catch (ConfigurationException $e) {
55+
$this->assertEquals($error, $e);
56+
throw $e;
57+
}
58+
}
59+
}

tests/ExportTableTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
class ExportTableTest extends TestCase
99
{
10+
1011
#[Test]
1112
public function itworks()
1213
{

0 commit comments

Comments
 (0)