Repository: googleapis/python-spanner-django

Issue:
django: icontains lookup with an F expression crashes
For example, a queryset like `Employee.objects.filter(firstname__iexact=F('lastname'))` crashes:
```
======================================================================
ERROR: test_ticket_11722_iexact_lookup (expressions.tests.BasicExpressionsTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tim/code/django/tests/expressions/tests.py", line 322, in test_ticket_11722_iexact_lookup
    self.assertQuerysetEqual(queryset, ["<Employee: Test test>"])
  File "/home/tim/code/django/django/test/testcases.py", line 1047, in assertQuerysetEqual
    items = map(transform, qs)
  File "/home/tim/code/django/django/db/models/query.py", line 274, in __iter__
    self._fetch_all()
  File "/home/tim/code/django/django/db/models/query.py", line 1242, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "/home/tim/code/django/django/db/models/query.py", line 55, in __iter__
    results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
  File "/home/tim/code/django/django/db/models/sql/compiler.py", line 1120, in execute_sql
    sql, params = self.as_sql()
  File "/home/tim/code/django/django/db/models/sql/compiler.py", line 489, in as_sql
    where, w_params = self.compile(self.where) if self.where is not None else ("", [])
  File "/home/tim/code/django/django/db/models/sql/compiler.py", line 405, in compile
    sql, params = node.as_sql(self, self.connection)
  File "/home/tim/code/django/django/db/models/sql/where.py", line 81, in as_sql
    sql, params = compiler.compile(child)
  File "/home/tim/code/django/django/db/models/sql/compiler.py", line 403, in compile
    sql, params = vendor_impl(self, self.connection)
  File "/home/tim/code/spanner-orm/spanner/django/lookups.py", line 45, in iexact
    params[0] = '^(?i)%s$' % params[0]
IndexError: list index out of range
```


Discussion:

Resolving patch:
diff --git a/django_spanner/features.py b/django_spanner/features.py
--- a/django_spanner/features.py
+++ b/django_spanner/features.py
@@ -160,9 +160,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
         # bitrightshift operator gives incorrect result:
         # https://github.com/orijtech/django-spanner/issues/335
         'expressions.tests.ExpressionOperatorTests.test_lefthand_bitwise_right_shift_operator',
-        # using an F expression as the value of a REGEXP_CONTAINS lookup
-        # crashes: https://github.com/orijtech/django-spanner/issues/251
-        'expressions.tests.BasicExpressionsTests.test_ticket_11722_iexact_lookup',
         # integer division produces a float result, which can't be assigned to
         # an integer column:
         # https://github.com/orijtech/django-spanner/issues/331
diff --git a/django_spanner/lookups.py b/django_spanner/lookups.py
--- a/django_spanner/lookups.py
+++ b/django_spanner/lookups.py
@@ -34,7 +34,13 @@ def iexact(self, compiler, connection):
     params.extend(rhs_params)
     rhs_sql = self.get_rhs_op(connection, rhs_sql)
     # Wrap the parameter in ^ and $ to restrict the regex to an exact match.
-    params[0] = '^(?i)%s$' % params[0]
+    if params:
+        params[0] = '^(?i)%s$' % params[0]
+    else:
+        # If no params, then lhs_sql is the expression/column to use as the
+        # regular expression. Use concat to make the value case-insensitive.
+        lhs_sql = "CONCAT('^(?i)', " + lhs_sql + ", '$')"
+        rhs_sql = rhs_sql.replace('%%s', '%s')
     # rhs_sql is REGEXP_CONTAINS(%s, %%s), and lhs_sql is the column name.
     return rhs_sql % lhs_sql, params
 


Test patch: