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.
- checksums.yaml +4 -4
- data/README.md +11 -3
- data/lib/rasti/db/collection.rb +10 -1
- data/lib/rasti/db/computed_attribute.rb +22 -0
- data/lib/rasti/db/nql/nodes/attribute.rb +37 -0
- data/lib/rasti/db/nql/nodes/binary_node.rb +4 -0
- data/lib/rasti/db/nql/nodes/comparisons/base.rb +5 -1
- data/lib/rasti/db/nql/nodes/comparisons/equal.rb +2 -2
- data/lib/rasti/db/nql/nodes/comparisons/greater_than.rb +2 -2
- data/lib/rasti/db/nql/nodes/comparisons/greater_than_or_equal.rb +2 -2
- data/lib/rasti/db/nql/nodes/comparisons/include.rb +2 -2
- data/lib/rasti/db/nql/nodes/comparisons/less_than.rb +2 -2
- data/lib/rasti/db/nql/nodes/comparisons/less_than_or_equal.rb +2 -2
- data/lib/rasti/db/nql/nodes/comparisons/like.rb +2 -2
- data/lib/rasti/db/nql/nodes/comparisons/not_equal.rb +2 -2
- data/lib/rasti/db/nql/nodes/comparisons/not_include.rb +2 -2
- data/lib/rasti/db/nql/nodes/conjunction.rb +2 -2
- data/lib/rasti/db/nql/nodes/disjunction.rb +2 -2
- data/lib/rasti/db/nql/nodes/parenthesis_sentence.rb +6 -2
- data/lib/rasti/db/nql/nodes/sentence.rb +6 -2
- data/lib/rasti/db/nql/syntax.rb +33 -33
- data/lib/rasti/db/nql/syntax.treetop +12 -12
- data/lib/rasti/db/query.rb +41 -7
- data/lib/rasti/db/version.rb +1 -1
- data/spec/computed_attribute_spec.rb +32 -0
- data/spec/minitest_helper.rb +30 -3
- data/spec/model_spec.rb +1 -1
- data/spec/nql/computed_attributes_spec.rb +29 -0
- data/spec/nql/filter_condition_spec.rb +4 -2
- data/spec/nql/syntax_parser_spec.rb +12 -5
- data/spec/query_spec.rb +146 -34
- metadata +8 -3
- data/lib/rasti/db/nql/nodes/field.rb +0 -23
@@ -42,44 +42,44 @@ module Rasti
|
|
42
42
|
comparison_equal
|
43
43
|
end
|
44
44
|
|
45
|
-
rule
|
46
|
-
_tables:(table:
|
45
|
+
rule attribute
|
46
|
+
_tables:(table:attribute_name '.')* _column:attribute_name <Nodes::Attribute>
|
47
47
|
end
|
48
48
|
|
49
49
|
rule comparison_include
|
50
|
-
|
50
|
+
attribute:attribute space* comparator:':' space* argument:basic <Nodes::Comparisons::Include>
|
51
51
|
end
|
52
52
|
|
53
53
|
rule comparison_not_include
|
54
|
-
|
54
|
+
attribute:attribute space* comparator:'!:' space* argument:basic <Nodes::Comparisons::NotInclude>
|
55
55
|
end
|
56
56
|
|
57
57
|
rule comparison_like
|
58
|
-
|
58
|
+
attribute:attribute space* comparator:'~' space* argument:basic <Nodes::Comparisons::Like>
|
59
59
|
end
|
60
60
|
|
61
61
|
rule comparison_greater_than
|
62
|
-
|
62
|
+
attribute:attribute space* comparator:'>' space* argument:basic <Nodes::Comparisons::GreaterThan>
|
63
63
|
end
|
64
64
|
|
65
65
|
rule comparison_greater_than_or_equal
|
66
|
-
|
66
|
+
attribute:attribute space* comparator:'>=' space* argument:basic <Nodes::Comparisons::GreaterThanOrEqual>
|
67
67
|
end
|
68
68
|
|
69
69
|
rule comparison_less_than
|
70
|
-
|
70
|
+
attribute:attribute space* comparator:'<' space* argument:basic <Nodes::Comparisons::LessThan>
|
71
71
|
end
|
72
72
|
|
73
73
|
rule comparison_less_than_or_equal
|
74
|
-
|
74
|
+
attribute:attribute space* comparator:'<=' space* argument:basic <Nodes::Comparisons::LessThanOrEqual>
|
75
75
|
end
|
76
76
|
|
77
77
|
rule comparison_not_equal
|
78
|
-
|
78
|
+
attribute:attribute space* comparator:'!=' space* argument:basic <Nodes::Comparisons::NotEqual>
|
79
79
|
end
|
80
80
|
|
81
81
|
rule comparison_equal
|
82
|
-
|
82
|
+
attribute:attribute space* comparator:'=' space* argument:basic <Nodes::Comparisons::Equal>
|
83
83
|
end
|
84
84
|
|
85
85
|
rule basic
|
@@ -95,7 +95,7 @@ module Rasti
|
|
95
95
|
[\s\t\n]
|
96
96
|
end
|
97
97
|
|
98
|
-
rule
|
98
|
+
rule attribute_name
|
99
99
|
[a-z_]+
|
100
100
|
end
|
101
101
|
|
data/lib/rasti/db/query.rb
CHANGED
@@ -57,6 +57,12 @@ module Rasti
|
|
57
57
|
build_query relations_graph: relations_graph.with_all_attributes_for(relations)
|
58
58
|
end
|
59
59
|
|
60
|
+
def append_computed_attribute(name)
|
61
|
+
computed_attribute = collection_class.computed_attributes[name]
|
62
|
+
ds = computed_attribute.apply_join(dataset).select_append(computed_attribute.identifier.as(name))
|
63
|
+
build_query dataset: ds
|
64
|
+
end
|
65
|
+
|
60
66
|
def all
|
61
67
|
with_graph(dataset.all).map do |row|
|
62
68
|
collection_class.model.new row
|
@@ -64,8 +70,19 @@ module Rasti
|
|
64
70
|
end
|
65
71
|
alias_method :to_a, :all
|
66
72
|
|
67
|
-
def each(&block)
|
68
|
-
|
73
|
+
def each(batch_size:nil, &block)
|
74
|
+
if batch_size.nil?
|
75
|
+
all.each(&block)
|
76
|
+
else
|
77
|
+
each_model_in_batches(size: batch_size, &block)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def each_batch(size:, &block)
|
82
|
+
dataset.each_page(size) do |page|
|
83
|
+
query = build_query dataset: page
|
84
|
+
block.call query.all
|
85
|
+
end
|
69
86
|
end
|
70
87
|
|
71
88
|
def graph(*relations)
|
@@ -94,12 +111,12 @@ module Rasti
|
|
94
111
|
|
95
112
|
def first
|
96
113
|
row = dataset.first
|
97
|
-
row ?
|
114
|
+
row ? build_model(row) : nil
|
98
115
|
end
|
99
116
|
|
100
117
|
def last
|
101
118
|
row = dataset.last
|
102
|
-
row ?
|
119
|
+
row ? build_model(row) : nil
|
103
120
|
end
|
104
121
|
|
105
122
|
def detect(*args, &block)
|
@@ -116,10 +133,15 @@ module Rasti
|
|
116
133
|
|
117
134
|
raise NQL::InvalidExpressionError.new(filter_expression) if sentence.nil?
|
118
135
|
|
136
|
+
ds = sentence.computed_attributes(collection_class).inject(dataset) do |ds, name|
|
137
|
+
collection_class.computed_attributes[name].apply_join ds
|
138
|
+
end
|
139
|
+
query = build_query dataset: ds
|
140
|
+
|
119
141
|
dependency_tables = sentence.dependency_tables
|
120
|
-
query =
|
121
|
-
|
122
|
-
query.where sentence.filter_condition
|
142
|
+
query = query.join(*dependency_tables) unless dependency_tables.empty?
|
143
|
+
|
144
|
+
query.where sentence.filter_condition(collection_class)
|
123
145
|
end
|
124
146
|
|
125
147
|
private
|
@@ -137,10 +159,22 @@ module Rasti
|
|
137
159
|
Query.new(**current_args.merge(args))
|
138
160
|
end
|
139
161
|
|
162
|
+
def build_model(row)
|
163
|
+
collection_class.model.new with_graph(row)
|
164
|
+
end
|
165
|
+
|
140
166
|
def chainable(&block)
|
141
167
|
build_query dataset: instance_eval(&block)
|
142
168
|
end
|
143
169
|
|
170
|
+
def each_model_in_batches(size:, &block)
|
171
|
+
dataset.each_page(size) do |page|
|
172
|
+
page.each do |row|
|
173
|
+
block.call build_model(row)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
144
178
|
def with_related(relation_name, primary_keys)
|
145
179
|
ds = collection_class.relations[relation_name].apply_filter environment, dataset, primary_keys
|
146
180
|
build_query dataset: ds
|
data/lib/rasti/db/version.rb
CHANGED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'minitest_helper'
|
2
|
+
|
3
|
+
describe 'ComputedAttribute' do
|
4
|
+
|
5
|
+
it 'Apply Join wiht join attribute must generate correct query' do
|
6
|
+
dataset = db[:users]
|
7
|
+
computed_attribute = Rasti::DB::ComputedAttribute.new(Sequel[:comments_count][:value]) do |dataset|
|
8
|
+
subquery = dataset.db.from(:comments)
|
9
|
+
.select(Sequel[:user_id], Sequel.function('count', :id).as(:value))
|
10
|
+
.group(:user_id)
|
11
|
+
.as(:comments_count)
|
12
|
+
|
13
|
+
dataset.join_table(:inner, subquery, :user_id => :id)
|
14
|
+
end
|
15
|
+
expected_query = "SELECT *, `comments_count`.`value` AS 'value' FROM `users` INNER JOIN (SELECT `user_id`, count(`id`) AS 'value' FROM `comments` GROUP BY `user_id`) AS 'comments_count' ON (`comments_count`.`user_id` = `users`.`id`)"
|
16
|
+
computed_attribute.apply_join(dataset)
|
17
|
+
.select_append(computed_attribute.identifier)
|
18
|
+
.sql
|
19
|
+
.must_equal expected_query
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'Apply join without join attribute must generate correct query' do
|
23
|
+
dataset = db[:people]
|
24
|
+
computed_attribute = Rasti::DB::ComputedAttribute.new Sequel.join([:first_name, ' ', :last_name])
|
25
|
+
expected_query = "SELECT * FROM `people` WHERE ((`first_name` || ' ' || `last_name`) = 'FULL NAME')"
|
26
|
+
computed_attribute.apply_join(dataset)
|
27
|
+
.where(computed_attribute.identifier => 'FULL NAME')
|
28
|
+
.sql
|
29
|
+
.must_equal expected_query
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
data/spec/minitest_helper.rb
CHANGED
@@ -13,11 +13,11 @@ Rasti::DB.configure do |config|
|
|
13
13
|
config.type_converters = [Rasti::DB::TypeConverters::TimeInZone]
|
14
14
|
end
|
15
15
|
|
16
|
-
User = Rasti::DB::Model[:id, :name, :posts, :comments, :person]
|
17
|
-
Post = Rasti::DB::Model[:id, :title, :body, :user_id, :user, :comments, :categories, :language_id, :language]
|
16
|
+
User = Rasti::DB::Model[:id, :name, :posts, :comments, :person, :comments_count]
|
17
|
+
Post = Rasti::DB::Model[:id, :title, :body, :user_id, :user, :comments, :categories, :language_id, :language, :notice, :author]
|
18
18
|
Comment = Rasti::DB::Model[:id, :text, :user_id, :user, :post_id, :post]
|
19
19
|
Category = Rasti::DB::Model[:id, :name, :posts]
|
20
|
-
Person = Rasti::DB::Model[:document_number, :first_name, :last_name, :birth_date, :user_id, :user, :languages]
|
20
|
+
Person = Rasti::DB::Model[:document_number, :first_name, :last_name, :birth_date, :user_id, :user, :languages, :full_name]
|
21
21
|
Language = Rasti::DB::Model[:id, :name, :people]
|
22
22
|
|
23
23
|
|
@@ -25,6 +25,18 @@ class Users < Rasti::DB::Collection
|
|
25
25
|
one_to_many :posts
|
26
26
|
one_to_many :comments
|
27
27
|
one_to_one :person
|
28
|
+
|
29
|
+
computed_attribute :comments_count do
|
30
|
+
Rasti::DB::ComputedAttribute.new(Sequel[:comments_count][:value]) do |dataset|
|
31
|
+
subquery = dataset.db.from(:comments)
|
32
|
+
.select(Sequel[:user_id], Sequel.function('count', :id).as(:value))
|
33
|
+
.group(:user_id)
|
34
|
+
.as(:comments_count)
|
35
|
+
|
36
|
+
dataset.join_table(:inner, subquery, :user_id => :id)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
28
40
|
end
|
29
41
|
|
30
42
|
class Posts < Rasti::DB::Collection
|
@@ -47,6 +59,15 @@ class Posts < Rasti::DB::Collection
|
|
47
59
|
.distinct
|
48
60
|
end
|
49
61
|
end
|
62
|
+
|
63
|
+
computed_attribute :notice do
|
64
|
+
Rasti::DB::ComputedAttribute.new Sequel.join([:title, ': ', :body])
|
65
|
+
end
|
66
|
+
|
67
|
+
computed_attribute :author do
|
68
|
+
Rasti::DB::ComputedAttribute.new Sequel[:user]
|
69
|
+
end
|
70
|
+
|
50
71
|
end
|
51
72
|
|
52
73
|
class Comments < Rasti::DB::Collection
|
@@ -73,6 +94,10 @@ class People < Rasti::DB::Collection
|
|
73
94
|
|
74
95
|
many_to_one :user
|
75
96
|
many_to_many :languages
|
97
|
+
|
98
|
+
computed_attribute :full_name do |db|
|
99
|
+
Rasti::DB::ComputedAttribute.new Sequel.join([:first_name, ' ', :last_name])
|
100
|
+
end
|
76
101
|
end
|
77
102
|
|
78
103
|
class Languages < Rasti::DB::Collection
|
@@ -107,6 +132,8 @@ class Minitest::Spec
|
|
107
132
|
let :db do
|
108
133
|
Sequel.connect(driver).tap do |db|
|
109
134
|
|
135
|
+
db.extension :pagination
|
136
|
+
|
110
137
|
db.create_table :users do
|
111
138
|
primary_key :id
|
112
139
|
String :name, null: false, unique: true
|
data/spec/model_spec.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'minitest_helper'
|
2
|
+
|
3
|
+
describe 'NQL::ComputedAttributes' do
|
4
|
+
|
5
|
+
let(:parser) { Rasti::DB::NQL::SyntaxParser.new }
|
6
|
+
|
7
|
+
def parse(expression)
|
8
|
+
parser.parse expression
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'must have one computed attributes' do
|
12
|
+
tree = parse 'notice = any notice'
|
13
|
+
|
14
|
+
tree.computed_attributes(Posts).must_equal [:notice]
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'must have multiple computed attributes' do
|
18
|
+
tree = parse 'notice = any notice & (author: anonym | title = good morning)'
|
19
|
+
|
20
|
+
tree.computed_attributes(Posts).must_equal [:notice, :author]
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'must have not repeated computed attributes when expression have it' do
|
24
|
+
tree = parse 'notice = Hi | notice = Bye'
|
25
|
+
|
26
|
+
tree.computed_attributes(Posts).must_equal [:notice]
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -4,9 +4,11 @@ describe 'NQL::FilterCondition' do
|
|
4
4
|
|
5
5
|
let(:parser) { Rasti::DB::NQL::SyntaxParser.new }
|
6
6
|
|
7
|
+
let(:collection_class) { Rasti::DB::Collection }
|
8
|
+
|
7
9
|
def filter_condition(expression)
|
8
10
|
tree = parser.parse expression
|
9
|
-
tree.filter_condition
|
11
|
+
tree.filter_condition(collection_class)
|
10
12
|
end
|
11
13
|
|
12
14
|
def assert_identifier(identifier, expected_value)
|
@@ -95,7 +97,7 @@ describe 'NQL::FilterCondition' do
|
|
95
97
|
|
96
98
|
end
|
97
99
|
|
98
|
-
it 'must create filter from expression with
|
100
|
+
it 'must create filter from expression with attribute with multiple tables' do
|
99
101
|
filter = filter_condition 'table_one.table_two.column = test'
|
100
102
|
identifier, value = filter.first
|
101
103
|
|
@@ -31,7 +31,7 @@ describe 'NQL::SyntaxParser' do
|
|
31
31
|
proposition = tree.proposition
|
32
32
|
proposition.must_be_instance_of node_class
|
33
33
|
proposition.comparator.text_value.must_equal comparator
|
34
|
-
proposition.
|
34
|
+
proposition.attribute.text_value.must_equal 'column'
|
35
35
|
proposition.argument.text_value.must_equal 'value'
|
36
36
|
end
|
37
37
|
end
|
@@ -44,7 +44,7 @@ describe 'NQL::SyntaxParser' do
|
|
44
44
|
proposition = tree.proposition
|
45
45
|
proposition.must_be_instance_of Rasti::DB::NQL::Nodes::Comparisons::Equal
|
46
46
|
proposition.comparator.text_value.must_equal '='
|
47
|
-
proposition.
|
47
|
+
proposition.attribute.text_value.must_equal 'column'
|
48
48
|
proposition.argument.text_value.must_equal 'value'
|
49
49
|
end
|
50
50
|
|
@@ -128,12 +128,19 @@ describe 'NQL::SyntaxParser' do
|
|
128
128
|
|
129
129
|
end
|
130
130
|
|
131
|
-
it 'must parse expression with
|
131
|
+
it 'must parse expression with attribute with tables' do
|
132
132
|
tree = parse 'relation_table_one.relation_table_two.column = 1'
|
133
133
|
|
134
|
-
left_hand_operand = tree.proposition.
|
134
|
+
left_hand_operand = tree.proposition.attribute
|
135
135
|
left_hand_operand.tables.must_equal ['relation_table_one', 'relation_table_two']
|
136
|
-
left_hand_operand.column.must_equal
|
136
|
+
left_hand_operand.column.must_equal :column
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'must parse expression with computed attribute' do
|
140
|
+
tree = parse 'comments_count = 1'
|
141
|
+
computed = tree.proposition.attribute
|
142
|
+
computed.tables.must_equal []
|
143
|
+
computed.computed_attributes(Users).must_equal [:comments_count]
|
137
144
|
end
|
138
145
|
|
139
146
|
end
|
data/spec/query_spec.rb
CHANGED
@@ -5,13 +5,13 @@ describe 'Query' do
|
|
5
5
|
before do
|
6
6
|
custom_db[:languages].insert name: 'Spanish'
|
7
7
|
|
8
|
-
1.upto(10) do |i|
|
8
|
+
1.upto(10) do |i|
|
9
9
|
db[:users].insert name: "User #{i}"
|
10
10
|
|
11
|
-
db[:people].insert user_id: i,
|
12
|
-
document_number: "document_#{i}",
|
13
|
-
first_name: "Name #{i}",
|
14
|
-
last_name: "Last Name #{i}",
|
11
|
+
db[:people].insert user_id: i,
|
12
|
+
document_number: "document_#{i}",
|
13
|
+
first_name: "Name #{i}",
|
14
|
+
last_name: "Last Name #{i}",
|
15
15
|
birth_date: Date.parse('2020-04-24')
|
16
16
|
|
17
17
|
db[:languages_people].insert language_id: 1, document_number: "document_#{i}"
|
@@ -22,7 +22,7 @@ describe 'Query' do
|
|
22
22
|
db[:posts].insert user_id: 4, title: 'Best post', body: '...', language_id: 1
|
23
23
|
|
24
24
|
1.upto(3) { |i| db[:categories].insert name: "Category #{i}" }
|
25
|
-
|
25
|
+
|
26
26
|
db[:comments].insert post_id: 1, user_id: 5, text: 'Comment 1'
|
27
27
|
db[:comments].insert post_id: 1, user_id: 7, text: 'Comment 2'
|
28
28
|
db[:comments].insert post_id: 2, user_id: 2, text: 'Comment 3'
|
@@ -35,11 +35,13 @@ describe 'Query' do
|
|
35
35
|
end
|
36
36
|
|
37
37
|
let(:users_query) { Rasti::DB::Query.new collection_class: Users, dataset: db[:users], environment: environment }
|
38
|
-
|
38
|
+
|
39
39
|
let(:posts_query) { Rasti::DB::Query.new collection_class: Posts, dataset: db[:posts], environment: environment }
|
40
|
-
|
40
|
+
|
41
41
|
let(:comments_query) { Rasti::DB::Query.new collection_class: Comments, dataset: db[:comments], environment: environment }
|
42
42
|
|
43
|
+
let(:people_query) { Rasti::DB::Query.new collection_class: People, dataset: db[:people], environment: environment }
|
44
|
+
|
43
45
|
let(:languages_query) { Rasti::DB::Query.new collection_class: Languages, dataset: custom_db[:languages], environment: environment }
|
44
46
|
|
45
47
|
it 'Count' do
|
@@ -87,8 +89,8 @@ describe 'Query' do
|
|
87
89
|
post = Post.new db[:posts].where(id: 1).first.merge(user: user, categories: categories)
|
88
90
|
|
89
91
|
selected_attributes = {
|
90
|
-
user: [:id],
|
91
|
-
'user.person' => [:document_number, :user_id],
|
92
|
+
user: [:id],
|
93
|
+
'user.person' => [:document_number, :user_id],
|
92
94
|
'user.person.languages' => [:id],
|
93
95
|
categories: [:id]
|
94
96
|
}
|
@@ -99,7 +101,7 @@ describe 'Query' do
|
|
99
101
|
.all
|
100
102
|
.must_equal [post]
|
101
103
|
end
|
102
|
-
|
104
|
+
|
103
105
|
it 'Exclude graph attributes' do
|
104
106
|
language = Language.new custom_db[:languages].where(id: 1).select(:id).first
|
105
107
|
|
@@ -112,8 +114,8 @@ describe 'Query' do
|
|
112
114
|
post = Post.new db[:posts].where(id: 1).first.merge(user: user, categories: categories)
|
113
115
|
|
114
116
|
excluded_attributes = {
|
115
|
-
user: [:name],
|
116
|
-
'user.person' => [:first_name, :last_name, :birth_date],
|
117
|
+
user: [:name],
|
118
|
+
'user.person' => [:first_name, :last_name, :birth_date],
|
117
119
|
'user.person.languages' => [:name],
|
118
120
|
categories: [:name]
|
119
121
|
}
|
@@ -124,7 +126,7 @@ describe 'Query' do
|
|
124
126
|
.all
|
125
127
|
.must_equal [post]
|
126
128
|
end
|
127
|
-
|
129
|
+
|
128
130
|
it 'All graph attributes' do
|
129
131
|
person = Person.new db[:people].where(document_number: 'document_2').first
|
130
132
|
|
@@ -140,6 +142,30 @@ describe 'Query' do
|
|
140
142
|
.must_equal [post]
|
141
143
|
end
|
142
144
|
|
145
|
+
describe 'Append computed attribute' do
|
146
|
+
it 'With join' do
|
147
|
+
db[:comments].insert post_id: 1, user_id: 5, text: 'Comment 4'
|
148
|
+
users_query.append_computed_attribute(: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.append_computed_attribute(:full_name)
|
163
|
+
.where(document_number: 'document_1')
|
164
|
+
.all
|
165
|
+
.must_equal [person_expected]
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
143
169
|
it 'Map' do
|
144
170
|
users_query.map(&:name).must_equal db[:users].map(:name)
|
145
171
|
end
|
@@ -148,45 +174,88 @@ describe 'Query' do
|
|
148
174
|
users_query.detect(id: 3).must_equal User.new(id: 3, name: 'User 3')
|
149
175
|
end
|
150
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
|
+
|
151
220
|
it 'Where' do
|
152
221
|
users_query.where(id: 3).all.must_equal [User.new(id: 3, name: 'User 3')]
|
153
222
|
end
|
154
|
-
|
223
|
+
|
155
224
|
it 'Exclude' do
|
156
225
|
users_query.exclude(id: [1,2,3,4,5,6,7,8,9]).all.must_equal [User.new(id: 10, name: 'User 10')]
|
157
226
|
end
|
158
|
-
|
227
|
+
|
159
228
|
it 'And' do
|
160
229
|
users_query.where(id: [1,2]).where(name: 'User 2').all.must_equal [User.new(id: 2, name: 'User 2')]
|
161
230
|
end
|
162
|
-
|
231
|
+
|
163
232
|
it 'Or' do
|
164
233
|
users_query.where(id: 1).or(name: 'User 2').all.must_equal [
|
165
|
-
User.new(id: 1, name: 'User 1'),
|
234
|
+
User.new(id: 1, name: 'User 1'),
|
166
235
|
User.new(id: 2, name: 'User 2')
|
167
236
|
]
|
168
237
|
end
|
169
|
-
|
238
|
+
|
170
239
|
it 'Order' do
|
171
240
|
posts_query.order(:title).all.must_equal [
|
172
|
-
Post.new(id: 2, user_id: 1, title: 'Another post', body: '...', language_id: 1),
|
173
|
-
Post.new(id: 3, user_id: 4, title: 'Best post', body: '...', language_id: 1),
|
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),
|
174
243
|
Post.new(id: 1, user_id: 2, title: 'Sample post', body: '...', language_id: 1)
|
175
244
|
]
|
176
245
|
end
|
177
|
-
|
246
|
+
|
178
247
|
it 'Reverse order' do
|
179
248
|
posts_query.reverse_order(:title).all.must_equal [
|
180
249
|
Post.new(id: 1, user_id: 2, title: 'Sample post', body: '...', language_id: 1),
|
181
|
-
Post.new(id: 3, user_id: 4, title: 'Best post', body: '...', language_id: 1),
|
250
|
+
Post.new(id: 3, user_id: 4, title: 'Best post', body: '...', language_id: 1),
|
182
251
|
Post.new(id: 2, user_id: 1, title: 'Another post', body: '...', language_id: 1)
|
183
252
|
]
|
184
253
|
end
|
185
|
-
|
254
|
+
|
186
255
|
it 'Limit and offset' do
|
187
256
|
users_query.limit(1).offset(1).all.must_equal [User.new(id: 2, name: 'User 2')]
|
188
257
|
end
|
189
|
-
|
258
|
+
|
190
259
|
it 'First' do
|
191
260
|
users_query.first.must_equal User.new(id: 1, name: 'User 1')
|
192
261
|
end
|
@@ -203,21 +272,21 @@ describe 'Query' do
|
|
203
272
|
language = Language.new id: 1, name: 'Spanish'
|
204
273
|
|
205
274
|
person = Person.new user_id: 2,
|
206
|
-
document_number: 'document_2',
|
207
|
-
first_name: 'Name 2',
|
208
|
-
last_name: 'Last Name 2',
|
275
|
+
document_number: 'document_2',
|
276
|
+
first_name: 'Name 2',
|
277
|
+
last_name: 'Last Name 2',
|
209
278
|
birth_date: Date.parse('2020-04-24'),
|
210
279
|
languages: [language]
|
211
280
|
|
212
|
-
user = User.new id: 2,
|
281
|
+
user = User.new id: 2,
|
213
282
|
name: 'User 2',
|
214
283
|
person: person
|
215
284
|
|
216
|
-
post = Post.new id: 1,
|
217
|
-
user_id: 2,
|
285
|
+
post = Post.new id: 1,
|
286
|
+
user_id: 2,
|
218
287
|
user: user,
|
219
|
-
title: 'Sample post',
|
220
|
-
body: '...',
|
288
|
+
title: 'Sample post',
|
289
|
+
body: '...',
|
221
290
|
language_id: 1,
|
222
291
|
language: language
|
223
292
|
|
@@ -323,7 +392,7 @@ describe 'Query' do
|
|
323
392
|
error = proc { posts_query.nql('a + b') }.must_raise Rasti::DB::NQL::InvalidExpressionError
|
324
393
|
error.message.must_equal 'Invalid filter expression: a + b'
|
325
394
|
end
|
326
|
-
|
395
|
+
|
327
396
|
it 'Filter to self table' do
|
328
397
|
posts_query.nql('user_id > 1')
|
329
398
|
.pluck(:user_id)
|
@@ -350,6 +419,49 @@ describe 'Query' do
|
|
350
419
|
.must_equal [2]
|
351
420
|
end
|
352
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
|
+
|
353
465
|
end
|
354
466
|
|
355
467
|
end
|