Skip to content

Commit

Permalink
Merge pull request #422 from mesozoic/populate_with_field_ids
Browse files Browse the repository at this point in the history
Model.from_ids should respect Meta.use_field_ids
  • Loading branch information
mesozoic authored Feb 22, 2025
2 parents eb1c815 + 608f855 commit 9c1a575
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 6 deletions.
5 changes: 1 addition & 4 deletions pyairtable/orm/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -449,10 +449,7 @@ def from_ids(
# Only retrieve records that aren't already memoized
formula = OR(EQ(RECORD_ID(), record_id) for record_id in sorted(remaining))
by_id.update(
{
record["id"]: cls.from_record(record, memoize=memoize)
for record in cls.meta.table.all(formula=formula)
}
{obj.id: obj for obj in cls.all(formula=formula, memoize=memoize)}
)

# Ensure we return records in the same order, and raise KeyError if any are missing
Expand Down
33 changes: 32 additions & 1 deletion tests/test_orm_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -877,7 +877,10 @@ class Book(Model):
book = Book.from_record(fake_record(Author=[a1, a2, a3]))
with mock.patch("pyairtable.Table.all", return_value=records) as m:
book.author
m.assert_called_once_with(formula=OR(RECORD_ID().eq(records[0]["id"])))
m.assert_called_once_with(
**Book.meta.request_kwargs,
formula=OR(RECORD_ID().eq(records[0]["id"])),
)

assert book.author.id == a1
assert book.author.name == "Author 1"
Expand Down Expand Up @@ -956,6 +959,34 @@ class T(Model):
T.link.populate(Linked())


@pytest.mark.parametrize("field_type", (f.LinkField, f.SingleLinkField))
def test_link_field__populate_with_field_ids(field_type, requests_mock):
"""
Test that implementers can use Model.link_field.populate(instance)
when the linked model uses field IDs rather than field names.
"""
field_id = fake_id("fld")
record_ids = [fake_id("rec", n) for n in range(3)]
records = [
fake_record(id=record_id, Name=f"link{n}")
for n, record_id in enumerate(record_ids)
]

class Linked(Model):
Meta = fake_meta(use_field_ids=True)
name = f.TextField(field_id)

class T(Model):
Meta = fake_meta()
link = field_type("Link", Linked)

m = requests_mock.get(Linked.meta.table.urls.records, json={"records": records})
obj = T.from_record(fake_record(Link=record_ids))
obj.link
assert m.call_count == 1
assert m.last_request.qs.get("returnFieldsByFieldId") == ["1"]


def test_lookup_field():
class T:
items = f.LookupField("Items")
Expand Down
12 changes: 11 additions & 1 deletion tests/test_orm_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,9 +227,10 @@ def test_from_ids(mock_api):
url=FakeModel.meta.table.urls.records,
fallback=("post", FakeModel.meta.table.urls.records_post),
options={
**FakeModel.meta.request_kwargs,
"formula": (
"OR(%s)" % ", ".join(f"RECORD_ID()='{id}'" for id in sorted(fake_ids))
)
),
},
)
assert len(contacts) == len(fake_records)
Expand All @@ -253,6 +254,15 @@ def test_from_ids__no_fetch(mock_all):
assert set(contact.id for contact in contacts) == set(fake_ids)


@mock.patch("pyairtable.Table.all")
def test_from_ids__use_field_ids(mock_all):
fake_ids = [fake_id() for _ in range(10)]
mock_all.return_value = [fake_record(id=id) for id in fake_ids]
FakeModelByIds.from_ids(fake_ids)
assert mock_all.call_count == 1
assert mock_all.mock_calls[-1].kwargs["use_field_ids"] is True


@pytest.mark.parametrize(
"methodname,returns",
(
Expand Down

0 comments on commit 9c1a575

Please sign in to comment.