Skip to content

Commit 0edd897

Browse files
committed
fix: handling query json result in postgresql/client
1 parent 5d32637 commit 0edd897

File tree

2 files changed

+93
-0
lines changed

2 files changed

+93
-0
lines changed

src/lib/postgresql/src/Flow/PostgreSql/Client/Infrastructure/PgSql/PgSqlClient.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ public function explain(SqlQuery|string $sql, array $parameters = [], ?ExplainCo
121121

122122
$jsonOutput = $this->fetchScalar($explainQuery, $parameters);
123123

124+
if ($jsonOutput instanceof Json) {
125+
$jsonOutput = $jsonOutput->toString();
126+
}
127+
124128
/** @var string $jsonOutput */
125129
return (new ExplainParser())->parse($jsonOutput);
126130
}

src/lib/postgresql/tests/Flow/PostgreSql/Tests/Integration/Client/PgSqlClientTest.php

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,23 @@
1313
data_type_double_precision,
1414
data_type_integer,
1515
delete,
16+
eq,
1617
func,
1718
gt,
1819
insert,
1920
literal,
2021
param,
2122
row_expr,
2223
select,
24+
sql_explain_config,
2325
star,
26+
table,
2427
values_table
2528
};
2629
use function Flow\Types\DSL\type_integer;
2730
use Flow\PostgreSql\Client\Exception\QueryException;
2831
use Flow\PostgreSql\Client\TypedValue;
32+
use Flow\PostgreSql\Explain\Plan\{Plan, PlanNodeType};
2933
use Flow\PostgreSql\QueryBuilder\Schema\{ColumnDefinition, DataType};
3034

3135
final class PgSqlClientTest extends ClientTestCase
@@ -57,6 +61,91 @@ public function test_execute_returns_affected_rows() : void
5761
self::assertSame(2, $affected);
5862
}
5963

64+
public function test_explain_returns_plan_for_select_query() : void
65+
{
66+
$this->client->execute(
67+
create()->temporaryTable('test_explain')
68+
->column(ColumnDefinition::create('id', DataType::integer()))
69+
->column(ColumnDefinition::create('name', DataType::text()))
70+
);
71+
72+
$plan = $this->client->explain(
73+
select(star())->from(table('test_explain'))
74+
);
75+
76+
self::assertInstanceOf(Plan::class, $plan);
77+
self::assertInstanceOf(PlanNodeType::class, $plan->rootNode()->nodeType());
78+
self::assertNotNull($plan->executionTime());
79+
self::assertNotNull($plan->planningTime());
80+
}
81+
82+
public function test_explain_returns_plan_with_parameters() : void
83+
{
84+
$this->client->execute(
85+
create()->temporaryTable('test_explain_params')
86+
->column(ColumnDefinition::create('id', DataType::integer()))
87+
->column(ColumnDefinition::create('name', DataType::text()))
88+
);
89+
90+
$plan = $this->client->explain(
91+
select(star())->from(table('test_explain_params'))->where(eq(col('id'), param(1))),
92+
[42]
93+
);
94+
95+
self::assertInstanceOf(Plan::class, $plan);
96+
self::assertGreaterThanOrEqual(0.0, $plan->totalCost());
97+
}
98+
99+
public function test_explain_returns_plan_with_raw_sql() : void
100+
{
101+
$plan = $this->client->explain(
102+
'SELECT $1::int + $2::int',
103+
[10, 32]
104+
);
105+
106+
self::assertInstanceOf(Plan::class, $plan);
107+
self::assertSame(PlanNodeType::RESULT, $plan->rootNode()->nodeType());
108+
}
109+
110+
public function test_explain_with_custom_config() : void
111+
{
112+
$this->client->execute(
113+
create()->temporaryTable('test_explain_config')
114+
->column(ColumnDefinition::create('id', DataType::integer()))
115+
);
116+
117+
$plan = $this->client->explain(
118+
select(star())->from(table('test_explain_config')),
119+
config: sql_explain_config(
120+
analyze: true,
121+
buffers: true,
122+
timing: true,
123+
costs: true,
124+
)
125+
);
126+
127+
self::assertInstanceOf(Plan::class, $plan);
128+
self::assertNotNull($plan->executionTime());
129+
self::assertGreaterThanOrEqual(0.0, $plan->rootNode()->cost()->totalCost());
130+
}
131+
132+
public function test_explain_without_analyze() : void
133+
{
134+
$plan = $this->client->explain(
135+
select(literal(1)),
136+
config: sql_explain_config(
137+
analyze: false,
138+
buffers: false,
139+
timing: false,
140+
)
141+
);
142+
143+
self::assertInstanceOf(Plan::class, $plan);
144+
self::assertGreaterThanOrEqual(0.0, $plan->totalCost());
145+
self::assertNull($plan->executionTime());
146+
self::assertNull($plan->rootNode()->timing());
147+
}
148+
60149
public function test_fetch_all_into_maps_to_objects() : void
61150
{
62151
$users = $this->client->fetchAllInto(

0 commit comments

Comments
 (0)