mochigome 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
data/lib/mochigome_ver.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Mochigome
2
- VERSION = "0.1.7"
2
+ VERSION = "0.1.8"
3
3
  end
@@ -75,7 +75,7 @@ module Mochigome
75
75
  end
76
76
 
77
77
  if assoc.options[:as]
78
- # FIXME Can we assume that this is the polymorphic type field?
78
+ # FIXME Can we really assume that this is the polymorphic type field?
79
79
  cond = cond.and(ftable["#{assoc.options[:as]}_type"].eq(model.name))
80
80
  end
81
81
 
@@ -156,6 +156,7 @@ module Mochigome
156
156
  @options = {}
157
157
  @options[:fields] = []
158
158
  @options[:custom_subgroup_exprs] = {}
159
+ @options[:custom_assocs] = {}
159
160
  end
160
161
 
161
162
  def type_name(n)
@@ -200,6 +201,10 @@ module Mochigome
200
201
  def custom_subgroup_expression(name, expr)
201
202
  @options[:custom_subgroup_exprs][name] = expr
202
203
  end
204
+
205
+ def custom_association(tgt_cls, expr)
206
+ @options[:custom_assocs][tgt_cls] = expr
207
+ end
203
208
  end
204
209
 
205
210
  class AggregationSettings
@@ -284,6 +289,12 @@ module Mochigome
284
289
  :sum => lambda{|a| a.sum}
285
290
  }
286
291
 
292
+ AGG_FUNC_DEFAULTS = {
293
+ :count => 0,
294
+ :distinct => 0,
295
+ :sum => 0
296
+ }
297
+
287
298
  # Given an object, tries to coerce it into a proc that takes a node
288
299
  # and returns an expression node to collect some aggregate data from it.
289
300
  def self.aggregation_proc(obj)
@@ -330,9 +341,15 @@ module Mochigome
330
341
  raise ModelSetupError.new "Wrong # of components for agg: #{obj.inspect}"
331
342
  end
332
343
 
333
- {
344
+ r = {
334
345
  :agg_proc => aggregation_proc(vals[0]),
335
346
  :value_proc => value_proc(vals[1])
336
347
  }.merge(vals[2] || {})
348
+
349
+ if AGG_FUNC_DEFAULTS.has_key?(vals[0])
350
+ r[:default] = AGG_FUNC_DEFAULTS[vals[0]]
351
+ end
352
+
353
+ r
337
354
  end
338
355
  end
data/lib/model_graph.rb CHANGED
@@ -114,6 +114,18 @@ module Mochigome
114
114
  @assoc_graph.add_edge(*edge)
115
115
  @edge_conditions[edge] = model.assoc_condition(name)
116
116
  end
117
+
118
+ if model.acts_as_mochigome_focus?
119
+ model.mochigome_focus_settings.options[:custom_assocs].each do |t,e|
120
+ cond = e.call(model.arel_table, t.arel_table)
121
+ [[model, t], [t, model]]. each do |edge|
122
+ @assoc_graph.add_edge(*edge)
123
+ # This deliberately allows custom assocs to overwrite normal ones
124
+ @edge_conditions[edge] = cond
125
+ end
126
+ added_models << t unless added_models.include?(t)
127
+ end
128
+ end
117
129
  end
118
130
 
119
131
  added_models.each do |model|
@@ -0,0 +1,7 @@
1
+ class Widget < ActiveRecord::Base
2
+ acts_as_mochigome_focus do |f|
3
+ f.name lambda {|r| "Widget #{r.number}"}
4
+ end
5
+
6
+ validates_presence_of :number
7
+ end
@@ -0,0 +1,12 @@
1
+ class WidgetDivisor < ActiveRecord::Base
2
+ acts_as_mochigome_focus do |f|
3
+ f.name lambda {|r| "Divisor #{r.divisor}"}
4
+ f.custom_association Widget, lambda {|src_tbl,tgt_tbl|
5
+ # Argh, arel doesn't provide easy access to the modulus operator
6
+ ((tgt_tbl[:number]/src_tbl[:divisor])*src_tbl[:divisor]).
7
+ eq(tgt_tbl[:number])
8
+ }
9
+ end
10
+
11
+ validates_presence_of :divisor
12
+ end
@@ -51,6 +51,14 @@ class CreateTables < ActiveRecord::Migration
51
51
  t.string :foo
52
52
  t.string :bar
53
53
  end
54
+
55
+ # These models are for testing custom associations
56
+ create_table :widgets do |t|
57
+ t.integer :number
58
+ end
59
+ create_table :widget_divisors do |t|
60
+ t.integer :divisor
61
+ end
54
62
  end
55
63
 
56
64
  def self.down
@@ -38,6 +38,14 @@ describe Mochigome::Query do
38
38
  ].each do |sp, n|
