# Path: tests/compat.py
# def wrap_testdata(func):
#     return func
# 
# Path: tests/testapp/models.py
# class Author(Model):
#     name = CharField(max_length=32, db_index=True)
#     tutor = ForeignKey("self", on_delete=CASCADE, null=True, related_name="tutees")
#     bio = TextField()
#     birthday = DateTimeField(null=True)
#     deathday = DateTimeField(null=True)
# 
# class AuthorExtra(Model):
#     author = OneToOneField(Author, on_delete=CASCADE, primary_key=True)
#     legs = IntegerField(default=2)
# 
# class AuthorMultiIndex(Model):
#     class Meta:
#         index_together = ("name", "country")
# 
#     name = CharField(max_length=32, db_index=True)
#     country = CharField(max_length=32)
# 
# class Book(Model):
#     title = CharField(max_length=32, db_index=True)
#     author = ForeignKey(Author, on_delete=CASCADE, related_name="books")
# 
# class NameAuthor(Model):
#     name = CharField(max_length=32, primary_key=True)
# 
# class NameAuthorExtra(Model):
#     name = OneToOneField(NameAuthor, on_delete=CASCADE, primary_key=True)
# 
# class VanillaAuthor(VanillaModel):
#     name = CharField(max_length=32)
# 
# Path: tests/testapp/utils.py
# class CaptureLastQuery:
#     def __init__(self, conn=None):
#         if conn is None:  # pragma: no branch
#             conn = connection
#         self.conn = conn
# 
#     def __enter__(self):
#         self.capturer = CaptureQueriesContext(self.conn)
#         self.capturer.__enter__()
#         return self
# 
#     def __exit__(self, a, b, c):
#         self.capturer.__exit__(a, b, c)
# 
#     @property
#     def query(self):
#         return self.capturer.captured_queries[-1]["sql"]
# 
# @contextmanager
# def skip_if_mysql_8_plus():
#     if not connection_is_mariadb(connection) and connection.mysql_version >= (8,):
#         pytest.skip("Requires MySQL<8 or MariaDB")
#     yield
# 
# def used_indexes(query, using=DEFAULT_DB_ALIAS):
#     """
#     Given SQL 'query', run EXPLAIN and return the names of the indexes used
#     """
#     connection = connections[using]
#     with connection.cursor() as cursor:
#         cursor.execute("EXPLAIN " + query)
# 
#         return {row["key"] for row in fetchall_dicts(cursor) if row["key"] is not None}


