Use ON CONFLICT for upsert, refs #652

* New upsert implementation, refs #652
* supports_strict now caches on self._supports_strict

PR: https://github.com/simonw/sqlite-utils/pull/653
This commit is contained in:
Simon Willison 2025-05-08 20:37:49 -07:00 committed by GitHub
commit 8e7d018fa2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 209 additions and 110 deletions

View file

@ -1116,11 +1116,8 @@ def test_upsert_alter(db_path, tmpdir):
cli.cli, ["upsert", db_path, "dogs", json_path, "--pk", "id"]
)
assert result.exit_code == 1
assert (
"Error: no such column: age\n\n"
"sql = UPDATE [dogs] SET [age] = ? WHERE [id] = ?\n"
"parameters = [5, 1]"
) == result.output.strip()
# Could be one of two errors depending on SQLite version
assert ("Try using --alter to add additional columns") in result.output.strip()
# Should succeed with --alter
result = CliRunner().invoke(
cli.cli, ["upsert", db_path, "dogs", json_path, "--pk", "id", "--alter"]
@ -2248,7 +2245,7 @@ def test_integer_overflow_error(tmpdir):
assert result.exit_code == 1
assert result.output == (
"Error: Python int too large to convert to SQLite INTEGER\n\n"
"sql = INSERT INTO [items] ([bignumber]) VALUES (?);\n"
"sql = INSERT INTO [items] ([bignumber]) VALUES (?)\n"
"parameters = [34223049823094832094802398430298048240]\n"
)

View file

@ -173,14 +173,16 @@ def test_create_table_from_example_with_compound_primary_keys(fresh_db):
@pytest.mark.parametrize(
"method_name", ("insert", "upsert", "insert_all", "upsert_all")
)
def test_create_table_with_custom_columns(fresh_db, method_name):
table = fresh_db["dogs"]
@pytest.mark.parametrize("use_old_upsert", (False, True))
def test_create_table_with_custom_columns(method_name, use_old_upsert):
db = Database(memory=True, use_old_upsert=use_old_upsert)
table = db["dogs"]
method = getattr(table, method_name)
record = {"id": 1, "name": "Cleo", "age": "5"}
if method_name.endswith("_all"):
record = [record]
method(record, pk="id", columns={"age": int, "weight": float})
assert ["dogs"] == fresh_db.table_names()
assert ["dogs"] == db.table_names()
expected_columns = [
{"name": "id", "type": "INTEGER"},
{"name": "name", "type": "TEXT"},

View file

@ -18,7 +18,7 @@ def test_tracer():
("select name from sqlite_master where type = 'view'", None),
("CREATE TABLE [dogs] (\n [name] TEXT\n);\n ", None),
("select name from sqlite_master where type = 'view'", None),
("INSERT INTO [dogs] ([name]) VALUES (?);", ["Cleopaws"]),
("INSERT INTO [dogs] ([name]) VALUES (?)", ["Cleopaws"]),
("select name from sqlite_master where type = 'view'", None),
(
"CREATE VIRTUAL TABLE [dogs_fts] USING FTS5 (\n [name],\n content=[dogs]\n)",

View file

@ -1,9 +1,12 @@
from sqlite_utils.db import PrimaryKeyRequired
from sqlite_utils import Database
import pytest
def test_upsert(fresh_db):
table = fresh_db["table"]
@pytest.mark.parametrize("use_old_upsert", (False, True))
def test_upsert(use_old_upsert):
db = Database(memory=True, use_old_upsert=use_old_upsert)
table = db["table"]
table.insert({"id": 1, "name": "Cleo"}, pk="id")
table.upsert({"id": 1, "age": 5}, pk="id", alter=True)
assert list(table.rows) == [{"id": 1, "name": "Cleo", "age": 5}]