Skip to content

Commit 5488781

Browse files
refactor: add split_full_table_name adapter method
Replace ad-hoc backtick/quote stripping with adapter.split_full_table_name() so that full table name parsing uses the correct quoting convention for each backend (backticks for MySQL, double quotes for PostgreSQL). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 34f744e commit 5488781

File tree

6 files changed

+40
-14
lines changed

6 files changed

+40
-14
lines changed

src/datajoint/adapters/base.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,27 @@ def quote_identifier(self, name: str) -> str:
169169
"""
170170
...
171171

172+
@abstractmethod
173+
def split_full_table_name(self, full_table_name: str) -> tuple[str, str]:
174+
"""
175+
Split a fully-qualified table name into schema and table components.
176+
177+
Inverse of quoting: strips backend-specific identifier quotes
178+
and splits into (schema, table).
179+
180+
Parameters
181+
----------
182+
full_table_name : str
183+
Quoted full table name (e.g., ```\\`schema\\`.\\`table\\` ``` or
184+
``"schema"."table"``).
185+
186+
Returns
187+
-------
188+
tuple[str, str]
189+
(schema_name, table_name) with quotes stripped.
190+
"""
191+
...
192+
172193
@abstractmethod
173194
def quote_string(self, value: str) -> str:
174195
"""

src/datajoint/adapters/mysql.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,11 @@ def quote_identifier(self, name: str) -> str:
200200
"""
201201
return f"`{name}`"
202202

203+
def split_full_table_name(self, full_table_name: str) -> tuple[str, str]:
204+
"""Split ```\\`schema\\`.\\`table\\` ``` into ``('schema', 'table')``."""
205+
schema, table = full_table_name.replace("`", "").split(".")
206+
return schema, table
207+
203208
def quote_string(self, value: str) -> str:
204209
"""
205210
Quote string literal for MySQL with escaping.

src/datajoint/adapters/postgres.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,11 @@ def quote_identifier(self, name: str) -> str:
249249
"""
250250
return f'"{name}"'
251251

252+
def split_full_table_name(self, full_table_name: str) -> tuple[str, str]:
253+
"""Split ``"schema"."table"`` into ``('schema', 'table')``."""
254+
schema, table = full_table_name.replace('"', "").split(".")
255+
return schema, table
256+
252257
def quote_string(self, value: str) -> str:
253258
"""
254259
Quote string literal for PostgreSQL with escaping.

src/datajoint/declare.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -294,12 +294,9 @@ def compile_foreign_key(
294294
# ref.support[0] may have cached quoting from a different backend
295295
# Extract database and table name and rebuild with current adapter
296296
parent_full_name = ref.support[0]
297-
# Try to parse as database.table (with or without quotes)
298-
parts = parent_full_name.replace('"', "").replace("`", "").split(".")
299-
if len(parts) == 2:
300-
ref_table_name = f"{adapter.quote_identifier(parts[0])}.{adapter.quote_identifier(parts[1])}"
301-
else:
302-
ref_table_name = adapter.quote_identifier(parts[0])
297+
# Parse as database.table using the adapter's quoting convention
298+
parts = adapter.split_full_table_name(parent_full_name)
299+
ref_table_name = f"{adapter.quote_identifier(parts[0])}.{adapter.quote_identifier(parts[1])}"
303300

304301
foreign_key_sql.append(
305302
f"FOREIGN KEY ({fk_cols}) REFERENCES {ref_table_name} ({pk_cols}) ON UPDATE CASCADE ON DELETE RESTRICT"

src/datajoint/schemas.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,7 @@ def save(self, python_filename: str | None = None) -> str:
549549

550550
def make_class_definition(table):
551551
tier = _get_tier(table).__name__
552-
class_name = table.split(".")[1].strip("`")
552+
class_name = self.connection.adapter.split_full_table_name(table)[1]
553553
indent = ""
554554
if tier == "Part":
555555
class_name = class_name.split("__")[-1]
@@ -608,7 +608,10 @@ def list_tables(self) -> list[str]:
608608
self.connection.dependencies.load()
609609
return [
610610
t
611-
for d, t in (table_name.replace("`", "").split(".") for table_name in self.connection.dependencies.topo_sort())
611+
for d, t in (
612+
self.connection.adapter.split_full_table_name(table_name)
613+
for table_name in self.connection.dependencies.topo_sort()
614+
)
612615
if d == self.database
613616
]
614617

src/datajoint/table.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -233,12 +233,7 @@ def _populate_lineage(self, primary_key, fk_attribute_map):
233233
# FK attributes: copy lineage from parent (whether in PK or not)
234234
for attr, (parent_table, parent_attr) in fk_attribute_map.items():
235235
# Parse parent table name: `schema`.`table` or "schema"."table" -> (schema, table)
236-
parent_clean = parent_table.replace("`", "").replace('"', "")
237-
if "." in parent_clean:
238-
parent_db, parent_tbl = parent_clean.split(".", 1)
239-
else:
240-
parent_db = self.database
241-
parent_tbl = parent_clean
236+
parent_db, parent_tbl = self.connection.adapter.split_full_table_name(parent_table)
242237

243238
# Get parent's lineage for this attribute
244239
parent_lineage = get_lineage(self.connection, parent_db, parent_tbl, parent_attr)

0 commit comments

Comments
 (0)