rasti-db 1.5.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +52 -19
  3. data/lib/rasti/db.rb +11 -2
  4. data/lib/rasti/db/collection.rb +67 -36
  5. data/lib/rasti/db/computed_attribute.rb +22 -0
  6. data/lib/rasti/db/data_source.rb +18 -0
  7. data/lib/rasti/db/environment.rb +32 -0
  8. data/lib/rasti/db/nql/filter_condition_strategies/base.rb +17 -0
  9. data/lib/rasti/db/nql/filter_condition_strategies/postgres.rb +21 -0
  10. data/lib/rasti/db/nql/filter_condition_strategies/sqlite.rb +21 -0
  11. data/lib/rasti/db/nql/filter_condition_strategies/types/generic.rb +49 -0
  12. data/lib/rasti/db/nql/filter_condition_strategies/types/pg_array.rb +32 -0
  13. data/lib/rasti/db/nql/filter_condition_strategies/types/sqlite_array.rb +34 -0
  14. data/lib/rasti/db/nql/filter_condition_strategies/unsupported_type_comparison.rb +22 -0
  15. data/lib/rasti/db/nql/nodes/array_content.rb +21 -0
  16. data/lib/rasti/db/nql/nodes/attribute.rb +37 -0
  17. data/lib/rasti/db/nql/nodes/binary_node.rb +4 -0
  18. data/lib/rasti/db/nql/nodes/comparisons/base.rb +15 -1
  19. data/lib/rasti/db/nql/nodes/comparisons/equal.rb +0 -4
  20. data/lib/rasti/db/nql/nodes/comparisons/greater_than.rb +0 -4
  21. data/lib/rasti/db/nql/nodes/comparisons/greater_than_or_equal.rb +0 -4
  22. data/lib/rasti/db/nql/nodes/comparisons/include.rb +0 -4
  23. data/lib/rasti/db/nql/nodes/comparisons/less_than.rb +0 -4
  24. data/lib/rasti/db/nql/nodes/comparisons/less_than_or_equal.rb +0 -4
  25. data/lib/rasti/db/nql/nodes/comparisons/like.rb +0 -4
  26. data/lib/rasti/db/nql/nodes/comparisons/not_equal.rb +0 -4
  27. data/lib/rasti/db/nql/nodes/comparisons/not_include.rb +0 -4
  28. data/lib/rasti/db/nql/nodes/conjunction.rb +2 -2
  29. data/lib/rasti/db/nql/nodes/constants/array.rb +17 -0
  30. data/lib/rasti/db/nql/nodes/constants/base.rb +17 -0
  31. data/lib/rasti/db/nql/nodes/constants/false.rb +1 -1
  32. data/lib/rasti/db/nql/nodes/constants/float.rb +1 -1
  33. data/lib/rasti/db/nql/nodes/constants/integer.rb +1 -1
  34. data/lib/rasti/db/nql/nodes/constants/literal_string.rb +1 -1
  35. data/lib/rasti/db/nql/nodes/constants/string.rb +1 -1
  36. data/lib/rasti/db/nql/nodes/constants/time.rb +1 -1
  37. data/lib/rasti/db/nql/nodes/constants/true.rb +1 -1
  38. data/lib/rasti/db/nql/nodes/disjunction.rb +2 -2
  39. data/lib/rasti/db/nql/nodes/parenthesis_sentence.rb +6 -2
  40. data/lib/rasti/db/nql/nodes/sentence.rb +6 -2
  41. data/lib/rasti/db/nql/syntax.rb +262 -44
  42. data/lib/rasti/db/nql/syntax.treetop +27 -14
  43. data/lib/rasti/db/query.rb +55 -23
  44. data/lib/rasti/db/relations/base.rb +22 -8
  45. data/lib/rasti/db/relations/graph.rb +10 -16
  46. data/lib/rasti/db/relations/many_to_many.rb +57 -23
  47. data/lib/rasti/db/relations/many_to_one.rb +9 -7
  48. data/lib/rasti/db/relations/one_to_many.rb +21 -13
  49. data/lib/rasti/db/type_converters/sqlite.rb +62 -0
  50. data/lib/rasti/db/type_converters/sqlite_types/array.rb +34 -0
  51. data/lib/rasti/db/version.rb +1 -1
  52. data/rasti-db.gemspec +1 -0
  53. data/spec/collection_spec.rb +210 -50
  54. data/spec/computed_attribute_spec.rb +32 -0
  55. data/spec/minitest_helper.rb +77 -15
  56. data/spec/model_spec.rb +4 -2
  57. data/spec/nql/computed_attributes_spec.rb +29 -0
  58. data/spec/nql/filter_condition_spec.rb +23 -4
  59. data/spec/nql/filter_condition_strategies_spec.rb +112 -0
  60. data/spec/nql/syntax_parser_spec.rb +36 -5
  61. data/spec/query_spec.rb +340 -54
  62. data/spec/relations_spec.rb +27 -7
  63. data/spec/type_converters/sqlite_spec.rb +66 -0
  64. metadata +40 -4
  65. data/lib/rasti/db/helpers.rb +0 -16
  66. data/lib/rasti/db/nql/nodes/field.rb +0 -23
