diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fbad4fe2..cd0c47c1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - #733 skip directories with perm error when building autoimport index (@MrBago) - #722, #723 Remove site-packages from packages search tree (@tkrabel) - #738 Implement os.PathLike on Resource (@lieryan) +- #739, #736 Ensure autoimport requests uses indexes (@lieryan) # Release 1.11.0 diff --git a/rope/contrib/autoimport/models.py b/rope/contrib/autoimport/models.py index 817a51ae7..d0acdca48 100644 --- a/rope/contrib/autoimport/models.py +++ b/rope/contrib/autoimport/models.py @@ -9,6 +9,9 @@ def __init__(self, query): def __repr__(self): return f'{self.__class__.__name__}("{self._query}")' + def explain(self): + return FinalQuery("EXPLAIN QUERY PLAN " + self._query) + class Query: def __init__(self, query: str, columns: List[str]): @@ -100,9 +103,14 @@ class Name(Model): @classmethod def create_table(cls, connection): super().create_table(connection) - connection.execute("CREATE INDEX IF NOT EXISTS name ON names(name)") - connection.execute("CREATE INDEX IF NOT EXISTS module ON names(module)") - connection.execute("CREATE INDEX IF NOT EXISTS package ON names(package)") + # fmt: off + connection.execute("CREATE INDEX IF NOT EXISTS names_name ON names(name)") + connection.execute("CREATE INDEX IF NOT EXISTS names_module ON names(module)") + connection.execute("CREATE INDEX IF NOT EXISTS names_package ON names(package)") + connection.execute("CREATE INDEX IF NOT EXISTS names_name_nocase ON names(name COLLATE NOCASE)") + connection.execute("CREATE INDEX IF NOT EXISTS names_module_nocase ON names(module COLLATE NOCASE)") + connection.execute("CREATE INDEX IF NOT EXISTS names_package_nocase ON names(package COLLATE NOCASE)") + # fmt: on search_submodule_like = objects.where('module LIKE ("%." || ?)') search_module_like = objects.where("module LIKE (?)") diff --git a/ropetest/contrib/autoimport/autoimporttest.py b/ropetest/contrib/autoimport/autoimporttest.py index d8bbd87ee..072ab1ed8 100644 --- a/ropetest/contrib/autoimport/autoimporttest.py +++ b/ropetest/contrib/autoimport/autoimporttest.py @@ -186,3 +186,39 @@ def test_setup_db_metadata_table_is_current(autoimport): with assert_database_is_preserved(conn), \ patch("rope.base.versioning.calculate_version_hash", return_value="up-to-date-value"): autoimport._setup_db() + + +class TestQueryUsesIndexes: + def explain(self, autoimport, query): + explanation = list(autoimport._execute(query.explain(), ("abc",)))[0][-1] + # the explanation text varies, on some sqlite version + explanation = explanation.replace("TABLE ", "") + return explanation + + def test_search_by_name_uses_index(self, autoimport): + query = models.Name.search_by_name.select_star() + assert ( + self.explain(autoimport, query) + == "SEARCH names USING INDEX names_name (name=?)" + ) + + def test_search_by_name_like_uses_index(self, autoimport): + query = models.Name.search_by_name_like.select_star() + assert ( + self.explain(autoimport, query) + == "SEARCH names USING INDEX names_name_nocase (name>? AND name? AND module