diff --git a/CHANGELOG.md b/CHANGELOG.md index d1ec8e5..15fefc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ -## 4.0.0 +## 4.0.0 (unreleased) - Drop support for Python 2.7 and 3.5 - Drop support for Django 1.11, 2.0, 2.1, 3.0 +- Fix index creation detection when table is being created in the transaction (issue #178) ## 3.0.1 diff --git a/django_migration_linter/sql_analyser/postgresql.py b/django_migration_linter/sql_analyser/postgresql.py index 140aba3..3eb18a5 100644 --- a/django_migration_linter/sql_analyser/postgresql.py +++ b/django_migration_linter/sql_analyser/postgresql.py @@ -3,14 +3,32 @@ import re from .base import BaseAnalyser +def has_create_index(sql_statements, **kwargs): + regex_result = None + for sql in sql_statements: + regex_result = re.search(r"CREATE (UNIQUE )?INDEX.*ON (.*) \(", sql) + if re.search("INDEX CONCURRENTLY", sql): + regex_result = None + elif regex_result: + break + if not regex_result: + return False + + concerned_table = regex_result.group(2) + table_is_added_in_transaction = any( + sql.startswith("CREATE TABLE {}".format(concerned_table)) + for sql in sql_statements + ) + return not table_is_added_in_transaction + + class PostgresqlAnalyser(BaseAnalyser): migration_tests = [ { "code": "CREATE_INDEX", - "fn": lambda sql, **kw: re.search("CREATE (UNIQUE )?INDEX", sql) - and not re.search("INDEX CONCURRENTLY", sql), + "fn": has_create_index, "msg": "CREATE INDEX locks table", - "mode": "one_liner", + "mode": "transaction", "type": "warning", }, { diff --git a/tests/unit/test_sql_analyser.py b/tests/unit/test_sql_analyser.py index 00dd50e..65ab7f0 100644 --- a/tests/unit/test_sql_analyser.py +++ b/tests/unit/test_sql_analyser.py @@ -233,6 +233,23 @@ class PostgresqlAnalyserTestCase(SqlAnalyserTestCase): sql = "CREATE UNIQUE INDEX title_idx ON films (title);" self.assertWarningSql(sql) + def test_create_index_non_concurrently_with_table_creation(self): + sql = [ + 'CREATE TABLE "films" ("title" text);', + 'CREATE INDEX ON "films" ((lower("title")));', + ] + self.assertValidSql(sql) + sql = [ + 'CREATE TABLE "some_table" ("title" text);', + 'CREATE INDEX ON "films" ((lower("title")));', + ] + self.assertWarningSql(sql) + sql = [ + 'CREATE TABLE "films" ("title" text);', + 'CREATE INDEX ON "some_table" ((lower("title")));', + ] + self.assertWarningSql(sql) + def test_create_index_concurrently(self): sql = "CREATE INDEX CONCURRENTLY ON films (lower(title));" self.assertValidSql(sql)