39
39
  n.times{create(:sale, :store_product => sp)}
40
40
  end
41
+
42
+ (1..5).each do |div_num|
43
+ WidgetDivisor.create(:divisor => div_num)
44
+ end
45
+
46
+ (1..25).each do |num|
47
+ Widget.create(:number => num)
48
+ end
41
49
  end
42
50
 
43
51
  after do
@@ -47,6 +55,8 @@ describe Mochigome::Query do
47
55
  Store.delete_all
48
56
  StoreProduct.delete_all
49
57
  Sale.delete_all
58
+ WidgetDivisor.delete_all
59
+ Widget.delete_all
50
60
  end
51
61
 
52
62
  # Convenience functions to check DataNode output validity
@@ -544,4 +554,37 @@ describe Mochigome::Query do
544
554
  assert_equal 0, (dn/0)['Gross']
545
555
  assert_equal 0, (dn/0/0)['Gross']
546
556
  end
557
+
558
+ it "assumes 0 as a default value for appropriate simple aggregations" do
559
+ Sale.destroy_all
560
+ q = Mochigome::Query.new(
561
+ [Store, Product],
562
+ :aggregate_sources => [[Product, Sale]]
563
+ )
564
+ dn = q.run
565
+ assert_equal 3, dn.children.size
566
+ assert_equal 0, dn['Sales count']
567
+ assert_equal 0, (dn/0)['Sales count']
568
+ assert_equal 0, (dn/0/0)['Sales count']
569
+ end
570
+
571
+ it "can use custom associations to link records" do
572
+ q = Mochigome::Query.new([WidgetDivisor, Widget])
573
+ dn = q.run
574
+ assert_equal "Divisor 1", (dn/0).name
575
+ assert_equal 25, (dn/0).children.size
576
+ assert_equal "Divisor 2", (dn/1).name
577
+ assert_equal 12, (dn/1).children.size
578
+ assert_equal "Divisor 5", (dn/4).name
579
+ assert_equal 5, (dn/4).children.size
580
+ end
581
+
582
+ it "can follow custom associations in reverse" do
583
+ q = Mochigome::Query.new([Widget, WidgetDivisor])
584
+ dn = q.run
585
+ assert_equal "Widget 1", (dn/0).name
586
+ assert_equal 1, (dn/0).children.size
587
+ assert_equal "Widget 6", (dn/5).name
588
+ assert_equal 3, (dn/5).children.size
589
+ end
547
590
  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: 21
4
+ hash: 11
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 7
10
- version: 0.1.7
9
+ - 8
10
+ version: 0.1.8
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-02 00:00:00 Z
18
+ date: 2012-05-07 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  version_requirements: &id001 !ruby/object:Gem::Requirement
@@ -124,6 +124,8 @@ files:
124
124
  - test/app_root/app/models/sale.rb
125
125
  - test/app_root/app/models/store.rb
126
126
  - test/app_root/app/models/store_product.rb
127
+ - test/app_root/app/models/widget.rb
128
+ - test/app_root/app/models/widget_divisor.rb
127
129
  - test/app_root/app/transforms/report.fo.via-html.xslt.haml
128
130
  - test/app_root/app/transforms/report.html.xslt.haml
129
131
  - test/app_root/app/views/layouts/application.html.haml