rasti-db 1.5.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
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