rasti-db 2.0.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +11 -3
  3. data/lib/rasti/db/collection.rb +10 -1
  4. data/lib/rasti/db/computed_attribute.rb +22 -0
  5. data/lib/rasti/db/nql/nodes/attribute.rb +37 -0
  6. data/lib/rasti/db/nql/nodes/binary_node.rb +4 -0
  7. data/lib/rasti/db/nql/nodes/comparisons/base.rb +5 -1
  8. data/lib/rasti/db/nql/nodes/comparisons/equal.rb +2 -2
  9. data/lib/rasti/db/nql/nodes/comparisons/greater_than.rb +2 -2
  10. data/lib/rasti/db/nql/nodes/comparisons/greater_than_or_equal.rb +2 -2
  11. data/lib/rasti/db/nql/nodes/comparisons/include.rb +2 -2
  12. data/lib/rasti/db/nql/nodes/comparisons/less_than.rb +2 -2
  13. data/lib/rasti/db/nql/nodes/comparisons/less_than_or_equal.rb +2 -2
  14. data/lib/rasti/db/nql/nodes/comparisons/like.rb +2 -2
  15. data/lib/rasti/db/nql/nodes/comparisons/not_equal.rb +2 -2
  16. data/lib/rasti/db/nql/nodes/comparisons/not_include.rb +2 -2
  17. data/lib/rasti/db/nql/nodes/conjunction.rb +2 -2
  18. data/lib/rasti/db/nql/nodes/disjunction.rb +2 -2
  19. data/lib/rasti/db/nql/nodes/parenthesis_sentence.rb +6 -2
  20. data/lib/rasti/db/nql/nodes/sentence.rb +6 -2
  21. data/lib/rasti/db/nql/syntax.rb +33 -33
  22. data/lib/rasti/db/nql/syntax.treetop +12 -12
  23. data/lib/rasti/db/query.rb +41 -7
  24. data/lib/rasti/db/version.rb +1 -1
  25. data/spec/computed_attribute_spec.rb +32 -0
  26. data/spec/minitest_helper.rb +30 -3
  27. data/spec/model_spec.rb +1 -1
  28. data/spec/nql/computed_attributes_spec.rb +29 -0
  29. data/spec/nql/filter_condition_spec.rb +4 -2
  30. data/spec/nql/syntax_parser_spec.rb +12 -5
  31. data/spec/query_spec.rb +146 -34
  32. metadata +8 -3
  33. data/lib/rasti/db/nql/nodes/field.rb +0 -23
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8b41f6198798c9bee6da1f94742378639bb3b900f3bda6471f791b42a71a24c7
4
- data.tar.gz: f470e1f1ef5673546e54e6c144e16ebba577b0f848b8fd59c8822489808a7cbf
3
+ metadata.gz: 3166fff22e51aca6cd07d0994d1bf6170438e0bc9aed41e90370a83920a0d9ff
4
+ data.tar.gz: 73e64013ec42740653058f0d9ff6c37ee45de41be0312f2296e4926fb7bff5b4
5
5
  SHA512:
6
- metadata.gz: f5e836d580a42656efe1d78ee2e193449edd1adf45dbccd0a4b4c9c4d6f263a0d92e844a142abb908a683a8dcad4865d5926aec10b5a0260c0240425dcd063dd
7
- data.tar.gz: 71148abafe56a6fe60613f2ebfa38138df2aaa656bdbe7116a834d41f3920fb49b97bfffac3235a520a6ffbb293184310d2d7fcefa552178d1cb767b94ce8e4d
6
+ metadata.gz: 55c6fc7f5b3ef1d904f252e6d54c595b5d4cb72f1fbdf67f3e577c9cc095bd838f0963f34f611f6b7069971f7ead1d96d7dd20864dbcfea8ed542c5a3008dfdc
7
+ data.tar.gz: 3b6c0136ba9823832cf329b3efe78406e69ea92d6d90f89950652628de740ea675a8b7d7152e530838f269b9b32140fa7f80750bcc2b41af70c9efc2b275cd78
data/README.md CHANGED
@@ -93,7 +93,7 @@ User = Rasti::DB::Model[:id, :name, :posts, :comments, :person]
93
93
  Post = Rasti::DB::Model[:id, :title, :body, :user_id, :user, :comments, :categories]
94
94
  Comment = Rasti::DB::Model[:id, :text, :user_id, :user, :post_id, :post]
95
95
  Category = Rasti::DB::Model[:id, :name, :posts]
