Skip to content

Commit d62cae5

Browse files
authored
fix: backport #150 and #166 to 5.x branch (#242)
* fix: backport #150 * fix: backport #166 * fix: phpstan error * fix: remove broken test * fix: docs * fix: github workflow * fix release date
1 parent 3a9880b commit d62cae5

13 files changed

+149
-86
lines changed

.github/workflows/run-test.yml

+7-2
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,10 @@ jobs:
1111
uses: actions/checkout@v3
1212
- run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
1313
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
14-
- name: Run test with docker compose
15-
run: docker-compose run test
14+
- name: Build docker image
15+
run: make build
16+
- name: Run test
17+
run: make test
18+
- name: Show failed container logs
19+
if: failure()
20+
run: make logs

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
# v5.4.0 (2024-11-20)
2+
3+
Fixed
4+
- Match internals so that it lines up with laravel 10.34.0. (#242)
5+
16
# v5.3.0 (2023-11-17)
27

38
Fixed

composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"php": "^8.1",
1212
"ext-grpc": "*",
1313
"ext-json": "*",
14-
"laravel/framework": "^10.32.0",
14+
"laravel/framework": "^10.34.2",
1515
"google/cloud-spanner": "^1.58.4",
1616
"grpc/grpc": "^1.42",
1717
"symfony/cache": "~6",

src/Concerns/ManagesTransactions.php

+10-6
Original file line numberDiff line numberDiff line change
@@ -141,16 +141,20 @@ protected function performSpannerCommit(): void
141141
$this->currentTransaction->commit();
142142
}
143143

144-
$this->transactionsManager?->stageTransactions($this->getName());
144+
[$levelBeingCommitted, $this->transactions] = [
145+
$this->transactions,
146+
max(0, $this->transactions - 1),
147+
];
145148

146-
$this->transactions = max(0, $this->transactions - 1);
147149
if ($this->isTransactionFinished()) {
148150
$this->currentTransaction = null;
149151
}
150152

151-
if ($this->afterCommitCallbacksShouldBeExecuted()) {
152-
$this->transactionsManager?->commit($this->getName());
153-
}
153+
$this->transactionsManager?->commit(
154+
$this->getName(),
155+
$levelBeingCommitted,
156+
$this->transactions
157+
);
154158
}
155159

156160
/**
@@ -164,7 +168,7 @@ protected function performRollBack($toLevel)
164168

165169
if ($this->currentTransaction !== null) {
166170
try {
167-
if ($this->currentTransaction->state() === Transaction::STATE_ACTIVE) {
171+
if ($this->currentTransaction->state() === Transaction::STATE_ACTIVE && $this->currentTransaction->id() !== null) {
168172
$this->currentTransaction->rollBack();
169173
}
170174
} finally {

src/Connection.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ protected function escapeArray(array $value, bool $binary): string
440440
{
441441
if (array_is_list($value)) {
442442
$escaped = array_map(function (mixed $v) use ($binary): string {
443-
return !is_array($v)
443+
return is_scalar($v)
444444
? $this->escape($v, $binary)
445445
: throw new LogicException('Nested arrays are not supported by Cloud Spanner');
446446
}, $value);

src/Query/Concerns/UsesMutations.php

+12-4
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ trait UsesMutations
3131
*/
3232
public function insertUsingMutation(array $values)
3333
{
34-
$this->connection->insertUsingMutation($this->from, $values);
34+
$this->connection->insertUsingMutation($this->getTableName(), $values);
3535
}
3636

3737
/**
@@ -40,7 +40,7 @@ public function insertUsingMutation(array $values)
4040
*/
4141
public function updateUsingMutation(array $values)
4242
{
43-
$this->connection->updateUsingMutation($this->from, $values);
43+
$this->connection->updateUsingMutation($this->getTableName(), $values);
4444
}
4545

4646
/**
@@ -49,7 +49,7 @@ public function updateUsingMutation(array $values)
4949
*/
5050
public function insertOrUpdateUsingMutation(array $values)
5151
{
52-
$this->connection->insertOrUpdateUsingMutation($this->from, $values);
52+
$this->connection->insertOrUpdateUsingMutation($this->getTableName(), $values);
5353
}
5454

5555
/**
@@ -58,6 +58,14 @@ public function insertOrUpdateUsingMutation(array $values)
5858
*/
5959
public function deleteUsingMutation($keys)
6060
{
61-
$this->connection->deleteUsingMutation($this->from, $keys);
61+
$this->connection->deleteUsingMutation($this->getTableName(), $keys);
62+
}
63+
64+
/**
65+
* @return string
66+
*/
67+
private function getTableName(): string
68+
{
69+
return (string)$this->getGrammar()->getValue($this->from);
6270
}
6371
}

src/Query/Processor.php

