Skip to content

Commit 9942e9b

Browse files
committed
docs: add test for using FOR UPDATE
Spanner now supports FOR UPDATE clauses. This change adds a test to verify that FOR UPDATE clauses can be generated with the Spanner SQLAlchemy provider. See also https://cloud.google.com/spanner/docs/release-notes#January_27_2025
1 parent 3abd48e commit 9942e9b

File tree

4 files changed

+71
-99
lines changed

4 files changed

+71
-99
lines changed

test/mockserver_tests/mock_server_test_base.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,50 @@ def add_single_result(
7878
result.rows.extend(row)
7979
MockServerTestBase.spanner_service.mock_spanner.add_result(sql, result)
8080

81+
def add_singer_query_result(sql: str):
82+
result = result_set.ResultSet(
83+
dict(
84+
metadata=result_set.ResultSetMetadata(
85+
dict(
86+
row_type=spanner_type.StructType(
87+
dict(
88+
fields=[
89+
spanner_type.StructType.Field(
90+
dict(
91+
name="singers_id",
92+
type=spanner_type.Type(
93+
dict(code=spanner_type.TypeCode.INT64)
94+
),
95+
)
96+
),
97+
spanner_type.StructType.Field(
98+
dict(
99+
name="singers_name",
100+
type=spanner_type.Type(
101+
dict(code=spanner_type.TypeCode.STRING)
102+
),
103+
)
104+
),
105+
]
106+
)
107+
)
108+
)
109+
),
110+
)
111+
)
112+
result.rows.extend(
113+
[
114+
(
115+
"1",
116+
"Jane Doe",
117+
),
118+
(
119+
"2",
120+
"John Doe",
121+
),
122+
]
123+
)
124+
add_result(sql, result)
81125

82126
class MockServerTestBase(fixtures.TestBase):
83127
server: grpc.Server = None

test/mockserver_tests/test_basics.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
func,
2727
text,
2828
)
29+
from sqlalchemy.orm import Session
2930
from sqlalchemy.testing import eq_, is_instance_of
3031
from google.cloud.spanner_v1 import (
3132
FixedSizePool,
@@ -40,8 +41,9 @@
4041
add_select1_result,
4142
add_result,
4243
add_single_result,
43-
add_update_count,
44+
add_update_count, add_singer_query_result,
4445
)
46+
from test.mockserver_tests.read_only_model import Singer
4547

4648

4749
class TestBasics(MockServerTestBase):
@@ -179,3 +181,23 @@ def test_partitioned_dml(self):
179181
)
180182
results = connection.execute(text(sql)).rowcount
181183
eq_(100, results)
184+
185+
def test_select_for_update(self):
186+
query = ("SELECT singers.id AS singers_id, singers.name AS singers_name\n"
187+
"FROM singers\n"
188+
"WHERE singers.id = @a0\n"
189+
" LIMIT @a1 FOR UPDATE")
190+
add_singer_query_result(query)
191+
update = "UPDATE singers SET name=@a0 WHERE singers.id = @a1"
192+
add_update_count(update, 1)
193+
194+
engine = create_engine(
195+
"spanner:///projects/p/instances/i/databases/d",
196+
connect_args={"client": self.client, "pool": FixedSizePool(size=10)},
197+
)
198+
199+
with Session(engine) as session:
200+
singer = session.query(Singer).filter(Singer.id==1).with_for_update().first()
201+
singer.name = "New Name"
202+
session.add(singer)
203+
session.commit()

test/mockserver_tests/test_read_only_transaction.py

Lines changed: 2 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,8 @@
2222
BeginTransactionRequest,
2323
TransactionOptions,
2424
)
25-
from test.mockserver_tests.mock_server_test_base import MockServerTestBase
26-
from test.mockserver_tests.mock_server_test_base import add_result
27-
import google.cloud.spanner_v1.types.type as spanner_type
28-
import google.cloud.spanner_v1.types.result_set as result_set
25+
from test.mockserver_tests.mock_server_test_base import MockServerTestBase, \
26+
add_singer_query_result
2927

3028

3129
class TestReadOnlyTransaction(MockServerTestBase):
@@ -73,47 +71,3 @@ def test_read_only_transaction(self):
7371
)
7472

7573

76-
def add_singer_query_result(sql: str):
77-
result = result_set.ResultSet(
78-
dict(
79-
metadata=result_set.ResultSetMetadata(
80-
dict(
81-
row_type=spanner_type.StructType(
82-
dict(
83-
fields=[
84-
spanner_type.StructType.Field(
85-
dict(
86-
name="singers_id",
87-
type=spanner_type.Type(
88-
dict(code=spanner_type.TypeCode.INT64)
89-
),
90-
)
91-
),
92-
spanner_type.StructType.Field(
93-
dict(
94-
name="singers_name",
95-
type=spanner_type.Type(
96-
dict(code=spanner_type.TypeCode.STRING)
97-
),
98-
)
99-
),
100-
]
101-
)
102-
)
103-
)
104-
),
105-
)
106-
)
107-
result.rows.extend(
108-
[
109-
(
110-
"1",
111-
"Jane Doe",
112-
),
113-
(
114-
"2",
115-
"John Doe",
116-
),
117-
]
118-
)
119-
add_result(sql, result)

test/mockserver_tests/test_stale_reads.py

Lines changed: 2 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,8 @@
2323
BeginTransactionRequest,
2424
TransactionOptions,
2525
)
26-
from test.mockserver_tests.mock_server_test_base import MockServerTestBase
27-
from test.mockserver_tests.mock_server_test_base import add_result
28-
import google.cloud.spanner_v1.types.type as spanner_type
29-
import google.cloud.spanner_v1.types.result_set as result_set
26+
from test.mockserver_tests.mock_server_test_base import MockServerTestBase, \
27+
add_singer_query_result
3028

3129

3230
class TestStaleReads(MockServerTestBase):
@@ -121,49 +119,3 @@ def test_stale_read_single_use(self):
121119
),
122120
execute_request.transaction.single_use,
123121
)
124-
125-
126-
def add_singer_query_result(sql: str):
127-
result = result_set.ResultSet(
128-
dict(
129-
metadata=result_set.ResultSetMetadata(
130-
dict(
131-
row_type=spanner_type.StructType(
132-
dict(
133-
fields=[
134-
spanner_type.StructType.Field(
135-
dict(
136-
name="singers_id",
137-
type=spanner_type.Type(
138-
dict(code=spanner_type.TypeCode.INT64)
139-
),
140-
)
141-
),
142-
spanner_type.StructType.Field(
143-
dict(
144-
name="singers_name",
145-
type=spanner_type.Type(
146-
dict(code=spanner_type.TypeCode.STRING)
147-
),
148-
)
149-
),
150-
]
151-
)
152-
)
153-
)
154-
),
155-
)
156-
)
157-
result.rows.extend(
158-
[
159-
(
160-
"1",
161-
"Jane Doe",
162-
),
163-
(
164-
"2",
165-
"John Doe",
166-
),
167-
]
168-
)
169-
add_result(sql, result)

0 commit comments

Comments
 (0)