From d978a391ac2c3de5fa150ad30c1f86528ae78803 Mon Sep 17 00:00:00 2001 From: 72004 Date: Sun, 11 Oct 2026 22:24:09 +0500 Subject: [PATCH] enable_fts(): materialize columns so a one-shot iterator works --- sqlite_utils/db.py | 3 +++ tests/test_fts.py | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/sqlite_utils/db.py b/sqlite_utils/db.py index c011d9bb0..e63b36412 100644 --- a/sqlite_utils/db.py +++ b/sqlite_utils/db.py @@ -3770,6 +3770,9 @@ def enable_fts( :param tokenize: Custom SQLite tokenizer to use, for example ``"porter"`` to enable Porter stemming. :param replace: Should any existing FTS index for this table be replaced by the new one? """ + # columns is used several times below, so a one-shot iterator + # would be exhausted after the CREATE VIRTUAL TABLE statement + columns = list(columns) create_fts_sql = ( textwrap.dedent(""" CREATE VIRTUAL TABLE {table_fts} USING {fts_version} ( diff --git a/tests/test_fts.py b/tests/test_fts.py index 04b5bc31f..dbbe75b98 100644 --- a/tests/test_fts.py +++ b/tests/test_fts.py @@ -51,6 +51,19 @@ def test_enable_fts(fresh_db): assert [] == list(table.search("bar")) +@pytest.mark.parametrize("create_triggers", [True, False]) +def test_enable_fts_columns_iterator(fresh_db, create_triggers): + # columns is typed Iterable[str], so a one-shot iterator has to work + table = fresh_db.table("searchable") + table.insert_all(search_records) + table.enable_fts(iter(["text", "country"]), create_triggers=create_triggers) + assert [row["rowid"] for row in table.search("tanuki")] == [1] + assert [row["rowid"] for row in table.search("usa")] == [2] + if create_triggers: + table.insert({"text": "kitsune", "country": "Japan", "not_searchable": "x"}) + assert [row["rowid"] for row in table.search("kitsune")] == [3] + + def test_enable_fts_escape_table_names(fresh_db): # Table names with restricted chars are handled correctly. # colons and dots are restricted characters for table names.