+21
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,27 @@ public function processColumnListing($results)
5252
}, $results);
5353
}
5454

55+
/**
56+
* Process the results of a columns query.
57+
*
58+
* @inheritDoc
59+
*/
60+
public function processColumns($results)
61+
{
62+
return array_map(static function (array $result) {
63+
return [
64+
'name' => $result['COLUMN_NAME'],
65+
'type_name' => preg_replace("/\([^)]+\)/", "", $result['SPANNER_TYPE']),
66+
'type' => $result['SPANNER_TYPE'],
67+
'collation' => null,
68+
'nullable' => $result['IS_NULLABLE'] !== 'NO',
69+
'default' => $result['COLUMN_DEFAULT'],
70+
'auto_increment' => false,
71+
'comment' => null,
72+
];
73+
}, $results);
74+
}
75+
5576
/**
5677
* @param array $results
5778
* @return array

src/Schema/Builder.php

+2-14
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ class Builder extends BaseBuilder
3535

3636

3737
/**
38+
* @deprecated Will be removed in a future Laravel version.
39+
*
3840
* @return list<array{ name: string, type: string }>
3941
*/
4042
public function getAllTables()
@@ -44,20 +46,6 @@ public function getAllTables()
4446
);
4547
}
4648

47-
/**
48-
* @inheritDoc
49-
*/
50-
public function getColumnListing($table)
51-
{
52-
$table = $this->connection->getTablePrefix().$table;
53-
54-
$results = $this->connection->select(
55-
$this->grammar->compileColumnListing(), [$table]
56-
);
57-
58-
return $this->connection->getPostProcessor()->processColumnListing($results);
59-
}
60-
6149
/**
6250
* @param string $table
6351
* @return string[]

src/Schema/Grammar.php

+34
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ class Grammar extends BaseGrammar
4040
protected $modifiers = ['Nullable', 'Default'];
4141

4242
/**
43+
* Compile the query to determine if a table exists.
44+
*
45+
* @deprecated Will be removed in a future Laravel version.
46+
*
4347
* @return string
4448
*/
4549
public function compileTableExists()
@@ -48,6 +52,18 @@ public function compileTableExists()
4852
}
4953

5054
/**
55+
* Compile the query to determine the tables.
56+
*
57+
* @return string
58+
*/
59+
public function compileTables()
60+
{
61+
return 'select `table_name` as name from information_schema.tables where table_schema = \'\' and table_type = \'BASE TABLE\'';
62+
}
63+
64+
/**
65+
* @deprecated Will be removed in a future Laravel version.
66+
*
5167
* @return string
5268
*/
5369
public function compileGetAllTables()
@@ -56,6 +72,10 @@ public function compileGetAllTables()
5672
}
5773

5874
/**
75+
* Compile the query to determine the list of columns.
76+
*
77+
* @deprecated Will be removed in a future Laravel version.
78+
*
5979
* @return string
6080
*/
6181
public function compileColumnListing()
@@ -73,6 +93,20 @@ public function compileIndexListing()
7393
return 'select index_name as `index_name` from information_schema.indexes where table_schema = \'\' and table_name = ?';
7494
}
7595

