Skip to content

Commit c2b78db

Browse files
committed
Add JsonTable and related test
1 parent fb4480b commit c2b78db

File tree

2 files changed

+68
-0
lines changed

2 files changed

+68
-0
lines changed

src/Tools/JsonTable.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
namespace Kir\MySQL\Tools;
4+
5+
use Kir\MySQL\Builder\Internal\Types;
6+
use Kir\MySQL\Common\SpecialTable;
7+
use Kir\MySQL\Database;
8+
use Stringable;
9+
10+
/**
11+
* @phpstan-type TColumn string|array{name: string, type: string, jsonPath: string}
12+
*
13+
* @phpstan-type TColumns list<string|TColumn>
14+
*/
15+
class JsonTable implements SpecialTable {
16+
/**
17+
* @param string $dataExpression The field to get the source json data from
18+
* @param string $jsonPath The json path to the array to be turned into a table
19+
* @param TColumns $columns The projected columns
20+
*/
21+
public function __construct(
22+
private string $dataExpression,
23+
private string $jsonPath,
24+
private $columns
25+
) {}
26+
27+
public function asString(Database $db): string {
28+
return sprintf(
29+
'JSON_TABLE(%s, %s, %s)',
30+
$this->dataExpression,
31+
$this->jsonPath,
32+
$this->translateColumns($db, $this->columns)
33+
);
34+
}
35+
36+
/**
37+
* @param Database $db
38+
* @param TColumns $columns
39+
* @return string
40+
*/
41+
private function translateColumns(Database $db, $columns) {
42+
$result = [];
43+
foreach($columns as $column) {
44+
if(!is_string($column)) {
45+
$column = sprintf('%s %s PATH \'%s\'', $column['name'], $column['type'], $column['jsonPath']);
46+
}
47+
$result[] = $column;
48+
}
49+
return sprintf('COLUMNS(%s)', implode(', ', $result));
50+
}
51+
}

tests/Builder/SelectTest.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Kir\MySQL\Builder\Value\DBOptionalValue;
1313
use Kir\MySQL\Common\DBTestCase;
1414
use Kir\MySQL\Databases\TestDB;
15+
use Kir\MySQL\Tools\JsonTable;
1516
use Kir\MySQL\Tools\VirtualTable;
1617

1718
class SelectTest extends DBTestCase {
@@ -555,4 +556,20 @@ public function testArrayTables(): void {
555556

556557
self::assertEquals("SELECT\n\ta.value\nFROM\n\t(SELECT 1 AS `value`\n\tUNION ALL\n\tSELECT 2 AS `value`\n\tUNION ALL\n\tSELECT 3 AS `value`\n\tUNION ALL\n\tSELECT 4 AS `value`\n\tUNION ALL\n\tSELECT 5 AS `value`\n\tUNION ALL\n\tSELECT 6 AS `value`\n\tUNION ALL\n\tSELECT 7 AS `value`\n\tUNION ALL\n\tSELECT 8 AS `value`\n\tUNION ALL\n\tSELECT 9 AS `value`) a\n", $vt1);
557558
}
559+
560+
public function testJsonTable(): void {
561+
$vt1 = $this->select()
562+
->field('a.id')
563+
->field('b.id', 'json_id')
564+
->field('b.title', 'json_title')
565+
->from('a', 'source_table')
566+
->joinInner('b', new JsonTable('a.json_field', '$.key', [[
567+
'name' => 'id', 'type' => 'INT', 'jsonPath' => '$.id'
568+
], [
569+
'name' => 'title', 'type' => 'VARCHAR(255)', 'jsonPath' => '$.title'
570+
]]), 'a.id = b.id')
571+
->asString();
572+
573+
self::assertEquals("SELECT\n\ta.id,\n\tb.id AS `json_id`,\n\tb.title AS `json_title`\nFROM\n\tsource_table a\nINNER JOIN\n\tJSON_TABLE(a.json_field, $.key, COLUMNS(id INT PATH '$.id', title VARCHAR(255) PATH '$.title')) b ON a.id = b.id\n", $vt1);
574+
}
558575
}

0 commit comments

Comments
 (0)