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.
@@ -33,25 +33,39 @@ module Rasti
33
33
  self.class == OneToOne
34
34
  end
35
35
 
36
- def join_relation_name(prefix)
37
- with_prefix prefix, name
36
+ def from_one?
37
+ one_to_one? || one_to_many?
38
38
  end
39
39
 
40
- private
40
+ def from_many?
41
+ many_to_one? || many_to_many?
42
+ end
41
43
 
42
- attr_reader :options
44
+ def to_one?
45
+ one_to_one? || many_to_one?
46
+ end
43
47
 
44
- def qualified_source_collection_name(schema=nil)
45
- schema.nil? ? Sequel[source_collection_class.collection_name] : Sequel[schema][source_collection_class.collection_name]
48
+ def to_many?
49
+ one_to_many? || many_to_many?
46
50
  end
47
51
 
48
- def qualified_target_collection_name(schema=nil)
49
- schema.nil? ? Sequel[target_collection_class.collection_name] : Sequel[schema][target_collection_class.collection_name]
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(db, schema, collection_class, relations=[], selected_attributes={}, excluded_attributes={})
7
- @db = db
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 db,
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 rows,
42
- db,
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.each do |node|
48
+ graph.roots.inject(dataset) do |ds, node|
52
49
  relation = relation_of node
53
- dataset = relation.add_join dataset, schema, prefix
54
- dataset = subgraph_of(node).add_joins dataset, relation.join_relation_name(prefix)
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 :db, :schema, :collection_class, :graph
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 db,
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 qualified_relation_collection_name(schema=nil)
19
- schema.nil? ? Sequel[relation_collection_name] : Sequel[schema][relation_collection_name]
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(rows, db, schema=nil, selected_attributes=nil, excluded_attributes=nil, relations_graph=nil)
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
- target_collection = target_collection_class.new db, schema
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
- relation_name = qualified_relation_collection_name schema
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
- join_rows = target_collection.dataset
30
- .join(relation_name, target_foreign_key => target_collection_class.primary_key)
31
- .where(Sequel[relation_name][source_foreign_key] => pks)
32
- .select_all(target_collection_class.collection_name)
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
+
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[target_collection_class.primary_key], []
63
+ row[name] = relation_rows.fetch row[source_collection_class.primary_key], []
45
64
  end
46
65
  end
47
66
 
48
- def add_join(dataset, schema=nil, prefix=nil)
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
- qualified_relation_source = prefix ? Sequel[prefix] : qualified_source_collection_name(schema)
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] => qualified_relation_source[source_collection_class.primary_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(schema).as(many_to_many_relation_alias), many_to_many_condition)
64
- .join(qualified_target_collection_name(schema).as(relation_alias), relation_condition)
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
- def apply_filter(dataset, schema=nil, primary_keys=[])
68
- relation_name = qualified_relation_collection_name schema
104
+ private
69
105
 
70
- dataset.join(relation_name, source_foreign_key => target_collection_class.primary_key)
71
- .where(Sequel[relation_name][target_foreign_key] => primary_keys)
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(rows, db, schema=nil, selected_attributes=nil, excluded_attributes=nil, relations_graph=nil)
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 db, schema
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(dataset, schema=nil, prefix=nil)
29
+ def add_join(environment, dataset, prefix=nil)
30
+ validate_join!
31
+
30
32
  relation_alias = join_relation_name prefix
31
33
 
32
- qualified_relation_source = prefix ? Sequel[prefix] : qualified_source_collection_name(schema)
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] => qualified_relation_source[foreign_key]
37
+ Sequel[relation_alias][target_collection_class.primary_key] => relation_name[foreign_key]
36
38
  }
37
39
 
38
- dataset.join(qualified_target_collection_name(schema).as(relation_alias), relation_condition)
40
+ dataset.join(environment.qualify_collection(target_collection_class).as(relation_alias), relation_condition)
39
41
  end
