mirror of
https://github.com/lancedb/lancedb.git
synced 2026-08-18 12:08:35 +00:00
fix: when_not_matched_by_source_delete() doesn't reset a previously-set condition (#3771)
## Summary `LanceMergeInsertBuilder.when_not_matched_by_source_delete()` didn't clear a previously-set condition when called again with no argument (or a different condition type). Per the docstring, `condition=None` means "delete all unmatched rows," but if the builder had already been configured with a string/Expr condition, a later no-arg call left the stale condition in place instead of widening the delete to unconditional. Fixes #3767 ## Change Each call now unconditionally sets both `_when_not_matched_by_source_condition` and `_when_not_matched_by_source_condition_expr` (one to the new value, the other to `None`), so the latest call always wins — consistent with every other setter on this builder (e.g. `when_matched_update_all(where=...)`). ## Test plan - [x] New regression test `test_merge_insert_by_source_delete_reconfigure` in `python/python/tests/test_table.py` - [x] `uv run --extra tests pytest python/tests/test_table.py::test_merge_insert_by_source_delete_reconfigure python/tests/test_table.py::test_merge_insert_by_source_delete_expr python/tests/test_table.py::test_merge_insert_by_source_delete_expr_async -vv` — 3 passed - [x] `uv run --extra dev ruff format` / `ruff check` — clean Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -92,8 +92,10 @@ class LanceMergeInsertBuilder(object):
|
||||
self._when_not_matched_by_source_delete = True
|
||||
if isinstance(condition, Expr):
|
||||
self._when_not_matched_by_source_condition_expr = condition._inner
|
||||
elif condition is not None:
|
||||
self._when_not_matched_by_source_condition = None
|
||||
else:
|
||||
self._when_not_matched_by_source_condition = condition
|
||||
self._when_not_matched_by_source_condition_expr = None
|
||||
return self
|
||||
|
||||
def use_index(self, use_index: bool) -> LanceMergeInsertBuilder:
|
||||
|
||||
@@ -2364,6 +2364,29 @@ def test_merge_insert_by_source_delete_expr(mem_db: DBConnection):
|
||||
assert table.to_arrow().sort_by("a") == expected
|
||||
|
||||
|
||||
def test_merge_insert_by_source_delete_reconfigure(mem_db: DBConnection):
|
||||
# Calling when_not_matched_by_source_delete() again with no condition must
|
||||
# widen the delete to unconditional, not keep the earlier condition around.
|
||||
table = mem_db.create_table(
|
||||
"my_table",
|
||||
data=pa.table({"a": [1, 2, 3], "b": ["a", "b", "c"]}),
|
||||
)
|
||||
new_data = pa.table({"a": [2, 4], "b": ["x", "z"]})
|
||||
|
||||
merge_insert_res = (
|
||||
table.merge_insert("a")
|
||||
.when_matched_update_all()
|
||||
.when_not_matched_insert_all()
|
||||
.when_not_matched_by_source_delete("a > 2")
|
||||
.when_not_matched_by_source_delete()
|
||||
.execute(new_data)
|
||||
)
|
||||
assert merge_insert_res.num_deleted_rows == 2
|
||||
|
||||
expected = pa.table({"a": [2, 4], "b": ["x", "z"]})
|
||||
assert table.to_arrow().sort_by("a") == expected
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_merge_insert_by_source_delete_expr_async(
|
||||
mem_db_async: AsyncConnection,
|
||||
|
||||
Reference in New Issue
Block a user