search_index_backend_spec.rb 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786
  1. require 'rails_helper'
  2. RSpec.describe SearchIndexBackend, searchindex: true do
  3. before do
  4. configure_elasticsearch
  5. rebuild_searchindex
  6. end
  7. describe '.build_query' do
  8. subject(:query) { described_class.build_query('', query_extension: params) }
  9. let(:params) { { 'bool' => { 'filter' => { 'term' => { 'a' => 'b' } } } } }
  10. it 'coerces :query_extension hash keys to symbols' do
  11. expect(query.dig(:query, :bool, :filter, :term, :a)).to eq('b')
  12. end
  13. end
  14. describe '.search' do
  15. context 'query finds results' do
  16. let(:record_type) { 'Ticket'.freeze }
  17. let(:record) { create :ticket }
  18. before do
  19. record.search_index_update_backend
  20. described_class.refresh
  21. end
  22. it 'finds added records' do
  23. result = described_class.search(record.number, record_type, sort_by: ['updated_at'], order_by: ['desc'])
  24. expect(result).to eq([{ id: record.id.to_s, type: record_type }])
  25. end
  26. end
  27. context 'when search for user firstname + double lastname' do
  28. let(:record_type) { 'User'.freeze }
  29. let(:record) { create :user, login: 'a', email: 'a@a.de', firstname: 'AnFirst', lastname: 'ASplit Lastname' }
  30. before do
  31. record.search_index_update_backend
  32. described_class.refresh
  33. end
  34. it 'finds user record' do
  35. result = described_class.search('AnFirst ASplit Lastname', record_type, sort_by: ['updated_at'], order_by: ['desc'])
  36. expect(result).to eq([{ id: record.id.to_s, type: record_type }])
  37. end
  38. end
  39. context 'for query with no results' do
  40. subject(:search) { described_class.search(query, index, limit: 3000) }
  41. let(:query) { 'preferences.notification_sound.enabled:*' }
  42. context 'on a single index' do
  43. let(:index) { 'User' }
  44. it { is_expected.to be_an(Array).and be_empty }
  45. end
  46. context 'on multiple indices' do
  47. let(:index) { %w[User Organization] }
  48. it { is_expected.to be_an(Array).and not_include(nil).and be_empty }
  49. end
  50. end
  51. end
  52. describe '.append_wildcard_to_simple_query' do
  53. context 'with "simple" queries' do
  54. let(:queries) { <<~QUERIES.lines.map { |x| x.split('#')[0] }.map(&:strip) }
  55. M
  56. Max
  57. Max. # dot and underscore are acceptable characters in simple queries
  58. A_
  59. A_B
  60. äöü
  61. 123
  62. *ax # wildcards are allowed in simple queries
  63. Max*
  64. M*x
  65. M?x
  66. test@example.com
  67. test@example.
  68. test@example
  69. test@
  70. QUERIES
  71. it 'appends a * to the original query' do
  72. expect(queries.map { |query| described_class.append_wildcard_to_simple_query(query) })
  73. .to eq(queries.map { |q| "#{q}*" })
  74. end
  75. end
  76. context 'with "complex" queries (using search operators)' do
  77. let(:queries) { <<~QUERIES.lines.map { |x| x.split('#')[0] }.map(&:strip) }
  78. title:"some words with spaces" # exact phrase / without quotation marks " an AND search for the words will be performed (in Zammad 1.5 and lower an OR search will be performed)
  79. title:"some wor*" # exact phrase beginning with "some wor*" will be searched
  80. created_at:[2017-01-01 TO 2017-12-31] # a time range
  81. created_at:>now-1h # created within last hour
  82. state:new OR state:open
  83. (state:new OR state:open) OR priority:"3 normal"
  84. (state:new OR state:open) AND customer.lastname:smith
  85. state:(new OR open) AND title:(full text search) # state: new OR open & title: full OR text OR search
  86. tags: "some tag"
  87. owner.email: "bod@example.com" AND state: (new OR open OR pending*) # show all open tickets of a certain agent
  88. state:closed AND _missing_:tag # all closed objects without tags
  89. article_count: [1 TO 5] # tickets with 1 to 5 articles
  90. article_count: [10 TO *] # tickets with 10 or more articles
  91. article.from: bob # also article.from can be used
  92. article.body: heat~ # using the fuzzy operator will also find terms that are similar, in this case also "head"
  93. article.body: /joh?n(ath[oa]n)/ # using regular expressions
  94. user:M
  95. user:Max
  96. user:Max.
  97. user:Max*
  98. organization:A_B
  99. organization:A_B*
  100. user: M
  101. user: Max
  102. user: Max.
  103. user: Max*
  104. organization: A_B
  105. organization: A_B*
  106. id:123
  107. number:123
  108. id:"123"
  109. number:"123"
  110. QUERIES
  111. it 'returns the original query verbatim' do
  112. expect(queries.map { |query| described_class.append_wildcard_to_simple_query(query) })
  113. .to eq(queries)
  114. end
  115. end
  116. end
  117. describe '.remove' do
  118. context 'record gets deleted' do
  119. let(:record_type) { 'Ticket'.freeze }
  120. let(:deleted_record) { create :ticket }
  121. before do
  122. described_class.add(record_type, deleted_record)
  123. described_class.refresh
  124. end
  125. it 'removes record from search index' do
  126. described_class.remove(record_type, deleted_record.id)
  127. described_class.refresh
  128. result = described_class.search(deleted_record.number, record_type, sort_by: ['updated_at'], order_by: ['desc'])
  129. expect(result).to eq([])
  130. end
  131. context 'other records present' do
  132. let(:other_record) { create :ticket }
  133. before do
  134. described_class.add(record_type, other_record)
  135. described_class.refresh
  136. end
  137. it "doesn't remove other records" do
  138. described_class.remove(record_type, deleted_record.id)
  139. described_class.refresh
  140. result = described_class.search(other_record.number, record_type, sort_by: ['updated_at'], order_by: ['desc'])
  141. expect(result).to eq([{ id: other_record.id.to_s, type: record_type }])
  142. end
  143. end
  144. end
  145. end
  146. describe '.selectors' do
  147. let(:group1) { create :group }
  148. let(:organization1) { create :organization, note: 'hihi' }
  149. let(:agent1) { create :agent, organization: organization1, groups: [group1] }
  150. let(:customer1) { create :customer, organization: organization1, firstname: 'special-first-name' }
  151. let(:ticket1) do
  152. ticket = create :ticket, title: 'some-title1', state_id: 1, created_by: agent1
  153. ticket.tag_add('t1', 1)
  154. ticket
  155. end
  156. let(:ticket2) do
  157. ticket = create :ticket, title: 'some_title2', state_id: 4
  158. ticket.tag_add('t2', 1)
  159. ticket
  160. end
  161. let(:ticket3) do
  162. ticket = create :ticket, title: 'some::title3', state_id: 1
  163. ticket.tag_add('t1', 1)
  164. ticket.tag_add('t2', 1)
  165. ticket
  166. end
  167. let(:ticket4) { create :ticket, title: 'phrase some-title4', state_id: 1 }
  168. let(:ticket5) { create :ticket, title: 'phrase some_title5', state_id: 1 }
  169. let(:ticket6) { create :ticket, title: 'phrase some::title6', state_id: 1 }
  170. let(:ticket7) { create :ticket, title: 'some title7', state_id: 1 }
  171. let(:ticket8) { create :ticket, title: 'sometitle', group: group1, state_id: 1, owner: agent1, customer: customer1, organization: organization1 }
  172. let(:article8) { create :ticket_article, ticket: ticket8, subject: 'lorem ipsum' }
  173. before do
  174. Ticket.destroy_all # needed to remove not created tickets
  175. travel(-1.hour)
  176. create(:mention, mentionable: ticket1, user: agent1)
  177. ticket1.search_index_update_backend
  178. travel 1.hour
  179. ticket2.search_index_update_backend
  180. travel 1.second
  181. ticket3.search_index_update_backend
  182. travel 1.second
  183. ticket4.search_index_update_backend
  184. travel 1.second
  185. ticket5.search_index_update_backend
  186. travel 1.second
  187. ticket6.search_index_update_backend
  188. travel 1.second
  189. ticket7.search_index_update_backend
  190. travel 1.hour
  191. article8.ticket.search_index_update_backend
  192. described_class.refresh
  193. end
  194. context 'query with contains' do
  195. it 'finds records with till (relative)' do
  196. result = described_class.selectors('Ticket',
  197. { 'ticket.created_at'=>{ 'operator' => 'till (relative)', 'value' => '30', 'range' => 'minute' } },
  198. {},
  199. {
  200. field: 'created_at', # sort to verify result
  201. })
  202. expect(result).to eq({ count: 7, ticket_ids: [ticket7.id.to_s, ticket6.id.to_s, ticket5.id.to_s, ticket4.id.to_s, ticket3.id.to_s, ticket2.id.to_s, ticket1.id.to_s] })
  203. end
  204. it 'finds records with from (relative)' do
  205. result = described_class.selectors('Ticket',
  206. { 'ticket.created_at'=>{ 'operator' => 'from (relative)', 'value' => '30', 'range' => 'minute' } },
  207. {},
  208. {
  209. field: 'created_at', # sort to verify result
  210. })
  211. expect(result).to eq({ count: 7, ticket_ids: [ticket8.id.to_s, ticket7.id.to_s, ticket6.id.to_s, ticket5.id.to_s, ticket4.id.to_s, ticket3.id.to_s, ticket2.id.to_s] })
  212. end
  213. it 'finds records with till (relative) including +1 hour ticket' do
  214. result = described_class.selectors('Ticket',
  215. { 'ticket.created_at'=>{ 'operator' => 'till (relative)', 'value' => '120', 'range' => 'minute' } },
  216. {},
  217. {
  218. field: 'created_at', # sort to verify result
  219. })
  220. expect(result).to eq({ count: 8, ticket_ids: [ticket8.id.to_s, ticket7.id.to_s, ticket6.id.to_s, ticket5.id.to_s, ticket4.id.to_s, ticket3.id.to_s, ticket2.id.to_s, ticket1.id.to_s] })
  221. end
  222. it 'finds records with from (relative) including -1 hour ticket' do
  223. result = described_class.selectors('Ticket',
  224. { 'ticket.created_at'=>{ 'operator' => 'from (relative)', 'value' => '120', 'range' => 'minute' } },
  225. {},
  226. {
  227. field: 'created_at', # sort to verify result
  228. })
  229. expect(result).to eq({ count: 8, ticket_ids: [ticket8.id.to_s, ticket7.id.to_s, ticket6.id.to_s, ticket5.id.to_s, ticket4.id.to_s, ticket3.id.to_s, ticket2.id.to_s, ticket1.id.to_s] })
  230. end
  231. it 'finds records with tags which contains all' do
  232. result = described_class.selectors('Ticket',
  233. { 'ticket.tags'=>{ 'operator' => 'contains all', 'value' => 't1, t2' } },
  234. {},
  235. {
  236. field: 'created_at', # sort to verify result
  237. })
  238. expect(result).to eq({ count: 1, ticket_ids: [ticket3.id.to_s] })
  239. end
  240. it 'finds records with tags which contains one' do
  241. result = described_class.selectors('Ticket',
  242. { 'ticket.tags'=>{ 'operator' => 'contains one', 'value' => 't1, t2' } },
  243. {},
  244. {
  245. field: 'created_at', # sort to verify result
  246. })
  247. expect(result).to eq({ count: 3, ticket_ids: [ticket3.id.to_s, ticket2.id.to_s, ticket1.id.to_s] })
  248. end
  249. it 'finds records with tags which contains all not' do
  250. result = described_class.selectors('Ticket',
  251. { 'ticket.tags'=>{ 'operator' => 'contains all not', 'value' => 't2' } },
  252. {},
  253. {
  254. field: 'created_at', # sort to verify result
  255. })
  256. expect(result).to eq({ count: 6, ticket_ids: [ticket8.id.to_s, ticket7.id.to_s, ticket6.id.to_s, ticket5.id.to_s, ticket4.id.to_s, ticket1.id.to_s] })
  257. end
  258. it 'finds records with tags which contains one not' do
  259. result = described_class.selectors('Ticket',
  260. { 'ticket.tags'=>{ 'operator' => 'contains one not', 'value' => 't1' } },
  261. {},
  262. {
  263. field: 'created_at', # sort to verify result
  264. })
  265. expect(result).to eq({ count: 6, ticket_ids: [ticket8.id.to_s, ticket7.id.to_s, ticket6.id.to_s, ticket5.id.to_s, ticket4.id.to_s, ticket2.id.to_s] })
  266. end
  267. it 'finds records with organization note' do
  268. result = described_class.selectors('Ticket',
  269. {
  270. 'organization.note' => {
  271. 'operator' => 'contains',
  272. 'value' => 'hihi',
  273. },
  274. },
  275. {},
  276. {
  277. field: 'created_at', # sort to verify result
  278. })
  279. expect(result).to eq({ count: 1, ticket_ids: [ticket8.id.to_s] })
  280. end
  281. it 'finds records with customer firstname' do
  282. result = described_class.selectors('Ticket',
  283. {
  284. 'customer.firstname' => {
  285. 'operator' => 'contains',
  286. 'value' => 'special',
  287. },
  288. },
  289. {},
  290. {
  291. field: 'created_at', # sort to verify result
  292. })
  293. expect(result).to eq({ count: 1, ticket_ids: [ticket8.id.to_s] })
  294. end
  295. it 'finds records with article subject' do
  296. result = described_class.selectors('Ticket',
  297. {
  298. 'article.subject' => {
  299. 'operator' => 'contains',
  300. 'value' => 'ipsum',
  301. },
  302. },
  303. {},
  304. {
  305. field: 'created_at', # sort to verify result
  306. })
  307. expect(result).to eq({ count: 1, ticket_ids: [ticket8.id.to_s] })
  308. end
  309. it 'finds records with pre_condition not_set' do
  310. result = described_class.selectors('Ticket',
  311. {
  312. 'created_by_id' => {
  313. 'pre_condition' => 'not_set',
  314. 'operator' => 'is',
  315. },
  316. },
  317. {},
  318. {
  319. field: 'created_at', # sort to verify result
  320. })
  321. expect(result).to eq({ count: 7, ticket_ids: [ticket8.id.to_s, ticket7.id.to_s, ticket6.id.to_s, ticket5.id.to_s, ticket4.id.to_s, ticket3.id.to_s, ticket2.id.to_s] })
  322. end
  323. it 'finds records with pre_condition current_user.id' do
  324. result = described_class.selectors('Ticket',
  325. {
  326. 'owner_id' => {
  327. 'pre_condition' => 'current_user.id',
  328. 'operator' => 'is',
  329. },
  330. },
  331. { current_user: agent1 },
  332. {
  333. field: 'created_at', # sort to verify result
  334. })
  335. expect(result).to eq({ count: 1, ticket_ids: [ticket8.id.to_s] })
  336. end
  337. it 'finds records with pre_condition current_user.organization_id' do
  338. result = described_class.selectors('Ticket',
  339. {
  340. 'organization_id' => {
  341. 'pre_condition' => 'current_user.organization_id',
  342. 'operator' => 'is',
  343. },
  344. },
  345. { current_user: agent1 },
  346. {
  347. field: 'created_at', # sort to verify result
  348. })
  349. expect(result).to eq({ count: 1, ticket_ids: [ticket8.id.to_s] })
  350. end
  351. it 'finds records with containing phrase' do
  352. result = described_class.selectors('Ticket',
  353. {
  354. 'title' => {
  355. 'operator' => 'contains',
  356. 'value' => 'phrase',
  357. },
  358. },
  359. {},
  360. {
  361. field: 'created_at', # sort to verify result
  362. })
  363. expect(result).to eq({ count: 3, ticket_ids: [ticket6.id.to_s, ticket5.id.to_s, ticket4.id.to_s] })
  364. end
  365. it 'finds records with containing some title7' do
  366. result = described_class.selectors('Ticket',
  367. 'title' => {
  368. 'operator' => 'contains',
  369. 'value' => 'some title7',
  370. })
  371. expect(result).to eq({ count: 1, ticket_ids: [ticket7.id.to_s] })
  372. end
  373. it 'finds records with containing -' do
  374. result = described_class.selectors('Ticket',
  375. 'title' => {
  376. 'operator' => 'contains',
  377. 'value' => 'some-title1',
  378. })
  379. expect(result).to eq({ count: 1, ticket_ids: [ticket1.id.to_s] })
  380. end
  381. it 'finds records with containing _' do
  382. result = described_class.selectors('Ticket',
  383. 'title' => {
  384. 'operator' => 'contains',
  385. 'value' => 'some_title2',
  386. })
  387. expect(result).to eq({ count: 1, ticket_ids: [ticket2.id.to_s] })
  388. end
  389. it 'finds records with containing ::' do
  390. result = described_class.selectors('Ticket',
  391. 'title' => {
  392. 'operator' => 'contains',
  393. 'value' => 'some::title3',
  394. })
  395. expect(result).to eq({ count: 1, ticket_ids: [ticket3.id.to_s] })
  396. end
  397. it 'finds records with containing 4' do
  398. result = described_class.selectors('Ticket',
  399. 'state_id' => {
  400. 'operator' => 'contains',
  401. 'value' => 4,
  402. })
  403. expect(result).to eq({ count: 1, ticket_ids: [ticket2.id.to_s] })
  404. end
  405. it 'finds records with containing "4"' do
  406. result = described_class.selectors('Ticket',
  407. 'state_id' => {
  408. 'operator' => 'contains',
  409. 'value' => '4',
  410. })
  411. expect(result).to eq({ count: 1, ticket_ids: [ticket2.id.to_s] })
  412. end
  413. end
  414. context 'query with contains not' do
  415. it 'finds records with containing not phrase' do
  416. result = described_class.selectors('Ticket',
  417. {
  418. 'title' => {
  419. 'operator' => 'contains not',
  420. 'value' => 'phrase',
  421. },
  422. },
  423. {},
  424. {
  425. field: 'created_at', # sort to verify result
  426. })
  427. expect(result).to eq({ count: 5, ticket_ids: [ticket8.id.to_s, ticket7.id.to_s, ticket3.id.to_s, ticket2.id.to_s, ticket1.id.to_s] })
  428. end
  429. it 'finds records with containing not some title7' do
  430. result = described_class.selectors('Ticket',
  431. 'title' => {
  432. 'operator' => 'contains not',
  433. 'value' => 'some title7',
  434. })
  435. expect(result).to eq({ count: 7, ticket_ids: [ticket8.id.to_s, ticket6.id.to_s, ticket5.id.to_s, ticket4.id.to_s, ticket3.id.to_s, ticket2.id.to_s, ticket1.id.to_s] })
  436. end
  437. it 'finds records with containing not -' do
  438. result = described_class.selectors('Ticket',
  439. 'title' => {
  440. 'operator' => 'contains not',
  441. 'value' => 'some-title1',
  442. })
  443. expect(result).to eq({ count: 7, ticket_ids: [ticket8.id.to_s, ticket7.id.to_s, ticket6.id.to_s, ticket5.id.to_s, ticket4.id.to_s, ticket3.id.to_s, ticket2.id.to_s] })
  444. end
  445. it 'finds records with containing not _' do
  446. result = described_class.selectors('Ticket',
  447. 'title' => {
  448. 'operator' => 'contains not',
  449. 'value' => 'some_title2',
  450. })
  451. expect(result).to eq({ count: 7, ticket_ids: [ticket8.id.to_s, ticket7.id.to_s, ticket6.id.to_s, ticket5.id.to_s, ticket4.id.to_s, ticket3.id.to_s, ticket1.id.to_s] })
  452. end
  453. it 'finds records with containing not ::' do
  454. result = described_class.selectors('Ticket',
  455. 'title' => {
  456. 'operator' => 'contains not',
  457. 'value' => 'some::title3',
  458. })
  459. expect(result).to eq({ count: 7, ticket_ids: [ticket8.id.to_s, ticket7.id.to_s, ticket6.id.to_s, ticket5.id.to_s, ticket4.id.to_s, ticket2.id.to_s, ticket1.id.to_s] })
  460. end
  461. it 'finds records with containing not 4' do
  462. result = described_class.selectors('Ticket',
  463. 'state_id' => {
  464. 'operator' => 'contains not',
  465. 'value' => 4,
  466. })
  467. expect(result).to eq({ count: 7, ticket_ids: [ticket8.id.to_s, ticket7.id.to_s, ticket6.id.to_s, ticket5.id.to_s, ticket4.id.to_s, ticket3.id.to_s, ticket1.id.to_s] })
  468. end
  469. it 'finds records with containing not "4"' do
  470. result = described_class.selectors('Ticket',
  471. 'state_id' => {
  472. 'operator' => 'contains not',
  473. 'value' => '4',
  474. })
  475. expect(result).to eq({ count: 7, ticket_ids: [ticket8.id.to_s, ticket7.id.to_s, ticket6.id.to_s, ticket5.id.to_s, ticket4.id.to_s, ticket3.id.to_s, ticket1.id.to_s] })
  476. end
  477. end
  478. context 'query with is' do
  479. it 'finds records with is phrase' do
  480. result = described_class.selectors('Ticket',
  481. 'title' => {
  482. 'operator' => 'is',
  483. 'value' => 'phrase',
  484. })
  485. expect(result).to eq({ count: 0, ticket_ids: [] })
  486. end
  487. it 'finds records with is some title7' do
  488. result = described_class.selectors('Ticket',
  489. 'title' => {
  490. 'operator' => 'is',
  491. 'value' => 'some title7',
  492. })
  493. expect(result).to eq({ count: 1, ticket_ids: [ticket7.id.to_s] })
  494. end
  495. it 'finds records with is -' do
  496. result = described_class.selectors('Ticket',
  497. 'title' => {
  498. 'operator' => 'is',
  499. 'value' => 'some-title1',
  500. })
  501. expect(result).to eq({ count: 1, ticket_ids: [ticket1.id.to_s] })
  502. end
  503. it 'finds records with is _' do
  504. result = described_class.selectors('Ticket',
  505. 'title' => {
  506. 'operator' => 'is',
  507. 'value' => 'some_title2',
  508. })
  509. expect(result).to eq({ count: 1, ticket_ids: [ticket2.id.to_s] })
  510. end
  511. it 'finds records with is ::' do
  512. result = described_class.selectors('Ticket',
  513. 'title' => {
  514. 'operator' => 'is',
  515. 'value' => 'some::title3',
  516. })
  517. expect(result).to eq({ count: 1, ticket_ids: [ticket3.id.to_s] })
  518. end
  519. it 'finds records with is 4' do
  520. result = described_class.selectors('Ticket',
  521. 'state_id' => {
  522. 'operator' => 'is',
  523. 'value' => 4,
  524. })
  525. expect(result).to eq({ count: 1, ticket_ids: [ticket2.id.to_s] })
  526. end
  527. it 'finds records with is "4"' do
  528. result = described_class.selectors('Ticket',
  529. 'state_id' => {
  530. 'operator' => 'is',
  531. 'value' => '4',
  532. })
  533. expect(result).to eq({ count: 1, ticket_ids: [ticket2.id.to_s] })
  534. end
  535. end
  536. context 'query with is not' do
  537. it 'finds records with is not phrase' do
  538. result = described_class.selectors('Ticket',
  539. 'title' => {
  540. 'operator' => 'is not',
  541. 'value' => 'phrase',
  542. })
  543. expect(result).to eq({ count: 8, ticket_ids: [ticket8.id.to_s, ticket7.id.to_s, ticket6.id.to_s, ticket5.id.to_s, ticket4.id.to_s, ticket3.id.to_s, ticket2.id.to_s, ticket1.id.to_s] })
  544. end
  545. it 'finds records with is not some title7' do
  546. result = described_class.selectors('Ticket',
  547. 'title' => {
  548. 'operator' => 'is not',
  549. 'value' => 'some title7',
  550. })
  551. expect(result).to eq({ count: 7, ticket_ids: [ticket8.id.to_s, ticket6.id.to_s, ticket5.id.to_s, ticket4.id.to_s, ticket3.id.to_s, ticket2.id.to_s, ticket1.id.to_s] })
  552. end
  553. it 'finds records with is not -' do
  554. result = described_class.selectors('Ticket',
  555. 'title' => {
  556. 'operator' => 'is not',
  557. 'value' => 'some-title1',
  558. })
  559. expect(result).to eq({ count: 7, ticket_ids: [ticket8.id.to_s, ticket7.id.to_s, ticket6.id.to_s, ticket5.id.to_s, ticket4.id.to_s, ticket3.id.to_s, ticket2.id.to_s] })
  560. end
  561. it 'finds records with is not _' do
  562. result = described_class.selectors('Ticket',
  563. 'title' => {
  564. 'operator' => 'is not',
  565. 'value' => 'some_title2',
  566. })
  567. expect(result).to eq({ count: 7, ticket_ids: [ticket8.id.to_s, ticket7.id.to_s, ticket6.id.to_s, ticket5.id.to_s, ticket4.id.to_s, ticket3.id.to_s, ticket1.id.to_s] })
  568. end
  569. it 'finds records with is not ::' do
  570. result = described_class.selectors('Ticket',
  571. 'title' => {
  572. 'operator' => 'is not',
  573. 'value' => 'some::title3',
  574. })
  575. expect(result).to eq({ count: 7, ticket_ids: [ticket8.id.to_s, ticket7.id.to_s, ticket6.id.to_s, ticket5.id.to_s, ticket4.id.to_s, ticket2.id.to_s, ticket1.id.to_s] })
  576. end
  577. it 'finds records with is not 4' do
  578. result = described_class.selectors('Ticket',
  579. 'state_id' => {
  580. 'operator' => 'is not',
  581. 'value' => 4,
  582. })
  583. expect(result).to eq({ count: 7, ticket_ids: [ticket8.id.to_s, ticket7.id.to_s, ticket6.id.to_s, ticket5.id.to_s, ticket4.id.to_s, ticket3.id.to_s, ticket1.id.to_s] })
  584. end
  585. it 'finds records with is not "4"' do
  586. result = described_class.selectors('Ticket',
  587. 'state_id' => {
  588. 'operator' => 'is not',
  589. 'value' => '4',
  590. })
  591. expect(result).to eq({ count: 7, ticket_ids: [ticket8.id.to_s, ticket7.id.to_s, ticket6.id.to_s, ticket5.id.to_s, ticket4.id.to_s, ticket3.id.to_s, ticket1.id.to_s] })
  592. end
  593. it 'finds records with is not state_id ["4"] and title ["sometitle"]' do
  594. result = described_class.selectors('Ticket',
  595. 'state_id' => {
  596. 'operator' => 'is not',
  597. 'value' => ['4'],
  598. },
  599. 'title' => {
  600. 'operator' => 'is',
  601. 'value' => ['sometitle'],
  602. })
  603. expect(result).to eq({ count: 1, ticket_ids: [ticket8.id.to_s] })
  604. end
  605. end
  606. context 'mentions' do
  607. it 'finds records with pre_condition is not_set' do
  608. result = described_class.selectors('Ticket',
  609. {
  610. 'ticket.mention_user_ids' => {
  611. 'pre_condition' => 'not_set',
  612. 'operator' => 'is',
  613. },
  614. },
  615. { current_user: agent1 },
  616. {
  617. field: 'created_at', # sort to verify result
  618. })
  619. expect(result).to eq({ count: 7, ticket_ids: [ticket8.id.to_s, ticket7.id.to_s, ticket6.id.to_s, ticket5.id.to_s, ticket4.id.to_s, ticket3.id.to_s, ticket2.id.to_s] })
  620. end
  621. it 'finds records with pre_condition is not not_set' do
  622. result = described_class.selectors('Ticket',
  623. {
  624. 'ticket.mention_user_ids' => {
  625. 'pre_condition' => 'not_set',
  626. 'operator' => 'is not',
  627. },
  628. },
  629. { current_user: agent1 },
  630. {
  631. field: 'created_at', # sort to verify result
  632. })
  633. expect(result).to eq({ count: 1, ticket_ids: [ticket1.id.to_s] })
  634. end
  635. it 'finds records with pre_condition is current_user.id' do
  636. result = described_class.selectors('Ticket',
  637. {
  638. 'ticket.mention_user_ids' => {
  639. 'pre_condition' => 'current_user.id',
  640. 'operator' => 'is',
  641. },
  642. },
  643. { current_user: agent1 },
  644. {
  645. field: 'created_at', # sort to verify result
  646. })
  647. expect(result).to eq({ count: 1, ticket_ids: [ticket1.id.to_s] })
  648. end
  649. it 'finds records with pre_condition is not current_user.id' do
  650. result = described_class.selectors('Ticket',
  651. {
  652. 'ticket.mention_user_ids' => {
  653. 'pre_condition' => 'current_user.id',
  654. 'operator' => 'is not',
  655. },
  656. },
  657. { current_user: agent1 },
  658. {
  659. field: 'created_at', # sort to verify result
  660. })
  661. expect(result).to eq({ count: 7, ticket_ids: [ticket8.id.to_s, ticket7.id.to_s, ticket6.id.to_s, ticket5.id.to_s, ticket4.id.to_s, ticket3.id.to_s, ticket2.id.to_s] })
  662. end
  663. it 'finds records with pre_condition is specific' do
  664. result = described_class.selectors('Ticket',
  665. {
  666. 'ticket.mention_user_ids' => {
  667. 'pre_condition' => 'specific',
  668. 'operator' => 'is',
  669. 'value' => agent1.id,
  670. },
  671. },
  672. {},
  673. {
  674. field: 'created_at', # sort to verify result
  675. })
  676. expect(result).to eq({ count: 1, ticket_ids: [ticket1.id.to_s] })
  677. end
  678. it 'finds records with pre_condition is not specific' do
  679. result = described_class.selectors('Ticket',
  680. {
  681. 'ticket.mention_user_ids' => {
  682. 'pre_condition' => 'specific',
  683. 'operator' => 'is not',
  684. 'value' => agent1.id,
  685. },
  686. },
  687. {},
  688. {
  689. field: 'created_at', # sort to verify result
  690. })
  691. expect(result).to eq({ count: 7, ticket_ids: [ticket8.id.to_s, ticket7.id.to_s, ticket6.id.to_s, ticket5.id.to_s, ticket4.id.to_s, ticket3.id.to_s, ticket2.id.to_s] })
  692. end
  693. end
  694. end
  695. end