rasti-db 1.4.0 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -3
- data/README.md +88 -24
- data/lib/rasti/db.rb +2 -1
- data/lib/rasti/db/collection.rb +79 -46
- data/lib/rasti/db/computed_attribute.rb +22 -0
- data/lib/rasti/db/data_source.rb +18 -0
- data/lib/rasti/db/environment.rb +32 -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 +107 -43
- data/lib/rasti/db/relations/base.rb +22 -8
- data/lib/rasti/db/relations/graph.rb +129 -0
- data/lib/rasti/db/relations/many_to_many.rb +58 -24
- data/lib/rasti/db/relations/many_to_one.rb +17 -12
- data/lib/rasti/db/relations/one_to_many.rb +27 -16
- data/lib/rasti/db/version.rb +1 -1
- data/rasti-db.gemspec +3 -7
- data/spec/collection_spec.rb +223 -52
- data/spec/computed_attribute_spec.rb +32 -0
- data/spec/minitest_helper.rb +76 -15
- data/spec/model_spec.rb +4 -2
- 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 +319 -85
- data/spec/relations_spec.rb +27 -7
- metadata +41 -7
- data/lib/rasti/db/helpers.rb +0 -16
- data/lib/rasti/db/nql/nodes/field.rb +0 -23
- data/lib/rasti/db/relations/graph_builder.rb +0 -60
@@ -15,25 +15,44 @@ module Rasti
|
|
15
15
|
@relation_collection_name ||= options[:relation_collection_name] || [source_collection_class.collection_name, target_collection_class.collection_name].sort.join('_').to_sym
|
16
16
|
end
|
17
17
|
|
18
|
-
def
|
19
|
-
|
18
|
+
def relation_data_source_name
|
19
|
+
@relation_data_source_name ||= options[:relation_data_source_name] || source_collection_class.data_source_name
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
22
|
+
def fetch_graph(environment, rows, selected_attributes=nil, excluded_attributes=nil, relations_graph=nil)
|
23
23
|
pks = rows.map { |row| row[source_collection_class.primary_key] }
|
24
24
|
|
25
|
-
|
25
|
+
if target_collection_class.data_source_name == relation_data_source_name
|
26
|
+
target_data_source = environment.data_source_of target_collection_class
|
26
27
|
|
27
|
-
|
28
|
+
dataset = target_data_source.db.from(environment.qualify_collection(target_collection_class))
|
29
|
+
.join(qualified_relation_collection_name(environment), target_foreign_key => target_collection_class.primary_key)
|
30
|
+
.where(Sequel[relation_collection_name][source_foreign_key] => pks)
|
31
|
+
.select_all(target_collection_class.collection_name)
|
28
32
|
|
29
|
-
|
30
|
-
|
31
|
-
.where(Sequel[relation_name][source_foreign_key] => pks)
|
32
|
-
.select_all(qualified_target_collection_name(schema))
|
33
|
-
.select_append(Sequel[relation_name][source_foreign_key].as(:source_foreign_key))
|
34
|
-
.all
|
33
|
+
selected_attributes ||= target_collection_class.collection_attributes - excluded_attributes if excluded_attributes
|
34
|
+
dataset = dataset.select(*selected_attributes.map { |a| Sequel[target_collection_class.collection_name][a] }) if selected_attributes
|
35
35
|
|
36
|
-
|
36
|
+
join_rows = dataset.select_append(Sequel[relation_collection_name][source_foreign_key].as(:source_foreign_key)).all
|
37
|
+
else
|
38
|
+
relation_data_source = environment.data_source relation_data_source_name
|
39
|
+
|
40
|
+
relation_index = relation_data_source.db.from(relation_data_source.qualify(relation_collection_name))
|
41
|
+
.where(source_foreign_key => pks)
|
42
|
+
.select_hash_groups(target_foreign_key, source_foreign_key)
|
43
|
+
|
44
|
+
query = target_collection_class.new environment
|
45
|
+
query = query.exclude_attributes(*excluded_attributes) if excluded_attributes
|
46
|
+
query = query.select_attributes(*selected_attributes) if selected_attributes
|
47
|
+
|
48
|
+
join_rows = query.where(target_collection_class.primary_key => relation_index.keys).raw.flat_map do |row|
|
49
|
+
relation_index[row[target_collection_class.primary_key]].map do |source_primary_key|
|
50
|
+
row.merge(source_foreign_key: source_primary_key)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
relations_graph.fetch_graph join_rows if relations_graph
|
37
56
|
|
38
57
|
relation_rows = join_rows.each_with_object(Hash.new { |h,k| h[k] = [] }) do |row, hash|
|
39
58
|
attributes = row.select { |attr,_| target_collection_class.model.attributes.include? attr }
|
@@ -41,17 +60,19 @@ module Rasti
|
|
41
60
|
end
|
42
61
|
|
43
62
|
rows.each do |row|
|
44
|
-
row[name] = relation_rows.fetch row[
|
63
|
+
row[name] = relation_rows.fetch row[source_collection_class.primary_key], []
|
45
64
|
end
|
46
65
|
end
|
47
66
|
|
48
|
-
def
|
67
|
+
def add_join(environment, dataset, prefix=nil)
|
68
|
+
validate_join!
|
69
|
+
|
49
70
|
many_to_many_relation_alias = with_prefix prefix, "#{relation_collection_name}_#{SecureRandom.base64}"
|
50
71
|
|
51
|
-
|
72
|
+
relation_name = prefix ? Sequel[prefix] : Sequel[source_collection_class.collection_name]
|
52
73
|
|
53
74
|
many_to_many_condition = {
|
54
|
-
Sequel[many_to_many_relation_alias][source_foreign_key] =>
|
75
|
+
Sequel[many_to_many_relation_alias][source_foreign_key] => relation_name[source_collection_class.primary_key]
|
55
76
|
}
|
56
77
|
|
57
78
|
relation_alias = join_relation_name prefix
|
@@ -60,17 +81,30 @@ module Rasti
|
|
60
81
|
Sequel[relation_alias][target_collection_class.primary_key] => Sequel[many_to_many_relation_alias][target_foreign_key]
|
61
82
|
}
|
62
83
|
|
63
|
-
dataset.join(qualified_relation_collection_name(
|
64
|
-
.join(
|
84
|
+
dataset.join(qualified_relation_collection_name(environment).as(many_to_many_relation_alias), many_to_many_condition)
|
85
|
+
.join(environment.qualify_collection(target_collection_class).as(relation_alias), relation_condition)
|
86
|
+
end
|
87
|
+
|
88
|
+
def apply_filter(environment, dataset, primary_keys)
|
89
|
+
if source_collection_class.data_source_name == relation_data_source_name
|
90
|
+
dataset.join(qualified_relation_collection_name(environment), source_foreign_key => source_collection_class.primary_key)
|
91
|
+
.where(Sequel[relation_collection_name][target_foreign_key] => primary_keys)
|
92
|
+
.select_all(source_collection_class.collection_name)
|
93
|
+
.distinct
|
94
|
+
else
|
95
|
+
data_source = environment.data_source relation_data_source_name
|
96
|
+
fks = data_source.db.from(data_source.qualify(relation_collection_name))
|
97
|
+
.where(target_collection_class.foreign_key => primary_keys)
|
98
|
+
.select_map(source_collection_class.foreign_key)
|
99
|
+
.uniq
|
100
|
+
dataset.where(source_collection_class.primary_key => fks)
|
101
|
+
end
|
65
102
|
end
|
66
103
|
|
67
|
-
|
68
|
-
relation_name = qualified_relation_collection_name schema
|
104
|
+
private
|
69
105
|
|
70
|
-
|
71
|
-
|
72
|
-
.select_all(qualified_source_collection_name(schema))
|
73
|
-
.distinct
|
106
|
+
def qualified_relation_collection_name(environment)
|
107
|
+
environment.qualify relation_data_source_name, relation_collection_name
|
74
108
|
end
|
75
109
|
|
76
110
|
end
|
@@ -7,35 +7,40 @@ module Rasti
|
|
7
7
|
@foreign_key ||= options[:foreign_key] || target_collection_class.foreign_key
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
10
|
+
def fetch_graph(environment, rows, selected_attributes=nil, excluded_attributes=nil, relations_graph=nil)
|
11
11
|
fks = rows.map { |row| row[foreign_key] }.uniq
|
12
12
|
|
13
|
-
target_collection = target_collection_class.new
|
13
|
+
target_collection = target_collection_class.new environment
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
query = target_collection.where(source_collection_class.primary_key => fks)
|
16
|
+
query = query.exclude_attributes(*excluded_attributes) if excluded_attributes
|
17
|
+
query = query.select_attributes(*selected_attributes) if selected_attributes
|
18
|
+
query = relations_graph.apply_to query if relations_graph
|
19
|
+
|
20
|
+
relation_rows = query.each_with_object({}) do |row, hash|
|
21
|
+
hash[row.public_send(source_collection_class.primary_key)] = row
|
22
|
+
end
|
20
23
|
|
21
24
|
rows.each do |row|
|
22
25
|
row[name] = relation_rows[row[foreign_key]]
|
23
26
|
end
|
24
27
|
end
|
25
28
|
|
26
|
-
def
|
29
|
+
def add_join(environment, dataset, prefix=nil)
|
30
|
+
validate_join!
|
31
|
+
|
27
32
|
relation_alias = join_relation_name prefix
|
28
33
|
|
29
|
-
|
34
|
+
relation_name = prefix ? Sequel[prefix] : Sequel[source_collection_class.collection_name]
|
30
35
|
|
31
36
|
relation_condition = {
|
32
|
-
Sequel[relation_alias][target_collection_class.primary_key] =>
|
37
|
+
Sequel[relation_alias][target_collection_class.primary_key] => relation_name[foreign_key]
|
33
38
|
}
|
34
39
|
|
35
|
-
dataset.join(
|
40
|
+
dataset.join(environment.qualify_collection(target_collection_class).as(relation_alias), relation_condition)
|
36
41
|
end
|
37
42
|
|
38
|
-
def apply_filter(
|
43
|
+
def apply_filter(environment, dataset, primary_keys)
|
39
44
|
dataset.where(foreign_key => primary_keys)
|
40
45
|
end
|
41
46
|
|
@@ -7,39 +7,50 @@ module Rasti
|
|
7
7
|
@foreign_key ||= options[:foreign_key] || source_collection_class.foreign_key
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
10
|
+
def fetch_graph(environment, rows, selected_attributes=nil, excluded_attributes=nil, relations_graph=nil)
|
11
11
|
pks = rows.map { |row| row[source_collection_class.primary_key] }.uniq
|
12
12
|
|
13
|
-
target_collection = target_collection_class.new
|
13
|
+
target_collection = target_collection_class.new environment
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
query = target_collection.where(foreign_key => pks)
|
16
|
+
query = query.exclude_attributes(*excluded_attributes) if excluded_attributes
|
17
|
+
query = query.select_attributes(*selected_attributes) if selected_attributes
|
18
|
+
query = relations_graph.apply_to query if relations_graph
|
19
|
+
|
20
|
+
relation_rows = query.group_by(&foreign_key)
|
18
21
|
|
19
22
|
rows.each do |row|
|
20
23
|
row[name] = build_graph_result relation_rows.fetch(row[source_collection_class.primary_key], [])
|
21
24
|
end
|
22
25
|
end
|
23
26
|
|
24
|
-
def
|
27
|
+
def add_join(environment, dataset, prefix=nil)
|
28
|
+
validate_join!
|
29
|
+
|
25
30
|
relation_alias = join_relation_name prefix
|
26
31
|
|
27
|
-
|
32
|
+
relation_name = prefix ? Sequel[prefix] : Sequel[source_collection_class.collection_name]
|
28
33
|
|
29
34
|
relation_condition = {
|
30
|
-
Sequel[relation_alias][foreign_key] =>
|
35
|
+
Sequel[relation_alias][foreign_key] => relation_name[source_collection_class.primary_key]
|
31
36
|
}
|
32
37
|
|
33
|
-
dataset.join(
|
38
|
+
dataset.join(environment.qualify_collection(target_collection_class).as(relation_alias), relation_condition)
|
34
39
|
end
|
35
40
|
|
36
|
-
def apply_filter(
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
41
|
+
def apply_filter(environment, dataset, primary_keys)
|
42
|
+
if source_collection_class.data_source_name == target_collection_class.data_source_name
|
43
|
+
dataset.join(environment.qualify_collection(target_collection_class), foreign_key => source_collection_class.primary_key)
|
44
|
+
.where(Sequel[target_collection_class.collection_name][target_collection_class.primary_key] => primary_keys)
|
45
|
+
.select_all(target_collection_class.collection_name)
|
46
|
+
.distinct
|
47
|
+
else
|
48
|
+
target_collection = target_collection_class.new environment
|
49
|
+
fks = target_collection.where(target_collection_class.primary_key => primary_keys)
|
50
|
+
.pluck(foreign_key)
|
51
|
+
.uniq
|
52
|
+
dataset.where(source_collection_class.primary_key => fks)
|
53
|
+
end
|
43
54
|
end
|
44
55
|
|
45
56
|
private
|
data/lib/rasti/db/version.rb
CHANGED
data/rasti-db.gemspec
CHANGED
@@ -24,8 +24,10 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.add_runtime_dependency 'timing', '~> 0.1', '>= 0.1.3'
|
25
25
|
spec.add_runtime_dependency 'class_config', '~> 0.0', '>= 0.0.2'
|
26
26
|
spec.add_runtime_dependency 'multi_require', '~> 1.0'
|
27
|
+
spec.add_runtime_dependency 'hierarchical_graph', '~> 1.0'
|
28
|
+
spec.add_runtime_dependency 'hash_ext', '~> 0.5'
|
27
29
|
|
28
|
-
spec.add_development_dependency 'rake', '~>
|
30
|
+
spec.add_development_dependency 'rake', '~> 12.3'
|
29
31
|
spec.add_development_dependency 'minitest', '~> 5.0', '< 5.11'
|
30
32
|
spec.add_development_dependency 'minitest-colorin', '~> 0.1'
|
31
33
|
spec.add_development_dependency 'minitest-line', '~> 0.6'
|
@@ -38,10 +40,4 @@ Gem::Specification.new do |spec|
|
|
38
40
|
else
|
39
41
|
spec.add_development_dependency 'sqlite3', '~> 1.3'
|
40
42
|
end
|
41
|
-
|
42
|
-
if RUBY_VERSION < '2'
|
43
|
-
spec.add_development_dependency 'term-ansicolor', '~> 1.3.0'
|
44
|
-
spec.add_development_dependency 'tins', '~> 1.6.0'
|
45
|
-
spec.add_development_dependency 'json', '~> 1.8'
|
46
|
-
end
|
47
43
|
end
|
data/spec/collection_spec.rb
CHANGED
@@ -6,18 +6,21 @@ describe 'Collection' do
|
|
6
6
|
|
7
7
|
it 'Implicit' do
|
8
8
|
Users.collection_name.must_equal :users
|
9
|
-
Users.
|
9
|
+
Users.collection_attributes.must_equal [:id, :name]
|
10
10
|
Users.model.must_equal User
|
11
11
|
Users.primary_key.must_equal :id
|
12
12
|
Users.foreign_key.must_equal :user_id
|
13
|
+
Users.data_source_name.must_equal :default
|
13
14
|
end
|
14
15
|
|
15
16
|
it 'Explicit' do
|
16
17
|
People.collection_name.must_equal :people
|
17
|
-
People.
|
18
|
+
People.collection_attributes.must_equal [:document_number, :first_name, :last_name, :birth_date, :user_id]
|
18
19
|
People.model.must_equal Person
|
19
20
|
People.primary_key.must_equal :document_number
|
20
21
|
People.foreign_key.must_equal :document_number
|
22
|
+
|
23
|
+
Languages.data_source_name.must_equal :custom
|
21
24
|
end
|
22
25
|
|
23
26
|
it 'Lazy model name' do
|
@@ -42,11 +45,11 @@ describe 'Collection' do
|
|
42
45
|
user_id = db[:users].insert name: 'User 1'
|
43
46
|
|
44
47
|
1.upto(2) do |i|
|
45
|
-
db[:posts].insert user_id: user_id, title: "Post #{i}", body: '...'
|
48
|
+
db[:posts].insert user_id: user_id, title: "Post #{i}", body: '...', language_id: 1
|
46
49
|
db[:categories].insert name: "Category #{i}"
|
47
50
|
end
|
48
51
|
|
49
|
-
post_id = posts.insert user_id: user_id, title: 'Post title', body: '...', categories: [1,2]
|
52
|
+
post_id = posts.insert user_id: user_id, title: 'Post title', body: '...', categories: [1,2], language_id: 1
|
50
53
|
category_id = categories.insert name: 'Category', posts: [1,2]
|
51
54
|
|
52
55
|
db[:categories_posts].where(post_id: post_id).map(:category_id).must_equal [1,2]
|
@@ -59,7 +62,7 @@ describe 'Collection' do
|
|
59
62
|
end
|
60
63
|
|
61
64
|
user_id = db[:users].insert name: 'User 1'
|
62
|
-
post_id = db[:posts].insert user_id: user_id, title: 'Post title', body: '...'
|
65
|
+
post_id = db[:posts].insert user_id: user_id, title: 'Post title', body: '...', language_id: 1
|
63
66
|
1.upto(2) { |category_id| db[:categories_posts].insert post_id: post_id, category_id: category_id }
|
64
67
|
|
65
68
|
posts.insert_relations post_id, categories: [3]
|
@@ -91,7 +94,7 @@ describe 'Collection' do
|
|
91
94
|
user_id = db[:users].insert name: 'User 1'
|
92
95
|
|
93
96
|
1.upto(3) do |i|
|
94
|
-
db[:posts].insert user_id: user_id, title: "Post #{i}", body: '...'
|
97
|
+
db[:posts].insert user_id: user_id, title: "Post #{i}", body: '...', language_id: 1
|
95
98
|
db[:categories].insert name: "Category #{i}"
|
96
99
|
end
|
97
100
|
|
@@ -114,7 +117,7 @@ describe 'Collection' do
|
|
114
117
|
|
115
118
|
it 'Bulk update' do
|
116
119
|
user_id = db[:users].insert name: 'User 1'
|
117
|
-
1.upto(3) { |i| db[:posts].insert user_id: user_id, title: "Post #{i}", body: '...' }
|
120
|
+
1.upto(3) { |i| db[:posts].insert user_id: user_id, title: "Post #{i}", body: '...', language_id: 1 }
|
118
121
|
|
119
122
|
posts.bulk_update(body: 'Updated ...') { where id: [1,2] }
|
120
123
|
|
@@ -139,7 +142,7 @@ describe 'Collection' do
|
|
139
142
|
end
|
140
143
|
|
141
144
|
user_id = db[:users].insert name: 'User 1'
|
142
|
-
post_id = db[:posts].insert user_id: user_id, title: 'Post title', body: '...'
|
145
|
+
post_id = db[:posts].insert user_id: user_id, title: 'Post title', body: '...', language_id: 1
|
143
146
|
1.upto(3) { |category_id| db[:categories_posts].insert post_id: post_id, category_id: category_id }
|
144
147
|
|
145
148
|
posts.delete_relations post_id, categories: [3]
|
@@ -170,7 +173,7 @@ describe 'Collection' do
|
|
170
173
|
category_id = db[:categories].insert name: "Category #{i}"
|
171
174
|
|
172
175
|
1.upto(3) do |n|
|
173
|
-
post_id = db[:posts].insert user_id: user_id, title: "Post #{i}.#{n}", body: '...'
|
176
|
+
post_id = db[:posts].insert user_id: user_id, title: "Post #{i}.#{n}", body: '...', language_id: 1
|
174
177
|
db[:categories_posts].insert post_id: post_id, category_id: category_id
|
175
178
|
end
|
176
179
|
end
|
@@ -227,6 +230,65 @@ describe 'Collection' do
|
|
227
230
|
|
228
231
|
end
|
229
232
|
|
233
|
+
describe 'Multiple data sources' do
|
234
|
+
|
235
|
+
before do
|
236
|
+
1.upto(3) do |i|
|
237
|
+
db[:users].insert name: "User #{i}"
|
238
|
+
db[:people].insert document_number: "document_#{i}",
|
239
|
+
first_name: "John #{i}",
|
240
|
+
last_name: "Doe #{i}",
|
241
|
+
birth_date: Time.now - i,
|
242
|
+
user_id: i
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
it 'Insert' do
|
247
|
+
id = languages.insert name: 'Spanish', people: ['document_1', 'document_2']
|
248
|
+
|
249
|
+
custom_db[:languages][id: id][:name].must_equal 'Spanish'
|
250
|
+
db[:languages_people].where(language_id: id).select_map(:document_number).must_equal ['document_1', 'document_2']
|
251
|
+
end
|
252
|
+
|
253
|
+
it 'Update' do
|
254
|
+
id = custom_db[:languages].insert name: 'Spanish'
|
255
|
+
db[:languages_people].insert language_id: id, document_number: 'document_1'
|
256
|
+
|
257
|
+
custom_db[:languages][id: id][:name].must_equal 'Spanish'
|
258
|
+
db[:languages_people].where(language_id: id).select_map(:document_number).must_equal ['document_1']
|
259
|
+
|
260
|
+
languages.update id, name: 'English', people: ['document_2', 'document_3']
|
261
|
+
|
262
|
+
custom_db[:languages][id: id][:name].must_equal 'English'
|
263
|
+
db[:languages_people].where(language_id: id).select_map(:document_number).must_equal ['document_2', 'document_3']
|
264
|
+
end
|
265
|
+
|
266
|
+
it 'Delete' do
|
267
|
+
id = custom_db[:languages].insert name: 'Spanish'
|
268
|
+
db[:languages_people].insert language_id: id, document_number: 'document_1'
|
269
|
+
db[:posts].insert user_id: 1, title: 'Post 1', body: '...', language_id: id
|
270
|
+
|
271
|
+
languages.delete id
|
272
|
+
|
273
|
+
custom_db[:languages].count.must_equal 0
|
274
|
+
db[:languages_people].where(language_id: id).count.must_equal 1
|
275
|
+
db[:posts].where(language_id: id).count.must_equal 1
|
276
|
+
end
|
277
|
+
|
278
|
+
it 'Delete cascade' do
|
279
|
+
id = custom_db[:languages].insert name: 'Spanish'
|
280
|
+
db[:languages_people].insert language_id: id, document_number: 'document_1'
|
281
|
+
db[:posts].insert user_id: 1, title: 'Post 1', body: '...', language_id: id
|
282
|
+
|
283
|
+
languages.delete_cascade id
|
284
|
+
|
285
|
+
custom_db[:languages].count.must_equal 0
|
286
|
+
db[:languages_people].where(language_id: id).count.must_equal 0
|
287
|
+
db[:posts].where(language_id: id).count.must_equal 0
|
288
|
+
end
|
289
|
+
|
290
|
+
end
|
291
|
+
|
230
292
|
end
|
231
293
|
|
232
294
|
describe 'Queries' do
|
@@ -239,11 +301,29 @@ describe 'Collection' do
|
|
239
301
|
|
240
302
|
it 'Find graph' do
|
241
303
|
user_id = db[:users].insert name: 'User 1'
|
242
|
-
db[:posts].insert user_id: user_id, title: 'Post 1', body: '...'
|
304
|
+
db[:posts].insert user_id: user_id, title: 'Post 1', body: '...', language_id: 1
|
243
305
|
|
244
306
|
users.find_graph(user_id, :posts).must_equal User.new id: user_id, name: 'User 1', posts: posts.all
|
245
307
|
end
|
246
308
|
|
309
|
+
it 'Select attributes' do
|
310
|
+
id = db[:users].insert name: 'User 1'
|
311
|
+
|
312
|
+
users.select_attributes(:id).all.must_equal [User.new(id: id)]
|
313
|
+
end
|
314
|
+
|
315
|
+
it 'Exclude attributes' do
|
316
|
+
db[:users].insert name: 'User 1'
|
317
|
+
|
318
|
+
users.exclude_attributes(:id).all.must_equal [User.new(name: 'User 1')]
|
319
|
+
end
|
320
|
+
|
321
|
+
it 'All attributes' do
|
322
|
+
id = db[:users].insert name: 'User 1'
|
323
|
+
|
324
|
+
users.select_attributes(:id).all_attributes.all.must_equal [User.new(id: id, name: 'User 1')]
|
325
|
+
end
|
326
|
+
|
247
327
|
it 'Count' do
|
248
328
|
1.upto(10) { |i| db[:users].insert name: "User #{i}" }
|
249
329
|
|
@@ -298,42 +378,51 @@ describe 'Collection' do
|
|
298
378
|
|
299
379
|
it 'Chain dataset as query' do
|
300
380
|
1.upto(2) { |i| db[:users].insert name: "User #{i}" }
|
301
|
-
1.upto(3) { |i| db[:posts].insert user_id: 1, title: "Post #{i}", body: '...' }
|
381
|
+
1.upto(3) { |i| db[:posts].insert user_id: 1, title: "Post #{i}", body: '...', language_id: 1 }
|
302
382
|
1.upto(2) { |i| db[:comments].insert post_id: i, user_id: 2, text: 'Comment' }
|
303
383
|
|
304
384
|
models = posts.commented_by(2).all
|
305
|
-
models.must_equal [1,2].map { |i| Post.new(id: i, user_id: 1, title: "Post #{i}", body: '...') }
|
385
|
+
models.must_equal [1,2].map { |i| Post.new(id: i, user_id: 1, title: "Post #{i}", body: '...', language_id: 1) }
|
306
386
|
end
|
307
387
|
|
308
388
|
it 'Custom query' do
|
309
389
|
1.upto(2) { |i| db[:users].insert name: "User #{i}" }
|
310
|
-
1.upto(3) { |i| db[:posts].insert user_id: 1, title: "Post #{i}", body: '...' }
|
390
|
+
1.upto(3) { |i| db[:posts].insert user_id: 1, title: "Post #{i}", body: '...', language_id: 1 }
|
311
391
|
1.upto(2) { |i| db[:comments].insert post_id: i, user_id: 2, text: 'Comment' }
|
312
392
|
|
313
393
|
models = comments.posts_commented_by(2)
|
314
|
-
models.must_equal [1,2].map { |i| Post.new(id: i, user_id: 1, title: "Post #{i}", body: '...') }
|
394
|
+
models.must_equal [1,2].map { |i| Post.new(id: i, user_id: 1, title: "Post #{i}", body: '...', language_id: 1) }
|
315
395
|
end
|
316
396
|
|
317
397
|
describe 'Named queries' do
|
318
398
|
|
319
399
|
before do
|
400
|
+
custom_db[:languages].insert name: 'Spanish'
|
401
|
+
custom_db[:languages].insert name: 'English'
|
402
|
+
|
320
403
|
1.upto(2) do |i|
|
321
404
|
db[:categories].insert name: "Category #{i}"
|
405
|
+
|
322
406
|
db[:users].insert name: "User #{i}"
|
407
|
+
|
323
408
|
db[:people].insert document_number: "document_#{i}",
|
324
409
|
first_name: "John #{i}",
|
325
410
|
last_name: "Doe #{i}",
|
326
411
|
birth_date: Time.now - i,
|
327
412
|
user_id: i
|
413
|
+
|
328
414
|
end
|
329
415
|
|
416
|
+
db[:languages_people].insert language_id: 1, document_number: 'document_1'
|
417
|
+
db[:languages_people].insert language_id: 2, document_number: 'document_2'
|
418
|
+
|
330
419
|
1.upto(3) do |i|
|
331
|
-
db[:posts].insert user_id: 1, title: "Post #{i}", body: '...'
|
420
|
+
db[:posts].insert user_id: 1, title: "Post #{i}", body: '...', language_id: 1
|
332
421
|
db[:categories_posts].insert category_id: 1, post_id: i
|
333
422
|
end
|
334
423
|
|
335
424
|
4.upto(5) do |i|
|
336
|
-
db[:posts].insert user_id: 2, title: "Post #{i}", body: '...'
|
425
|
+
db[:posts].insert user_id: 2, title: "Post #{i}", body: '...', language_id: 2
|
337
426
|
db[:categories_posts].insert category_id: 2, post_id: i
|
338
427
|
end
|
339
428
|
end
|
@@ -356,6 +445,23 @@ describe 'Collection' do
|
|
356
445
|
users.with_people('document_1').primary_keys.must_equal [1]
|
357
446
|
end
|
358
447
|
|
448
|
+
describe 'Multiple data sources' do
|
449
|
+
|
450
|
+
it 'One to many' do
|
451
|
+
languages.with_posts([1,2]).primary_keys.must_equal [1]
|
452
|
+
end
|
453
|
+
|
454
|
+
it 'Many to one' do
|
455
|
+
posts.with_languages([2]).primary_keys.must_equal [4,5]
|
456
|
+
end
|
457
|
+
|
458
|
+
it 'Many to Many' do
|
459
|
+
languages.with_people(['document_1']).primary_keys.must_equal [1]
|
460
|
+
people.with_languages([2]).primary_keys.must_equal ['document_2']
|
461
|
+
end
|
462
|
+
|
463
|
+
end
|
464
|
+
|
359
465
|
end
|
360
466
|
|
361
467
|
it 'Global' do
|
@@ -382,7 +488,7 @@ describe 'Collection' do
|
|
382
488
|
birth_date: Time.now - i,
|
383
489
|
user_id: i
|
384
490
|
db[:categories].insert name: "Category #{i}"
|
385
|
-
db[:posts].insert user_id: i, title: "Post #{i}", body: '...'
|
491
|
+
db[:posts].insert user_id: i, title: "Post #{i}", body: '...', language_id: 1
|
386
492
|
db[:categories_posts].insert post_id: i, category_id: i
|
387
493
|
end
|
388
494
|
|
@@ -430,21 +536,21 @@ describe 'Collection' do
|
|
430
536
|
stubs = Proc.new do |sql|
|
431
537
|
case sql
|
432
538
|
|
433
|
-
when 'SELECT
|
434
|
-
'SELECT
|
539
|
+
when 'SELECT users.* FROM schema_1.users',
|
540
|
+
'SELECT users.* FROM schema_1.users WHERE (users.id IN (2, 1))'
|
435
541
|
[
|
436
542
|
{id: 1},
|
437
543
|
{id: 2}
|
438
544
|
]
|
439
545
|
|
440
|
-
when 'SELECT
|
441
|
-
'SELECT
|
546
|
+
when 'SELECT posts.* FROM schema_1.posts',
|
547
|
+
'SELECT posts.* FROM schema_1.posts WHERE (posts.user_id IN (1, 2))'
|
442
548
|
[
|
443
|
-
{id: 3, user_id: 1},
|
444
|
-
{id: 4, user_id: 2}
|
549
|
+
{id: 3, user_id: 1, language_id: 1},
|
550
|
+
{id: 4, user_id: 2, language_id: 2}
|
445
551
|
]
|
446
552
|
|
447
|
-
when 'SELECT
|
553
|
+
when 'SELECT comments.* FROM schema_1.comments WHERE (comments.post_id IN (3, 4))'
|
448
554
|
[
|
449
555
|
{id: 5, user_id: 2, post_id: 3},
|
450
556
|
{id: 6, user_id: 1, post_id: 3},
|
@@ -452,87 +558,152 @@ describe 'Collection' do
|
|
452
558
|
{id: 8, user_id: 2, post_id: 4}
|
453
559
|
]
|
454
560
|
|
455
|
-
|
456
|
-
|
561
|
+
when 'SELECT languages.* FROM schema_2.languages WHERE (languages.id IN (1, 2))'
|
562
|
+
[
|
563
|
+
{id: 1},
|
564
|
+
{id: 2}
|
565
|
+
]
|
566
|
+
|
457
567
|
end
|
458
568
|
end
|
459
569
|
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
570
|
+
last_id = 0
|
571
|
+
autoid = Proc.new do |sql|
|
572
|
+
case sql
|
573
|
+
when "INSERT INTO schema_1.people (document_number, first_name, last_name, birth_date, user_id) VALUES ('document_1', 'John', 'Doe', '2020-04-24 00:00:00.000000', 1)"
|
574
|
+
'document_1'
|
575
|
+
else
|
576
|
+
last_id += 1
|
464
577
|
end
|
465
578
|
end
|
579
|
+
|
580
|
+
Sequel.mock fetch: stubs, autoid: autoid
|
581
|
+
end
|
582
|
+
|
583
|
+
let :stub_environment do
|
584
|
+
Rasti::DB::Environment.new default: Rasti::DB::DataSource.new(stub_db, :schema_1),
|
585
|
+
custom: Rasti::DB::DataSource.new(stub_db, :schema_2)
|
466
586
|
end
|
467
587
|
|
468
|
-
let(:stub_users)
|
469
|
-
let(:stub_posts)
|
470
|
-
let(:stub_comments)
|
588
|
+
let(:stub_users) { Users.new stub_environment }
|
589
|
+
let(:stub_posts) { Posts.new stub_environment }
|
590
|
+
let(:stub_comments) { Comments.new stub_environment }
|
591
|
+
let(:stub_people) { People.new stub_environment }
|
592
|
+
let(:stub_languages) { Languages.new stub_environment }
|
471
593
|
|
472
594
|
it 'Insert' do
|
473
595
|
stub_users.insert name: 'User 1'
|
596
|
+
|
474
597
|
stub_db.sqls.must_equal [
|
475
598
|
'BEGIN',
|
476
|
-
"INSERT INTO
|
599
|
+
"INSERT INTO schema_1.users (name) VALUES ('User 1')",
|
477
600
|
'COMMIT'
|
478
601
|
]
|
479
602
|
end
|
480
603
|
|
481
604
|
it 'Insert with many to many relation' do
|
482
|
-
stub_posts.insert user_id: 1, title: 'Post 1', body: '...', categories: [2,3]
|
605
|
+
stub_posts.insert user_id: 1, title: 'Post 1', body: '...', categories: [2,3], language_id: 1
|
606
|
+
|
607
|
+
stub_db.sqls.must_equal [
|
608
|
+
'BEGIN',
|
609
|
+
"INSERT INTO schema_1.posts (user_id, title, body, language_id) VALUES (1, 'Post 1', '...', 1)",
|
610
|
+
'DELETE FROM schema_1.categories_posts WHERE (post_id IN (1))',
|
611
|
+
'INSERT INTO schema_1.categories_posts (post_id, category_id) VALUES (1, 2)',
|
612
|
+
'INSERT INTO schema_1.categories_posts (post_id, category_id) VALUES (1, 3)',
|
613
|
+
'COMMIT'
|
614
|
+
]
|
615
|
+
end
|
616
|
+
|
617
|
+
it 'Insert in multiple schemas' do
|
618
|
+
stub_languages.insert name: 'Spanish'
|
619
|
+
|
620
|
+
stub_users.insert name: 'User 1'
|
621
|
+
|
622
|
+
stub_people.insert document_number: 'document_1',
|
623
|
+
first_name: 'John',
|
624
|
+
last_name: 'Doe',
|
625
|
+
birth_date: Time.parse('2020-04-24'),
|
626
|
+
user_id: 1,
|
627
|
+
languages: [1]
|
628
|
+
|
483
629
|
stub_db.sqls.must_equal [
|
484
630
|
'BEGIN',
|
485
|
-
"INSERT INTO
|
486
|
-
'
|
487
|
-
'
|
488
|
-
|
631
|
+
"INSERT INTO schema_2.languages (name) VALUES ('Spanish')",
|
632
|
+
'COMMIT',
|
633
|
+
'BEGIN',
|
634
|
+
"INSERT INTO schema_1.users (name) VALUES ('User 1')",
|
635
|
+
'COMMIT',
|
636
|
+
'BEGIN',
|
637
|
+
"INSERT INTO schema_1.people (document_number, first_name, last_name, birth_date, user_id) VALUES ('document_1', 'John', 'Doe', '2020-04-24 00:00:00.000000', 1)",
|
638
|
+
"DELETE FROM schema_1.languages_people WHERE (document_number IN ('document_1'))",
|
639
|
+
"INSERT INTO schema_1.languages_people (document_number, language_id) VALUES ('document_1', 1)",
|
489
640
|
'COMMIT'
|
490
641
|
]
|
491
642
|
end
|
492
643
|
|
493
644
|
it 'Update' do
|
494
645
|
stub_users.update 1, name: 'Updated name'
|
646
|
+
|
495
647
|
stub_db.sqls.must_equal [
|
496
648
|
'BEGIN',
|
497
|
-
"UPDATE
|
649
|
+
"UPDATE schema_1.users SET name = 'Updated name' WHERE (id = 1)",
|
498
650
|
'COMMIT'
|
499
651
|
]
|
500
652
|
end
|
501
653
|
|
502
654
|
it 'Delete' do
|
503
655
|
stub_users.delete 1
|
504
|
-
|
656
|
+
|
657
|
+
stub_db.sqls.must_equal [
|
658
|
+
'DELETE FROM schema_1.users WHERE (id = 1)'
|
659
|
+
]
|
505
660
|
end
|
506
661
|
|
507
662
|
it 'Chained query' do
|
508
663
|
stub_users.where(id: [1,2]).limit(1).order(:name).all
|
509
|
-
|
664
|
+
|
665
|
+
stub_db.sqls.must_equal [
|
666
|
+
'SELECT users.* FROM schema_1.users WHERE (users.id IN (1, 2)) ORDER BY users.name LIMIT 1'
|
667
|
+
]
|
510
668
|
end
|
511
669
|
|
512
670
|
it 'Graph' do
|
513
|
-
stub_posts.graph(:user, :categories, 'comments.user.posts.categories').all
|
671
|
+
stub_posts.graph(:user, :categories, 'comments.user.posts.categories', 'language.people').all
|
672
|
+
|
673
|
+
stub_db.sqls.must_equal [
|
674
|
+
'SELECT posts.* FROM schema_1.posts',
|
675
|
+
'SELECT categories.*, categories_posts.post_id AS source_foreign_key FROM schema_1.categories INNER JOIN schema_1.categories_posts ON (schema_1.categories_posts.category_id = schema_1.categories.id) WHERE (categories_posts.post_id IN (3, 4))',
|
676
|
+
'SELECT comments.* FROM schema_1.comments WHERE (comments.post_id IN (3, 4))',
|
677
|
+
'SELECT users.* FROM schema_1.users WHERE (users.id IN (2, 1))',
|
678
|
+
'SELECT posts.* FROM schema_1.posts WHERE (posts.user_id IN (1, 2))',
|
679
|
+
'SELECT categories.*, categories_posts.post_id AS source_foreign_key FROM schema_1.categories INNER JOIN schema_1.categories_posts ON (schema_1.categories_posts.category_id = schema_1.categories.id) WHERE (categories_posts.post_id IN (3, 4))',
|
680
|
+
'SELECT languages.* FROM schema_2.languages WHERE (languages.id IN (1, 2))',
|
681
|
+
'SELECT people.*, languages_people.language_id AS source_foreign_key FROM schema_1.people INNER JOIN schema_1.languages_people ON (schema_1.languages_people.document_number = schema_1.people.document_number) WHERE (languages_people.language_id IN (1, 2))',
|
682
|
+
'SELECT users.* FROM schema_1.users WHERE (users.id IN (1, 2))'
|
683
|
+
]
|
684
|
+
end
|
685
|
+
|
686
|
+
it 'Join' do
|
687
|
+
stub_posts.join('user.person').where(document_number: 'document_1').all
|
688
|
+
|
514
689
|
stub_db.sqls.must_equal [
|
515
|
-
|
516
|
-
'SELECT * FROM custom_schema.users WHERE (id IN (1, 2))',
|
517
|
-
'SELECT custom_schema.categories.*, custom_schema.categories_posts.post_id AS source_foreign_key FROM custom_schema.categories INNER JOIN custom_schema.categories_posts ON (custom_schema.categories_posts.category_id = custom_schema.categories.id) WHERE (custom_schema.categories_posts.post_id IN (3, 4))',
|
518
|
-
'SELECT * FROM custom_schema.comments WHERE (post_id IN (3, 4))',
|
519
|
-
'SELECT * FROM custom_schema.users WHERE (id IN (2, 1))',
|
520
|
-
'SELECT * FROM custom_schema.posts WHERE (user_id IN (1, 2))',
|
521
|
-
'SELECT custom_schema.categories.*, custom_schema.categories_posts.post_id AS source_foreign_key FROM custom_schema.categories INNER JOIN custom_schema.categories_posts ON (custom_schema.categories_posts.category_id = custom_schema.categories.id) WHERE (custom_schema.categories_posts.post_id IN (3, 4))'
|
690
|
+
"SELECT DISTINCT posts.* FROM schema_1.posts INNER JOIN schema_1.users AS user ON (user.id = posts.user_id) INNER JOIN schema_1.people AS user__person ON (user__person.user_id = user.id) WHERE (posts.document_number = 'document_1')"
|
522
691
|
]
|
523
692
|
end
|
524
693
|
|
525
694
|
it 'Named query' do
|
526
695
|
stub_posts.commented_by(1).all
|
696
|
+
|
527
697
|
stub_db.sqls.must_equal [
|
528
|
-
'SELECT DISTINCT
|
698
|
+
'SELECT DISTINCT posts.* FROM schema_1.posts INNER JOIN schema_1.comments ON (schema_1.comments.post_id = schema_1.posts.id) WHERE (comments.user_id = 1)'
|
529
699
|
]
|
530
700
|
end
|
531
701
|
|
532
702
|
it 'Custom query' do
|
533
703
|
stub_comments.posts_commented_by(2)
|
704
|
+
|
534
705
|
stub_db.sqls.must_equal [
|
535
|
-
'SELECT
|
706
|
+
'SELECT posts.* FROM schema_1.comments INNER JOIN schema_1.posts ON (schema_1.posts.id = schema_1.comments.post_id) WHERE (comments.user_id = 2)'
|
536
707
|
]
|
537
708
|
end
|
538
709
|
|