import pickle
import re
import pytest
from unittest import mock, skipUnless
from django.contrib.contenttypes.models import ContentType
from django.db import DEFAULT_DB_ALIAS, connections
from django.db.models import Exists, OuterRef
from django.db.models.query import QuerySet
from django.template import Context, Template
from django.test import TestCase
from django.test.utils import captured_stdout, override_settings
from django_mysql.models import ApproximateInt, SmartIterator, add_QuerySetMixin
from django_mysql.utils import have_program, index_name
from tests.compat import wrap_testdata
from tests.testapp.models import (
    Author,
    AuthorExtra,
    AuthorMultiIndex,
    Book,
    NameAuthor,
    NameAuthorExtra,
    VanillaAuthor,
)
from tests.testapp.utils import CaptureLastQuery, skip_if_mysql_8_plus, used_indexes
    def test_force_index_at_least_one(self):
        with pytest.raises(ValueError) as excinfo:
            Author.objects.force_index()
        assert str(excinfo.value) == "force_index requires at least one index name"

    def test_force_index_invalid_for(self):
        with pytest.raises(ValueError) as excinfo:
            Author.objects.force_index("a", for_="INVALID")
        assert "for_ must be one of" in str(excinfo.value)

    def test_index_hint_force_order_by(self):
        name_idx = index_name(Author, "name")
        with CaptureLastQuery() as cap:
            list(Author.objects.force_index(name_idx, for_="ORDER BY").order_by("name"))

        assert ("FORCE INDEX FOR ORDER BY (`" + name_idx + "`)") in cap.query
        assert name_idx in used_indexes(cap.query)

    def test_use_index_none(self):
        with CaptureLastQuery() as cap:
            list(Author.objects.values_list("name").distinct().use_index())
        assert "USE INDEX () " in cap.query
        assert used_indexes(cap.query) == set()

    def test_use_index_table_name(self):
        extra_table = "testapp_authorextra"
        with CaptureLastQuery() as cap:
            list(
                Author.objects.select_related("authorextra").use_index(
                    "PRIMARY", table_name=extra_table

# Path: tests/compat.py
# def wrap_testdata(func):
#     return func
# 
# Path: tests/testapp/models.py
# class Author(Model):
#     name = CharField(max_length=32, db_index=True)
#     tutor = ForeignKey("self", on_delete=CASCADE, null=True, related_name="tutees")
#     bio = TextField()
#     birthday = DateTimeField(null=True)
#     deathday = DateTimeField(null=True)
# 
# class AuthorExtra(Model):
#     author = OneToOneField(Author, on_delete=CASCADE, primary_key=True)
#     legs = IntegerField(default=2)
# 
# class AuthorMultiIndex(Model):
#     class Meta:
#         index_together = ("name", "country")
# 
#     name = CharField(max_length=32, db_index=True)
#     country = CharField(max_length=32)
# 
# class Book(Model):
#     title = CharField(max_length=32, db_index=True)
#     author = ForeignKey(Author, on_delete=CASCADE, related_name="books")
# 
# class NameAuthor(Model):
#     name = CharField(max_length=32, primary_key=True)
# 
# class NameAuthorExtra(Model):
#     name = OneToOneField(NameAuthor, on_delete=CASCADE, primary_key=True)
# 
# class VanillaAuthor(VanillaModel):
#     name = CharField(max_length=32)
# 
# Path: tests/testapp/utils.py
# class CaptureLastQuery:
#     def __init__(self, conn=None):
#         if conn is None:  # pragma: no branch
#             conn = connection
#         self.conn = conn
# 
#     def __enter__(self):
#         self.capturer = CaptureQueriesContext(self.conn)
#         self.capturer.__enter__()
#         return self
# 
#     def __exit__(self, a, b, c):
#         self.capturer.__exit__(a, b, c)
# 
#     @property
#     def query(self):
#         return self.capturer.captured_queries[-1]["sql"]
# 
# @contextmanager
# def skip_if_mysql_8_plus():
#     if not connection_is_mariadb(connection) and connection.mysql_version >= (8,):
#         pytest.skip("Requires MySQL<8 or MariaDB")
#     yield
# 
# def used_indexes(query, using=DEFAULT_DB_ALIAS):
#     """
#     Given SQL 'query', run EXPLAIN and return the names of the indexes used
#     """
#     connection = connections[using]
#     with connection.cursor() as cursor:
#         cursor.execute("EXPLAIN " + query)
# 
#         return {row["key"] for row in fetchall_dicts(cursor) if row["key"] is not None}


# Path: tests/testapp/test_models.py
import pickle
import re
import pytest
from unittest import mock, skipUnless
from django.contrib.contenttypes.models import ContentType
from django.db import DEFAULT_DB_ALIAS, connections
from django.db.models import Exists, OuterRef
from django.db.models.query import QuerySet
from django.template import Context, Template
from django.test import TestCase
from django.test.utils import captured_stdout, override_settings
from django_mysql.models import ApproximateInt, SmartIterator, add_QuerySetMixin
from django_mysql.utils import have_program, index_name
from tests.compat import wrap_testdata
from tests.testapp.models import (
    Author,
    AuthorExtra,
    AuthorMultiIndex,
    Book,
    NameAuthor,
    NameAuthorExtra,
    VanillaAuthor,
)
from tests.testapp.utils import CaptureLastQuery, skip_if_mysql_8_plus, used_indexes

    def test_force_index_at_least_one(self):
        with pytest.raises(ValueError) as excinfo:
            Author.objects.force_index()
        assert str(excinfo.value) == "force_index requires at least one index name"

    def test_force_index_invalid_for(self):
        with pytest.raises(ValueError) as excinfo:
            Author.objects.force_index("a", for_="INVALID")
        assert "for_ must be one of" in str(excinfo.value)

    def test_index_hint_force_order_by(self):
        name_idx = index_name(Author, "name")
        with CaptureLastQuery() as cap:
            list(Author.objects.force_index(name_idx, for_="ORDER BY").order_by("name"))

        assert ("FORCE INDEX FOR ORDER BY (`" + name_idx + "`)") in cap.query
        assert name_idx in used_indexes(cap.query)

    def test_use_index_none(self):
        with CaptureLastQuery() as cap:
            list(Author.objects.values_list("name").distinct().use_index())
        assert "USE INDEX () " in cap.query
        assert used_indexes(cap.query) == set()

    def test_use_index_table_name(self):
        extra_table = "testapp_authorextra"
        with CaptureLastQuery() as cap:
            list(
                Author.objects.select_related("authorextra").use_index(
                    "PRIMARY", table_name=extra_table

                )