@@ -3,22 +3,26 @@ require 'minitest_helper'
3
3
  describe 'Query' do
4
4
 
5
5
  before do
6
- 1.upto(10) do |i|
6
+ custom_db[:languages].insert name: 'Spanish'
7
+
8
+ 1.upto(10) do |i|
7
9
  db[:users].insert name: "User #{i}"
8
10
 
9
- db[:people].insert user_id: i,
10
- document_number: i,
11
- first_name: "Name #{i}",
12
- last_name: "Last Name #{i}",
13
- birth_date: Time.now
11
+ db[:people].insert user_id: i,
12
+ document_number: "document_#{i}",
13
+ first_name: "Name #{i}",
14
+ last_name: "Last Name #{i}",
15
+ birth_date: Date.parse('2020-04-24')
16
+
17
+ db[:languages_people].insert language_id: 1, document_number: "document_#{i}"
14
18
  end
15
19
 
16
- db[:posts].insert user_id: 2, title: 'Sample post', body: '...'
17
- db[:posts].insert user_id: 1, title: 'Another post', body: '...'
18
- db[:posts].insert user_id: 4, title: 'Best post', body: '...'
20
+ db[:posts].insert user_id: 2, title: 'Sample post', body: '...', language_id: 1
21
+ db[:posts].insert user_id: 1, title: 'Another post', body: '...', language_id: 1
22
+ db[:posts].insert user_id: 4, title: 'Best post', body: '...', language_id: 1
19
23
 
20
24
  1.upto(3) { |i| db[:categories].insert name: "Category #{i}" }
21
-
25
+
22
26
  db[:comments].insert post_id: 1, user_id: 5, text: 'Comment 1'
23
27
  db[:comments].insert post_id: 1, user_id: 7, text: 'Comment 2'
24
28
  db[:comments].insert post_id: 2, user_id: 2, text: 'Comment 3'
@@ -30,11 +34,15 @@ describe 'Query' do
30
34
  db[:categories_posts].insert post_id: 3, category_id: 3
31
35
  end
32
36
 
33
- let(:users_query) { Rasti::DB::Query.new collection_class: Users, dataset: db[:users] }
34
-
35
- let(:posts_query) { Rasti::DB::Query.new collection_class: Posts, dataset: db[:posts] }
36
-
37
- let(:comments_query) { Rasti::DB::Query.new collection_class: Comments, dataset: db[:comments] }
37
+ let(:users_query) { Rasti::DB::Query.new collection_class: Users, dataset: db[:users], environment: environment }
38
+
39
+ let(:posts_query) { Rasti::DB::Query.new collection_class: Posts, dataset: db[:posts], environment: environment }
40
+
41
+ let(:comments_query) { Rasti::DB::Query.new collection_class: Comments, dataset: db[:comments], environment: environment }
42
+
43
+ let(:people_query) { Rasti::DB::Query.new collection_class: People, dataset: db[:people], environment: environment }
44
+
45
+ let(:languages_query) { Rasti::DB::Query.new collection_class: Languages, dataset: custom_db[:languages], environment: environment }
38
46
 
