search_index_backend_spec.rb 37 KB

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