rasti-db 1.5.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +52 -19
  3. data/lib/rasti/db.rb +11 -2
  4. data/lib/rasti/db/collection.rb +67 -36
  5. data/lib/rasti/db/computed_attribute.rb +22 -0
  6. data/lib/rasti/db/data_source.rb +18 -0
  7. data/lib/rasti/db/environment.rb +32 -0
  8. data/lib/rasti/db/nql/filter_condition_strategies/base.rb +17 -0
  9. data/lib/rasti/db/nql/filter_condition_strategies/postgres.rb +21 -0
  10. data/lib/rasti/db/nql/filter_condition_strategies/sqlite.rb +21 -0
  11. data/lib/rasti/db/nql/filter_condition_strategies/types/generic.rb +49 -0
  12. data/lib/rasti/db/nql/filter_condition_strategies/types/pg_array.rb +32 -0
  13. data/lib/rasti/db/nql/filter_condition_strategies/types/sqlite_array.rb +34 -0
  14. data/lib/rasti/db/nql/filter_condition_strategies/unsupported_type_comparison.rb +22 -0
  15. data/lib/rasti/db/nql/nodes/array_content.rb +21 -0
  16. data/lib/rasti/db/nql/nodes/attribute.rb +37 -0
  17. data/lib/rasti/db/nql/nodes/binary_node.rb +4 -0
  18. data/lib/rasti/db/nql/nodes/comparisons/base.rb +15 -1
  19. data/lib/rasti/db/nql/nodes/comparisons/equal.rb +0 -4
  20. data/lib/rasti/db/nql/nodes/comparisons/greater_than.rb +0 -4
  21. data/lib/rasti/db/nql/nodes/comparisons/greater_than_or_equal.rb +0 -4
  22. data/lib/rasti/db/nql/nodes/comparisons/include.rb +0 -4
  23. data/lib/rasti/db/nql/nodes/comparisons/less_than.rb +0 -4
  24. data/lib/rasti/db/nql/nodes/comparisons/less_than_or_equal.rb +0 -4
  25. data/lib/rasti/db/nql/nodes/comparisons/like.rb +0 -4
  26. data/lib/rasti/db/nql/nodes/comparisons/not_equal.rb +0 -4
  27. data/lib/rasti/db/nql/nodes/comparisons/not_include.rb +0 -4
  28. data/lib/rasti/db/nql/nodes/conjunction.rb +2 -2
  29. data/lib/rasti/db/nql/nodes/constants/array.rb +17 -0
  30. data/lib/rasti/db/nql/nodes/constants/base.rb +17 -0
  31. data/lib/rasti/db/nql/nodes/constants/false.rb +1 -1
  32. data/lib/rasti/db/nql/nodes/constants/float.rb +1 -1
  33. data/lib/rasti/db/nql/nodes/constants/integer.rb +1 -1
  34. data/lib/rasti/db/nql/nodes/constants/literal_string.rb +1 -1
  35. data/lib/rasti/db/nql/nodes/constants/string.rb +1 -1
  36. data/lib/rasti/db/nql/nodes/constants/time.rb +1 -1
  37. data/lib/rasti/db/nql/nodes/constants/true.rb +1 -1
  38. data/lib/rasti/db/nql/nodes/disjunction.rb +2 -2
  39. data/lib/rasti/db/nql/nodes/parenthesis_sentence.rb +6 -2
  40. data/lib/rasti/db/nql/nodes/sentence.rb +6 -2
  41. data/lib/rasti/db/nql/syntax.rb +262 -44
  42. data/lib/rasti/db/nql/syntax.treetop +27 -14
  43. data/lib/rasti/db/query.rb +55 -23
  44. data/lib/rasti/db/relations/base.rb +22 -8
  45. data/lib/rasti/db/relations/graph.rb +10 -16
  46. data/lib/rasti/db/relations/many_to_many.rb +57 -23
  47. data/lib/rasti/db/relations/many_to_one.rb +9 -7
  48. data/lib/rasti/db/relations/one_to_many.rb +21 -13
  49. data/lib/rasti/db/type_converters/sqlite.rb +62 -0
  50. data/lib/rasti/db/type_converters/sqlite_types/array.rb +34 -0
  51. data/lib/rasti/db/version.rb +1 -1
  52. data/rasti-db.gemspec +1 -0
  53. data/spec/collection_spec.rb +210 -50
  54. data/spec/computed_attribute_spec.rb +32 -0
  55. data/spec/minitest_helper.rb +77 -15
  56. data/spec/model_spec.rb +4 -2
  57. data/spec/nql/computed_attributes_spec.rb +29 -0
  58. data/spec/nql/filter_condition_spec.rb +23 -4
  59. data/spec/nql/filter_condition_strategies_spec.rb +112 -0
  60. data/spec/nql/syntax_parser_spec.rb +36 -5
  61. data/spec/query_spec.rb +340 -54
  62. data/spec/relations_spec.rb +27 -7
  63. data/spec/type_converters/sqlite_spec.rb +66 -0
  64. metadata +40 -4
  65. data/lib/rasti/db/helpers.rb +0 -16
  66. data/lib/rasti/db/nql/nodes/field.rb +0 -23
