|
17 | 17 |
|
18 | 18 | namespace Google\Cloud\BigQuery; |
19 | 19 |
|
| 20 | +use InvalidArgumentException; |
| 21 | +use LogicException; |
| 22 | + |
20 | 23 | /** |
21 | 24 | * Represents a configuration for a query job. For more information on the |
22 | 25 | * available settings please see the |
@@ -287,6 +290,82 @@ public function parameters(array $parameters) |
287 | 290 | return $this; |
288 | 291 | } |
289 | 292 |
|
| 293 | + /** |
| 294 | + * Sets the parameter types for positional parameters. |
| 295 | + * Note, that this is of high importance when an empty array can be passed as |
| 296 | + * a positional parameter, as we have no way of guessing the data type of the |
| 297 | + * array contents. |
| 298 | + * |
| 299 | + * ``` |
| 300 | + * $queryStr = 'SELECT * FROM `bigquery-public-data.github_repos.commits` ' . |
| 301 | + * 'WHERE author.time_sec IN UNNEST (?) AND message IN UNNEST (?) AND committer.name = ? LIMIT 10'; |
| 302 | + * |
| 303 | + * $queryJobConfig = $bigQuery->query("") |
| 304 | + * ->parameters([[], ["abc", "def"], "John"]) |
| 305 | + * ->setParamTypes(['INT64']); |
| 306 | + * ``` |
| 307 | + * In the above example, the first array will have a type of INT64 |
| 308 | + * while the next one will have a type of |
| 309 | + * STRING (even though the second array type is not supplied). |
| 310 | + * |
| 311 | + * For named params, we can simply call: |
| 312 | + * ``` |
| 313 | + * $queryJobConfig = $bigQuery->query("") |
| 314 | + * ->parameters(['times' => [], 'messages' => ["abc", "def"]]) |
| 315 | + * ->setParamTypes(['times' => 'INT64']); |
| 316 | + * ``` |
| 317 | + * |
| 318 | + * @param array $userTypes The user supplied types for the positional parameters. |
| 319 | + * This overrides the guessed types that the ValueMapper got from the toParameter |
| 320 | + * method call. |
| 321 | + * |
| 322 | + * @return QueryJobConfiguration |
| 323 | + */ |
| 324 | + public function setParamTypes(array $userTypes) |
| 325 | + { |
| 326 | + $queryParams = $this->config['configuration']['query']['queryParameters'] ?? null; |
| 327 | + $mode = $this->config['configuration']['query']['parameterMode'] ?? null; |
| 328 | + |
| 329 | + if (is_null($queryParams)) { |
| 330 | + throw new LogicException('QueryJobConfiguration::parameters must be called before setParamTypes'); |
| 331 | + } |
| 332 | + |
| 333 | + foreach ($queryParams as $index => &$param) { |
| 334 | + // If the user supplied named params, we use the `name` attribute of the parameter |
| 335 | + // otherwise we just use the index to map. |
| 336 | + $key = $mode === 'named' ? $param['name'] : $index; |
| 337 | + $userType = $this->pluck($key, $userTypes, false); |
| 338 | + |
| 339 | + // If the user hasn't supplied this key in the setParamTypes |
| 340 | + // call, then we just use the $guessedType(no need to override) |
| 341 | + if (is_null($userType)) { |
| 342 | + continue; |
| 343 | + } |
| 344 | + |
| 345 | + $guessedType = $param['parameterType']['type']; |
| 346 | + |
| 347 | + if ($guessedType === $this->mapper::TYPE_ARRAY) { |
| 348 | + $param['parameterType']['arrayType'] = ['type' => $userType]; |
| 349 | + } else { |
| 350 | + $param['parameterType']['type'] = $userType; |
| 351 | + } |
| 352 | + } |
| 353 | + |
| 354 | + // If the $userTypes still contains a value, |
| 355 | + // that means it had an extra key which doesn't exist |
| 356 | + // in the parameters() call |
| 357 | + if (count($userTypes) > 0) { |
| 358 | + throw new InvalidArgumentException(sprintf( |
| 359 | + 'The key \'%s\' doesn\'t exist in the parameters', |
| 360 | + key($userTypes) |
| 361 | + )); |
| 362 | + } |
| 363 | + |
| 364 | + $this->config['configuration']['query']['queryParameters'] = $queryParams; |
| 365 | + |
| 366 | + return $this; |
| 367 | + } |
| 368 | + |
290 | 369 | /** |
291 | 370 | * Sets a priority for the query. |
292 | 371 | * |
|
0 commit comments