96
- Person = Rasti::DB::Model[:document_number, :first_name, :last_name, :birth_date, :user_id, :user]
96
+ Person = Rasti::DB::Model[:document_number, :first_name, :last_name, :full_name, :birth_date, :user_id, :user]
97
97
  Language = Rasti::DB::Model[:id, :name, :people]
98
98
  ```
99
99
 
@@ -111,10 +111,10 @@ class Posts < Rasti::DB::Collection
111
111
  many_to_many :categories
112
112
  one_to_many :comments
113
113
 
114
- query :created_by do |user_id|
114
+ query :created_by do |user_id|
115
115
  where user_id: user_id
116
116
  end
117
-
117
+
118
118
  query :entitled, -> (title) { where title: title }
119
119
 
120
120
  query :commented_by do |user_id|
@@ -144,6 +144,10 @@ class People < Rasti::DB::Collection
144
144
 
145
145
  many_to_one :user
146
146
  many_to_many :languages
147
+
148
+ computed_attribute :full_name do
149
+ Rasti::DB::ComputedAttribute.new Sequel.join([:first_name, ' ', :last_name])
150
+ end
147
151
  end
148
152
 
149
153
  class Languages < Rasti::DB::Collection
@@ -210,6 +214,10 @@ posts.all_attributes # => [Post, ...]
210
214
  posts.graph('user.person').select_graph_attributes(user: [:id], 'user.person': [:last_name, :user_id]) # => [Post, ...]
211
215
  posts.graph('user.person').exclude_graph_attributes(user: [:name], 'user.person': [:first_name, :last_name]) # => [Post, ...]
212
216
  posts.graph('user.person').all_graph_attributes('user.person') # => [Post, ...]
217
+
218
+ posts.each { |post| do_something post } # Iterate posts loading all at first
219
+ posts.each(batch_size: 1000) { |post| do_something post } # Iterate posts loading in batches
220
+ posts.each_batch(size: 1000) { |posts| do_something posts } # Iterate batches of posts
213
221
  ```
214
222
  ### Natural Query Language
215
223
 
@@ -14,7 +14,7 @@ module Rasti
14
14
  end
15
15
 
16
16
  def collection_attributes
17
- @collection_attributes ||= model.attributes - relations.keys
17
+ @collection_attributes ||= model.attributes - relations.keys - computed_attributes.keys
18
18
  end
19
19
 
20
20
  def primary_key
@@ -47,6 +47,10 @@ module Rasti
47
47
  @queries ||= Hash::Indifferent.new
48
48
  end
49
49
 
50
+ def computed_attributes
51
+ @computed_attributes ||= Hash::Indifferent.new
52
+ end
53
+
50
54
  private
51
55
 
52
56
  def set_collection_name(collection_name)
@@ -91,6 +95,11 @@ module Rasti
91
95
  end
92
96
  end
93
97
 
98
+ def computed_attribute(name, &block)
99
+ raise "Computed Attribute #{name} already exists" if computed_attributes.key? name
100
+ computed_attributes[name] = block.call
101
+ end
102
+
94
103
  end
95
104
 
96
105
  def initialize(environment)
@@ -0,0 +1,22 @@
1
+ module Rasti
2
+ module DB
3
+ class ComputedAttribute
4
+
5
+ attr_reader :identifier
6
+
7
+ def initialize(identifier, &join)
8
+ @identifier = identifier
9
+ @join = join
10
+ end
11
+
12
+ def apply_join(dataset)
13
+ join ? join.call(dataset) : dataset
14
+ end
15
+
16
+ private
17
+
18
+ attr_reader :join
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,37 @@
1
+ module Rasti
2
+ module DB
3
+ module NQL
4
+ module Nodes
5
+ class Attribute < Treetop::Runtime::SyntaxNode
6
+
7
+ def identifier(collection_class)
8
+ if computed? collection_class
9
+ collection_class.computed_attributes[column].identifier
10
+ else
11
+ tables.empty? ? Sequel[column] : Sequel[tables.join('__').to_sym][column]
12
+ end
13
+ end
14
+
15
+ def tables
16
+ _tables.elements.map{ |e| e.table.text_value }
17
+ end
18
+
19
+ def column
20
+ _column.text_value.to_sym
21
+ end
22
+
23
+ def computed_attributes(collection_class)
24
+ computed?(collection_class) ? [column] : []
25
+ end
26
+
27
+ private
28
+
29
+ def computed?(collection_class)
30
+ collection_class.computed_attributes.key? column
31
+ end
32
+
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -8,6 +8,10 @@ module Rasti
8
8
  values.flat_map(&:dependency_tables)
9
9
  end
10
10
 
11
+ def computed_attributes(collection_class)
12
+ left.computed_attributes(collection_class) | right.computed_attributes(collection_class)
13
+ end
14
+
11
15
  def values
