1. from unittest import skipUnless
    
  2. 
    
  3. from django.db import connection
    
  4. from django.db.models import CharField, TextField
    
  5. from django.db.models import Value as V
    
  6. from django.db.models.functions import Concat, ConcatPair, Upper
    
  7. from django.test import TestCase
    
  8. from django.utils import timezone
    
  9. 
    
  10. from ..models import Article, Author
    
  11. 
    
  12. lorem_ipsum = """
    
  13.     Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
    
  14.     tempor incididunt ut labore et dolore magna aliqua."""
    
  15. 
    
  16. 
    
  17. class ConcatTests(TestCase):
    
  18.     def test_basic(self):
    
  19.         Author.objects.create(name="Jayden")
    
  20.         Author.objects.create(name="John Smith", alias="smithj", goes_by="John")
    
  21.         Author.objects.create(name="Margaret", goes_by="Maggie")
    
  22.         Author.objects.create(name="Rhonda", alias="adnohR")
    
  23.         authors = Author.objects.annotate(joined=Concat("alias", "goes_by"))
    
  24.         self.assertQuerysetEqual(
    
  25.             authors.order_by("name"),
    
  26.             [
    
  27.                 "",
    
  28.                 "smithjJohn",
    
  29.                 "Maggie",
    
  30.                 "adnohR",
    
  31.             ],
    
  32.             lambda a: a.joined,
    
  33.         )
    
  34. 
    
  35.     def test_gt_two_expressions(self):
    
  36.         with self.assertRaisesMessage(
    
  37.             ValueError, "Concat must take at least two expressions"
    
  38.         ):
    
  39.             Author.objects.annotate(joined=Concat("alias"))
    
  40. 
    
  41.     def test_many(self):
    
  42.         Author.objects.create(name="Jayden")
    
  43.         Author.objects.create(name="John Smith", alias="smithj", goes_by="John")
    
  44.         Author.objects.create(name="Margaret", goes_by="Maggie")
    
  45.         Author.objects.create(name="Rhonda", alias="adnohR")
    
  46.         authors = Author.objects.annotate(
    
  47.             joined=Concat("name", V(" ("), "goes_by", V(")"), output_field=CharField()),
    
  48.         )
    
  49.         self.assertQuerysetEqual(
    
  50.             authors.order_by("name"),
    
  51.             [
    
  52.                 "Jayden ()",
    
  53.                 "John Smith (John)",
    
  54.                 "Margaret (Maggie)",
    
  55.                 "Rhonda ()",
    
  56.             ],
    
  57.             lambda a: a.joined,
    
  58.         )
    
  59. 
    
  60.     def test_mixed_char_text(self):
    
  61.         Article.objects.create(
    
  62.             title="The Title", text=lorem_ipsum, written=timezone.now()
    
  63.         )
    
  64.         article = Article.objects.annotate(
    
  65.             title_text=Concat("title", V(" - "), "text", output_field=TextField()),
    
  66.         ).get(title="The Title")
    
  67.         self.assertEqual(article.title + " - " + article.text, article.title_text)
    
  68.         # Wrap the concat in something else to ensure that text is returned
    
  69.         # rather than bytes.
    
  70.         article = Article.objects.annotate(
    
  71.             title_text=Upper(
    
  72.                 Concat("title", V(" - "), "text", output_field=TextField())
    
  73.             ),
    
  74.         ).get(title="The Title")
    
  75.         expected = article.title + " - " + article.text
    
  76.         self.assertEqual(expected.upper(), article.title_text)
    
  77. 
    
  78.     @skipUnless(connection.vendor == "sqlite", "sqlite specific implementation detail.")
    
  79.     def test_coalesce_idempotent(self):
    
  80.         pair = ConcatPair(V("a"), V("b"))
    
  81.         # Check nodes counts
    
  82.         self.assertEqual(len(list(pair.flatten())), 3)
    
  83.         self.assertEqual(
    
  84.             len(list(pair.coalesce().flatten())), 7
    
  85.         )  # + 2 Coalesce + 2 Value()
    
  86.         self.assertEqual(len(list(pair.flatten())), 3)
    
  87. 
    
  88.     def test_sql_generation_idempotency(self):
    
  89.         qs = Article.objects.annotate(description=Concat("title", V(": "), "summary"))
    
  90.         # Multiple compilations should not alter the generated query.
    
  91.         self.assertEqual(str(qs.query), str(qs.all().query))