From 210a28922d6ba017af4c0a72788a2ba5626a1d8d Mon Sep 17 00:00:00 2001 From: hectorhammett Date: Tue, 3 Feb 2026 20:54:40 +0000 Subject: [PATCH 1/5] Stateless query prototype: --- BigQuery/src/BigQueryClient.php | 9 +++ .../src/Connection/ConnectionInterface.php | 6 ++ BigQuery/src/Connection/Rest.php | 5 ++ BigQuery/src/JobConfigurationTrait.php | 60 +++++++++++++++++++ 4 files changed, 80 insertions(+) diff --git a/BigQuery/src/BigQueryClient.php b/BigQuery/src/BigQueryClient.php index df14869c75f3..975134611c8b 100644 --- a/BigQuery/src/BigQueryClient.php +++ b/BigQuery/src/BigQueryClient.php @@ -34,6 +34,8 @@ use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; +use function PHPUnit\Framework\isNull; + /** * Google Cloud BigQuery allows you to create, manage, share and query data. * Find more information at the @@ -417,6 +419,13 @@ public function runQuery(JobConfigurationInterface $query, array $options = []) ], $options); $queryResultsOptions['initialTimeoutMs'] = 10000; + // Check if we can build a query Request + $queryRequest = $query->getQueryRequest(); + + if (!isNull($queryRequest)) { + $this->connection->statelessQuery($queryRequest); + } + $queryResults = $this->startQuery( $query, $options diff --git a/BigQuery/src/Connection/ConnectionInterface.php b/BigQuery/src/Connection/ConnectionInterface.php index 63b14bb83c97..8a1b1ad84614 100644 --- a/BigQuery/src/Connection/ConnectionInterface.php +++ b/BigQuery/src/Connection/ConnectionInterface.php @@ -218,4 +218,10 @@ public function setTableIamPolicy(array $args = []); * @return array */ public function testTableIamPermissions(array $args = []); + + /** + * @param array $args + * @return array + */ + public function statelessQuery(array $args = []); } diff --git a/BigQuery/src/Connection/Rest.php b/BigQuery/src/Connection/Rest.php index 693d154d7bb6..5550df274d77 100644 --- a/BigQuery/src/Connection/Rest.php +++ b/BigQuery/src/Connection/Rest.php @@ -414,6 +414,11 @@ public function setTableIamPolicy(array $args = []) return $this->send('tables', 'setIamPolicy', $args); } + public function statelessQuery(array $args = []) + { + return $this->send('query', $args); + } + /** * @param array $args * @return array diff --git a/BigQuery/src/JobConfigurationTrait.php b/BigQuery/src/JobConfigurationTrait.php index b4775235ef07..07105a95062a 100644 --- a/BigQuery/src/JobConfigurationTrait.php +++ b/BigQuery/src/JobConfigurationTrait.php @@ -27,6 +27,8 @@ trait JobConfigurationTrait { use ArrayTrait; + private const JOB_CREATION_MODE_OPTIONAL = 'JOB_CREATION_OPTIONAL'; + /** * @var string $jobIdPrefix */ @@ -184,6 +186,64 @@ public function toArray() return $this->config; } + /** + * Returns an array that represents a QueryRequest for a stateless query. + * Returns null if one of the conditions are not met for a stateless query. + * + * @return array|null + */ + public function getQueryRequest(): array|null + { + if( + isset($this->config['configuration']['destination']) || + isset($this->config['configuration']['tableDefinitions']) || + isset($this->config['configuration']['createDisposition']) || + isset($this->config['configuration']['writeDisposition']) || + ( + isset($this->config['configuration']['priority']) && + $this->config['configuration']['priority'] !== 'INTERACTIVE' + ) || + isset($this->config['configuration']['useLegacySql']) || + isset($this->config['configuration']['maximumBillingTier']) || + isset($this->config['configuration']['timePartitioning']) || + isset($this->config['configuration']['rangePartitioning']) || + isset($this->config['configuration']['clustering']) || + isset($this->config['configuration']['destinationEncryptionConfiguration']) || + isset($this->config['configuration']['schemaUpdateOptions']) || + isset($this->config['configuration']['jobTimeoutMs']) || + isset($this->config['configuration']['jobId']) + ) { + return null; + } + + if (isset($this->config['configuration']['dryRun']) && $this->config['configuration']['dryRun']) { + return null; + } + + if (isset($this->config['configuration']['job'])) { + return null; + } + + return [ + 'useCacheQuery' => $this->config['configuration']['useCacheQuery'], + 'labels' => $this->config['configuration']['labels'], + 'defaultDataset' => $this->config['configuration']['default'], + 'createSession' => $this->config['configuration']['createSession'], + 'maximumBytesBilled' => $this->config['configuration']['maximumBytesBilled'], + 'timeoutMs' => $this->config['configuration']['timeoutMs'], + 'location' => $this->config['configuration']['timeoutMs'], + 'formatOptions' => [ + 'useInt64Timestamp' => true + ], + 'maxResults' => $this->config['configuration']['maxResults'], + 'maxResults' => $this->config['configuration']['maxResults'], + 'query' => $this->config['configuration']['query'], + 'useLegacySql' => false, + 'requestId' => $this->generateJobId(), + 'jobCreationMode' => self::JOB_CREATION_MODE_OPTIONAL + ]; + } + /** * Generate a Job ID. * From e844b37e279a35de4e842699e01d19b3f87b4d8f Mon Sep 17 00:00:00 2001 From: hectorhammett Date: Tue, 17 Feb 2026 18:21:16 +0000 Subject: [PATCH 2/5] Continue prototype for Stateless query --- BigQuery/src/BigQueryClient.php | 27 ++++- BigQuery/src/Connection/Rest.php | 2 +- BigQuery/src/JobConfigurationTrait.php | 68 ++----------- BigQuery/src/QueryResults.php | 44 +++++++++ BigQuery/src/StatelessJobConfiguration.php | 110 +++++++++++++++++++++ BigQuery/tests/Unit/BigQueryClientTest.php | 30 ++++++ 6 files changed, 219 insertions(+), 62 deletions(-) create mode 100644 BigQuery/src/StatelessJobConfiguration.php diff --git a/BigQuery/src/BigQueryClient.php b/BigQuery/src/BigQueryClient.php index 975134611c8b..e8a4d593d825 100644 --- a/BigQuery/src/BigQueryClient.php +++ b/BigQuery/src/BigQueryClient.php @@ -420,10 +420,31 @@ public function runQuery(JobConfigurationInterface $query, array $options = []) $queryResultsOptions['initialTimeoutMs'] = 10000; // Check if we can build a query Request - $queryRequest = $query->getQueryRequest(); + $queryRequest = StatelessJobConfiguration::getQueryRequest($query); - if (!isNull($queryRequest)) { - $this->connection->statelessQuery($queryRequest); + if (!is_null($queryRequest)) { + $statelessArgs = $queryRequest + $queryResultsOptions + [ + 'projectId' => $this->projectId + ] + $options; + + if (!isset($statelessArgs['timeoutMs'])) { + $statelessArgs['timeoutMs'] = $statelessArgs['initialTimeoutMs']; + } + + $statelessResponse = $this->connection->statelessQuery($statelessArgs); + + $queryResults = QueryResults::fromStatelessQuery( + $this->connection, + $statelessResponse, + $this->mapper, + $queryResultsOptions + $options + ); + + if (!$queryResults->isComplete()) { + $queryResults->waitUntilComplete(); + } + + return $queryResults; } $queryResults = $this->startQuery( diff --git a/BigQuery/src/Connection/Rest.php b/BigQuery/src/Connection/Rest.php index 5550df274d77..90f77d8888a5 100644 --- a/BigQuery/src/Connection/Rest.php +++ b/BigQuery/src/Connection/Rest.php @@ -416,7 +416,7 @@ public function setTableIamPolicy(array $args = []) public function statelessQuery(array $args = []) { - return $this->send('query', $args); + return $this->send('jobs', 'query', $args); } /** diff --git a/BigQuery/src/JobConfigurationTrait.php b/BigQuery/src/JobConfigurationTrait.php index 07105a95062a..5c2de3029c6f 100644 --- a/BigQuery/src/JobConfigurationTrait.php +++ b/BigQuery/src/JobConfigurationTrait.php @@ -39,6 +39,8 @@ trait JobConfigurationTrait */ private $config = []; + private bool $isJobIdGenerated = false; + /** * Sets shared job configuration properties. * @@ -64,6 +66,9 @@ public function jobConfigurationProperties( if (!isset($this->config['jobReference']['jobId'])) { $this->config['jobReference']['jobId'] = $this->generateJobId(); + + // Used for the Stateless query logic + $this->isJobIdGenerated = true; } } @@ -167,6 +172,11 @@ public function location($location) return $this; } + public function isJobIdGenerated(): bool + { + return $this->isJobIdGenerated; + } + /** * Returns the job config as an array. * @@ -186,64 +196,6 @@ public function toArray() return $this->config; } - /** - * Returns an array that represents a QueryRequest for a stateless query. - * Returns null if one of the conditions are not met for a stateless query. - * - * @return array|null - */ - public function getQueryRequest(): array|null - { - if( - isset($this->config['configuration']['destination']) || - isset($this->config['configuration']['tableDefinitions']) || - isset($this->config['configuration']['createDisposition']) || - isset($this->config['configuration']['writeDisposition']) || - ( - isset($this->config['configuration']['priority']) && - $this->config['configuration']['priority'] !== 'INTERACTIVE' - ) || - isset($this->config['configuration']['useLegacySql']) || - isset($this->config['configuration']['maximumBillingTier']) || - isset($this->config['configuration']['timePartitioning']) || - isset($this->config['configuration']['rangePartitioning']) || - isset($this->config['configuration']['clustering']) || - isset($this->config['configuration']['destinationEncryptionConfiguration']) || - isset($this->config['configuration']['schemaUpdateOptions']) || - isset($this->config['configuration']['jobTimeoutMs']) || - isset($this->config['configuration']['jobId']) - ) { - return null; - } - - if (isset($this->config['configuration']['dryRun']) && $this->config['configuration']['dryRun']) { - return null; - } - - if (isset($this->config['configuration']['job'])) { - return null; - } - - return [ - 'useCacheQuery' => $this->config['configuration']['useCacheQuery'], - 'labels' => $this->config['configuration']['labels'], - 'defaultDataset' => $this->config['configuration']['default'], - 'createSession' => $this->config['configuration']['createSession'], - 'maximumBytesBilled' => $this->config['configuration']['maximumBytesBilled'], - 'timeoutMs' => $this->config['configuration']['timeoutMs'], - 'location' => $this->config['configuration']['timeoutMs'], - 'formatOptions' => [ - 'useInt64Timestamp' => true - ], - 'maxResults' => $this->config['configuration']['maxResults'], - 'maxResults' => $this->config['configuration']['maxResults'], - 'query' => $this->config['configuration']['query'], - 'useLegacySql' => false, - 'requestId' => $this->generateJobId(), - 'jobCreationMode' => self::JOB_CREATION_MODE_OPTIONAL - ]; - } - /** * Generate a Job ID. * diff --git a/BigQuery/src/QueryResults.php b/BigQuery/src/QueryResults.php index 4da695acfe59..fd2b007a3b45 100644 --- a/BigQuery/src/QueryResults.php +++ b/BigQuery/src/QueryResults.php @@ -371,4 +371,48 @@ public function getIterator() { return $this->rows(); } + + /** + * @param ConnectionInterface $connection Represents a connection to + * BigQuery. This object is created by BigQueryClient, + * and should not be instantiated outside of this client. + * @param string $jobId The job's ID. + * @param string $projectId The project's ID. + * @param array $info The query result's metadata. + * @param ValueMapper $mapper Maps values between PHP and BigQuery. + * @param Job $job The job from which the query results originated. + * @param array $queryResultsOptions Default options to be used for calls to + * get query results. See + * [documentation](https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/getQueryResults#query-parameters) + * for available options. + */ + public static function fromStatelessQuery( + ConnectionInterface $connection, + array $statelessResponse, + ValueMapper $mapper, + array $queryResultsOptions = [] + ): QueryResults { + $jobId = $statelessResponse['jobReference']['jobId']; + $projectId = $statelessResponse['jobReference']['projectId']; + $location = $statelessResponse['jobReference']['location'] ?? null; + + $job = new Job( + $connection, + $jobId, + $projectId, + $mapper, + [], + $location + ); + + return new QueryResults( + $connection, + $jobId, + $projectId, + $statelessResponse, + $mapper, + $job, + $queryResultsOptions + ); + } } diff --git a/BigQuery/src/StatelessJobConfiguration.php b/BigQuery/src/StatelessJobConfiguration.php new file mode 100644 index 000000000000..a8764e0c8f9f --- /dev/null +++ b/BigQuery/src/StatelessJobConfiguration.php @@ -0,0 +1,110 @@ +|null + */ + public static function getQueryRequest(JobConfigurationInterface $jobConfiguration): array|null + { + $config = $jobConfiguration->toArray(); + $queryConfig = $config['configuration']['query']; + + if ( + isset($queryConfig['destinationTable']) || + isset($queryConfig['tableDefinitions']) || + isset($queryConfig['createDisposition']) || + isset($queryConfig['writeDisposition']) || + ( + isset($queryConfig['priority']) && + $queryConfig['priority'] !== 'INTERACTIVE' + ) || + (isset($queryConfig['useLegacySql']) && $queryConfig['useLegacySql']) || + isset($queryConfig['maximumBillingTier']) || + isset($queryConfig['timePartitioning']) || + isset($queryConfig['rangePartitioning']) || + isset($queryConfig['clustering']) || + isset($queryConfig['destinationEncryptionConfiguration']) || + isset($queryConfig['schemaUpdateOptions']) || + isset($queryConfig['jobTimeoutMs']) || + isset($queryConfig['jobId']) + ) { + return null; + } + + if (isset($config['configuration']['dryRun']) && $config['configuration']['dryRun']) { + return null; + } + + if ( + isset($config['jobReference']['jobId']) && + method_exists($jobConfiguration, 'isJobIdGenerated') && + !$jobConfiguration->isJobIdGenerated() + ) { + return null; + } + + return [ + 'query' => $queryConfig['query'], + 'maxResults' => $queryConfig['maxResults'] ?? null, + 'defaultDataset' => $queryConfig['defaultDataset'] ?? null, + 'timeoutMs' => $queryConfig['timeoutMs'] ?? null, + 'useQueryCache' => $queryConfig['useQueryCache'] ?? null, + 'useLegacySql' => false, + 'queryParameters' => $queryConfig['queryParameters'] ?? null, + 'parameterMode' => $queryConfig['parameterMode'] ?? null, + 'labels' => $config['configuration']['labels'] ?? null, + 'createSession' => $queryConfig['createSession'] ?? null, + 'maximumBytesBilled' => $queryConfig['maximumBytesBilled'] ?? null, + 'location' => $config['jobReference']['location'] ?? null, + 'formatOptions' => [ + 'useInt64Timestamp' => true + ], + 'requestId' => self::generateJobId(), + 'jobCreationMode' => self::JOB_CREATION_MODE_OPTIONAL + ]; + } + + /** + * Generate a Job ID. + * + * @return string + */ + protected static function generateJobId() + { + return Uuid::uuid4()->toString(); + } +} diff --git a/BigQuery/tests/Unit/BigQueryClientTest.php b/BigQuery/tests/Unit/BigQueryClientTest.php index cb36f6f58c50..ff33b5c26364 100644 --- a/BigQuery/tests/Unit/BigQueryClientTest.php +++ b/BigQuery/tests/Unit/BigQueryClientTest.php @@ -157,6 +157,36 @@ public function testRunsQuery() $this->assertEquals(self::JOB_ID, $queryResults->identity()['jobId']); } + public function testRunQueryStateless() + { + $client = $this->getClient(); + $query = $client->query(self::QUERY_STRING); + + $this->connection->statelessQuery(Argument::allOf( + Argument::withEntry('projectId', self::PROJECT_ID), + Argument::withEntry('query', self::QUERY_STRING), + Argument::withEntry('jobCreationMode', 'JOB_CREATION_OPTIONAL') + )) + ->willReturn([ + 'jobReference' => [ + 'jobId' => self::JOB_ID, + 'projectId' => self::PROJECT_ID, + 'location' => self::LOCATION + ], + 'jobComplete' => true, + 'schema' => ['fields' => []], + 'rows' => [] + ]) + ->shouldBeCalledTimes(1); + + $client->___setProperty('connection', $this->connection->reveal()); + $queryResults = $client->runQuery($query); + + $this->assertInstanceOf(QueryResults::class, $queryResults); + $this->assertEquals(self::JOB_ID, $queryResults->identity()['jobId']); + $this->assertTrue($queryResults->isComplete()); + } + public function testRunsQueryWithRetry() { $client = $this->getClient(); From 71174bd450309678e13531e263f61c3f9f6b2c7d Mon Sep 17 00:00:00 2001 From: hectorhammett Date: Fri, 20 Feb 2026 22:21:09 +0000 Subject: [PATCH 3/5] Functioning version of Stateless query --- BigQuery/src/BigQueryClient.php | 13 ++++++++++++- BigQuery/src/Connection/ConnectionInterface.php | 6 ------ BigQuery/src/QueryResults.php | 17 +++++++++++------ BigQuery/src/StatelessJobConfiguration.php | 8 ++++---- BigQuery/tests/Unit/BigQueryClientTest.php | 2 +- 5 files changed, 28 insertions(+), 18 deletions(-) diff --git a/BigQuery/src/BigQueryClient.php b/BigQuery/src/BigQueryClient.php index e8a4d593d825..e2be642e15c2 100644 --- a/BigQuery/src/BigQueryClient.php +++ b/BigQuery/src/BigQueryClient.php @@ -423,6 +423,16 @@ public function runQuery(JobConfigurationInterface $query, array $options = []) $queryRequest = StatelessJobConfiguration::getQueryRequest($query); if (!is_null($queryRequest)) { + if (isset($queryResultsOptions['formatOptions.useInt64Timestamp'])) { + $useInt64 = $this->pluck('formatOptions.useInt64Timestamp', $queryResultsOptions, false); + + if (!isset($queryResultsOptions['formatOptions']) || !is_array($queryResultsOptions['formatOptions'])) { + $queryResultsOptions['formatOptions'] = []; + } + + $queryResultsOptions['formatOptions']['useInt64Timestamp'] = $useInt64; + } + $statelessArgs = $queryRequest + $queryResultsOptions + [ 'projectId' => $this->projectId ] + $options; @@ -431,10 +441,11 @@ public function runQuery(JobConfigurationInterface $query, array $options = []) $statelessArgs['timeoutMs'] = $statelessArgs['initialTimeoutMs']; } - $statelessResponse = $this->connection->statelessQuery($statelessArgs); + $statelessResponse = $this->connection->query($statelessArgs); $queryResults = QueryResults::fromStatelessQuery( $this->connection, + $this->projectId, $statelessResponse, $this->mapper, $queryResultsOptions + $options diff --git a/BigQuery/src/Connection/ConnectionInterface.php b/BigQuery/src/Connection/ConnectionInterface.php index 8a1b1ad84614..63b14bb83c97 100644 --- a/BigQuery/src/Connection/ConnectionInterface.php +++ b/BigQuery/src/Connection/ConnectionInterface.php @@ -218,10 +218,4 @@ public function setTableIamPolicy(array $args = []); * @return array */ public function testTableIamPermissions(array $args = []); - - /** - * @param array $args - * @return array - */ - public function statelessQuery(array $args = []); } diff --git a/BigQuery/src/QueryResults.php b/BigQuery/src/QueryResults.php index fd2b007a3b45..ed4d9d87fdd4 100644 --- a/BigQuery/src/QueryResults.php +++ b/BigQuery/src/QueryResults.php @@ -292,6 +292,10 @@ public function info() */ public function reload(array $options = []) { + if (!isset($this->info['jobReference'])) { + return $this->info; + } + return $this->info = $this->connection->getQueryResults( $options + $this->identity ); @@ -376,11 +380,9 @@ public function getIterator() * @param ConnectionInterface $connection Represents a connection to * BigQuery. This object is created by BigQueryClient, * and should not be instantiated outside of this client. - * @param string $jobId The job's ID. * @param string $projectId The project's ID. - * @param array $info The query result's metadata. + * @param array $statelessResponse The query result's metadata. * @param ValueMapper $mapper Maps values between PHP and BigQuery. - * @param Job $job The job from which the query results originated. * @param array $queryResultsOptions Default options to be used for calls to * get query results. See * [documentation](https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/getQueryResults#query-parameters) @@ -388,13 +390,16 @@ public function getIterator() */ public static function fromStatelessQuery( ConnectionInterface $connection, + string $projectId, array $statelessResponse, ValueMapper $mapper, array $queryResultsOptions = [] ): QueryResults { - $jobId = $statelessResponse['jobReference']['jobId']; - $projectId = $statelessResponse['jobReference']['projectId']; - $location = $statelessResponse['jobReference']['location'] ?? null; + $jobReference = $statelessResponse['jobReference'] ?? []; + // If jobId is null, it was a stateless request that completed in one request. + $jobId = $jobReference['jobId'] ?? null; + $projectId = $jobReference['projectId'] ?? $projectId; + $location = $jobReference['location'] ?? ($statelessResponse['location'] ?? null); $job = new Job( $connection, diff --git a/BigQuery/src/StatelessJobConfiguration.php b/BigQuery/src/StatelessJobConfiguration.php index a8764e0c8f9f..b46b8a56dc96 100644 --- a/BigQuery/src/StatelessJobConfiguration.php +++ b/BigQuery/src/StatelessJobConfiguration.php @@ -69,6 +69,9 @@ public static function getQueryRequest(JobConfigurationInterface $jobConfigurati return null; } + // Creating a jobConfiguration from the library sets the JobId always meaning we do not have a way + // to determine if this jobId was set by the user or our library. + // We check if this was autogenerated to circumvent this issue. if ( isset($config['jobReference']['jobId']) && method_exists($jobConfiguration, 'isJobIdGenerated') && @@ -90,10 +93,7 @@ public static function getQueryRequest(JobConfigurationInterface $jobConfigurati 'createSession' => $queryConfig['createSession'] ?? null, 'maximumBytesBilled' => $queryConfig['maximumBytesBilled'] ?? null, 'location' => $config['jobReference']['location'] ?? null, - 'formatOptions' => [ - 'useInt64Timestamp' => true - ], - 'requestId' => self::generateJobId(), + 'requestId' => $config['jobReference']['jobId'], 'jobCreationMode' => self::JOB_CREATION_MODE_OPTIONAL ]; } diff --git a/BigQuery/tests/Unit/BigQueryClientTest.php b/BigQuery/tests/Unit/BigQueryClientTest.php index ff33b5c26364..f7f7f5f5a0d8 100644 --- a/BigQuery/tests/Unit/BigQueryClientTest.php +++ b/BigQuery/tests/Unit/BigQueryClientTest.php @@ -162,7 +162,7 @@ public function testRunQueryStateless() $client = $this->getClient(); $query = $client->query(self::QUERY_STRING); - $this->connection->statelessQuery(Argument::allOf( + $this->connection->query(Argument::allOf( Argument::withEntry('projectId', self::PROJECT_ID), Argument::withEntry('query', self::QUERY_STRING), Argument::withEntry('jobCreationMode', 'JOB_CREATION_OPTIONAL') From 5ef86ea61744b8672812ea1a610a6af2526e62a4 Mon Sep 17 00:00:00 2001 From: hectorhammett Date: Mon, 23 Feb 2026 22:58:27 +0000 Subject: [PATCH 4/5] Change location of constant for job creation mode --- BigQuery/src/JobConfigurationTrait.php | 2 -- BigQuery/src/StatelessJobConfiguration.php | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/BigQuery/src/JobConfigurationTrait.php b/BigQuery/src/JobConfigurationTrait.php index 5c2de3029c6f..14fa99028899 100644 --- a/BigQuery/src/JobConfigurationTrait.php +++ b/BigQuery/src/JobConfigurationTrait.php @@ -27,8 +27,6 @@ trait JobConfigurationTrait { use ArrayTrait; - private const JOB_CREATION_MODE_OPTIONAL = 'JOB_CREATION_OPTIONAL'; - /** * @var string $jobIdPrefix */ diff --git a/BigQuery/src/StatelessJobConfiguration.php b/BigQuery/src/StatelessJobConfiguration.php index b46b8a56dc96..38c7da3f50dd 100644 --- a/BigQuery/src/StatelessJobConfiguration.php +++ b/BigQuery/src/StatelessJobConfiguration.php @@ -31,6 +31,7 @@ class StatelessJobConfiguration implements JobConfigurationInterface { use JobConfigurationTrait; + const JOB_CREATION_MODE_OPTIONAL = 'JOB_CREATION_OPTIONAL'; /** * Returns an array that represents a QueryRequest for a stateless query. From 8fcd59e10eace002f43698d54d7916d60ac68bee Mon Sep 17 00:00:00 2001 From: hectorhammett Date: Thu, 26 Feb 2026 21:21:42 +0000 Subject: [PATCH 5/5] Fix snippet tests --- BigQuery/tests/Snippet/BigQueryClientTest.php | 106 ++++++++++-------- 1 file changed, 59 insertions(+), 47 deletions(-) diff --git a/BigQuery/tests/Snippet/BigQueryClientTest.php b/BigQuery/tests/Snippet/BigQueryClientTest.php index 06f189299285..a6cff07dd077 100644 --- a/BigQuery/tests/Snippet/BigQueryClientTest.php +++ b/BigQuery/tests/Snippet/BigQueryClientTest.php @@ -154,7 +154,7 @@ public function testRunQuery() { $snippet = $this->snippetFromMethod(BigQueryClient::class, 'runQuery'); $snippet->addLocal('bigQuery', $this->client); - $this->connection->insertJob(Argument::any()) + $this->connection->query(Argument::any()) ->shouldBeCalled() ->willReturn([ 'jobComplete' => false, @@ -179,36 +179,42 @@ public function testRunQueryWithNamedParameters() $expectedQuery = 'SELECT commit FROM `bigquery-public-data.github_repos.commits`' . 'WHERE author.date < @date AND message = @message LIMIT 100'; $this->connection - ->insertJob([ - 'projectId' => self::PROJECT_ID, - 'jobReference' => ['projectId' => self::PROJECT_ID, 'jobId' => self::JOB_ID], - 'configuration' => [ - 'query' => [ - 'parameterMode' => 'named', - 'useLegacySql' => false, - 'queryParameters' => [ - [ - 'name' => 'date', - 'parameterType' => [ - 'type' => 'TIMESTAMP' - ], - 'parameterValue' => [ - 'value' => '1980-01-01 12:15:00.000000+00:00' - ] - ], - [ - 'name' => 'message', - 'parameterType' => [ - 'type' => 'STRING' - ], - 'parameterValue' => [ - 'value' => 'A commit message.' - ] - ] + ->query([ + "query"=> "SELECT commit FROM `bigquery-public-data.github_repos.commits`WHERE author.date < @date AND message = @message LIMIT 100", + "maxResults"=> null, + "defaultDataset"=> null, + "timeoutMs"=> 10000, + "useQueryCache"=> null, + "useLegacySql"=> false, + "queryParameters"=> [ + [ + "parameterType"=> [ + "type"=> "TIMESTAMP" + ], + "parameterValue"=> [ + "value"=> "1980-01-01 12:15:00.000000+00:00" + ], + "name"=> "date" + ], + [ + "parameterType"=> [ + "type"=> "STRING" + ], + "parameterValue"=> [ + "value"=> "A commit message." ], - 'query' => $expectedQuery + "name"=> "message" ] - ] + ], + "parameterMode"=> "named", + "labels"=> null, + "createSession"=> null, + "maximumBytesBilled"=> null, + "location"=> null, + "requestId"=> "myJobId", + "jobCreationMode"=> "JOB_CREATION_OPTIONAL", + "initialTimeoutMs"=> 10000, + "projectId"=> "my-awesome-project" ]) ->shouldBeCalledTimes(1) ->willReturn([ @@ -233,26 +239,32 @@ public function testRunQueryWithPositionalParameters() $snippet->addLocal('bigQuery', $this->client); $expectedQuery = 'SELECT commit FROM `bigquery-public-data.github_repos.commits` WHERE message = ? LIMIT 100'; $this->connection - ->insertJob([ - 'projectId' => self::PROJECT_ID, - 'jobReference' => ['projectId' => self::PROJECT_ID, 'jobId' => self::JOB_ID], - 'configuration' => [ - 'query' => [ - 'parameterMode' => 'positional', - 'useLegacySql' => false, - 'queryParameters' => [ - [ - 'parameterType' => [ - 'type' => 'STRING' - ], - 'parameterValue' => [ - 'value' => 'A commit message.' - ] - ] + ->query([ + "query"=> "SELECT commit FROM `bigquery-public-data.github_repos.commits` WHERE message = ? LIMIT 100", + "maxResults"=> null, + "defaultDataset"=> null, + "timeoutMs"=> 10000, + "useQueryCache"=> null, + "useLegacySql"=> false, + "queryParameters"=> [ + [ + "parameterType"=> [ + "type"=> "STRING" ], - 'query' => $expectedQuery + "parameterValue"=> [ + "value"=> "A commit message." + ] ] - ] + ], + "parameterMode"=> "positional", + "labels"=> null, + "createSession"=> null, + "maximumBytesBilled"=> null, + "location"=> null, + "requestId"=> "myJobId", + "jobCreationMode"=> "JOB_CREATION_OPTIONAL", + "initialTimeoutMs"=> 10000, + "projectId"=> "my-awesome-project" ]) ->shouldBeCalledTimes(1) ->willReturn([