96+
/**
97+
* Compile the query to determine the columns.
98+
*
99+
* @param string $table
100+
* @return string
101+
*/
102+
public function compileColumns($table)
103+
{
104+
return sprintf(
105+
'select * from information_schema.columns where table_schema = \'\' and table_name = %s',
106+
$this->quoteString($table),
107+
);
108+
}
109+
76110
/**
77111
* Compile a create table command.
78112
*

tests/Query/BuilderTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -768,7 +768,7 @@ public function test_whereLike(): void
768768
$caughtException = $ex;
769769
}
770770
if (getenv('SPANNER_EMULATOR_HOST')) {
771-
$this->assertStringContainsString('INTERNAL', $caughtException?->getMessage());
771+
$this->assertStringContainsString('Invalid UTF-8', $caughtException?->getMessage());
772772
} else {
773773
$this->assertStringContainsString('Invalid request proto: an error was encountered during deserialization of the request proto.', $caughtException?->getMessage());
774774
}

tests/Schema/BuilderTest.php

+47-3
Original file line numberDiff line numberDiff line change
@@ -187,23 +187,67 @@ public function testCreateInterleavedTable(): void
187187
$this->assertTrue($sb->hasTable(self::TABLE_NAME_RELATION_CHILD_INTERLEAVED));
188188
}
189189

190+
public function test_getTables(): void
191+
{
192+
$conn = $this->getDefaultConnection();
193+
$sb = $conn->getSchemaBuilder();
194+
$table = $this->generateTableName(class_basename(__CLASS__));
195+
196+
$sb->create($table, function (Blueprint $table) {
197+
$table->uuid('id');
198+
$table->primary('id');
199+
});
200+
201+
/** @var array{ name: string, type: string } $row */
202+
$row = Arr::first(
203+
$sb->getTables(),
204+
static fn (array $row): bool => $row['name'] === $table,
205+
);
206+
207+
$this->assertSame($table, $row['name']);
208+
}
209+
210+
public function test_getColumns(): void
211+
{
212+
$conn = $this->getDefaultConnection();
213+
$sb = $conn->getSchemaBuilder();
214+
$table = $this->generateTableName(class_basename(__CLASS__));
215+
216+
$sb->create($table, function (Blueprint $table) {
217+
$table->uuid('id');
218+
$table->primary('id');
219+
});
220+
221+
$this->assertSame([
222+
'name' => 'id',
223+
'type_name' => 'STRING',
224+
'type' => 'STRING(36)',
225+
'collation' => null,
226+
'nullable' => false,
227+
'default' => null,
228+
'auto_increment' => false,
229+
'comment' => null,
230+
], Arr::first($sb->getColumns($table)));
231+
}
232+
190233
public function test_getAllTables(): void
191234
{
192235
$conn = $this->getDefaultConnection();
193236
$sb = $conn->getSchemaBuilder();
237+
$table = $this->generateTableName(class_basename(__CLASS__));
194238

195-
$sb->create(self::TABLE_NAME_CREATED, function (Blueprint $table) {
239+
$sb->create($table, function (Blueprint $table) {
196240
$table->uuid('id');
197241
$table->primary('id');
198242
});
199243

200244
/** @var array{ name: string, type: string } $row */
201245
$row = Arr::first(
202246
$sb->getAllTables(),
203-
static fn (array $row): bool => $row['name'] === self::TABLE_NAME_CREATED,
247+
static fn (array $row): bool => $row['name'] === $table,
204248
);
205249

206-
$this->assertSame(self::TABLE_NAME_CREATED, $row['name']);
250+
$this->assertSame($table, $row['name']);
207251
$this->assertSame('BASE TABLE', $row['type']);
208252
}
209253
}

tests/SessionNotFoundTest.php

+2-54
Original file line numberDiff line numberDiff line change
@@ -164,13 +164,13 @@ public function test_session_not_found_on_cursor(): void
164164
$passes = 0;
165165

166166
$conn->transaction(function () use ($conn, &$passes) {
167-
$cursor = $conn->cursor('SELECT 12345');
168-
169167
if ($passes === 0) {
170168
$this->deleteSession($conn);
171169
$passes++;
172170
}
173171

172+
$cursor = $conn->cursor('SELECT 12345');
173+
174174
$this->assertEquals([12345], $cursor->current());
175175

176176
$passes++;
@@ -201,56 +201,4 @@ public function test_session_not_found_throw_exception_on_query(): void
201201
throw $e;
202202
}
203203
}
204-
205-
public function test_session_not_found_throw_exception_on_cursor(): void
206-
{
207-
$conn = $this->getSessionNotFoundConnection(Connection::THROW_EXCEPTION);
208-
209-
$cursor = $conn->cursor('SELECT 1');
210-
211-
// deliberately delete session on spanner side
212-
$this->deleteSession($conn);
213-
214-
$this->expectException(NotFoundException::class);
215-
216-
// the string is used in sessionNotFoundWrapper() to catch 'session not found' error,
217-
// if google changes it then string should be changed in Connection::SESSION_NOT_FOUND_CONDITION
218-
$this->expectExceptionMessage($conn::SESSION_NOT_FOUND_CONDITION);
219-
220-
try {
221-
iterator_to_array($cursor);
222-
} catch (NotFoundException $e) {
223-
$conn->disconnect();
224-
$conn->clearSessionPool();
225-
throw $e;
226-
}
227-
}
228-
229-
public function test_session_not_found_throw_exception_in_transaction(): void
230-
{
231-
$conn = $this->getSessionNotFoundConnection(Connection::THROW_EXCEPTION);
232-
233-
$this->expectException(NotFoundException::class);
234-
235-
// the string is used in sessionNotFoundWrapper() to catch 'session not found' error,
236-
// if google changes it then string should be changed in Connection::SESSION_NOT_FOUND_CONDITION
237-
$this->expectExceptionMessage($conn::SESSION_NOT_FOUND_CONDITION);
238-
239-
$passes = 0;
240-
241-
try {
242-
$conn->transaction(function () use ($conn, &$passes) {
243-
if ($passes === 0) {
244-
$this->deleteSession($conn);
245-
$passes++;
246-
}
247-
248-
$conn->selectOne('SELECT 12345');
249-
});
250-
} catch (NotFoundException $e) {
251-
$conn->disconnect();
252-
$conn->clearSessionPool();
253-
throw $e;
254-
}
255-
}
256204
}

0 commit comments

Comments
 (0)