@@ -42,44 +42,49 @@ module Rasti
42
42
  comparison_equal
43
43
  end
44
44
 
45
- rule field
46
- _tables:(table:field_name '.')* _column:field_name <Nodes::Field>
45
+ rule attribute
46
+ _tables:(table:attribute_name '.')* _column:attribute_name <Nodes::Attribute>
47
47
  end
48
48
 
49
49
  rule comparison_include
50
- field:field space* comparator:':' space* argument:basic <Nodes::Comparisons::Include>
50
+ attribute:attribute space* comparator:':' space* argument:argument <Nodes::Comparisons::Include>
51
51
  end
52
52
 
53
53
  rule comparison_not_include
54
- field:field space* comparator:'!:' space* argument:basic <Nodes::Comparisons::NotInclude>
54
+ attribute:attribute space* comparator:'!:' space* argument:argument <Nodes::Comparisons::NotInclude>
55
55
  end
56
56
 
57
57
  rule comparison_like
58
- field:field space* comparator:'~' space* argument:basic <Nodes::Comparisons::Like>
58
+ attribute:attribute space* comparator:'~' space* argument:argument <Nodes::Comparisons::Like>
59
59
  end
60
60
 
61
61
  rule comparison_greater_than
62
- field:field space* comparator:'>' space* argument:basic <Nodes::Comparisons::GreaterThan>
62
+ attribute:attribute space* comparator:'>' space* argument:argument <Nodes::Comparisons::GreaterThan>
63
63
  end
64
64
 
65
65
  rule comparison_greater_than_or_equal
66
- field:field space* comparator:'>=' space* argument:basic <Nodes::Comparisons::GreaterThanOrEqual>
66
+ attribute:attribute space* comparator:'>=' space* argument:argument <Nodes::Comparisons::GreaterThanOrEqual>
67
67
  end
68
68
 
69
69
  rule comparison_less_than
70
- field:field space* comparator:'<' space* argument:basic <Nodes::Comparisons::LessThan>
70
+ attribute:attribute space* comparator:'<' space* argument:argument <Nodes::Comparisons::LessThan>
71
71
  end
72
72
 
73
73
  rule comparison_less_than_or_equal
74
- field:field space* comparator:'<=' space* argument:basic <Nodes::Comparisons::LessThanOrEqual>
74
+ attribute:attribute space* comparator:'<=' space* argument:argument <Nodes::Comparisons::LessThanOrEqual>
75
75
  end
76
76
 
77
77
  rule comparison_not_equal
78
- field:field space* comparator:'!=' space* argument:basic <Nodes::Comparisons::NotEqual>
78
+ attribute:attribute space* comparator:'!=' space* argument:argument <Nodes::Comparisons::NotEqual>
79
79
  end
80
80
 
81
81
  rule comparison_equal
