Skip to content

Commit 53a1c7b

Browse files
splaskyclaude
andcommitted
feat: wire database parameter through parse_url and dialect
Extract `database` from URL query params in parse_url() and pass it through create_connect_args() to create_datastore_client(), enabling users to target non-default Datastore databases via the connection URI (e.g. `datastore://project/?database=my-db`). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 3c6dfb0 commit 53a1c7b

3 files changed

Lines changed: 91 additions & 2 deletions

File tree

‎sqlalchemy_datastore/base.py‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ def __init__(
8383
self.location = location
8484
self.identifier_preparer = self.preparer(self)
8585
self.dataset_id = None
86+
self.database_id = None
8687
self.list_tables_page_size = list_tables_page_size
8788
self._client = None
8889

@@ -124,6 +125,7 @@ def create_connect_args(self, url):
124125
provided_job_config,
125126
list_tables_page_size,
126127
user_supplied_client,
128+
database_id,
127129
) = parse_url(url)
128130

129131
self.arraysize = arraysize or self.arraysize
@@ -133,6 +135,7 @@ def create_connect_args(self, url):
133135
self.credentials_path = credentials_path
134136
self.credentials_base64 = credentials_base64 or self.credentials_base64
135137
self.dataset_id = dataset_id
138+
self.database_id = database_id
136139
self.billing_project_id = self.billing_project_id or self.project_id
137140

138141
if user_supplied_client:
@@ -143,7 +146,7 @@ def create_connect_args(self, url):
143146
credentials_info=self.credentials_info,
144147
credentials_base64=self.credentials_base64,
145148
project_id=self.billing_project_id,
146-
database=None,
149+
database=self.database_id,
147150
)
148151
self.project_id = self.project_id if self.project_id else client.project
149152
self.billing_project_id = (

‎sqlalchemy_datastore/parse_url.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ def parse_url(url): # noqa: C901
7272
credentials_base64 = None
7373
list_tables_page_size = None
7474
user_supplied_client = False
75+
database = None
76+
77+
# database
78+
if "database" in query:
79+
database = query.pop("database")
7580

7681
# location
7782
if "location" in query:
@@ -122,6 +127,7 @@ def parse_url(url): # noqa: C901
122127
QueryJobConfig(),
123128
list_tables_page_size,
124129
user_supplied_client,
130+
database,
125131
)
126132
else:
127133
return (
@@ -134,6 +140,7 @@ def parse_url(url): # noqa: C901
134140
None,
135141
list_tables_page_size,
136142
user_supplied_client,
143+
database,
137144
)
138145

139146
job_config = QueryJobConfig()
@@ -284,4 +291,5 @@ def parse_url(url): # noqa: C901
284291
job_config,
285292
list_tables_page_size,
286293
user_supplied_client,
294+
database,
287295
)

‎tests/test_unit_base.py‎

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@
1717
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1818
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1919
"""Unit tests for base.py CloudDatastoreDialect (no emulator required)."""
20-
from unittest.mock import MagicMock
20+
from unittest.mock import MagicMock, patch
21+
22+
from sqlalchemy.engine.url import make_url
2123

2224
from sqlalchemy_datastore import CloudDatastoreDialect, datastore_dbapi
25+
from sqlalchemy_datastore.parse_url import parse_url
2326

2427
# ---------------------------------------------------------------------------
2528
# Dialect metadata
@@ -224,3 +227,78 @@ def test_get_table_names_empty():
224227

225228
result = d.get_table_names(None)
226229
assert result == []
230+
231+
232+
# ---------------------------------------------------------------------------
233+
# parse_url – database parameter
234+
# ---------------------------------------------------------------------------
235+
236+
def test_parse_url_extracts_database():
237+
url = make_url("datastore://my-project/?database=my-db")
238+
result = parse_url(url)
239+
assert len(result) == 10
240+
assert result[9] == "my-db"
241+
242+
243+
def test_parse_url_no_database():
244+
url = make_url("datastore://my-project/")
245+
result = parse_url(url)
246+
assert len(result) == 10
247+
assert result[9] is None
248+
249+
250+
def test_parse_url_database_with_location():
251+
url = make_url("datastore://my-project/?database=my-db&location=us-east1")
252+
result = parse_url(url)
253+
assert result[9] == "my-db"
254+
assert result[1] == "us-east1"
255+
256+
257+
# ---------------------------------------------------------------------------
258+
# create_connect_args – database parameter
259+
# ---------------------------------------------------------------------------
260+
261+
def test_create_connect_args_passes_database():
262+
d = CloudDatastoreDialect()
263+
url = make_url("datastore://my-project/?database=my-db")
264+
265+
with patch(
266+
"sqlalchemy_datastore.base.create_datastore_client"
267+
) as mock_create:
268+
mock_client = MagicMock()
269+
mock_client.project = "my-project"
270+
mock_create.return_value = (mock_client, MagicMock())
271+
272+
d.create_connect_args(url)
273+
274+
mock_create.assert_called_once_with(
275+
credentials_path=None,
276+
credentials_info=None,
277+
credentials_base64=None,
278+
project_id="my-project",
279+
database="my-db",
280+
)
281+
assert d.database_id == "my-db"
282+
283+
284+
def test_create_connect_args_no_database():
285+
d = CloudDatastoreDialect()
286+
url = make_url("datastore://my-project/")
287+
288+
with patch(
289+
"sqlalchemy_datastore.base.create_datastore_client"
290+
) as mock_create:
291+
mock_client = MagicMock()
292+
mock_client.project = "my-project"
293+
mock_create.return_value = (mock_client, MagicMock())
294+
295+
d.create_connect_args(url)
296+
297+
mock_create.assert_called_once_with(
298+
credentials_path=None,
299+
credentials_info=None,
300+
credentials_base64=None,
301+
project_id="my-project",
302+
database=None,
303+
)
304+
assert d.database_id is None

0 commit comments

Comments
 (0)