Skip to content

Commit 75d4d74

Browse files
committed
feat!: Spanner V2
1 parent 670112d commit 75d4d74

169 files changed

Lines changed: 5443 additions & 21955 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/emulator-system-tests-spanner.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ jobs:
4949
- name: Install dependencies
5050
run: |
5151
# ensure composer uses local Core instead of pulling from packagist
52-
composer config repositories.local --json '{"type":"path", "url": "../Core", "options": {"versions": {"google/cloud-core": "1.100"}}}' -d Spanner
52+
composer config repositories.local --json '{"type":"path", "url": "../Core", "options": {"versions": {"google/cloud-core": "1.100"}},"canonical":false}' -d Spanner
5353
composer update --prefer-dist --no-interaction --no-suggest -d Spanner/
5454
5555
- name: Run system tests

Core/src/ApiHelperTrait.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717
*/
1818
namespace Google\Cloud\Core;
1919

20+
use Exception;
2021
use Google\ApiCore\ArrayTrait;
2122
use Google\ApiCore\Options\CallOptions;
2223
use Google\Protobuf\Internal\Message;
2324
use Google\Protobuf\NullValue;
25+
use LogicException;
2426

2527
/**
2628
* @internal
@@ -276,6 +278,8 @@ private function splitOptionalArgs(array $input, array $extraAllowedKeys = []):
276278
* $optionTypes can be an array of string keys, a protobuf Message classname, or a
277279
* the CallOptions classname. Parameters are split and returned in the order
278280
* that the options types are provided.
281+
*
282+
* @throws LogicException
279283
*/
280284
private function validateOptions(array $options, array|Message|string ...$optionTypes): array
281285
{

Core/src/Iam/Iam.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
*
3535
* use Google\Cloud\Spanner\SpannerClient;
3636
*
37-
* $spanner = new SpannerClient();
37+
* $spanner = new SpannerClient(['projectId' => 'my-project']);
3838
* $instance = $spanner->instance('my-new-instance');
3939
*
4040
* $iam = $instance->iam();
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Google Inc.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
namespace Google\Cloud\Core\LongRunning;
19+
20+
use Google\ApiCore\OperationResponse;
21+
use Google\ApiCore\Serializer;
22+
use Google\Cloud\Core\RequestProcessorTrait;
23+
use Google\LongRunning\ListOperationsRequest;
24+
use Google\Protobuf\Any;
25+
26+
/**
27+
* Defines the calls required to manage Long Running Operations using a GAPIC
28+
* generated client.
29+
*
30+
* @internal
31+
*/
32+
class LongRunningClientConnection implements LongRunningConnectionInterface
33+
{
34+
use RequestProcessorTrait;
35+
36+
public function __construct(
37+
private object $gapicClient,
38+
private Serializer $serializer
39+
) {
40+
}
41+
42+
/**
43+
* @param array $args
44+
* @return array
45+
*/
46+
public function get(array $args): array
47+
{
48+
$operationResponse = $this->gapicClient->resumeOperation($args['name']);
49+
50+
return $this->operationResponseToArray($operationResponse);
51+
}
52+
53+
/**
54+
* @param array $args
55+
* @return array
56+
*/
57+
public function cancel(array $args): array
58+
{
59+
$operationResponse = $this->gapicClient->resumeOperation(
60+
$args['name'],
61+
$args['method'] ?? null
62+
);
63+
$operationResponse->cancel();
64+
65+
return $this->operationResponseToArray($operationResponse);
66+
}
67+
68+
/**
69+
* @param array $args
70+
* @return array
71+
*/
72+
public function delete(array $args): array
73+
{
74+
$operationResponse = $this->gapicClient->resumeOperation(
75+
$args['name'],
76+
$args['method'] ?? null
77+
);
78+
$operationResponse->cancel();
79+
80+
return $this->operationResponseToArray($operationResponse);
81+
}
82+
83+
/**
84+
* @param array $args
85+
* @return array
86+
*/
87+
public function operations(array $args): array
88+
{
89+
$request = ListOperationsRequest::build($args['name'], $args['filter'] ?? null);
90+
$response = $this->gapicClient->getOperationsClient()->listOperations($request);
91+
92+
return $this->handleResponse($response);
93+
}
94+
95+
private function operationResponseToArray(OperationResponse $operationResponse): array
96+
{
97+
$response = $this->handleResponse($operationResponse->getLastProtoResponse());
98+
$metaType = $response['metadata']['typeUrl'];
99+
100+
// unpack result Any type
101+
$result = $operationResponse->getResult();
102+
if ($result instanceof Any) {
103+
// For some reason we aren't doing this in GAX OperationResponse (but we should)
104+
$result = $result->unpack();
105+
}
106+
$response['response'] = $this->handleResponse($result);
107+
108+
// unpack error Any type
109+
$response['error'] = $this->handleResponse($operationResponse->getError());
110+
111+
$metadata = $operationResponse->getMetadata();
112+
if ($metadata instanceof Any) {
113+
// For some reason we aren't doing this in GAX OperationResponse (but we should)
114+
$metadata = $metadata->unpack();
115+
}
116+
$response['metadata'] = $this->handleResponse($metadata);
117+
118+
// Used in LongRunningOperation to invoke callables
119+
$response['metadata'] += ['typeUrl' => $metaType];
120+
121+
return $response;
122+
}
123+
}

Core/src/LongRunning/LongRunningOperation.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
/**
2121
* Represent and interact with a Long Running Operation.
22+
* @template T
2223
*/
2324
class LongRunningOperation
2425
{
@@ -180,7 +181,7 @@ public function state(array $options = [])
180181
* ```
181182
*
182183
* @param array $options [optional] Configuration options.
183-
* @return mixed|null
184+
* @return T|mixed|null
184185
*/
185186
public function result(array $options = [])
186187
{
@@ -252,12 +253,11 @@ public function reload(array $options = [])
252253

253254
$this->result = null;
254255
$this->error = null;
255-
if (isset($res['done']) && $res['done']) {
256+
257+
if ($res['done'] ?? false && isset($res['metadata']['typeUrl'])) {
256258
$type = $res['metadata']['typeUrl'];
257259
$this->result = $this->executeDoneCallback($type, $res['response']);
258-
$this->error = (isset($res['error']))
259-
? $res['error']
260-
: null;
260+
$this->error = $res['error'] ?? null;
261261
}
262262

263263
return $this->info = $res;

Core/src/OptionsValidator.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ class OptionsValidator
3636
* @param ?Serializer $serializer use a serializer to decode protobuf messages
3737
* instead of calling {@see Message::mergeFromJsonString()}.
3838
*/
39-
public function __construct(private ?Serializer $serializer = null)
40-
{
39+
public function __construct(
40+
private ?Serializer $serializer = null
41+
) {
4142
}
4243

4344
/**
@@ -90,6 +91,8 @@ public function validateOptions(array $options, array|Message|string ...$optionT
9091
$optionType->mergeFromJsonString(json_encode($messageOptions, JSON_FORCE_OBJECT));
9192
}
9293
$splitOptions[] = $optionType;
94+
} elseif (is_string($optionType)) {
95+
$splitOptions[] = $this->pluck($optionType, $options, false);
9396
} else {
9497
throw new LogicException(sprintf('Invalid option type: %s', $optionType));
9598
}

Core/src/RequestHandler.php

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,16 @@ class RequestHandler
4242
*/
4343
private Serializer $serializer;
4444

45-
private array $clients;
45+
private array $clients = [];
4646

4747
/**
4848
* @param Serializer $serializer
49-
* @param array $clientClasses
49+
* @param array<string|object> $clients
5050
* @param array $clientConfig
5151
*/
5252
public function __construct(
5353
Serializer $serializer,
54-
array $clientClasses,
54+
array $clients,
5555
array $clientConfig = []
5656
) {
5757
//@codeCoverageIgnoreStart
@@ -75,9 +75,12 @@ public function __construct(
7575
//@codeCoverageIgnoreEnd
7676

7777
// Initialize the client classes and store them in memory
78-
$this->clients = [];
79-
foreach ($clientClasses as $className) {
80-
$this->clients[$className] = new $className($clientConfig);
78+
foreach ($clients as $client) {
79+
if (is_object($client)) {
80+
$this->clients[get_class($client)] = $client;
81+
} else {
82+
$this->clients[$client] = new $client($clientConfig);
83+
}
8184
}
8285
}
8386

Core/src/ServiceBuilder.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ public function pubsub(array $config = [])
257257
*
258258
* Example:
259259
* ```
260-
* $spanner = $cloud->spanner();
260+
* $spanner = $cloud->spanner(['projectId' => 'my-project']);
261261
* ```
262262
*
263263
* @param array $config [optional] {

Core/src/TimeTrait.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,12 @@ private function formatTimeAsString(\DateTimeInterface $dateTime, $ns)
7979
$dateTime = $dateTime->setTimeZone(new \DateTimeZone('UTC'));
8080
if ($ns === null) {
8181
return $dateTime->format(Timestamp::FORMAT);
82-
} else {
83-
return sprintf(
84-
$dateTime->format(Timestamp::FORMAT_INTERPOLATE),
85-
$this->convertNanoSecondsToFraction($ns)
86-
);
8782
}
83+
84+
return sprintf(
85+
$dateTime->format(Timestamp::FORMAT_INTERPOLATE),
86+
$this->convertNanoSecondsToFraction($ns)
87+
);
8888
}
8989

9090
/**
@@ -95,10 +95,10 @@ private function formatTimeAsString(\DateTimeInterface $dateTime, $ns)
9595
* $dateTime will be used instead.
9696
* @return array
9797
*/
98-
private function formatTimeAsArray(\DateTimeInterface $dateTime, $ns)
98+
private function formatTimeAsArray(\DateTimeInterface $dateTime, $ns = null)
9999
{
100100
if ($ns === null) {
101-
$ns = $dateTime->format('u');
101+
$ns = $this->convertFractionToNanoSeconds($dateTime->format('u'));
102102
}
103103
return [
104104
'seconds' => (int) $dateTime->format('U'),

Core/src/Timestamp.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
namespace Google\Cloud\Core;
1919

20+
use DateTimeInterface;
21+
2022
/**
2123
* Represents a Timestamp value.
2224
*
@@ -85,9 +87,9 @@ public function __construct(\DateTimeInterface $value, $nanoSeconds = null)
8587
* $dateTime = $timestamp->get();
8688
* ```
8789
*
88-
* @return \DateTimeInterface
90+
* @return DateTimeInterface
8991
*/
90-
public function get()
92+
public function get(): DateTimeInterface
9193
{
9294
return $this->value;
9395
}
@@ -102,7 +104,7 @@ public function get()
102104
*
103105
* @return int
104106
*/
105-
public function nanoSeconds()
107+
public function nanoSeconds(): int
106108
{
107109
return $this->nanoSeconds === null
108110
? (int) $this->value->format('u') * 1000
@@ -119,7 +121,7 @@ public function nanoSeconds()
119121
*
120122
* @return string
121123
*/
122-
public function formatAsString()
124+
public function formatAsString(): string
123125
{
124126
return $this->formatTimeAsString(
125127
$this->value,
@@ -143,7 +145,7 @@ public function __toString()
143145
*
144146
* @return array
145147
*/
146-
public function formatForApi()
148+
public function formatForApi(): array
147149
{
148150
return $this->formatTimeAsArray($this->value, $this->nanoSeconds());
149151
}
@@ -155,7 +157,7 @@ public function formatForApi()
155157
* @access private
156158
*/
157159
#[\ReturnTypeWillChange]
158-
public function jsonSerialize()
160+
public function jsonSerialize(): string
159161
{
160162
return $this->formatAsString();
161163
}

0 commit comments

Comments
 (0)