12
16
  @values ||= values_for(left) + values_for(right)
13
17
  end
@@ -6,7 +6,11 @@ module Rasti
6
6
  class Base < Treetop::Runtime::SyntaxNode
7
7
 
8
8
  def dependency_tables
9
- field.tables.empty? ? [] : [field.tables.join('.')]
9
+ attribute.tables.empty? ? [] : [attribute.tables.join('.')]
10
+ end
11
+
12
+ def computed_attributes(collection_class)
13
+ attribute.computed_attributes(collection_class)
10
14
  end
11
15
 
12
16
  end
@@ -5,8 +5,8 @@ module Rasti
5
5
  module Comparisons
6
6
  class Equal < Base
7
7
 
8
- def filter_condition
9
- { field.identifier => argument.value }
8
+ def filter_condition(collection_class)
9
+ { attribute.identifier(collection_class) => argument.value }
10
10
  end
11
11
 
12
12
  end
@@ -5,8 +5,8 @@ module Rasti
5
5
  module Comparisons
6
6
  class GreaterThan < Base
7
7
 
8
- def filter_condition
9
- field.identifier > argument.value
8
+ def filter_condition(collection_class)
9
+ attribute.identifier(collection_class) > argument.value
10
10
  end
11
11
 
12
12
  end
@@ -5,8 +5,8 @@ module Rasti
5
5
  module Comparisons
6
6
  class GreaterThanOrEqual < Base
7
7
 
8
- def filter_condition
9
- field.identifier >= argument.value
8
+ def filter_condition(collection_class)
9
+ attribute.identifier(collection_class) >= argument.value
10
10
  end
11
11
 
12
12
  end
@@ -5,8 +5,8 @@ module Rasti
5
5
  module Comparisons
6
6
  class Include < Base
7
7
 
8
- def filter_condition
9
- Sequel.ilike(field.identifier, "%#{argument.value}%")
8
+ def filter_condition(collection_class)
9
+ Sequel.ilike(attribute.identifier(collection_class), "%#{argument.value}%")
10
10
  end
11
11
 
12
12
  end
@@ -5,8 +5,8 @@ module Rasti
5
5
  module Comparisons
6
6
  class LessThan < Base
7
7
 
8
- def filter_condition
9
- field.identifier < argument.value
8
+ def filter_condition(collection_class)
9
+ attribute.identifier(collection_class) < argument.value
10
10
  end
11
11
 
12
12
  end
@@ -5,8 +5,8 @@ module Rasti
5
5
  module Comparisons
6
6
  class LessThanOrEqual < Base
7
7
 
8
- def filter_condition
9
- field.identifier <= argument.value
8
+ def filter_condition(collection_class)
9
+ attribute.identifier(collection_class) <= argument.value
10
10
  end
11
11
 
12
12
  end
@@ -5,8 +5,8 @@ module Rasti
5
5
  module Comparisons
6
6
  class Like < Base
7
7
 
8
- def filter_condition
9
- Sequel.ilike(field.identifier, argument.value)
8
+ def filter_condition(collection_class)
9
+ Sequel.ilike(attribute.identifier(collection_class), argument.value)
10
10
  end
11
11
 
12
12
  end
@@ -5,8 +5,8 @@ module Rasti
5
5
  module Comparisons
6
6
  class NotEqual < Base
7
7
 
8
- def filter_condition
9
- Sequel.negate(field.identifier => argument.value)
8
+ def filter_condition(collection_class)
9
+ Sequel.negate(attribute.identifier(collection_class) => argument.value)
10
10
  end
11
11
 
12
12
  end
@@ -5,8 +5,8 @@ module Rasti
5
5
  module Comparisons
6
6
  class NotInclude < Base
7
7
 
8
- def filter_condition
9
- ~ Sequel.ilike(field.identifier, "%#{argument.value}%")
8
+ def filter_condition(collection_class)
9
+ ~ Sequel.ilike(attribute.identifier(collection_class), "%#{argument.value}%")
10
10
  end
11
11
 
12
12
  end
@@ -4,8 +4,8 @@ module Rasti
4
4
  module Nodes
5
5
  class Conjunction < BinaryNode
6
6
 
7
- def filter_condition
8
- Sequel.&(*values.map(&:filter_condition))
7
+ def filter_condition(collection_class)
8
+ Sequel.&(*values.map { |value| value.filter_condition(collection_class) } )
9
9
  end
10
10
 
11
11
  end
@@ -4,8 +4,8 @@ module Rasti
4
4
  module Nodes
5
5
  class Disjunction < BinaryNode
