Skip to content

Commit b2f0e89

Browse files
authored
docs: add sample for parse_json (#752)
Add a sample and test for using the parse_json function with SQLAlchemy. Fixes #735
1 parent 4bc0589 commit b2f0e89

File tree

3 files changed

+75
-3
lines changed

3 files changed

+75
-3
lines changed

samples/noxfile.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@ def insertmany(session):
9797
_sample(session)
9898

9999

100+
@nox.session()
101+
def parse_json(session):
102+
_sample(session)
103+
104+
100105
@nox.session()
101106
def _all_samples(session):
102107
_sample(session)

samples/parse_json_sample.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Copyright 2025 Google LLC All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from sqlalchemy import create_engine, func, text
16+
from sqlalchemy.orm import Session
17+
18+
from sample_helper import run_sample
19+
from model import Venue
20+
21+
# Shows how to use the PARSE_JSON function in Spanner using SQLAlchemy.
22+
def parse_json_sample():
23+
engine = create_engine(
24+
"spanner:///projects/sample-project/"
25+
"instances/sample-instance/"
26+
"databases/sample-database",
27+
echo=True,
28+
)
29+
with Session(engine) as session:
30+
venue = Venue(
31+
code="LCH",
32+
active=True,
33+
name="Large Concert Hall",
34+
# The SQLAlchemy func function is very lenient and allows you to call any
35+
# database function that Spanner supports. Use a text instance to add a
36+
# specific SQL fragment to the function call.
37+
description=func.parse_json(
38+
'{"type": "Stadium", "size": 13.7391432}',
39+
text("wide_number_mode=>'round'"),
40+
),
41+
)
42+
session.add(venue)
43+
session.commit()
44+
45+
venue = session.query(Venue).filter_by(code="LCH").one()
46+
print(venue.description)
47+
48+
49+
if __name__ == "__main__":
50+
run_sample(parse_json_sample)

test/mockserver_tests/test_json.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from sqlalchemy import select
15+
from sqlalchemy import func, select, text
1616
from sqlalchemy.orm import Session
1717
from sqlalchemy.testing import eq_, is_instance_of
1818
from google.cloud.spanner_v1 import (
@@ -73,7 +73,24 @@ def test_insert_array(self):
7373
'[{"size":"Great","type":"Stadium"}]',
7474
)
7575

76-
def _test_insert_json(self, description, expected):
76+
def test_insert_fn(self):
77+
add_update_count(
78+
"INSERT INTO venues (id, name, description) "
79+
"VALUES (@a0, @a1, parse_json(@a2, wide_number_mode=>'round'))",
80+
1,
81+
)
82+
self._test_insert_json(
83+
func.parse_json(
84+
'{"type": "Stadium", "size": "Great"}',
85+
text("wide_number_mode=>'round'"),
86+
),
87+
'{"type": "Stadium", "size": "Great"}',
88+
expected_type_code=TypeCode.STRING,
89+
)
90+
91+
def _test_insert_json(
92+
self, description, expected, expected_type_code=TypeCode.JSON
93+
):
7794
from test.mockserver_tests.json_model import Venue
7895

7996
add_update_count(
@@ -100,7 +117,7 @@ def _test_insert_json(self, description, expected):
100117
eq_(expected, request.params["a2"])
101118
eq_(TypeCode.INT64, request.param_types["a0"].code)
102119
eq_(TypeCode.STRING, request.param_types["a1"].code)
103-
eq_(TypeCode.JSON, request.param_types["a2"].code)
120+
eq_(expected_type_code, request.param_types["a2"].code)
104121

105122
def test_select_dict(self):
106123
self._test_select_json(

0 commit comments

Comments
 (0)