40
42
 
41
- def apply_filter(dataset, schema=nil, primary_keys=[])
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(rows, db, schema=nil, selected_attributes=nil, excluded_attributes=nil, relations_graph=nil)
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 db, schema
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(dataset, schema=nil, prefix=nil)
27
+ def add_join(environment, dataset, prefix=nil)
28
+ validate_join!
29
+
28
30
  relation_alias = join_relation_name prefix
29
31
 
30
- qualified_relation_source = prefix ? Sequel[prefix] : qualified_source_collection_name(schema)
32
+ relation_name = prefix ? Sequel[prefix] : Sequel[source_collection_class.collection_name]
31
33
 
32
34
  relation_condition = {
33
- Sequel[relation_alias][foreign_key] => qualified_relation_source[source_collection_class.primary_key]
35
+ Sequel[relation_alias][foreign_key] => relation_name[source_collection_class.primary_key]
34
36
  }
35
37
 
36
- dataset.join(qualified_target_collection_name(schema).as(relation_alias), relation_condition)
38
+ dataset.join(environment.qualify_collection(target_collection_class).as(relation_alias), relation_condition)
37
39
  end
38
40
 
39
- def apply_filter(dataset, schema=nil, primary_keys=[])
40
- target_name = qualified_target_collection_name schema
41
-
42
- dataset.join(target_name, foreign_key => source_collection_class.primary_key)
43
- .where(Sequel[target_name][target_collection_class.primary_key] => primary_keys)
44
- .select_all(qualified_source_collection_name(schema))
45
- .distinct
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
@@ -1,5 +1,5 @@
1
1
  module Rasti
2
2
  module DB
3
- VERSION = '1.5.0'
3
+ VERSION = '2.0.0'
4
4
  end
5
5
  end
@@ -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 custom_schema.users',
452
- 'SELECT users.* FROM custom_schema.users WHERE (id IN (2, 1))'
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 custom_schema.posts',
459
- 'SELECT posts.* FROM custom_schema.posts WHERE (user_id IN (1, 2))'
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 custom_schema.comments WHERE (post_id IN (3, 4))'
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
- else
474
- nil
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
- Sequel.mock(fetch: stubs, autoid: 1).tap do |mock|
479
- get_schema_block = ->(table_name) { db.schema table_name }
480
- mock.define_singleton_method(:schema_parse_table) do |table_name, opts|
481
- get_schema_block.call table_name
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) { Users.new stub_db, :custom_schema }
487
- let(:stub_posts) { Posts.new stub_db, :custom_schema }
488
- let(:stub_comments) { Comments.new stub_db, :custom_schema }
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 custom_schema.users (name) VALUES ('User 1')",
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 custom_schema.posts (user_id, title, body) VALUES (1, 'Post 1', '...')",
504
- 'DELETE FROM custom_schema.categories_posts WHERE (post_id IN (1))',
505
- 'INSERT INTO custom_schema.categories_posts (post_id, category_id) VALUES (1, 2)',
506
- 'INSERT INTO custom_schema.categories_posts (post_id, category_id) VALUES (1, 3)',
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 custom_schema.users SET name = 'Updated name' WHERE (id = 1)",
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
- stub_db.sqls.must_equal ['DELETE FROM custom_schema.users WHERE (id = 1)']
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
- stub_db.sqls.must_equal ['SELECT users.* FROM custom_schema.users WHERE (id IN (1, 2)) ORDER BY name LIMIT 1']
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
- 'SELECT posts.* FROM custom_schema.posts',
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 custom_schema.posts INNER JOIN custom_schema.comments ON (custom_schema.comments.post_id = custom_schema.posts.id) WHERE (custom_schema.comments.user_id = 1)'
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 custom_schema.comments INNER JOIN custom_schema.posts ON (custom_schema.posts.id = custom_schema.comments.post_id) WHERE (comments.user_id = 2)'
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