39
47
  it 'Count' do
40
48
  users_query.count.must_equal 10
@@ -62,7 +70,7 @@ describe 'Query' do
62
70
  end
63
71
 
64
72
  it 'Exclude attributes' do
65
- posts_query.exclude_attributes(:body).all.must_equal db[:posts].select(:id, :user_id, :title).map { |r| Post.new r }
73
+ posts_query.exclude_attributes(:body).all.must_equal db[:posts].select(:id, :user_id, :title, :language_id).map { |r| Post.new r }
66
74
  end
67
75
 
68
76
  it 'All attributes' do
@@ -70,35 +78,57 @@ describe 'Query' do
70
78
  end
71
79
 
72
80
  it 'Select graph attributes' do
73
- person = Person.new db[:people].where(document_number: 2).select(:first_name, :last_name, :user_id).first
81
+ language = Language.new custom_db[:languages].where(id: 1).select(:id).first
82
+
83
+ person = Person.new db[:people].where(document_number: 'document_2').select(:document_number, :user_id).first.merge(languages: [language])
74
84
 
75
85
  user = User.new db[:users].where(id: 2).select(:id).first.merge(person: person)
76
86
 
77
- post = Post.new db[:posts].where(id: 1).first.merge(user: user)
87
+ categories = db[:categories].where(id: [1,2]).select(:id).map { |c| Category.new c }
88
+
89
+ post = Post.new db[:posts].where(id: 1).first.merge(user: user, categories: categories)
90
+
91
+ selected_attributes = {
92
+ user: [:id],
93
+ 'user.person' => [:document_number, :user_id],
94
+ 'user.person.languages' => [:id],
95
+ categories: [:id]
96
+ }
78
97
 
79
98
  posts_query.where(id: 1)
80
- .graph('user.person')
81
- .select_graph_attributes(user: [:id], 'user.person' => [:first_name, :last_name, :user_id])
99
+ .graph(*selected_attributes.keys)
100
+ .select_graph_attributes(selected_attributes)
82
101
  .all
83
102
  .must_equal [post]
84
103
  end
85
-
104
+
86
105
  it 'Exclude graph attributes' do
87
- person = Person.new db[:people].where(document_number: 2).select(:document_number, :last_name, :user_id).first
106
+ language = Language.new custom_db[:languages].where(id: 1).select(:id).first
107
+
108
+ person = Person.new db[:people].where(document_number: 'document_2').select(:document_number, :user_id).first.merge(languages: [language])
88
109
 
89
110
  user = User.new db[:users].where(id: 2).select(:id).first.merge(person: person)
90
111
 
91
- post = Post.new db[:posts].where(id: 1).first.merge(user: user)
112
+ categories = db[:categories].where(id: [1,2]).select(:id).map { |c| Category.new c }
113
+
114
+ post = Post.new db[:posts].where(id: 1).first.merge(user: user, categories: categories)
115
+
116
+ excluded_attributes = {
117
+ user: [:name],
118
+ 'user.person' => [:first_name, :last_name, :birth_date],
119
+ 'user.person.languages' => [:name],
120
+ categories: [:name]
121
+ }
92
122
 
93
123
  posts_query.where(id: 1)
94
- .graph('user.person')
95
- .exclude_graph_attributes(user: [:name], 'user.person' => [:first_name, :birth_date])
124
+ .graph(*excluded_attributes.keys)
125
+ .exclude_graph_attributes(excluded_attributes)
96
126
  .all
97
127
  .must_equal [post]
98
128
  end
99
-
129
+
100
130
  it 'All graph attributes' do
101
- person = Person.new db[:people].where(document_number: 2).first
131
+ person = Person.new db[:people].where(document_number: 'document_2').first
102
132
 
103
133
  user = User.new db[:users].where(id: 2).select(:id).first.merge(person: person)
104
134
 
@@ -112,6 +142,30 @@ describe 'Query' do
112
142
  .must_equal [post]
