rasti-db 1.5.0 → 2.0.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 +41 -16
- data/lib/rasti/db.rb +0 -1
- data/lib/rasti/db/collection.rb +57 -35
- data/lib/rasti/db/data_source.rb +18 -0
- data/lib/rasti/db/environment.rb +32 -0
- data/lib/rasti/db/query.rb +13 -9
- data/lib/rasti/db/relations/base.rb +22 -8
- data/lib/rasti/db/relations/graph.rb +10 -16
- data/lib/rasti/db/relations/many_to_many.rb +57 -23
- data/lib/rasti/db/relations/many_to_one.rb +9 -7
- data/lib/rasti/db/relations/one_to_many.rb +21 -13
- data/lib/rasti/db/version.rb +1 -1
- data/spec/collection_spec.rb +202 -50
- data/spec/minitest_helper.rb +47 -12
- data/spec/model_spec.rb +3 -1
- data/spec/query_spec.rb +104 -33
- data/spec/relations_spec.rb +27 -7
- metadata +4 -3
- data/lib/rasti/db/helpers.rb +0 -16
@@ -33,25 +33,39 @@ module Rasti
|
|
33
33
|
self.class == OneToOne
|
34
34
|
end
|
35
35
|
|
36
|
-
def
|
37
|
-
|
36
|
+
def from_one?
|
37
|
+
one_to_one? || one_to_many?
|
38
38
|
end
|
39
39
|
|
40
|
-
|
40
|
+
def from_many?
|
41
|
+
many_to_one? || many_to_many?
|
42
|
+
end
|
41
43
|
|
42
|
-
|
44
|
+
def to_one?
|
45
|
+
one_to_one? || many_to_one?
|
46
|
+
end
|
43
47
|
|
44
|
-
def
|
45
|
-
|
48
|
+
def to_many?
|
49
|
+
one_to_many? || many_to_many?
|
46
50
|
end
|
47
51
|
|
48
|
-
def
|
49
|
-
|
52
|
+
def join_relation_name(prefix)
|
53
|
+
with_prefix prefix, name
|
50
54
|
end
|
51
55
|
|
56
|
+
private
|
57
|
+
|
58
|
+
attr_reader :options
|
59
|
+
|
52
60
|
def with_prefix(prefix, name)
|
53
61
|
[prefix, name].compact.join('__').to_sym
|
54
62
|
end
|
63
|
+
|
64
|
+
def validate_join!
|
65
|
+
if source_collection_class.data_source_name != target_collection_class.data_source_name
|
66
|
+
raise "Invalid join of multiple data sources: #{source_collection_class.data_source_name}.#{source_collection_class.collection_name} > #{target_collection_class.data_source_name}.#{target_collection_class.collection_name}"
|
67
|
+
end
|
68
|
+
end
|
55
69
|
|
56
70
|
end
|
57
71
|
end
|
@@ -3,9 +3,8 @@ module Rasti
|
|
3
3
|
module Relations
|
4
4
|
class Graph
|
5
5
|
|
6
|
-
def initialize(
|
7
|
-
@
|
8
|
-
@schema = schema
|
6
|
+
def initialize(environment, collection_class, relations=[], selected_attributes={}, excluded_attributes={})
|
7
|
+
@environment = environment
|
9
8
|
@collection_class = collection_class
|
10
9
|
@graph = build_graph relations,
|
11
10
|
Hash::Indifferent.new(selected_attributes),
|
@@ -13,8 +12,7 @@ module Rasti
|
|
13
12
|
end
|
14
13
|
|
15
14
|
def merge(relations:[], selected_attributes:{}, excluded_attributes:{})
|
16
|
-
Graph.new
|
17
|
-
schema,
|
15
|
+
Graph.new environment,
|
18
16
|
collection_class,
|
19
17
|
(flat_relations | relations),
|
20
18
|
flat_selected_attributes.merge(selected_attributes),
|
@@ -38,9 +36,8 @@ module Rasti
|
|
38
36
|
return if rows.empty?
|
39
37
|
|
40
38
|
graph.roots.each do |node|
|
41
|
-
relation_of(node).fetch_graph
|
42
|
-
|
43
|
-
schema,
|
39
|
+
relation_of(node).fetch_graph environment,
|
40
|
+
rows,
|
44
41
|
node[:selected_attributes],
|
45
42
|
node[:excluded_attributes] ,
|
46
43
|
subgraph_of(node)
|
@@ -48,18 +45,16 @@ module Rasti
|
|
48
45
|
end
|
49
46
|
|
50
47
|
def add_joins(dataset, prefix=nil)
|
51
|
-
graph.roots.
|
48
|
+
graph.roots.inject(dataset) do |ds, node|
|
52
49
|
relation = relation_of node
|
53
|
-
|
54
|
-
|
50
|
+
dataset_with_relation = relation.add_join environment, ds, prefix
|
51
|
+
subgraph_of(node).add_joins dataset_with_relation, relation.join_relation_name(prefix)
|
55
52
|
end
|
56
|
-
|
57
|
-
dataset
|
58
53
|
end
|
59
54
|
|
60
55
|
private
|
61
56
|
|
62
|
-
attr_reader :
|
57
|
+
attr_reader :environment, :collection_class, :graph
|
63
58
|
|
64
59
|
def relation_of(node)
|
65
60
|
collection_class.relations.fetch(node[:name])
|
@@ -93,8 +88,7 @@ module Rasti
|
|
93
88
|
excluded[id] = descendant[:excluded_attributes]
|
94
89
|
end
|
95
90
|
|
96
|
-
Graph.new
|
97
|
-
schema,
|
91
|
+
Graph.new environment,
|
98
92
|
relation_of(node).target_collection_class,
|
99
93
|
relations,
|
100
94
|
selected,
|
@@ -15,23 +15,42 @@ 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 fetch_graph(
|
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
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
+
|
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
|
35
54
|
|
36
55
|
relations_graph.fetch_graph join_rows if relations_graph
|
37
56
|
|
@@ -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 add_join(
|
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(source_collection_class.collection_name)
|
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,10 +7,10 @@ module Rasti
|
|
7
7
|
@foreign_key ||= options[:foreign_key] || target_collection_class.foreign_key
|
8
8
|
end
|
9
9
|
|
10
|
-
def fetch_graph(
|
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
15
|
query = target_collection.where(source_collection_class.primary_key => fks)
|
16
16
|
query = query.exclude_attributes(*excluded_attributes) if excluded_attributes
|
@@ -26,19 +26,21 @@ module Rasti
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
def add_join(
|
29
|
+
def add_join(environment, dataset, prefix=nil)
|
30
|
+
validate_join!
|
31
|
+
|
30
32
|
relation_alias = join_relation_name prefix
|
31
33
|
|
32
|
-
|
34
|
+
relation_name = prefix ? Sequel[prefix] : Sequel[source_collection_class.collection_name]
|
33
35
|
|
34
36
|
relation_condition = {
|
35
|
-
Sequel[relation_alias][target_collection_class.primary_key] =>
|
37
|
+
Sequel[relation_alias][target_collection_class.primary_key] => relation_name[foreign_key]
|
36
38
|
}
|
37
39
|
|
38
|
-
dataset.join(
|
40
|
+
dataset.join(environment.qualify_collection(target_collection_class).as(relation_alias), relation_condition)
|
39
41
|
end
|
40
42
|
|
41
|
-
def apply_filter(
|
43
|
+
def apply_filter(environment, dataset, primary_keys)
|
42
44
|
dataset.where(foreign_key => primary_keys)
|
43
45
|
end
|
44
46
|
|
@@ -7,10 +7,10 @@ module Rasti
|
|
7
7
|
@foreign_key ||= options[:foreign_key] || source_collection_class.foreign_key
|
8
8
|
end
|
9
9
|
|
10
|
-
def fetch_graph(
|
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
15
|
query = target_collection.where(foreign_key => pks)
|
16
16
|
query = query.exclude_attributes(*excluded_attributes) if excluded_attributes
|
@@ -24,25 +24,33 @@ module Rasti
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
def add_join(
|
27
|
+
def add_join(environment, dataset, prefix=nil)
|
28
|
+
validate_join!
|
29
|
+
|
28
30
|
relation_alias = join_relation_name prefix
|
29
31
|
|
30
|
-
|
32
|
+
relation_name = prefix ? Sequel[prefix] : Sequel[source_collection_class.collection_name]
|
31
33
|
|
32
34
|
relation_condition = {
|
33
|
-
Sequel[relation_alias][foreign_key] =>
|
35
|
+
Sequel[relation_alias][foreign_key] => relation_name[source_collection_class.primary_key]
|
34
36
|
}
|
35
37
|
|
36
|
-
dataset.join(
|
38
|
+
dataset.join(environment.qualify_collection(target_collection_class).as(relation_alias), relation_condition)
|
37
39
|
end
|
38
40
|
|
39
|
-
def apply_filter(
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
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
|
46
54
|
end
|
47
55
|
|
48
56
|
private
|
data/lib/rasti/db/version.rb
CHANGED
data/spec/collection_spec.rb
CHANGED
@@ -10,6 +10,7 @@ describe 'Collection' do
|
|
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
|
@@ -18,6 +19,8 @@ describe 'Collection' do
|
|
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,7 +301,7 @@ 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
|
@@ -316,42 +378,51 @@ describe 'Collection' do
|
|
316
378
|
|
317
379
|
it 'Chain dataset as query' do
|
318
380
|
1.upto(2) { |i| db[:users].insert name: "User #{i}" }
|
319
|
-
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 }
|
320
382
|
1.upto(2) { |i| db[:comments].insert post_id: i, user_id: 2, text: 'Comment' }
|
321
383
|
|
322
384
|
models = posts.commented_by(2).all
|
323
|
-
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) }
|
324
386
|
end
|
325
387
|
|
326
388
|
it 'Custom query' do
|
327
389
|
1.upto(2) { |i| db[:users].insert name: "User #{i}" }
|
328
|
-
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 }
|
329
391
|
1.upto(2) { |i| db[:comments].insert post_id: i, user_id: 2, text: 'Comment' }
|
330
392
|
|
331
393
|
models = comments.posts_commented_by(2)
|
332
|
-
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) }
|
333
395
|
end
|
334
396
|
|
335
397
|
describe 'Named queries' do
|
336
398
|
|
337
399
|
before do
|
400
|
+
custom_db[:languages].insert name: 'Spanish'
|
401
|
+
custom_db[:languages].insert name: 'English'
|
402
|
+
|
338
403
|
1.upto(2) do |i|
|
339
404
|
db[:categories].insert name: "Category #{i}"
|
405
|
+
|
340
406
|
db[:users].insert name: "User #{i}"
|
407
|
+
|
341
408
|
db[:people].insert document_number: "document_#{i}",
|
342
409
|
first_name: "John #{i}",
|
343
410
|
last_name: "Doe #{i}",
|
344
411
|
birth_date: Time.now - i,
|
345
412
|
user_id: i
|
413
|
+
|
346
414
|
end
|
347
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
|
+
|
348
419
|
1.upto(3) do |i|
|
349
|
-
db[:posts].insert user_id: 1, title: "Post #{i}", body: '...'
|
420
|
+
db[:posts].insert user_id: 1, title: "Post #{i}", body: '...', language_id: 1
|
350
421
|
db[:categories_posts].insert category_id: 1, post_id: i
|
351
422
|
end
|
352
423
|
|
353
424
|
4.upto(5) do |i|
|
354
|
-
db[:posts].insert user_id: 2, title: "Post #{i}", body: '...'
|
425
|
+
db[:posts].insert user_id: 2, title: "Post #{i}", body: '...', language_id: 2
|
355
426
|
db[:categories_posts].insert category_id: 2, post_id: i
|
356
427
|
end
|
357
428
|
end
|
@@ -374,6 +445,23 @@ describe 'Collection' do
|
|
374
445
|
users.with_people('document_1').primary_keys.must_equal [1]
|
375
446
|
end
|
376
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
|
+
|
377
465
|
end
|
378
466
|
|
379
467
|
it 'Global' do
|
@@ -400,7 +488,7 @@ describe 'Collection' do
|
|
400
488
|
birth_date: Time.now - i,
|
401
489
|
user_id: i
|
402
490
|
db[:categories].insert name: "Category #{i}"
|
403
|
-
db[:posts].insert user_id: i, title: "Post #{i}", body: '...'
|
491
|
+
db[:posts].insert user_id: i, title: "Post #{i}", body: '...', language_id: 1
|
404
492
|
db[:categories_posts].insert post_id: i, category_id: i
|
405
493
|
end
|
406
494
|
|
@@ -448,21 +536,21 @@ describe 'Collection' do
|
|
448
536
|
stubs = Proc.new do |sql|
|
449
537
|
case sql
|
450
538
|
|
451
|
-
when 'SELECT users.* FROM
|
452
|
-
'SELECT users.* FROM
|
539
|
+
when 'SELECT users.* FROM schema_1.users',
|
540
|
+
'SELECT users.* FROM schema_1.users WHERE (id IN (2, 1))'
|
453
541
|
[
|
454
542
|
{id: 1},
|
455
543
|
{id: 2}
|
456
544
|
]
|
457
545
|
|
458
|
-
when 'SELECT posts.* FROM
|
459
|
-
'SELECT posts.* FROM
|
546
|
+
when 'SELECT posts.* FROM schema_1.posts',
|
547
|
+
'SELECT posts.* FROM schema_1.posts WHERE (user_id IN (1, 2))'
|
460
548
|
[
|
461
|
-
{id: 3, user_id: 1},
|
462
|
-
{id: 4, user_id: 2}
|
549
|
+
{id: 3, user_id: 1, language_id: 1},
|
550
|
+
{id: 4, user_id: 2, language_id: 2}
|
463
551
|
]
|
464
552
|
|
465
|
-
when 'SELECT comments.* FROM
|
553
|
+
when 'SELECT comments.* FROM schema_1.comments WHERE (post_id IN (3, 4))'
|
466
554
|
[
|
467
555
|
{id: 5, user_id: 2, post_id: 3},
|
468
556
|
{id: 6, user_id: 1, post_id: 3},
|
@@ -470,88 +558,152 @@ describe 'Collection' do
|
|
470
558
|
{id: 8, user_id: 2, post_id: 4}
|
471
559
|
]
|
472
560
|
|
473
|
-
|
474
|
-
|
561
|
+
when 'SELECT languages.* FROM schema_2.languages WHERE (id IN (1, 2))'
|
562
|
+
[
|
563
|
+
{id: 1},
|
564
|
+
{id: 2}
|
565
|
+
]
|
566
|
+
|
475
567
|
end
|
476
568
|
end
|
477
569
|
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
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
|
482
577
|
end
|
483
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)
|
484
586
|
end
|
485
587
|
|
486
|
-
let(:stub_users)
|
487
|
-
let(:stub_posts)
|
488
|
-
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 }
|
489
593
|
|
490
594
|
it 'Insert' do
|
491
595
|
stub_users.insert name: 'User 1'
|
596
|
+
|
492
597
|
stub_db.sqls.must_equal [
|
493
598
|
'BEGIN',
|
494
|
-
"INSERT INTO
|
599
|
+
"INSERT INTO schema_1.users (name) VALUES ('User 1')",
|
495
600
|
'COMMIT'
|
496
601
|
]
|
497
602
|
end
|
498
603
|
|
499
604
|
it 'Insert with many to many relation' do
|
500
|
-
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
|
+
|
501
629
|
stub_db.sqls.must_equal [
|
502
630
|
'BEGIN',
|
503
|
-
"INSERT INTO
|
504
|
-
'
|
505
|
-
'
|
506
|
-
|
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)",
|
507
640
|
'COMMIT'
|
508
641
|
]
|
509
642
|
end
|
510
643
|
|
511
644
|
it 'Update' do
|
512
645
|
stub_users.update 1, name: 'Updated name'
|
646
|
+
|
513
647
|
stub_db.sqls.must_equal [
|
514
648
|
'BEGIN',
|
515
|
-
"UPDATE
|
649
|
+
"UPDATE schema_1.users SET name = 'Updated name' WHERE (id = 1)",
|
516
650
|
'COMMIT'
|
517
651
|
]
|
518
652
|
end
|
519
653
|
|
520
654
|
it 'Delete' do
|
521
655
|
stub_users.delete 1
|
522
|
-
|
656
|
+
|
657
|
+
stub_db.sqls.must_equal [
|
658
|
+
'DELETE FROM schema_1.users WHERE (id = 1)'
|
659
|
+
]
|
523
660
|
end
|
524
661
|
|
525
662
|
it 'Chained query' do
|
526
663
|
stub_users.where(id: [1,2]).limit(1).order(:name).all
|
527
|
-
|
664
|
+
|
665
|
+
stub_db.sqls.must_equal [
|
666
|
+
'SELECT users.* FROM schema_1.users WHERE (id IN (1, 2)) ORDER BY name LIMIT 1'
|
667
|
+
]
|
528
668
|
end
|
529
669
|
|
530
670
|
it 'Graph' do
|
531
|
-
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 (post_id IN (3, 4))',
|
677
|
+
'SELECT users.* FROM schema_1.users WHERE (id IN (2, 1))',
|
678
|
+
'SELECT posts.* FROM schema_1.posts WHERE (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 (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 (id IN (1, 2))'
|
683
|
+
]
|
684
|
+
end
|
685
|
+
|
686
|
+
it 'Join' do
|
687
|
+
stub_posts.join('user.person').where(document_number: 'document_1').all
|
532
688
|
|
533
689
|
stub_db.sqls.must_equal [
|
534
|
-
|
535
|
-
'SELECT 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))',
|
536
|
-
'SELECT comments.* FROM custom_schema.comments WHERE (post_id IN (3, 4))',
|
537
|
-
'SELECT users.* FROM custom_schema.users WHERE (id IN (2, 1))',
|
538
|
-
'SELECT posts.* FROM custom_schema.posts WHERE (user_id IN (1, 2))',
|
539
|
-
'SELECT 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))',
|
540
|
-
'SELECT users.* FROM custom_schema.users WHERE (id IN (1, 2))'
|
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 (document_number = 'document_1')"
|
541
691
|
]
|
542
692
|
end
|
543
693
|
|
544
694
|
it 'Named query' do
|
545
695
|
stub_posts.commented_by(1).all
|
696
|
+
|
546
697
|
stub_db.sqls.must_equal [
|
547
|
-
'SELECT DISTINCT posts.* FROM
|
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)'
|
548
699
|
]
|
549
700
|
end
|
550
701
|
|
551
702
|
it 'Custom query' do
|
552
703
|
stub_comments.posts_commented_by(2)
|
704
|
+
|
553
705
|
stub_db.sqls.must_equal [
|
554
|
-
'SELECT posts.* FROM
|
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)'
|
555
707
|
]
|
556
708
|
end
|
557
709
|
|