rasti-db 1.5.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|