6
6
 
7
- def filter_condition
8
- Sequel.|(*values.map(&:filter_condition))
7
+ def filter_condition(collection_class)
8
+ Sequel.|(*values.map { |value| value.filter_condition(collection_class) } )
9
9
  end
10
10
 
11
11
  end
@@ -8,8 +8,12 @@ module Rasti
8
8
  sentence.dependency_tables
9
9
  end
10
10
 
11
- def filter_condition
12
- sentence.filter_condition
11
+ def computed_attributes(collection_class)
12
+ sentence.computed_attributes(collection_class)
13
+ end
14
+
15
+ def filter_condition(collection_class)
16
+ sentence.filter_condition collection_class
13
17
  end
14
18
 
15
19
  end
@@ -8,8 +8,12 @@ module Rasti
8
8
  proposition.dependency_tables
9
9
  end
10
10
 
11
- def filter_condition
12
- proposition.filter_condition
11
+ def computed_attributes(collection_class)
12
+ proposition.computed_attributes collection_class
13
+ end
14
+
15
+ def filter_condition(collection_class)
16
+ proposition.filter_condition collection_class
13
17
  end
14
18
 
15
19
  end
@@ -433,14 +433,14 @@ module Rasti
433
433
  r0
434
434
  end
435
435
 
436
- module Field0
436
+ module Attribute0
437
437
  def table
438
438
  elements[0]
439
439
  end
440
440
 
441
441
  end
442
442
 
443
- module Field1
443
+ module Attribute1
444
444
  def _tables
445
445
  elements[0]
446
446
  end
@@ -450,10 +450,10 @@ module Rasti
450
450
  end
451
451
  end
452
452
 
453
- def _nt_field
453
+ def _nt_attribute
454
454
  start_index = index
455
- if node_cache[:field].has_key?(index)
456
- cached = node_cache[:field][index]
455
+ if node_cache[:attribute].has_key?(index)
456
+ cached = node_cache[:attribute][index]
457
457
  if cached
458
458
  cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
459
459
  @index = cached.interval.end
@@ -465,7 +465,7 @@ module Rasti
465
465
  s1, i1 = [], index
466
466
  loop do
467
467
  i2, s2 = index, []
468
- r3 = _nt_field_name
468
+ r3 = _nt_attribute_name
469
469
  s2 << r3
470
470
  if r3
471
471
  if has_terminal?('.', false, index)
@@ -479,7 +479,7 @@ module Rasti
479
479
  end
480
480
  if s2.last
481
481
  r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
482
- r2.extend(Field0)
482
+ r2.extend(Attribute0)
483
483
  else
484
484
  @index = i2
485
485
  r2 = nil
@@ -493,24 +493,24 @@ module Rasti
493
493
  r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
494
494
  s0 << r1
495
495
  if r1
496
- r5 = _nt_field_name
496
+ r5 = _nt_attribute_name
497
497
  s0 << r5
498
498
  end
499
499
  if s0.last
500
- r0 = instantiate_node(Nodes::Field,input, i0...index, s0)
501
- r0.extend(Field1)
500
+ r0 = instantiate_node(Nodes::Attribute,input, i0...index, s0)
501
+ r0.extend(Attribute1)
502
502
  else
503
503
  @index = i0
504
504
  r0 = nil
505
505
  end
506
506
 
507
- node_cache[:field][start_index] = r0
507
+ node_cache[:attribute][start_index] = r0
508
508
 
509
509
  r0
510
510
  end
511
511
 
512
512
  module ComparisonInclude0
513
- def field
513
+ def attribute
514
514
  elements[0]
515
515
  end
516
516
 
@@ -535,7 +535,7 @@ module Rasti
535
535
  end
536
536
 
537
537
  i0, s0 = index, []
538
- r1 = _nt_field
538
+ r1 = _nt_attribute
539
539
  s0 << r1
540
540
  if r1
541
541
  s2, i2 = [], index
@@ -591,7 +591,7 @@ module Rasti
591
591
  end
592
592
 
593
593
  module ComparisonNotInclude0
594
- def field
594
+ def attribute
595
595
  elements[0]
596
596
  end
597
597
 
@@ -616,7 +616,7 @@ module Rasti
616
616
  end
617
617
 
618
618
  i0, s0 = index, []
619
- r1 = _nt_field
619
+ r1 = _nt_attribute
620
620
  s0 << r1
621
621
  if r1
622
622
  s2, i2 = [], index
@@ -672,7 +672,7 @@ module Rasti
672
672
  end
673
673
 
674
674
  module ComparisonLike0
675
- def field
675
+ def attribute
676
676
  elements[0]
