No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_filtered.py 7.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. #
  2. # This file is part of Lodel 2 (https://github.com/OpenEdition)
  3. #
  4. # Copyright (C) 2015-2017 Cléo UMS-3287
  5. #
  6. # This program is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU Affero General Public License as published
  8. # by the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU Affero General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU Affero General Public License
  17. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. #
  19. import unittest
  20. import tests.loader_utils
  21. from tests.leapi.query.utils import dyncode_module as dyncode
  22. from lodel.leapi.exceptions import *
  23. from lodel.leapi.query import LeDeleteQuery, LeUpdateQuery, LeGetQuery
  24. class LeFilteredQueryTestCase(unittest.TestCase):
  25. q_classes = [ LeDeleteQuery, LeUpdateQuery, LeGetQuery ]
  26. def test_filters(self):
  27. """ Testing FilteredQuery filters handling """
  28. test_datas = [ ( 'lodel_id = 42',
  29. ( [('lodel_id','=',42)],
  30. [])),
  31. ( 'lodel_id <= 42',
  32. ( [('lodel_id','<=',42)],
  33. [])),
  34. ( ['lodel_id <= 42'],
  35. ( [('lodel_id','<=',42)],
  36. [])),
  37. ( ('lodel_id <= 42',),
  38. ( [('lodel_id','<=',42)],
  39. [])),
  40. ( ['lodel_id <= 42','lodel_id >= 33'],
  41. ( [ ('lodel_id','<=',42),
  42. ('lodel_id', '>=',33)],
  43. [])),
  44. ]
  45. for q_class in self.q_classes:
  46. for q_filter_arg, e_qfilter in test_datas:
  47. get_q = q_class(dyncode.Publication, q_filter_arg)
  48. self.assertEqual(
  49. sorted(get_q.dump_infos()['query_filter'][0]),
  50. sorted(e_qfilter[0]))
  51. def test_invalid_filters(self):
  52. """ Testing invalid filters detection """
  53. invalid_filters = ( 'lodel_id',
  54. '',
  55. '"',
  56. "'",
  57. "not_exists != bar",
  58. "lodel_id # bar",
  59. "lodel_id == bar",
  60. "lodel_id =! bar",
  61. "lodel_id >> bar",
  62. "lodel_id ind 42,43",
  63. "lodel_id llike 42",
  64. ('lodel_id', '', '42'),
  65. )
  66. for invalid_filter in invalid_filters:
  67. for q_class in self.q_classes:
  68. with self.assertRaises( LeApiDataCheckErrors,
  69. msg="for filter '%s'" % (invalid_filter,)):
  70. q_class(dyncode.Publication, invalid_filter)
  71. def test_filters_operators(self):
  72. """ Testing FilteredQuery filters operator recognition """
  73. ops = [ '=',
  74. '<=',
  75. '>=',
  76. '!=',
  77. '<',
  78. '>',
  79. 'in',
  80. 'not in',
  81. 'like',
  82. 'not like']
  83. values = ( 42,
  84. 'not in',
  85. 'in',
  86. 'like',
  87. '=',
  88. '!=',
  89. "'",
  90. '"',
  91. '"hello world !"')
  92. for q_class in self.q_classes:
  93. for op in ops:
  94. for v in values:
  95. get_q = q_class( dyncode.Publication,
  96. 'lodel_id %s %s' % (op,v))
  97. self.assertEqual( get_q.dump_infos()['query_filter'],
  98. ([('lodel_id',op,v)],[]))
  99. def test_rel_filters(self):
  100. """ Testing relational filters recognition """
  101. test_datas = [ ( dyncode.Subsection,
  102. 'parent.title = 42',
  103. ( [],
  104. [(('parent', {dyncode.Section: 'title'}), '=', '42')])),
  105. ( dyncode.Section,
  106. 'childs.title = 42',
  107. ( [],
  108. [(('childs', {dyncode.Subsection: 'title'}), '=', '42')]))
  109. ]
  110. for le_class, q_filter_arg, e_qfilter in test_datas:
  111. get_q = LeGetQuery(le_class, q_filter_arg)
  112. qinfos = get_q.dump_infos()
  113. self.assertEqual( qinfos['query_filter'],
  114. e_qfilter)
  115. class LeFilteredQueryMultiDataHandlerTestCase(unittest.TestCase):
  116. """ Testing LeFilteredQuery behavior when relational fields implies
  117. different datasources """
  118. q_classes = [LeDeleteQuery, LeUpdateQuery, LeGetQuery]
  119. def test_basic(self):
  120. """ Testing a LeGetQuery with a relationnal field implying another
  121. datasource """
  122. getq = LeGetQuery(
  123. dyncode.Indextheme,
  124. "texts.title = super titre !")
  125. qinfos = getq.dump_infos()
  126. # The single query filter should be in subquery
  127. self.assertEqual(qinfos['query_filter'], ([],[]))
  128. self.assertEqual(len(qinfos['subqueries']), 1)
  129. rfield, subq = qinfos['subqueries'][0]
  130. # Checking subquery
  131. self.assertEqual(rfield, 'texts') # The reference field of the subquery
  132. qinfos = subq.dump_infos()
  133. self.assertEqual(qinfos['target_class'], dyncode.Text)
  134. self.assertEqual(
  135. qinfos['query_filter'],
  136. ([('title', '=', 'super titre !')],[]))
  137. self.assertEqual(qinfos['field_list'], ['title'])
  138. def test_uid_as_ref_field(self):
  139. """ Testing basic query optimisation with a relationnal filter
  140. with lodel_id as referenced field"""
  141. getq = LeGetQuery(
  142. dyncode.Indextheme,
  143. "texts.lodel_id in 1,2,3,42")
  144. qinfos = getq.dump_infos()
  145. #No subqueries should be created because referenced field is
  146. #the referenced class UID
  147. self.assertEqual(qinfos['subqueries'],[])
  148. self.assertEqual(
  149. qinfos['query_filter'],
  150. ([('texts', 'in', '1,2,3,42')], []))
  151. def test_implicit_uid(self):
  152. """ Testing query with an UID as implicit referenced field for a
  153. relationnal filter """
  154. getq = LeGetQuery(
  155. dyncode.Indextheme,
  156. "texts in 13,1337,357,80")
  157. qinfos = getq.dump_infos()
  158. #No subqueries expected
  159. self.assertEqual(qinfos['subqueries'],[])
  160. self.assertEqual(
  161. qinfos['query_filter'],
  162. ([('texts', 'in', '13,1337,357,80')], []))
  163. def test_same_datasource(self):
  164. """ Testing a query with relationnal filters concerning only one
  165. datasource to check for 'false positive' in subqueries creation """
  166. getq = LeGetQuery(
  167. dyncode.Text,
  168. "linked_persons.fullname = John Doe")
  169. qinfos = getq.dump_infos()
  170. self.assertEqual(qinfos['subqueries'],[])
  171. self.assertEqual(
  172. qinfos['query_filter'],
  173. ( [],
  174. [(('linked_persons', {dyncode.Person:'fullname'}),'=', 'John Doe')]))