mochigome 0.1.9 → 0.1.10
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.
- data/lib/mochigome.rb +1 -0
- data/lib/mochigome_ver.rb +1 -1
- data/lib/query.rb +0 -134
- data/lib/relation.rb +141 -0
- metadata +5 -4
data/lib/mochigome.rb
CHANGED
data/lib/mochigome_ver.rb
CHANGED
data/lib/query.rb
CHANGED
@@ -187,138 +187,4 @@ module Mochigome
|
|
187
187
|
end
|
188
188
|
end
|
189
189
|
end
|
190
|
-
|
191
|
-
private
|
192
|
-
|
193
|
-
class Relation
|
194
|
-
attr_reader :joins, :spine_layers
|
195
|
-
|
196
|
-
def initialize(layers)
|
197
|
-
@model_graph = ModelGraph.new
|
198
|
-
@spine_layers = layers
|
199
|
-
@models = Set.new
|
200
|
-
@spine = []
|
201
|
-
@joins = []
|
202
|
-
|
203
|
-
@spine_layers.map(&:to_real_model).uniq.each do |m|
|
204
|
-
if @rel
|
205
|
-
join_to_model(m)
|
206
|
-
else
|
207
|
-
@rel = @model_graph.relation_init(m)
|
208
|
-
@models.add m
|
209
|
-
end
|
210
|
-
@spine << m
|
211
|
-
end
|
212
|
-
@spine_layers.each{|m| select_model_id(m)}
|
213
|
-
end
|
214
|
-
|
215
|
-
def to_arel
|
216
|
-
@rel.clone
|
217
|
-
end
|
218
|
-
|
219
|
-
def to_sql
|
220
|
-
@rel.to_sql
|
221
|
-
end
|
222
|
-
|
223
|
-
def clone
|
224
|
-
c = super
|
225
|
-
c.instance_variable_set :@models, @models.clone
|
226
|
-
c.instance_variable_set :@rel, @rel.clone
|
227
|
-
c
|
228
|
-
end
|
229
|
-
|
230
|
-
def join_to_model(model)
|
231
|
-
return if @models.include?(model)
|
232
|
-
|
233
|
-
# Route to it in as few steps as possible, closer to spine end if tie.
|
234
|
-
best_path = nil
|
235
|
-
(@spine.reverse + (@models.to_a - @spine)).each do |link_model|
|
236
|
-
path = @model_graph.path_thru([link_model, model])
|
237
|
-
if path && (best_path.nil? || path.size < best_path.size)
|
238
|
-
best_path = path
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
raise QueryError.new("No path to #{model}") unless best_path
|
243
|
-
join_on_path(best_path)
|
244
|
-
|
245
|
-
# TODO: Write a test that requires the below code to work
|
246
|
-
@models.reject{|n| best_path.include?(n)}.each do |n|
|
247
|
-
cond = @model_graph.edge_condition(n, model)
|
248
|
-
if cond
|
249
|
-
@rel = @rel.where(cond)
|
250
|
-
end
|
251
|
-
end
|
252
|
-
end
|
253
|
-
|
254
|
-
def join_on_path_thru(path)
|
255
|
-
full_path = @model_graph.path_thru(path).uniq
|
256
|
-
if full_path
|
257
|
-
join_on_path(full_path)
|
258
|
-
else
|
259
|
-
raise QueryError.new("Cannot route thru #{path.map(&:name).inspect}")
|
260
|
-
end
|
261
|
-
end
|
262
|
-
|
263
|
-
def join_on_path(path)
|
264
|
-
path = path.map(&:to_real_model).uniq
|
265
|
-
join_to_model path.first
|
266
|
-
(0..(path.size-2)).map{|i| [path[i], path[i+1]]}.each do |src, tgt|
|
267
|
-
add_join_link(src, tgt) unless @models.include?(tgt)
|
268
|
-
end
|
269
|
-
end
|
270
|
-
|
271
|
-
def select_model_id(m)
|
272
|
-
@rel = @rel.project(m.arel_primary_key.as("#{m.name}_id"))
|
273
|
-
end
|
274
|
-
|
275
|
-
def select_expr(e)
|
276
|
-
@model_graph.expr_models(e).each{|m| join_to_model(m)}
|
277
|
-
@rel = @rel.project(e)
|
278
|
-
end
|
279
|
-
|
280
|
-
def apply_condition(cond)
|
281
|
-
return unless cond
|
282
|
-
if cond.is_a?(ActiveRecord::Base)
|
283
|
-
cond = [cond]
|
284
|
-
end
|
285
|
-
if cond.is_a?(Array)
|
286
|
-
# TODO: Should group by type and use IN expressions
|
287
|
-
cond = cond.inject(nil) do |expr, obj|
|
288
|
-
subexpr = obj.class.arel_primary_key.eq(obj.id)
|
289
|
-
expr ? expr.or(subexpr) : subexpr
|
290
|
-
end
|
291
|
-
end
|
292
|
-
|
293
|
-
@model_graph.expr_models(cond).each{|m| join_to_model(m)}
|
294
|
-
@rel = @rel.where(cond)
|
295
|
-
end
|
296
|
-
|
297
|
-
def apply_access_filter_func(func)
|
298
|
-
@models.each do |m|
|
299
|
-
h = func.call(m)
|
300
|
-
h.delete(:join_paths).try :each do |path|
|
301
|
-
join_on_path path
|
302
|
-
end
|
303
|
-
if h[:condition]
|
304
|
-
apply_condition h.delete(:condition)
|
305
|
-
end
|
306
|
-
unless h.empty?
|
307
|
-
raise QueryError.new("Unknown assoc filter keys #{h.keys.inspect}")
|
308
|
-
end
|
309
|
-
end
|
310
|
-
end
|
311
|
-
|
312
|
-
private
|
313
|
-
|
314
|
-
def add_join_link(src, tgt)
|
315
|
-
raise QueryError.new("Can't join from #{src}, not available") unless
|
316
|
-
@models.include?(src)
|
317
|
-
@rel = @rel.join(tgt.arel_table, Arel::Nodes::InnerJoin).on(
|
318
|
-
@model_graph.edge_condition(src, tgt)
|
319
|
-
)
|
320
|
-
@models.add tgt
|
321
|
-
@joins << [src, tgt]
|
322
|
-
end
|
323
|
-
end
|
324
190
|
end
|
data/lib/relation.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
module Mochigome
|
2
|
+
private
|
3
|
+
|
4
|
+
class Relation
|
5
|
+
attr_reader :joins, :spine_layers
|
6
|
+
|
7
|
+
def initialize(layers)
|
8
|
+
@model_graph = ModelGraph.new
|
9
|
+
@spine_layers = layers
|
10
|
+
@models = Set.new
|
11
|
+
@spine = []
|
12
|
+
@joins = []
|
13
|
+
|
14
|
+
@spine_layers.map(&:to_real_model).uniq.each do |m|
|
15
|
+
if @rel
|
16
|
+
join_to_model(m)
|
17
|
+
else
|
18
|
+
@rel = @model_graph.relation_init(m)
|
19
|
+
@models.add m
|
20
|
+
end
|
21
|
+
@spine << m
|
22
|
+
end
|
23
|
+
@spine_layers.each{|m| select_model_id(m)}
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_arel
|
27
|
+
@rel.clone
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_sql
|
31
|
+
@rel.to_sql
|
32
|
+
end
|
33
|
+
|
34
|
+
def clone
|
35
|
+
c = super
|
36
|
+
c.instance_variable_set :@models, @models.clone
|
37
|
+
c.instance_variable_set :@rel, @rel.clone
|
38
|
+
c
|
39
|
+
end
|
40
|
+
|
41
|
+
def join_to_model(model)
|
42
|
+
return if @models.include?(model)
|
43
|
+
|
44
|
+
# Route to it in as few steps as possible, closer to spine end if tie.
|
45
|
+
best_path = nil
|
46
|
+
(@spine.reverse + (@models.to_a - @spine)).each do |link_model|
|
47
|
+
path = @model_graph.path_thru([link_model, model])
|
48
|
+
if path && (best_path.nil? || path.size < best_path.size)
|
49
|
+
best_path = path
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
raise QueryError.new("No path to #{model}") unless best_path
|
54
|
+
join_on_path(best_path)
|
55
|
+
|
56
|
+
# Also use the conditions of any other direct assoc to the target
|
57
|
+
# TODO: Or maybe any other assoc that's equal length?
|
58
|
+
# TODO: Write a test that requires the below code to work
|
59
|
+
@models.reject{|n| best_path.include?(n)}.each do |n|
|
60
|
+
cond = @model_graph.edge_condition(n, model)
|
61
|
+
if cond
|
62
|
+
@rel = @rel.where(cond)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def join_on_path_thru(path)
|
68
|
+
full_path = @model_graph.path_thru(path).uniq
|
69
|
+
if full_path
|
70
|
+
join_on_path(full_path)
|
71
|
+
else
|
72
|
+
raise QueryError.new("Cannot route thru #{path.map(&:name).inspect}")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def join_on_path(path)
|
77
|
+
path = path.map(&:to_real_model).uniq
|
78
|
+
join_to_model path.first
|
79
|
+
(0..(path.size-2)).map{|i| [path[i], path[i+1]]}.each do |src, tgt|
|
80
|
+
add_join_link(src, tgt) unless @models.include?(tgt)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def select_model_id(m)
|
85
|
+
@rel = @rel.project(m.arel_primary_key.as("#{m.name}_id"))
|
86
|
+
end
|
87
|
+
|
88
|
+
def select_expr(e)
|
89
|
+
join_to_expr_models(e)
|
90
|
+
@rel = @rel.project(e)
|
91
|
+
end
|
92
|
+
|
93
|
+
def apply_condition(cond)
|
94
|
+
return unless cond
|
95
|
+
if cond.is_a?(ActiveRecord::Base)
|
96
|
+
cond = [cond]
|
97
|
+
end
|
98
|
+
if cond.is_a?(Array)
|
99
|
+
# TODO: Should group by type and use IN expressions
|
100
|
+
cond = cond.inject(nil) do |expr, obj|
|
101
|
+
subexpr = obj.class.arel_primary_key.eq(obj.id)
|
102
|
+
expr ? expr.or(subexpr) : subexpr
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
join_to_expr_models(cond)
|
107
|
+
@rel = @rel.where(cond)
|
108
|
+
end
|
109
|
+
|
110
|
+
def apply_access_filter_func(func)
|
111
|
+
@models.each do |m|
|
112
|
+
h = func.call(m)
|
113
|
+
h.delete(:join_paths).try :each do |path|
|
114
|
+
join_on_path path
|
115
|
+
end
|
116
|
+
if h[:condition]
|
117
|
+
apply_condition h.delete(:condition)
|
118
|
+
end
|
119
|
+
unless h.empty?
|
120
|
+
raise QueryError.new("Unknown assoc filter keys #{h.keys.inspect}")
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
def add_join_link(src, tgt)
|
128
|
+
raise QueryError.new("Can't join from #{src}, not available") unless
|
129
|
+
@models.include?(src)
|
130
|
+
@models.add tgt
|
131
|
+
cond = @model_graph.edge_condition(src, tgt)
|
132
|
+
join_to_expr_models(cond)
|
133
|
+
@rel = @rel.join(tgt.arel_table, Arel::Nodes::InnerJoin).on(cond)
|
134
|
+
@joins << [src, tgt]
|
135
|
+
end
|
136
|
+
|
137
|
+
def join_to_expr_models(expr)
|
138
|
+
@model_graph.expr_models(expr).each{|m| join_to_model(m)}
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mochigome
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 10
|
10
|
+
version: 0.1.10
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- David Mike Simon
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-05-
|
18
|
+
date: 2012-05-17 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
version_requirements: &id001 !ruby/object:Gem::Requirement
|
@@ -113,6 +113,7 @@ files:
|
|
113
113
|
- lib/model_extensions.rb
|
114
114
|
- lib/model_graph.rb
|
115
115
|
- lib/query.rb
|
116
|
+
- lib/relation.rb
|
116
117
|
- lib/subgroup_model.rb
|
117
118
|
- test/app_root/app/controllers/application_controller.rb
|
118
119
|
- test/app_root/app/controllers/report_controller.rb
|