-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Support snapshot queries (#215)
Co-authored-by: halnique <shunsuke4dev@gmail.com>
- Loading branch information
1 parent
6ba4a72
commit 72c61a5
Showing
7 changed files
with
235 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
<?php | ||
/** | ||
* Copyright 2019 Colopl Inc. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
namespace Colopl\Spanner\Concerns; | ||
|
||
use Closure; | ||
use Colopl\Spanner\TimestampBound\TimestampBoundInterface; | ||
use Google\Cloud\Spanner\Snapshot; | ||
use LogicException; | ||
|
||
trait ManagesSnapshots | ||
{ | ||
/** | ||
* @var Snapshot|null | ||
*/ | ||
protected ?Snapshot $currentSnapshot = null; | ||
|
||
/** | ||
* @template TReturn | ||
* @param TimestampBoundInterface $timestampBound | ||
* @param Closure(): TReturn $callback | ||
* @return TReturn | ||
*/ | ||
public function snapshot(TimestampBoundInterface $timestampBound, Closure $callback): mixed | ||
{ | ||
if ($this->currentSnapshot !== null) { | ||
throw new LogicException('Nested snapshots are not supported.'); | ||
} | ||
|
||
$options = $timestampBound->transactionOptions(); | ||
try { | ||
$this->currentSnapshot = $this->getSpannerDatabase()->snapshot($options); | ||
return $callback(); | ||
This comment has been minimized.
Sorry, something went wrong. |
||
} finally { | ||
$this->currentSnapshot = null; | ||
} | ||
} | ||
|
||
/** | ||
* @return bool | ||
*/ | ||
public function inSnapshot(): bool | ||
{ | ||
return $this->currentSnapshot !== null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
<?php | ||
/** | ||
* Copyright 2019 Colopl Inc. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
namespace Colopl\Spanner\Tests; | ||
|
||
use Colopl\Spanner\TimestampBound\ExactStaleness; | ||
use Colopl\Spanner\TimestampBound\StrongRead; | ||
use LogicException; | ||
use RuntimeException; | ||
|
||
class SnapshotTest extends TestCase | ||
{ | ||
public function test_snapshot(): void | ||
{ | ||
$conn = $this->getDefaultConnection(); | ||
|
||
$conn->transaction(function () use ($conn) { | ||
$this->assertFalse($conn->inSnapshot()); | ||
$conn->table(self::TABLE_NAME_USER)->insert(['userId' => $this->generateUuid(), 'name' => 't']); | ||
}); | ||
|
||
$this->assertFalse($conn->inSnapshot()); | ||
$result = $conn->snapshot(new StrongRead(), function () use ($conn) { | ||
$this->assertTrue($conn->inSnapshot()); | ||
// call it multiple times | ||
$this->assertSame('t', $conn->table(self::TABLE_NAME_USER)->value('name')); | ||
$this->assertSame('t', $conn->table(self::TABLE_NAME_USER)->value('name')); | ||
|
||
return 'ok'; | ||
}); | ||
|
||
$this->assertSame('ok', $result); | ||
} | ||
|
||
public function test_snapshot_with_staleness(): void | ||
{ | ||
$conn = $this->getDefaultConnection(); | ||
|
||
$conn->transaction(function () use ($conn) { | ||
$conn->table(self::TABLE_NAME_USER)->insert(['userId' => $this->generateUuid(), 'name' => 't']); | ||
}); | ||
|
||
$conn->snapshot(new ExactStaleness(10), function () use ($conn) { | ||
$this->assertNull($conn->table(self::TABLE_NAME_USER)->first()); | ||
$this->assertSame(0, $conn->table(self::TABLE_NAME_USER)->count()); | ||
}); | ||
|
||
$conn->snapshot(new StrongRead(), function () use ($conn) { | ||
$this->assertNotNull($conn->table(self::TABLE_NAME_USER)->first()); | ||
$this->assertSame(1, $conn->table(self::TABLE_NAME_USER)->count()); | ||
}); | ||
} | ||
|
||
public function test_snapshot_can_call_after_error(): void | ||
{ | ||
$conn = $this->getDefaultConnection(); | ||
|
||
try { | ||
$conn->snapshot(new ExactStaleness(10), function () use ($conn) { | ||
$this->assertSame(0, $conn->table(self::TABLE_NAME_USER)->count()); | ||
throw new RuntimeException('error'); | ||
}); | ||
} catch (RuntimeException $e) { | ||
// ignore | ||
} | ||
|
||
$conn->transaction(function () use ($conn) { | ||
$conn->table(self::TABLE_NAME_USER)->insert(['userId' => $this->generateUuid(), 'name' => 't']); | ||
}); | ||
|
||
$conn->snapshot(new ExactStaleness(0), function () use ($conn) { | ||
$this->assertSame(1, $conn->table(self::TABLE_NAME_USER)->count()); | ||
}); | ||
} | ||
|
||
public function test_snapshot_fails_on_nested(): void | ||
{ | ||
$this->expectException(LogicException::class); | ||
$this->expectExceptionMessage('Nested snapshots are not supported.'); | ||
|
||
$conn = $this->getDefaultConnection(); | ||
$conn->snapshot(new ExactStaleness(10), function () use ($conn) { | ||
$conn->snapshot(new StrongRead(), function () { | ||
}); | ||
}); | ||
} | ||
|
||
public function test_snapshot_fails_in_transaction(): void | ||
{ | ||
$this->expectException(LogicException::class); | ||
$this->expectExceptionMessage('Nested transactions are not supported by this client.'); | ||
|
||
$conn = $this->getDefaultConnection(); | ||
$conn->transaction(function () use ($conn) { | ||
$conn->snapshot(new StrongRead(), function () use ($conn) { | ||
$conn->select('SELECT 1'); | ||
}); | ||
}); | ||
} | ||
|
||
public function test_snapshot_fails_when_transaction_called_inside(): void | ||
{ | ||
$this->expectException(LogicException::class); | ||
$this->expectExceptionMessage('Calling transaction() inside a snapshot is not supported.'); | ||
|
||
$conn = $this->getDefaultConnection(); | ||
$conn->snapshot(new StrongRead(), function () use ($conn) { | ||
$conn->transaction(function () use ($conn) { | ||
$conn->select('SELECT 1'); | ||
}); | ||
}); | ||
} | ||
} |
Wouldnt it make sense the pass
$this
to$callback($this)
here, so when using it you dont have to keep track of the connection in questionFor example instead of requiring the additional
use ($conn)
clause in your tests, you could just do:It makes sense to pass the active connection down to the callback in all cases right?