(self, compiler, connection)
| 371 | return compiler.compile(Tuple(*result)) |
| 372 | |
| 373 | def get_fallback_sql(self, compiler, connection): |
| 374 | rhs = self.rhs |
| 375 | if not rhs: |
| 376 | raise EmptyResultSet |
| 377 | if isinstance(rhs, Query): |
| 378 | rhs_exprs = itertools.chain.from_iterable( |
| 379 | ( |
| 380 | select_expr |
| 381 | if isinstance((select_expr := select[0]), ColPairs) |
| 382 | else [select_expr] |
| 383 | ) |
| 384 | for select in rhs.get_compiler(connection=connection).get_select()[0] |
| 385 | ) |
| 386 | rhs = rhs.clone() |
| 387 | rhs.add_q( |
| 388 | models.Q(*[Exact(col, val) for col, val in zip(self.lhs, rhs_exprs)]) |
| 389 | ) |
| 390 | return compiler.compile(Exists(rhs)) |
| 391 | elif not self.rhs_is_direct_value(): |
| 392 | return super(TupleLookupMixin, self).as_sql(compiler, connection) |
| 393 | |
| 394 | # e.g.: (a, b, c) in [(x1, y1, z1), (x2, y2, z2)] as SQL: |
| 395 | # WHERE (a = x1 AND b = y1 AND c = z1) |
| 396 | # OR (a = x2 AND b = y2 AND c = z2) |
| 397 | root = WhereNode([], connector=OR) |
| 398 | lhs = self.lhs |
| 399 | |
| 400 | for vals in rhs: |
| 401 | # Remove any tuple containing None from the list as NULL is never |
| 402 | # equal to anything. |
| 403 | if any(val is None for val in vals): |
| 404 | continue |
| 405 | lookups = [Exact(col, val) for col, val in zip(lhs, vals)] |
| 406 | root.children.append(WhereNode(lookups, connector=AND)) |
| 407 | |
| 408 | if not root.children: |
| 409 | raise EmptyResultSet |
| 410 | return root.as_sql(compiler, connection) |
| 411 | |
| 412 | |
| 413 | tuple_lookups = { |
nothing calls this directly
no test coverage detected