@@ -37,10 +37,13 @@ class QueryJobConfiguration implements JobConfigurationInterface
3737{
3838 use JobConfigurationTrait;
3939
40+ private const JOB_CREATION_MODE_OPTIONAL = 'JOB_CREATION_OPTIONAL ' ;
41+
4042 /**
4143 * @var ValueMapper Maps values between PHP and BigQuery.
4244 */
4345 private $ mapper ;
46+ private bool $ isJobIdGenerated = false ;
4447
4548 /**
4649 * @param ValueMapper $mapper Maps values between PHP and BigQuery.
@@ -58,6 +61,13 @@ public function __construct(
5861 $ this ->mapper = $ mapper ;
5962 $ this ->jobConfigurationProperties ($ projectId , $ config , $ location );
6063
64+ if (!isset ($ config ['jobReference ' ]['jobId ' ])) {
65+ // If the user did not submit a jobId to the configuration array, the library will create a JobId before
66+ // the request is sent. This is used to keep track if it is the user who set the JobId or the library
67+ /// for stateless queries.
68+ $ this ->isJobIdGenerated = true ;
69+ }
70+
6171 if (!isset ($ this ->config ['configuration ' ]['query ' ]['useLegacySql ' ])) {
6272 $ this ->config ['configuration ' ]['query ' ]['useLegacySql ' ] = false ;
6373 }
@@ -593,4 +603,89 @@ public function writeDisposition($writeDisposition)
593603
594604 return $ this ;
595605 }
606+
607+ /**
608+ * Returns true if the current configuration is compatible with the stateless query API.
609+ * False if not
610+ *
611+ * @internal
612+ * @return bool
613+ */
614+ public function isStateless (): bool
615+ {
616+ $ config = $ this ->config ;
617+ $ queryConfig = $ config ['configuration ' ]['query ' ];
618+
619+ if (isset ($ queryConfig ['destinationTable ' ]) ||
620+ isset ($ queryConfig ['tableDefinitions ' ]) ||
621+ isset ($ queryConfig ['createDisposition ' ]) ||
622+ isset ($ queryConfig ['writeDisposition ' ]) ||
623+ ($ queryConfig ['useLegacySql ' ] ?? false ) ||
624+ isset ($ queryConfig ['maximumBillingTier ' ]) ||
625+ isset ($ queryConfig ['timePartitioning ' ]) ||
626+ isset ($ queryConfig ['rangePartitioning ' ]) ||
627+ isset ($ queryConfig ['clustering ' ]) ||
628+ isset ($ queryConfig ['destinationEncryptionConfiguration ' ]) ||
629+ isset ($ queryConfig ['schemaUpdateOptions ' ]) ||
630+ isset ($ queryConfig ['jobTimeoutMs ' ])
631+ ) {
632+ return false ;
633+ }
634+
635+ if (isset ($ queryConfig ['priority ' ]) && $ queryConfig ['priority ' ] !== 'INTERACTIVE ' ) {
636+ return false ;
637+ }
638+
639+ if ($ config ['configuration ' ]['dryRun ' ] ?? false ) {
640+ return false ;
641+ }
642+
643+ // Creating a jobConfiguration from the library sets the JobId always meaning we do not have a way
644+ // to determine if this jobId was set by the user or our library.
645+ // We check if this was autogenerated to circumvent this issue.
646+ if (isset ($ config ['jobReference ' ]['jobId ' ]) && !$ this ->isJobIdGenerated ()) {
647+ return false ;
648+ }
649+
650+ return true ;
651+ }
652+
653+ /**
654+ * Returns an array representation of a QueryRequest:
655+ * [QueryRequest](https://docs.cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#QueryRequest)
656+ *
657+ * @return array
658+ */
659+ public function toQueryRequest (): array
660+ {
661+ $ config = $ this ->config ;
662+ $ queryConfig = $ config ['configuration ' ]['query ' ];
663+
664+ return [
665+ 'query ' => $ queryConfig ['query ' ],
666+ 'maxResults ' => $ queryConfig ['maxResults ' ] ?? null ,
667+ 'defaultDataset ' => $ queryConfig ['defaultDataset ' ] ?? null ,
668+ 'timeoutMs ' => $ queryConfig ['timeoutMs ' ] ?? null ,
669+ 'useQueryCache ' => $ queryConfig ['useQueryCache ' ] ?? null ,
670+ 'useLegacySql ' => false ,
671+ 'queryParameters ' => $ queryConfig ['queryParameters ' ] ?? null ,
672+ 'parameterMode ' => $ queryConfig ['parameterMode ' ] ?? null ,
673+ 'labels ' => $ config ['configuration ' ]['labels ' ] ?? null ,
674+ 'createSession ' => $ queryConfig ['createSession ' ] ?? null ,
675+ 'maximumBytesBilled ' => $ queryConfig ['maximumBytesBilled ' ] ?? null ,
676+ 'location ' => $ config ['jobReference ' ]['location ' ] ?? null ,
677+ 'requestId ' => $ config ['jobReference ' ]['jobId ' ],
678+ 'jobCreationMode ' => self ::JOB_CREATION_MODE_OPTIONAL
679+ ];
680+ }
681+
682+ /**
683+ * Returns if the JobId was generated by the JobConfigurationTrait
684+ *
685+ * @return bool
686+ */
687+ private function isJobIdGenerated (): bool
688+ {
689+ return $ this ->isJobIdGenerated ;
690+ }
596691}
0 commit comments