Use existing m2m table if one exists

This commit is contained in:
Simon Willison 2019-08-03 21:15:16 +03:00
commit d96a8f149e
2 changed files with 45 additions and 5 deletions

View file

@ -1069,7 +1069,22 @@ class Table:
assert record_or_list is not None, "Provide lookup= or record, not both"
tables = list(sorted([self.name, other_table]))
columns = ["{}_id".format(t) for t in tables]
m2m_table_name = m2m_table or "{}_{}".format(*tables)
if m2m_table is not None:
m2m_table_name = m2m_table
else:
# Detect if there is a single, unambiguous option
candidates = self.db.m2m_table_candidates(self.name, other_table)
if len(candidates) == 1:
m2m_table_name = candidates[0]
elif len(candidates) > 1:
raise NoObviousTable(
"No single obvious m2m table for {}, {} - use m2m_table= parameter".format(
self.name, other_table
)
)
else:
# If not, create a new table
m2m_table_name = m2m_table or "{}_{}".format(*tables)
m2m_table = self.db.table(m2m_table_name, pk=columns, foreign_keys=columns)
if lookup is None:
records = (

View file

@ -1,4 +1,4 @@
from sqlite_utils.db import ForeignKey
from sqlite_utils.db import ForeignKey, NoObviousTable
import pytest
@ -107,12 +107,37 @@ def test_m2m_table_candidates(fresh_db):
def test_uses_existing_m2m_table_if_exists(fresh_db):
# Code should look for an existing toble with fks to both tables
# Code should look for an existing table with fks to both tables
# and use that if it exists.
assert False
people = fresh_db.create_table("people", {"id": int, "name": str}, pk="id")
fresh_db["tags"].lookup({"tag": "Coworker"})
fresh_db.create_table(
"tagged",
{"people_id": int, "tags_id": int},
foreign_keys=["people_id", "tags_id"],
)
people.insert({"name": "Wahyu"}).m2m("tags", lookup={"tag": "Coworker"})
assert fresh_db["tags"].exists
assert fresh_db["tagged"].exists
assert not fresh_db["people_tags"].exists
assert not fresh_db["tags_people"].exists
assert [{"people_id": 1, "tags_id": 1}] == list(fresh_db["tagged"].rows)
def test_requires_explicit_m2m_table_if_multiple_options(fresh_db):
# If the code scans for m2m tables and finds more than one candidate
# it should require that the m2m_table=x argument is used
assert False
people = fresh_db.create_table("people", {"id": int, "name": str}, pk="id")
fresh_db["tags"].lookup({"tag": "Coworker"})
fresh_db.create_table(
"tagged",
{"people_id": int, "tags_id": int},
foreign_keys=["people_id", "tags_id"],
)
fresh_db.create_table(
"tagged2",
{"people_id": int, "tags_id": int},
foreign_keys=["people_id", "tags_id"],
)
with pytest.raises(NoObviousTable):
people.insert({"name": "Wahyu"}).m2m("tags", lookup={"tag": "Coworker"})