From 4dc2e2e9c8f1e879941118a9bcba65bb9d8e82b7 Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Sat, 23 Nov 2024 14:27:21 -0800 Subject: [PATCH] Use REAL for floating point columns if table is strict, closes #644 Refs #645 --- docs/python-api.rst | 3 +++ sqlite_utils/db.py | 7 ++++++- tests/test_cli.py | 4 +++- tests/test_create.py | 6 +++++- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/docs/python-api.rst b/docs/python-api.rst index 4b8e4e5d..7b11c225 100644 --- a/docs/python-api.rst +++ b/docs/python-api.rst @@ -1249,6 +1249,9 @@ If you pass a Python type, it will be mapped to SQLite types as shown here:: np.float32: "FLOAT" np.float64: "FLOAT" +.. note:: + In sqlite-utils 3.x ``FLOAT`` is used for floating point columns when the correct column type is actually ``REAL``. If you specify ``strict=True`` tables created in strict mode will use the correct column type of ``REAL`` instead. We plan to change this behavior in ``sqlite-utils`` 4.x to always use ``REAL``, but this will represent a minor breaking change and so is being held for the next major release, see issue :issue:`645`. + You can also add a column that is a foreign key reference to another table using the ``fk`` parameter: .. code-block:: python diff --git a/sqlite_utils/db.py b/sqlite_utils/db.py index 51987b83..ef8c40e6 100644 --- a/sqlite_utils/db.py +++ b/sqlite_utils/db.py @@ -938,10 +938,15 @@ def sort_key(p): other_column=foreign_keys_by_column[column_name].other_column, ) ) + column_type_str = COLUMN_TYPE_MAPPING[column_type] + # Special case for strict tables to map FLOAT to REAL + # Refs https://github.com/simonw/sqlite-utils/issues/644 + if strict and column_type_str == "FLOAT": + column_type_str = "REAL" column_defs.append( " [{column_name}] {column_type}{column_extras}".format( column_name=column_name, - column_type=COLUMN_TYPE_MAPPING[column_type], + column_type=column_type_str, column_extras=( (" " + " ".join(column_extras)) if column_extras else "" ), diff --git a/tests/test_cli.py b/tests/test_cli.py index bc04fd4a..4e564f13 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -2416,11 +2416,13 @@ def test_create_table_strict(strict): db = Database("test.db") result = runner.invoke( cli.cli, - ["create-table", "test.db", "items", "id", "integer"] + ["create-table", "test.db", "items", "id", "integer", "w", "float"] + (["--strict"] if strict else []), ) assert result.exit_code == 0 assert db["items"].strict == strict or not db.supports_strict + # Should have a floating point column + assert db["items"].columns_dict == {"id": int, "w": float} @pytest.mark.parametrize("method", ("insert", "upsert")) diff --git a/tests/test_create.py b/tests/test_create.py index 3bf1004a..9d8d038c 100644 --- a/tests/test_create.py +++ b/tests/test_create.py @@ -1350,8 +1350,12 @@ def test_insert_upsert_strict(fresh_db, method_name, strict): @pytest.mark.parametrize("strict", (False, True)) def test_create_table_strict(fresh_db, strict): - table = fresh_db.create_table("t", {"id": int}, strict=strict) + table = fresh_db.create_table("t", {"id": int, "f": float}, strict=strict) assert table.strict == strict or not fresh_db.supports_strict + expected_schema = "CREATE TABLE [t] (\n" " [id] INTEGER,\n" " [f] FLOAT\n" ")" + if strict: + expected_schema = "CREATE TABLE [t] (\n [id] INTEGER,\n [f] REAL\n) STRICT" + assert table.schema == expected_schema @pytest.mark.parametrize("strict", (False, True))