# Generated by Django 3.2.4 on 2021-07-12 22:49
# Renamed and updated to remove from Wagtail on 2025-03-24

from django.db import connection, migrations, models

from modelsearch.models import IndexEntry


# This migration takes on the base model defined in 0001_initial and adds certain fields that are specific to each database system
class Migration(migrations.Migration):
    dependencies = [
        ("modelsearch", "0001_initial"),
    ]

    if connection.vendor == "postgresql":
        import django.contrib.postgres.indexes
        import django.contrib.postgres.search

        operations = [
            migrations.AddField(
                model_name="indexentry",
                name="autocomplete",
                field=django.contrib.postgres.search.SearchVectorField(),
            ),
            migrations.AddField(
                model_name="indexentry",
                name="title",
                field=django.contrib.postgres.search.SearchVectorField(),
            ),
            migrations.AddField(
                model_name="indexentry",
                name="body",
                field=django.contrib.postgres.search.SearchVectorField(),
            ),
            migrations.AddIndex(
                model_name="indexentry",
                index=django.contrib.postgres.indexes.GinIndex(
                    fields=["autocomplete"], name="modelsear_autocom_476c89_gin"
                ),
            ),
            migrations.AddIndex(
                model_name="indexentry",
                index=django.contrib.postgres.indexes.GinIndex(
                    fields=["title"], name="modelsear_title_9caae0_gin"
                ),
            ),
            migrations.AddIndex(
                model_name="indexentry",
                index=django.contrib.postgres.indexes.GinIndex(
                    fields=["body"], name="modelsear_body_90c85d_gin"
                ),
            ),
        ]

    elif connection.vendor == "sqlite":
        from modelsearch.backends.database.sqlite.utils import fts5_available

        operations = [
            migrations.AddField(
                model_name="indexentry",
                name="autocomplete",
                field=models.TextField(null=True),
            ),
            migrations.AddField(
                model_name="indexentry",
                name="body",
                field=models.TextField(null=True),
            ),
            migrations.AddField(
                model_name="indexentry",
                name="title",
                field=models.TextField(),
            ),
        ]

        if fts5_available():
            operations.append(
                migrations.SeparateDatabaseAndState(
                    state_operations=[
                        migrations.CreateModel(
                            name="sqliteftsindexentry",
                            fields=[
                                (
                                    "index_entry",
                                    models.OneToOneField(
                                        primary_key=True,
                                        serialize=False,
                                        to="modelsearch.indexentry",
                                        on_delete=models.CASCADE,
                                        db_column="rowid",
                                    ),
                                ),
                                ("title", models.TextField()),
                                ("body", models.TextField(null=True)),
                                ("autocomplete", models.TextField(null=True)),
                            ],
                            options={"db_table": f"{IndexEntry._meta.db_table}_fts"},
                        ),
                    ],
                    database_operations=[
                        migrations.RunSQL(
                            sql=(
                                f"CREATE VIRTUAL TABLE {IndexEntry._meta.db_table}_fts USING fts5(autocomplete, body, title)"
                            ),
                            reverse_sql=(
                                f"DROP TABLE IF EXISTS {IndexEntry._meta.db_table}_fts"
                            ),
                        ),
                        migrations.RunSQL(
                            sql=(
                                f"CREATE TRIGGER insert_modelsearch_indexentry_fts AFTER INSERT ON {IndexEntry._meta.db_table} BEGIN INSERT INTO {IndexEntry._meta.db_table}_fts(title, body, autocomplete, rowid) VALUES (NEW.title, NEW.body, NEW.autocomplete, NEW.id); END"  # NOQA: S608
                            ),
                            reverse_sql=(
                                "DROP TRIGGER IF EXISTS insert_modelsearch_indexentry_fts"
                            ),
                        ),
                        migrations.RunSQL(
                            sql=(
                                f"CREATE TRIGGER update_modelsearch_indexentry_fts AFTER UPDATE ON {IndexEntry._meta.db_table} BEGIN UPDATE {IndexEntry._meta.db_table}_fts SET title=NEW.title, body=NEW.body, autocomplete=NEW.autocomplete WHERE rowid=NEW.id; END"  # NOQA: S608
                            ),
                            reverse_sql=(
                                "DROP TRIGGER IF EXISTS update_modelsearch_indexentry_fts"
                            ),
                        ),
                        migrations.RunSQL(
                            sql=(
                                f"CREATE TRIGGER delete_modelsearch_indexentry_fts AFTER DELETE ON {IndexEntry._meta.db_table} BEGIN DELETE FROM {IndexEntry._meta.db_table}_fts WHERE rowid=OLD.id; END"  # NOQA: S608
                            ),
                            reverse_sql=(
                                "DROP TRIGGER IF EXISTS delete_modelsearch_indexentry_fts"
                            ),
                        ),
                    ],
                )
            )

    elif connection.vendor == "mysql":
        operations = [
            migrations.AddField(
                model_name="indexentry",
                name="autocomplete",
                field=models.TextField(null=True),
            ),
            migrations.AddField(
                model_name="indexentry",
                name="body",
                field=models.TextField(null=True),
            ),
            migrations.AddField(
                model_name="indexentry",
                name="title",
                field=models.TextField(default=""),
                preserve_default=False,
            ),
        ]

        # Create FULLTEXT indexes
        # We need to add these indexes manually because Django imposes an artificial limitation
        # that forces to specify the max length of the TextFields that get referenced by the
        # FULLTEXT index. If we do it manually, it works, because Django can't check that we are
        # defining a new index.
        operations.append(
            migrations.RunSQL(
                sql="""
                ALTER TABLE modelsearch_indexentry
                    ADD FULLTEXT INDEX `fulltext_body` (`body`)
                """,
                reverse_sql="""
                ALTER TABLE modelsearch_indexentry
                    DROP INDEX `fulltext_body`
                """,
            )
        )

        # We create two separate FULLTEXT indexes for the 'body' and 'title' columns, so that we are able to handle them separately afterwards.
        # We handle them separately, for example, when we do scoring: there, we multiply the 'title' score by the value of the 'title_norm' column. This can't be done if we index 'title' and 'body' in the same index, because MySQL doesn't allow to search on subparts of a defined index (we need to search all the columns of the index at the same time).
        operations.append(
            migrations.RunSQL(
                sql="""
                ALTER TABLE modelsearch_indexentry
                    ADD FULLTEXT INDEX `fulltext_title` (`title`)
                """,
                reverse_sql="""
                ALTER TABLE modelsearch_indexentry
                    DROP INDEX `fulltext_title`
                """,
            )
        )

        # We also need to create a joint index on 'title' and 'body', to be able to query both at the same time. If we don't have this, some queries may return wrong results. For example, if we match 'A AND (NOT B)' against 'A, B', it returns false, but if we do (match 'A AND (NOT B)' against 'A') or (match 'A AND (NOT B)' against 'B'), the first one would return True, and the whole expression would be True (wrong result). That's the same as saying that testing subsets does not necessarily produce the same result as testing the whole set.
        operations.append(
            migrations.RunSQL(
                sql="""
                ALTER TABLE modelsearch_indexentry
                    ADD FULLTEXT INDEX `fulltext_title_body` (`title`, `body`)
                """,
                reverse_sql="""
                ALTER TABLE modelsearch_indexentry
                    DROP INDEX `fulltext_title_body`
                """,
            )
        )

        operations.append(
            migrations.RunSQL(
                sql="""
                ALTER TABLE modelsearch_indexentry
                    ADD FULLTEXT INDEX `fulltext_autocomplete` (`autocomplete`)
                """,
                reverse_sql="""
                ALTER TABLE modelsearch_indexentry
                    DROP INDEX `fulltext_autocomplete`
                """,
            )
        )