113
143
  end
114
144
 
145
+ describe 'Select computed attributes' do
146
+ it 'With join' do
147
+ db[:comments].insert post_id: 1, user_id: 5, text: 'Comment 4'
148
+ users_query.select_computed_attributes(:comments_count)
149
+ .where(id: 5)
150
+ .all
151
+ .must_equal [User.new(id: 5, name: 'User 5', comments_count: 2)]
152
+ end
153
+
154
+ it 'Without join' do
155
+ person_expected = Person.new user_id: 1,
156
+ document_number: 'document_1',
157
+ first_name: 'Name 1',
158
+ last_name: 'Last Name 1',
159
+ birth_date: Date.parse('2020-04-24'),
160
+ full_name: 'Name 1 Last Name 1'
161
+
162
+ people_query.select_computed_attributes(:full_name)
163
+ .where(document_number: 'document_1')
164
+ .all
165
+ .must_equal [person_expected]
166
+ end
167
+ end
168
+
115
169
  it 'Map' do
116
170
  users_query.map(&:name).must_equal db[:users].map(:name)
117
171
  end
@@ -120,45 +174,88 @@ describe 'Query' do
120
174
  users_query.detect(id: 3).must_equal User.new(id: 3, name: 'User 3')
121
175
  end
122
176
 
177
+ describe 'Each' do
178
+
179
+ it 'without size' do
180
+ users = []
181
+
182
+ users_query.each do |user|
183
+ users << user
184
+ end
185
+
186
+ users.size.must_equal 10
187
+ users.each_with_index do |user, i|
188
+ user.must_equal User.new(id: i+1, name: "User #{i+1}")
189
+ end
190
+ end
191
+
192
+ it 'with size' do
193
+ users = []
194
+ users_query.each(batch_size: 2) do |user|
195
+ users << user
196
+ end
197
+
198
+ users.size.must_equal 10
199
+ users.each_with_index do |user, i|
200
+ user.must_equal User.new(id: i+1, name: "User #{i+1}")
201
+ end
202
+ end
203
+
204
+ end
205
+
206
+ it 'Each batch' do
207
+ users_batch = []
208
+ users_query.each_batch(size: 2) do |page|
209
+ users_batch << page
210
+ end
211
+
212
+ users_batch.size.must_equal 5
213
+ i = 1
214
+ users_batch.each do |user_page|
215
+ user_page.must_equal [User.new(id: i, name: "User #{i}"), User.new(id: i+1, name: "User #{i+1}")]
216
+ i += 2
217
+ end
218
+ end
219
+
123
220
  it 'Where' do
124
221
  users_query.where(id: 3).all.must_equal [User.new(id: 3, name: 'User 3')]
125
222
  end
126
-
223
+
127
224
  it 'Exclude' do
128
225
  users_query.exclude(id: [1,2,3,4,5,6,7,8,9]).all.must_equal [User.new(id: 10, name: 'User 10')]
129
226
  end
130
-
227
+
131
228
  it 'And' do
132
229
  users_query.where(id: [1,2]).where(name: 'User 2').all.must_equal [User.new(id: 2, name: 'User 2')]
133
230
  end
134
-
231
+
135
232
  it 'Or' do
136
233
  users_query.where(id: 1).or(name: 'User 2').all.must_equal [
137
- User.new(id: 1, name: 'User 1'),
234
+ User.new(id: 1, name: 'User 1'),
138
235
  User.new(id: 2, name: 'User 2')
139
236
  ]
140
237
  end
141
-
238
+
142
239
  it 'Order' do
143
240
  posts_query.order(:title).all.must_equal [
144
- Post.new(id: 2, user_id: 1, title: 'Another post', body: '...'),
145
- Post.new(id: 3, user_id: 4, title: 'Best post', body: '...'),
146
- Post.new(id: 1, user_id: 2, title: 'Sample post', body: '...')
241
+ Post.new(id: 2, user_id: 1, title: 'Another post', body: '...', language_id: 1),
242
+ Post.new(id: 3, user_id: 4, title: 'Best post', body: '...', language_id: 1),
243
+ Post.new(id: 1, user_id: 2, title: 'Sample post', body: '...', language_id: 1)
147
244
  ]