677
677
  end
678
678
 
@@ -697,7 +697,7 @@ module Rasti
697
697
  end
698
698
 
699
699
  i0, s0 = index, []
700
- r1 = _nt_field
700
+ r1 = _nt_attribute
701
701
  s0 << r1
702
702
  if r1
703
703
  s2, i2 = [], index
@@ -753,7 +753,7 @@ module Rasti
753
753
  end
754
754
 
755
755
  module ComparisonGreaterThan0
756
- def field
756
+ def attribute
757
757
  elements[0]
758
758
  end
759
759
 
@@ -778,7 +778,7 @@ module Rasti
778
778
  end
779
779
 
780
780
  i0, s0 = index, []
781
- r1 = _nt_field
781
+ r1 = _nt_attribute
782
782
  s0 << r1
783
783
  if r1
784
784
  s2, i2 = [], index
@@ -834,7 +834,7 @@ module Rasti
834
834
  end
835
835
 
836
836
  module ComparisonGreaterThanOrEqual0
837
- def field
837
+ def attribute
838
838
  elements[0]
839
839
  end
840
840
 
@@ -859,7 +859,7 @@ module Rasti
859
859
  end
860
860
 
861
861
  i0, s0 = index, []
862
- r1 = _nt_field
862
+ r1 = _nt_attribute
863
863
  s0 << r1
864
864
  if r1
865
865
  s2, i2 = [], index
@@ -915,7 +915,7 @@ module Rasti
915
915
  end
916
916
 
917
917
  module ComparisonLessThan0
918
- def field
918
+ def attribute
919
919
  elements[0]
920
920
  end
921
921
 
@@ -940,7 +940,7 @@ module Rasti
940
940
  end
941
941
 
942
942
  i0, s0 = index, []
943
- r1 = _nt_field
943
+ r1 = _nt_attribute
944
944
  s0 << r1
945
945
  if r1
946
946
  s2, i2 = [], index
@@ -996,7 +996,7 @@ module Rasti
996
996
  end
997
997
 
998
998
  module ComparisonLessThanOrEqual0
999
- def field
999
+ def attribute
1000
1000
  elements[0]
1001
1001
  end
1002
1002
 
@@ -1021,7 +1021,7 @@ module Rasti
1021
1021
  end
1022
1022
 
1023
1023
  i0, s0 = index, []
1024
- r1 = _nt_field
1024
+ r1 = _nt_attribute
1025
1025
  s0 << r1
1026
1026
  if r1
1027
1027
  s2, i2 = [], index
@@ -1077,7 +1077,7 @@ module Rasti
1077
1077
  end
1078
1078
 
1079
1079
  module ComparisonNotEqual0
1080
- def field
1080
+ def attribute
1081
1081
  elements[0]
1082
1082
  end
1083
1083
 
@@ -1102,7 +1102,7 @@ module Rasti
1102
1102
  end
1103
1103
 
1104
1104
  i0, s0 = index, []
1105
- r1 = _nt_field
1105
+ r1 = _nt_attribute
1106
1106
  s0 << r1
1107
1107
  if r1
1108
1108
  s2, i2 = [], index
@@ -1158,7 +1158,7 @@ module Rasti
1158
1158
  end
1159
1159
 
1160
1160
  module ComparisonEqual0
1161
- def field
1161
+ def attribute
1162
1162
  elements[0]
1163
1163
  end
1164
1164
 
@@ -1183,7 +1183,7 @@ module Rasti
1183
1183
  end
1184
1184
 
1185
1185
  i0, s0 = index, []
1186
- r1 = _nt_field
1186
+ r1 = _nt_attribute
1187
1187
  s0 << r1
1188
1188
  if r1
1189
1189
  s2, i2 = [], index
@@ -1311,10 +1311,10 @@ module Rasti
1311
1311
  r0
1312
1312
  end
1313
1313
 
1314
- def _nt_field_name
1314
+ def _nt_attribute_name
1315
1315
  start_index = index
1316
- if node_cache[:field_name].has_key?(index)
1317
- cached = node_cache[:field_name][index]
1316
+ if node_cache[:attribute_name].has_key?(index)
1317
+ cached = node_cache[:attribute_name][index]
1318
1318
  if cached
1319
1319
  cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
1320
1320
  @index = cached.interval.end
@@ -1343,7 +1343,7 @@ module Rasti
1343
1343
  r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
1344
1344
  end
1345
1345
 
1346
- node_cache[:field_name][start_index] = r0
1346
+ node_cache[:attribute_name][start_index] = r0
1347
1347
 
1348
1348
  r0
1349
1349
  end