82
- field:field space* comparator:'=' space* argument:basic <Nodes::Comparisons::Equal>
82
+ attribute:attribute space* comparator:'=' space* argument:argument <Nodes::Comparisons::Equal>
83
+ end
84
+
85
+ rule argument
86
+ array /
87
+ basic
83
88
  end
84
89
 
85
90
  rule basic
@@ -91,11 +96,19 @@ module Rasti
91
96
  string
92
97
  end
93
98
 
99
+ rule array
100
+ open:'[' space* contents:(array_content / basic) space* close:']' <Nodes::Constants::Array>
101
+ end
102
+
103
+ rule array_content
104
+ left:basic space* ',' space* right:(array_content / basic) <Nodes::ArrayContent>
105
+ end
106
+
94
107
  rule space
95
108
  [\s\t\n]
96
109
  end
97
110
 
98
- rule field_name
111
+ rule attribute_name
99
112
  [a-z_]+
100
113
  end
101
114
 
@@ -130,7 +143,7 @@ module Rasti
130
143
  end
131
144
 
132
145
  rule valid_character
133
- [0-9a-zA-ZÁÀÄÂÃÅĀĂǍáàäâãåāăǎÉÈËÊĒĔĖĚéèëêēĕėěÍÌÏÎĨĬǏíìïîĩĭǐÓÒÖÔÕŌŎŐǑóòöôõōŏőǒÚÙÜÛŨŪŬŮŰǓúùüûũūŭůűǔÑñçÇ%@#+-_'?!$*/\s]
146
+ [0-9a-zA-ZÁÀÄÂÃÅĀĂǍáàäâãåāăǎÉÈËÊĒĔĖĚéèëêēĕėěÍÌÏÎĨĬǏíìïîĩĭǐÓÒÖÔÕŌŎŐǑóòöôõōŏőǒÚÙÜÛŨŪŬŮŰǓúùüûũūŭůűǔÑñçÇ%@#+\--Z\\^_'?!$*/\s]
134
147
  end
135
148
 
136
149
  rule boolean
@@ -159,7 +172,7 @@ module Rasti
159
172
  end
160
173
 
161
174
  rule reserved_character
162
- [&|.():!=<>~]
175
+ [&|.():!=<>~,\]\[]
163
176
  end
164
177
 
165
178
  end
@@ -5,13 +5,12 @@ module Rasti
5
5
  DATASET_CHAINED_METHODS = [:where, :exclude, :or, :order, :reverse_order, :limit, :offset].freeze
6
6
 
7
7
  include Enumerable
8
- include Helpers::WithSchema
9
8
 
10
- def initialize(collection_class:, dataset:, relations_graph:nil, schema:nil)
9
+ def initialize(environment:, collection_class:, dataset:, relations_graph:nil)
10
+ @environment = environment
11
11
  @collection_class = collection_class
12
- @dataset = dataset
13
- @relations_graph = relations_graph || Relations::Graph.new(dataset.db, schema, collection_class)
14
- @schema = schema
12
+ @dataset = dataset.qualify collection_class.collection_name
13
+ @relations_graph = relations_graph || Relations::Graph.new(environment, collection_class)
15
14
  end
16
15
 
17
16
  DATASET_CHAINED_METHODS.each do |method|
@@ -58,15 +57,36 @@ module Rasti
58
57
  build_query relations_graph: relations_graph.with_all_attributes_for(relations)
59
58
  end
60
59
 
60
+ def select_computed_attributes(*computed_attributes)
61
+ ds = computed_attributes.inject(dataset) do |ds, name|
62
+ computed_attribute = collection_class.computed_attributes[name]
63
+ computed_attribute.apply_join(ds).select_append(computed_attribute.identifier.as(name))
64
+ end
65
+ build_query dataset: ds
66
+ end
67
+
61
68
  def all
62
- with_graph(dataset.all).map do |row|
69
+ with_graph(dataset.all).map do |row|
63
70
  collection_class.model.new row
64
71
  end
65
72
  end
66
73
  alias_method :to_a, :all
67
74
 
68
- def each(&block)
69
- all.each(&block)
75
+ def each(batch_size:nil, &block)
76
+ if batch_size.nil?
77
+ all.each(&block)
78
+ else
79
+ each_batch(size: batch_size) do |models|
80
+ models.each { |model| block.call model }
81
+ end
82
+ end
83
+ end
84
+
85
+ def each_batch(size:, &block)
86
+ primary_keys.each_slice(size) do |pks|
87
+ query = where(collection_class.primary_key => pks)
88
+ block.call query.all
89
+ end
70
90
  end
71
91
 
72
92
  def graph(*relations)
@@ -74,12 +94,10 @@ module Rasti
74
94
  end
75
95
 
76
96
  def join(*relations)
77
- graph = Relations::Graph.new dataset.db, schema, collection_class, relations
78
-
79
- ds = graph.add_joins(dataset)
80
- .distinct
81
- .select_all(collection_class.collection_name)
82
-
97
+ graph = Relations::Graph.new environment, collection_class, relations
98
+
99
+ ds = graph.add_joins(dataset).distinct
100
+
83
101
  build_query dataset: ds
84
102
  end
85
103
 
@@ -97,12 +115,12 @@ module Rasti
97
115
 
98
116
  def first
99
117
  row = dataset.first
100
- row ? collection_class.model.new(with_graph(row)) : nil
118
+ row ? build_model(row) : nil
101
119
  end
102
120
 
103
121
  def last
104
122
  row = dataset.last
105
- row ? collection_class.model.new(with_graph(row)) : nil
123
+ row ? build_model(row) : nil
106
124
  end
107
125
 
108
126
  def detect(*args, &block)
@@ -119,33 +137,42 @@ module Rasti
119
137
 
120
138
  raise NQL::InvalidExpressionError.new(filter_expression) if sentence.nil?
121
139
 
140
+ ds = sentence.computed_attributes(collection_class).inject(dataset) do |ds, name|
141
+ collection_class.computed_attributes[name].apply_join ds
142
+ end
143
+ query = build_query dataset: ds
144
+
122
145
  dependency_tables = sentence.dependency_tables
123
- query = dependency_tables.empty? ? self : join(*dependency_tables)
124
-
125
- query.where sentence.filter_condition
146
+ query = query.join(*dependency_tables) unless dependency_tables.empty?
147
+
148
+ query.where sentence.filter_condition(collection_class)
126
149
  end
127
150
 
128
151
  private
129
152
 
130
- attr_reader :collection_class, :dataset, :relations_graph, :schema
153
+ attr_reader :environment, :collection_class, :dataset, :relations_graph
131
154
 
132
155
  def build_query(**args)
133
156
  current_args = {
157
+ environment: environment,
134
158
  collection_class: collection_class,
135
159
  dataset: dataset,
136
- relations_graph: relations_graph,
137
- schema: schema
160
+ relations_graph: relations_graph
138
161
  }
139
162
 
140
163
  Query.new(**current_args.merge(args))
141
164
  end
142
165
 
166
+ def build_model(row)
167
+ collection_class.model.new with_graph(row)
168
+ end
169
+
143
170
  def chainable(&block)
144
171
  build_query dataset: instance_eval(&block)
145
172
  end
146
173
 
147
174
  def with_related(relation_name, primary_keys)
148
- ds = collection_class.relations[relation_name].apply_filter dataset, schema, primary_keys
175
+ ds = collection_class.relations[relation_name].apply_filter environment, dataset, primary_keys
149
176
  build_query dataset: ds
150
177
  end
151
178
 
@@ -155,6 +182,11 @@ module Rasti
155
182
  data
156
183
  end
157
184
 
185
+ def qualify(collection_name, data_source_name: nil)
186
+ data_source_name ||= collection_class.data_source_name
187
+ environment.qualify data_source_name, collection_name
188
+ end
189
+
158
190
  def nql_parser
159
191
  NQL::SyntaxParser.new
160
192
  end
@@ -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