4
4
5
5
use Exception ;
6
6
use GuzzleHttp \Client ;
7
- use GuzzleHttp \Exception \GuzzleException ;
8
- use GuzzleHttp \Exception \RequestException ;
9
- use Neo4j \QueryAPI \Objects \ChildQueryPlan ;
10
- use Neo4j \QueryAPI \Objects \QueryArguments ;
7
+ use Neo4j \QueryAPI \Objects \ProfiledQueryPlanArguments ;
11
8
use Neo4j \QueryAPI \Objects \ResultCounters ;
12
9
use Neo4j \QueryAPI \Objects \ProfiledQueryPlan ;
13
10
use Neo4j \QueryAPI \Results \ResultRow ;
@@ -26,18 +23,9 @@ public function __construct(Client $client)
26
23
{
27
24
$ this ->client = $ client ;
28
25
}
29
- /**
30
- * @api
31
- */
26
+
32
27
public static function login (string $ address , string $ username , string $ password ): self
33
28
{
34
- if (empty ($ address )) {
35
- throw new RuntimeException ('Address cannot be empty ' );
36
- }
37
- if (empty ($ username ) || empty ($ password )) {
38
- throw new RuntimeException ('Missing username or password ' );
39
- }
40
-
41
29
$ client = new Client ([
42
30
'base_uri ' => rtrim ($ address , '/ ' ),
43
31
'timeout ' => 10.0 ,
@@ -54,7 +42,6 @@ public static function login(string $address, string $username, string $password
54
42
/**
55
43
* @throws Neo4jException
56
44
* @throws RequestExceptionInterface
57
- * @api
58
45
*/
59
46
public function run (string $ cypher , array $ parameters = [], string $ database = 'neo4j ' , Bookmarks $ bookmark = null ): ResultSet
60
47
{
@@ -69,15 +56,21 @@ public function run(string $cypher, array $parameters = [], string $database = '
69
56
$ payload ['bookmarks ' ] = $ bookmark ->getBookmarks ();
70
57
}
71
58
72
- $ response = $ this ->client ->post ( '/db/ ' . $ database . '/query/v2 ' , [
59
+ $ response = $ this ->client ->request ( ' POST ' , '/db/ ' . $ database . '/query/v2 ' , [
73
60
'json ' => $ payload ,
74
61
]);
75
62
76
- $ data = json_decode ($ response ->getBody ()->getContents (), true );
63
+ $ contents = $ response ->getBody ()->getContents ();
64
+ $ data = json_decode ($ contents , true , flags: JSON_THROW_ON_ERROR );
77
65
$ ogm = new OGM ();
78
66
79
- $ keys = $ data ['data ' ]['fields ' ];
80
- $ values = $ data ['data ' ]['values ' ];
67
+ $ keys = $ data ['data ' ]['fields ' ] ?? [];
68
+ $ values = $ data ['data ' ]['values ' ] ?? []; // Ensure $values is an array
69
+
70
+ if (!is_array ($ values )) {
71
+ throw new RuntimeException ('Unexpected response format: values is not an array. ' );
72
+ }
73
+
81
74
$ rows = array_map (function ($ resultRow ) use ($ ogm , $ keys ) {
82
75
$ data = [];
83
76
foreach ($ keys as $ index => $ key ) {
@@ -86,10 +79,7 @@ public function run(string $cypher, array $parameters = [], string $database = '
86
79
}
87
80
return new ResultRow ($ data );
88
81
}, $ values );
89
-
90
- if (isset ($ data ['profiledQueryPlan ' ])) {
91
- $ profile = $ this ->createProfileData ($ data ['profiledQueryPlan ' ]);
92
- }
82
+ $ profile = isset ($ data ['profiledQueryPlan ' ]) ? $ this ->createProfileData ($ data ['profiledQueryPlan ' ]) : null ;
93
83
94
84
$ resultCounters = new ResultCounters (
95
85
containsUpdates: $ data ['counters ' ]['containsUpdates ' ] ?? false ,
@@ -119,19 +109,14 @@ public function run(string $cypher, array $parameters = [], string $database = '
119
109
if ($ response !== null ) {
120
110
$ contents = $ response ->getBody ()->getContents ();
121
111
$ errorResponse = json_decode ($ contents , true );
122
-
123
112
throw Neo4jException::fromNeo4jResponse ($ errorResponse , $ e );
124
113
}
114
+ throw $ e ;
125
115
}
126
- throw new RuntimeException ('Error executing query: ' . $ e ->getMessage (), 0 , $ e );
127
116
}
128
117
129
- /**
130
- * @api
131
- */
132
118
public function beginTransaction (string $ database = 'neo4j ' ): Transaction
133
119
{
134
- unset($ database );
135
120
$ response = $ this ->client ->post ("/db/neo4j/query/v2/tx " );
136
121
137
122
$ clusterAffinity = $ response ->getHeaderLine ('neo4j-cluster-affinity ' );
@@ -143,27 +128,43 @@ public function beginTransaction(string $database = 'neo4j'): Transaction
143
128
144
129
private function createProfileData (array $ data ): ProfiledQueryPlan
145
130
{
131
+ $ ogm = new OGM ();
132
+
133
+ // Map arguments using OGM
146
134
$ arguments = $ data ['arguments ' ];
135
+ $ mappedArguments = [];
136
+ foreach ($ arguments as $ key => $ value ) {
137
+ if (is_array ($ value ) && array_key_exists ('$type ' , $ value ) && array_key_exists ('_value ' , $ value )) {
138
+ $ mappedArguments [$ key ] = $ ogm ->map ($ value );
139
+ } else {
140
+ $ mappedArguments [$ key ] = $ value ;
141
+ }
142
+ }
147
143
148
- $ queryArguments = new QueryArguments (
149
- $ arguments ['globalMemory ' ] ?? 0 ,
150
- $ arguments ['plannerImpl ' ] ?? '' ,
151
- $ arguments ['memory ' ] ?? 0 ,
152
- $ arguments ['stringRepresentation ' ] ?? '' ,
153
- is_string ($ arguments ['runtime ' ] ?? '' ) ? $ arguments ['runtime ' ] : json_encode ($ arguments ['runtime ' ]),
154
- $ arguments ['runtimeImpl ' ] ?? '' ,
155
- $ arguments ['dbHits ' ] ?? 0 ,
156
- $ arguments ['batchSize ' ] ?? 0 ,
157
- $ arguments ['details ' ] ?? '' ,
158
- $ arguments ['plannerVersion ' ] ?? '' ,
159
- $ arguments ['pipelineInfo ' ] ?? '' ,
160
- $ arguments ['runtimeVersion ' ] ?? '' ,
161
- $ arguments ['id ' ] ?? 0 ,
162
- $ arguments ['estimatedRows ' ] ?? 0.0 ,
163
- is_string ($ arguments ['planner ' ] ?? '' ) ? $ arguments ['planner ' ] : json_encode ($ arguments ['planner ' ]),
164
- $ arguments ['rows ' ] ?? 0
144
+ $ queryArguments = new ProfiledQueryPlanArguments (
145
+ globalMemory: $ mappedArguments ['GlobalMemory ' ] ?? null ,
146
+ plannerImpl: $ mappedArguments ['planner-impl ' ] ?? null ,
147
+ memory: $ mappedArguments ['Memory ' ] ?? null ,
148
+ stringRepresentation: $ mappedArguments ['string-representation ' ] ?? null ,
149
+ runtime: $ mappedArguments ['runtime ' ] ?? null ,
150
+ time: $ mappedArguments ['Time ' ] ?? null ,
151
+ pageCacheMisses: $ mappedArguments ['PageCacheMisses ' ] ?? null ,
152
+ pageCacheHits: $ mappedArguments ['PageCacheHits ' ] ?? null ,
153
+ runtimeImpl: $ mappedArguments ['runtime-impl ' ] ?? null ,
154
+ version: $ mappedArguments ['version ' ] ?? null ,
155
+ dbHits: $ mappedArguments ['DbHits ' ] ?? null ,
156
+ batchSize: $ mappedArguments ['batch-size ' ] ?? null ,
157
+ details: $ mappedArguments ['Details ' ] ?? null ,
158
+ plannerVersion: $ mappedArguments ['planner-version ' ] ?? null ,
159
+ pipelineInfo: $ mappedArguments ['PipelineInfo ' ] ?? null ,
160
+ runtimeVersion: $ mappedArguments ['runtime-version ' ] ?? null ,
161
+ id: $ mappedArguments ['Id ' ] ?? null ,
162
+ estimatedRows: $ mappedArguments ['EstimatedRows ' ] ?? null ,
163
+ planner: $ mappedArguments ['planner ' ] ?? null ,
164
+ rows: $ mappedArguments ['Rows ' ?? null ]
165
165
);
166
166
167
+ $ identifiers = $ data ['identifiers ' ] ?? [];
167
168
$ profiledQueryPlan = new ProfiledQueryPlan (
168
169
$ data ['dbHits ' ],
169
170
$ data ['records ' ],
@@ -173,17 +174,17 @@ private function createProfileData(array $data): ProfiledQueryPlan
173
174
$ data ['pageCacheHitRatio ' ],
174
175
$ data ['time ' ],
175
176
$ data ['operatorType ' ],
176
- $ queryArguments
177
+ $ queryArguments ,
178
+ children: [],
179
+ identifiers: $ identifiers
177
180
);
178
-
181
+ // Process children recursively
179
182
foreach ($ data ['children ' ] as $ child ) {
180
183
$ childQueryPlan = $ this ->createProfileData ($ child );
181
-
182
184
$ profiledQueryPlan ->addChild ($ childQueryPlan );
183
185
}
184
186
185
187
return $ profiledQueryPlan ;
186
188
}
187
189
188
-
189
190
}
0 commit comments