148
245
  end
149
-
246
+
150
247
  it 'Reverse order' do
151
248
  posts_query.reverse_order(:title).all.must_equal [
152
- Post.new(id: 1, user_id: 2, title: 'Sample post', body: '...'),
153
- Post.new(id: 3, user_id: 4, title: 'Best post', body: '...'),
154
- Post.new(id: 2, user_id: 1, title: 'Another post', body: '...')
249
+ Post.new(id: 1, user_id: 2, title: 'Sample post', body: '...', language_id: 1),
250
+ Post.new(id: 3, user_id: 4, title: 'Best post', body: '...', language_id: 1),
251
+ Post.new(id: 2, user_id: 1, title: 'Another post', body: '...', language_id: 1)
155
252
  ]
156
253
  end
157
-
254
+
158
255
  it 'Limit and offset' do
159
256
  users_query.limit(1).offset(1).all.must_equal [User.new(id: 2, name: 'User 2')]
160
257
  end
161
-
258
+
162
259
  it 'First' do
163
260
  users_query.first.must_equal User.new(id: 1, name: 'User 1')
164
261
  end
@@ -168,7 +265,32 @@ describe 'Query' do
168
265
  end
169
266
 
170
267
  it 'Graph' do
171
- users_query.graph(:posts).where(id: 1).first.must_equal User.new(id: 1, name: 'User 1', posts: [Post.new(id: 2, user_id: 1, title: 'Another post', body: '...')])
268
+ users_query.graph(:posts).where(id: 1).first.must_equal User.new(id: 1, name: 'User 1', posts: [Post.new(id: 2, user_id: 1, title: 'Another post', body: '...', language_id: 1)])
269
+ end
270
+
271
+ it 'Graph with multiple data sources' do
272
+ language = Language.new id: 1, name: 'Spanish'
273
+
274
+ person = Person.new user_id: 2,
275
+ document_number: 'document_2',
276
+ first_name: 'Name 2',
277
+ last_name: 'Last Name 2',
278
+ birth_date: Date.parse('2020-04-24'),
279
+ languages: [language]
280
+
281
+ user = User.new id: 2,
282
+ name: 'User 2',
283
+ person: person
284
+
285
+ post = Post.new id: 1,
286
+ user_id: 2,
287
+ user: user,
288
+ title: 'Sample post',
289
+ body: '...',
290
+ language_id: 1,
291
+ language: language
292
+
293
+ posts_query.where(id: 1).graph(:language, 'user.person.languages').first.must_equal post
172
294
  end
173
295
 
174
296
  it 'Any?' do
@@ -184,7 +306,7 @@ describe 'Query' do
184
306
  end
185
307
 
186
308
  it 'To String' do
187
- users_query.where(id: [1,2,3]).order(:name).to_s.must_equal '#<Rasti::DB::Query: "SELECT * FROM `users` WHERE (`id` IN (1, 2, 3)) ORDER BY `name`">'
309
+ users_query.where(id: [1,2,3]).order(:name).to_s.must_equal '#<Rasti::DB::Query: "SELECT `users`.* FROM `users` WHERE (`users`.`id` IN (1, 2, 3)) ORDER BY `users`.`name`">'
188
310
  end
189
311
 
190
312
  describe 'Named queries' do
@@ -204,30 +326,62 @@ describe 'Query' do
204
326
  describe 'Join' do
205
327
 
206
328
  it 'One to Many' do
207
- users_query.join(:posts).where(title: 'Sample post').all.must_equal [User.new(id: 2, name: 'User 2')]
329
+ users_query.join(:posts).where(Sequel[:posts][:title] => 'Sample post').all.must_equal [User.new(id: 2, name: 'User 2')]
208
330
  end
209
331
 
210
332
  it 'Many to One' do
