Coverage for databases/tests/test_full_text_search.py: 100%

40 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2024-08-27 18:25 +0000

1from typing import Optional, cast 

2 

3import pytest 

4from pydantic import BaseModel 

5 

6from prisma import Prisma 

7 

8from .._types import DatabaseMapping, SupportedDatabase 

9 

10 

11# Define a class to hold the search queries 

12class FullTextSearchSyntax(BaseModel): 

13 search_or: str 

14 search_and: str 

15 

16 

17# Define the queries for MySQL 

18_mysql_syntax = FullTextSearchSyntax( 

19 search_or='cats dogs', 

20 search_and='+cats +dogs', 

21) 

22 

23# Define the queries for PostgreSQL 

24_postgresql_syntax = FullTextSearchSyntax( 

25 search_or='cats | dogs', 

26 search_and='cats & dogs', 

27) 

28 

29# Map the syntax to the corresponding database 

30FULL_TEXT_SEARCH_SYNTAX: DatabaseMapping[Optional[FullTextSearchSyntax]] = { 

31 'mysql': _mysql_syntax, 

32 'postgresql': _postgresql_syntax, 

33 'cockroachdb': None, 

34 'mariadb': None, 

35 'sqlite': None, 

36} 

37 

38 

39@pytest.mark.asyncio 

40async def test_full_text_search(client: Prisma) -> None: 

41 """Ensure that full-text search works correctly on both PostgreSQL and MySQL""" 

42 

43 # Determine the correct syntax based on the database 

44 db_type = cast(SupportedDatabase, client._active_provider) 

45 syntax = FULL_TEXT_SEARCH_SYNTAX[db_type] 

46 

47 if syntax is None: 

48 pytest.skip(f'Skipping test for {db_type}') 

49 

50 # Create some posts with varied content 

51 await client.post.create_many( 

52 data=[ 

53 { 

54 'title': 'cats are great pets. dogs are loyal companions.', 

55 'published': True, 

56 }, 

57 { 

58 'title': 'cats are independent and mysterious animals.', 

59 'published': True, 

60 }, 

61 { 

62 'title': 'rabbits and hamsters are small and cute pets.', 

63 'published': True, 

64 }, 

65 ] 

66 ) 

67 

68 # Test: Search for posts that contain 'cats' or 'dogs' 

69 posts = await client.post.find_many( 

70 where={ 

71 'title': { 

72 'search': syntax.search_or, 

73 }, 

74 } 

75 ) 

76 assert len(posts) == 2 

77 for post in posts: 

78 assert 'cats' in post.title or 'dogs' in post.title 

79 

80 # Test: Search for posts that contain both 'cats' and 'dogs' 

81 posts = await client.post.find_many( 

82 where={ 

83 'title': { 

84 'search': syntax.search_and, 

85 }, 

86 } 

87 ) 

88 assert len(posts) == 1 

89 assert 'cats' in posts[0].title 

90 assert 'dogs' in posts[0].title 

91 

92 

93@pytest.mark.asyncio 

94async def test_order_by_relevance(client: Prisma) -> None: 

95 """Ensure that ordering by relevance works correctly on both PostgreSQL and MySQL""" 

96 

97 # Determine the correct syntax based on the database 

98 db_type = cast(SupportedDatabase, client._active_provider) 

99 syntax = FULL_TEXT_SEARCH_SYNTAX[db_type] 

100 

101 if syntax is None: 

102 pytest.skip(f'Skipping test for {db_type}') 

103 

104 # Create some posts with varied content 

105 await client.post.create_many( 

106 data=[ 

107 { 

108 'title': 'cats are great pets. dogs are loyal companions.', 

109 'published': True, 

110 }, 

111 { 

112 'title': 'cats are independent and mysterious animals.', 

113 'published': True, 

114 }, 

115 { 

116 'title': 'rabbits and hamsters are small and cute pets.', 

117 'published': True, 

118 }, 

119 ] 

120 ) 

121 

122 # Test: Order posts by relevance descending 

123 post = await client.post.find_first( 

124 order={ 

125 '_relevance': { 

126 'fields': ['title'], 

127 'search': syntax.search_or, 

128 'sort': 'desc', 

129 }, 

130 } 

131 ) 

132 assert post is not None 

133 assert 'cats' in post.title 

134 assert 'dogs' in post.title 

135 

136 # Test: Order posts by relevance ascending 

137 post = await client.post.find_first( 

138 order={ 

139 '_relevance': { 

140 'fields': ['title'], 

141 'search': syntax.search_or, 

142 'sort': 'asc', 

143 }, 

144 } 

145 ) 

146 assert post is not None 

147 assert 'rabbits' in post.title