211
- posts_query.join(:user).where(name: 'User 4').all.must_equal [Post.new(id: 3, user_id: 4, title: 'Best post', body: '...')]
333
+ posts_query.join(:user).where(Sequel[:user][:name] => 'User 4').all.must_equal [Post.new(id: 3, user_id: 4, title: 'Best post', body: '...', language_id: 1)]
212
334
  end
213
335
 
214
336
  it 'One to One' do
215
- users_query.join(:person).where(document_number: 1).all.must_equal [User.new(id: 1, name: 'User 1')]
337
+ users_query.join(:person).where(Sequel[:person][:document_number] => 'document_1').all.must_equal [User.new(id: 1, name: 'User 1')]
216
338
  end
217
339
 
218
340
  it 'Many to Many' do
219
- posts_query.join(:categories).where(name: 'Category 3').order(:id).all.must_equal [
220
- Post.new(id: 2, user_id: 1, title: 'Another post', body: '...'),
221
- Post.new(id: 3, user_id: 4, title: 'Best post', body: '...'),
341
+ posts_query.join(:categories).where(Sequel[:categories][:name] => 'Category 3').order(:id).all.must_equal [
342
+ Post.new(id: 2, user_id: 1, title: 'Another post', body: '...', language_id: 1),
343
+ Post.new(id: 3, user_id: 4, title: 'Best post', body: '...', language_id: 1),
222
344
  ]
223
345
  end
224
346
 
225
347
  it 'Nested' do
226
348
  posts_query.join('categories', 'comments.user.person')
227
349
  .where(Sequel[:categories][:name] => 'Category 2')
228
- .where(Sequel[:comments__user__person][:document_number] => 7)
350
+ .where(Sequel[:comments__user__person][:document_number] => 'document_7')
229
351
  .all
230
- .must_equal [Post.new(id: 1, user_id: 2, title: 'Sample post', body: '...')]
352
+ .must_equal [Post.new(id: 1, user_id: 2, title: 'Sample post', body: '...', language_id: 1)]
353
+ end
354
+
355
+ it 'Excluded attributes permanents excluded when join' do
356
+ posts_query.join(:user)
357
+ .exclude_attributes(:body)
358
+ .where(Sequel[:user][:name] => 'User 4')
359
+ .all
360
+ .must_equal [Post.new(id: 3, title: 'Best post', user_id: 4, language_id: 1)]
361
+
362
+ posts_query.exclude_attributes(:body)
363
+ .join(:user)
364
+ .where(Sequel[:user][:name] => 'User 4')
365
+ .all
366
+ .must_equal [Post.new(id: 3, title: 'Best post', user_id: 4, language_id: 1)]
367
+ end
368
+
369
+ describe 'Multiple data sources' do
370
+
371
+ it 'One to Many' do
372
+ error = proc { languages_query.join(:posts).all }.must_raise RuntimeError
373
+ error.message.must_equal 'Invalid join of multiple data sources: custom.languages > default.posts'
374
+ end
375
+
376
+ it 'Many to One' do
377
+ error = proc { posts_query.join(:language).all }.must_raise RuntimeError
378
+ error.message.must_equal 'Invalid join of multiple data sources: default.posts > custom.languages'
379
+ end
380
+
381
+ it 'Many to Many' do
382
+ error = proc { languages_query.join(:people).all }.must_raise RuntimeError
383
+ error.message.must_equal 'Invalid join of multiple data sources: custom.languages > default.people'
384
+ end
231
385
  end
232
386
 
233
387
  end
@@ -238,7 +392,7 @@ describe 'Query' do
238
392
  error = proc { posts_query.nql('a + b') }.must_raise Rasti::DB::NQL::InvalidExpressionError
239
393
  error.message.must_equal 'Invalid filter expression: a + b'
240
394
  end
241
-
395
+
242
396
  it 'Filter to self table' do
243
397
  posts_query.nql('user_id > 1')
244
398
  .pluck(:user_id)
@@ -254,17 +408,149 @@ describe 'Query' do
254
408
  end
255
409
 
256
410
  it 'Filter to 2nd order relation' do
257
- posts_query.nql('comments.user.person.document_number = 7')
411
+ posts_query.nql('comments.user.person.document_number = document_7')
258
412
  .pluck(:id)
259
413
  .must_equal [1]
260
414
  end
261
415
 
262
416
  it 'Filter combined' do
263
- posts_query.nql('(categories.id = 1 | categories.id = 3) & comments.user.person.document_number = 2')
417
+ posts_query.nql('(categories.id = 1 | categories.id = 3) & comments.user.person.document_number = document_2')
264
418
  .pluck(:id)
265
419
  .must_equal [2]
266
420
  end
267
421
 
422
+ describe 'Computed Attributes' do
423
+
424
+ it 'Filter relation computed attribute' do
425
+ db[:comments].insert post_id: 1, user_id: 5, text: 'Comment 4'
426
+ users_query.nql('comments_count = 2').all.must_equal [User.new(id: 5, name: 'User 5')]
427
+ end
428
+
429
+ it 'Filter with relation computed attribute with "and" combined' do
430
+ db[:comments].insert post_id: 1, user_id: 5, text: 'Comment 4'
431
+ db[:comments].insert post_id: 1, user_id: 4, text: 'Comment 3'
432
+ users_query.nql('(comments_count > 1) & (id = 5)').all.must_equal [User.new(id: 5, name: 'User 5')]
433
+ end
434
+
435
+ it 'Filter relation computed attribute with "or" combined' do
436
+ db[:comments].insert post_id: 1, user_id: 2, text: 'Comment 3'
437
+ users_query.nql('(comments_count = 2) | (id = 5)')
438
+ .order(:id)
439
+ .all
440
+ .must_equal [ User.new(id: 2, name: 'User 2'), User.new(id: 5, name: 'User 5') ]
441
+ end
442
+
443
+ it 'Filter relation computed attribute with "and" and "or" combined' do
444
+ db[:comments].insert post_id: 1, user_id: 2, text: 'Comment 3'
445
+ users_query.nql('((comments_count = 2) | (id = 5)) & (name: User 5)')
446
+ .order(:id)
447
+ .all
448
+ .must_equal [ User.new(id: 5, name: 'User 5') ]
449
+ end
450
+
451
+ it 'Filter simple computed attribute' do
452
+ person_expected = Person.new user_id: 1,
453
+ document_number: 'document_1',
454
+ first_name: 'Name 1',
455
+ last_name: 'Last Name 1',
456
+ birth_date: Date.parse('2020-04-24')
457
+
458
+ people_query.nql('full_name = Name 1 Last Name 1')
459
+ .all
460
+ .must_equal [person_expected]
461
+ end
462
+
463
+ end
464
+
465
+ describe 'Filter Array' do
466
+
467
+ def filter_condition_must_raise(comparison_symbol, comparison_name)
468
+ error = proc { comments_query.nql("tags #{comparison_symbol} [fake, notice]") }.must_raise Rasti::DB::NQL::FilterConditionStrategies::UnsupportedTypeComparison
469
+ error.argument_type.must_equal Rasti::DB::NQL::FilterConditionStrategies::Types::SQLiteArray
470
+ error.comparison_name.must_equal comparison_name
471
+ error.message.must_equal "Unsupported comparison #{comparison_name} for Rasti::DB::NQL::FilterConditionStrategies::Types::SQLiteArray"
472
+ end
473
+
474
+ it 'Must raise exception from not supported methods' do
475
+ comparisons = {
476
+ greater_than: '>',
477
+ greater_than_or_equal: '>=',
478
+ less_than: '<',
479
+ less_than_or_equal: '<='
480
+ }
481
+
482
+ comparisons.each do |name, symbol|
483
+ filter_condition_must_raise symbol, name
484
+ end
485
+ end
486
+
487
+ it 'Included any of these elements' do
488
+ db[:comments].insert post_id: 1, user_id: 5, text: 'fake notice', tags: '["fake","notice"]'
489
+ db[:comments].insert post_id: 1, user_id: 5, text: 'fake notice 2', tags: '["notice"]'
490
+ db[:comments].insert post_id: 1, user_id: 5, text: 'fake notice 3', tags: '["fake_notice"]'
491
+ expected_comments = [
492
+ Comment.new(id: 4, text: 'fake notice', tags: ['fake','notice'], user_id: 5, post_id: 1),
493
+ Comment.new(id: 5, text: 'fake notice 2', tags: ['notice'], user_id: 5, post_id: 1)
494
+ ]
495
+
496
+ comments_query.nql('tags: [ fake, notice ]')
497
+ .all
498
+ .must_equal expected_comments
499
+ end
500
+
501
+ it 'Included exactly all these elements' do
502
+ db[:comments].insert post_id: 1, user_id: 5, text: 'fake notice', tags: '["fake","notice"]'
503
+ db[:comments].insert post_id: 1, user_id: 5, text: 'fake notice 2', tags: '["notice"]'
504
+ comments_query.nql('tags = [fake, notice]')
505
+ .all
506
+ .must_equal [Comment.new(id: 4, text: 'fake notice', tags: ['fake','notice'], user_id: 5, post_id: 1)]
507
+ end
508
+
509
+ it 'Not included anyone of these elements' do
510
+ db[:comments].insert post_id: 1, user_id: 5, text: 'fake notice', tags: '["fake","notice"]'
511
+ db[:comments].insert post_id: 1, user_id: 5, text: 'Good notice!', tags: '["good"]'
512
+ db[:comments].insert post_id: 1, user_id: 5, text: 'fake notice', tags: '["fake"]'
513
+ expected_comments = [
514
+ Comment.new(id: 1, text: 'Comment 1', tags: [], user_id: 5, post_id: 1),
515
+ Comment.new(id: 2, text: 'Comment 2', tags: [], user_id: 7, post_id: 1),
516
+ Comment.new(id: 3, text: 'Comment 3', tags: [], user_id: 2, post_id: 2),
517
+ Comment.new(id: 5, text: 'Good notice!', tags: ['good'], user_id: 5, post_id: 1)
518
+ ]
519
+ comments_query.nql('tags !: [fake, notice]')
520
+ .all
521
+ .must_equal expected_comments
522
+ end
523
+
524
+ it 'Not include any of these elements' do
525
+ db[:comments].insert post_id: 1, user_id: 5, text: 'fake notice', tags: '["fake","notice"]'
526
+ db[:comments].insert post_id: 1, user_id: 5, text: 'Good notice!', tags: '["good"]'
527
+ db[:comments].insert post_id: 1, user_id: 5, text: 'fake notice', tags: '["fake"]'
528
+ expected_comments = [
529
+ Comment.new(id: 1, text: 'Comment 1', tags: '[]', user_id: 5, post_id: 1),
530
+ Comment.new(id: 2, text: 'Comment 2', tags: '[]', user_id: 7, post_id: 1),
531
+ Comment.new(id: 3, text: 'Comment 3', tags: '[]', user_id: 2, post_id: 2),
532
+ Comment.new(id: 5, text: 'Good notice!', tags: ['good'], user_id: 5, post_id: 1),
533
+ Comment.new(id: 6, text: 'fake notice', tags: ['fake'], user_id: 5, post_id: 1)
534
+ ]
535
+ comments_query.nql('tags != [fake, notice]')
536
+ .all
537
+ .must_equal expected_comments
538
+ end
539
+
540
+ it 'Include any like these elements' do
541
+ db[:comments].insert post_id: 1, user_id: 5, text: 'fake notice', tags: '["fake","notice"]'
542
+ db[:comments].insert post_id: 1, user_id: 5, text: 'this is a fake notice!', tags: '["fake_notice"]'
543
+ expected_comments = [
544
+ Comment.new(id: 4, text: 'fake notice', tags: ['fake','notice'], user_id: 5, post_id: 1),
545
+ Comment.new(id: 5, text: 'this is a fake notice!', tags: ['fake_notice'], user_id: 5, post_id: 1)
546
+ ]
547
+ comments_query.nql('tags ~ [fake]')
548
+ .all
549
+ .must_equal expected_comments
550
+ end
551
+
552
+ end
553
+
268
554
  end
269
555
 
270
556
  end