mochigome 0.1.14 → 0.1.15

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/TODO CHANGED
@@ -5,5 +5,6 @@
5
5
  - Named subsets of different fields and agg fields on a single model
6
6
  - Some kind of single-page preview on the edit screen would be cool. Maybe use FOP with fake data and the PNG output option?
7
7
  - Automatically set default to 0 on sum and count aggregation
8
- - Treat through-associations as hints for preferred paths
9
8
  - Better handling of nil in subgroup fields
9
+ - Handle has_and_belongs_to_many correctly
10
+ - Deal with ignore_assoc properly in both directions and when we see :through assocs
data/lib/mochigome_ver.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Mochigome
2
- VERSION = "0.1.14"
2
+ VERSION = "0.1.15"
3
3
  end
@@ -6,9 +6,9 @@ module Mochigome
6
6
  base.write_inheritable_attribute :mochigome_focus_settings, nil
7
7
  base.class_inheritable_reader :mochigome_focus_settings
8
8
 
9
- # TODO: Use an ordered hash for this
10
- base.write_inheritable_attribute :mochigome_aggregation_settings, nil
11
- base.class_inheritable_reader :mochigome_aggregation_settings
9
+ # FIXME: Unclear on how this interacts with inheritance...
10
+ base.write_inheritable_attribute :mochigome_aggregation_settings_sets, {}
11
+ base.class_inheritable_reader :mochigome_aggregation_settings_sets
12
12
  end
13
13
 
14
14
  module ClassMethods
@@ -45,13 +45,18 @@ module Mochigome
45
45
 
46
46
  # TODO: Split out aggregation stuff into its own module
47
47
 
48
- def has_mochigome_aggregations
49
- if self.try(:mochigome_aggregation_settings).try(:model) == self
50
- raise Mochigome::ModelSetupError.new("Already aggregation settings for #{self.name}")
48
+ def has_mochigome_aggregations(name = :default)
49
+ name = name.to_sym
50
+ if mochigome_aggregation_settings_sets[name].try(:model) == self
51
+ raise Mochigome::ModelSetupError.new("Can't overwrite aggregation settings for #{self.name}")
51
52
  end
52
53
  settings = AggregationSettings.new(self)
53
54
  yield settings if block_given?
54
- write_inheritable_attribute :mochigome_aggregation_settings, settings
55
+ mochigome_aggregation_settings_sets[name] = settings
56
+ end
57
+
58
+ def mochigome_aggregation_settings(name = :default)
59
+ mochigome_aggregation_settings_sets[name]
55
60
  end
56
61
 
57
62
  def assoc_condition(name)
data/lib/query.rb CHANGED
@@ -17,9 +17,14 @@ module Mochigome
17
17
 
18
18
  @aggregate_rels = ActiveSupport::OrderedHash.new
19
19
  aggregate_sources.each do |a|
20
- focus_model, data_model = case a
21
- when Array then [a.first, a.second]
22
- else [a, a]
20
+ focus_model, data_model, agg_setting_name = nil, nil, nil
21
+ if a.is_a?(Array) then
22
+ focus_model = a.select{|e| e.is_a?(Class)}.first
23
+ data_model = a.select{|e| e.is_a?(Class)}.last
24
+ agg_setting_name = a.select{|e| e.is_a?(Symbol)}.first || :default
25
+ else
26
+ focus_model = data_model = a
27
+ agg_setting_name = :default
23
28
  end
24
29
 
25
30
  agg_rel = Relation.new(@layer_types)
@@ -28,15 +33,21 @@ module Mochigome
28
33
 
29
34
  key_cols = @ids_rel.spine_layers.map{|m| m.arel_primary_key}
30
35
 
31
- agg_fields = data_model.mochigome_aggregation_settings.
36
+ agg_fields = data_model.
37
+ mochigome_aggregation_settings(agg_setting_name).
32
38
  options[:fields].reject{|a| a[:in_ruby]}
33
39
  agg_fields.each_with_index do |a, i|
34
40
  d_expr = a[:value_proc].call(data_model.arel_table)
35
41
  agg_rel.select_expr(d_expr.as("d%03u" % i))
36
42
  end
37
43
 
38
- @aggregate_rels[focus_model] ||= ActiveSupport::OrderedHash.new
39
- @aggregate_rels[focus_model][data_model] = (0..key_cols.length).map{|n|
44
+ agg_rel_key = {
45
+ :focus_model => focus_model,
46
+ :data_model => data_model,
47
+ :agg_setting_name => agg_setting_name
48
+ }
49
+
50
+ @aggregate_rels[agg_rel_key] = (0..key_cols.length).map{|n|
40
51
  lambda {|cond|
41
52
  data_rel = agg_rel.clone
42
53
  data_rel.apply_condition(cond)
@@ -134,55 +145,53 @@ module Mochigome
134
145
  end
135
146
 
136
147
  def load_aggregate_data(node, cond)
137
- @aggregate_rels.each do |focus_model, data_model_rels|
138
- # TODO Actually get the key types found in init for this aggregation
139
- super_types = @layer_types.take_while{|m| m != focus_model}
140
- data_model_rels.each do |data_model, rel_funcs|
141
- aggs = data_model.mochigome_aggregation_settings.options[:fields]
142
- aggs_count = aggs.reject{|a| a[:in_ruby]}.size
143
- rel_funcs.each do |rel_func|
144
- q = rel_func.call(cond)
145
- data_tree = {}
146
- @layer_types.first.connection.select_all(q.to_sql).each do |row|
147
- group_values = row.keys.select{|k| k.start_with?("g")}.sort.map{|k| row[k]}
148
- data_values = row.keys.select{|k| k.start_with?("d")}.sort.map{|k| row[k]}
149
- if group_values.empty?
150
- data_tree = data_values
151
- else
152
- c = data_tree
153
- group_values.take(group_values.size-1).each do |group_id|
154
- c = (c[group_id] ||= {})
155
- end
156
- c[group_values.last] = data_values
148
+ @aggregate_rels.each do |key, rel_funcs|
149
+ data_model = key[:data_model]
150
+ agg_name = key[:agg_setting_name]
151
+ agg_settings = data_model.mochigome_aggregation_settings(agg_name)
152
+
153
+ rel_funcs.each do |rel_func|
154
+ q = rel_func.call(cond)
155
+ data_tree = {}
156
+ @layer_types.first.connection.select_all(q.to_sql).each do |row|
157
+ group_values = row.keys.select{|k| k.start_with?("g")}.sort.map{|k| row[k]}
158
+ data_values = row.keys.select{|k| k.start_with?("d")}.sort.map{|k| row[k]}
159
+ if group_values.empty?
160
+ data_tree = data_values
161
+ else
162
+ c = data_tree
163
+ group_values.take(group_values.size-1).each do |group_id|
164
+ c = (c[group_id] ||= {})
157
165
  end
166
+ c[group_values.last] = data_values
158
167
  end
159
- insert_aggregate_data_fields(node, data_tree, data_model)
160
168
  end
169
+ insert_aggregate_data_fields(node, data_tree, agg_settings)
161
170
  end
162
171
  end
163
172
  end
164
173
 
165
- def insert_aggregate_data_fields(node, table, data_model)
174
+ def insert_aggregate_data_fields(node, table, agg_settings)
166
175
  if table.is_a? Array
167
- fields = data_model.mochigome_aggregation_settings.options[:fields]
176
+ fields = agg_settings.options[:fields]
168
177
  # Pre-fill the node with all fields in the right order
169
- fields.each{|agg| node[agg[:name]] = agg[:default] unless agg[:hidden] }
170
- agg_row = {} # Hold regular aggs here to be used in ruby-based aggs
171
- fields.reject{|agg| agg[:in_ruby]}.zip(table).each do |agg, v|
172
- v ||= agg[:default]
173
- agg_row[agg[:name]] = v
174
- node[agg[:name]] = v unless agg[:hidden]
178
+ fields.each{|fld| node[fld[:name]] = fld[:default] unless fld[:hidden] }
179
+ agg_row = {} # Hold regular results here to be used in ruby-based fields
180
+ fields.reject{|fld| fld[:in_ruby]}.zip(table).each do |fld, v|
181
+ v ||= fld[:default]
182
+ agg_row[fld[:name]] = v
183
+ node[fld[:name]] = v unless fld[:hidden]
175
184
  end
176
- fields.select{|agg| agg[:in_ruby]}.each do |agg|
177
- node[agg[:name]] = agg[:ruby_proc].call(agg_row)
185
+ fields.select{|fld| fld[:in_ruby]}.each do |fld|
186
+ node[fld[:name]] = fld[:ruby_proc].call(agg_row)
178
187
  end
179
188
  node.children.each do |c|
180
- insert_aggregate_data_fields(c, [], data_model)
189
+ insert_aggregate_data_fields(c, [], agg_settings)
181
190
  end
182
191
  else
183
192
  node.children.each do |c|
184
193
  subtable = table[c[:id]] || []
185
- insert_aggregate_data_fields(c, subtable, data_model)
194
+ insert_aggregate_data_fields(c, subtable, agg_settings)
186
195
  end
187
196
  end
188
197
  end
@@ -9,6 +9,7 @@ class Product < ActiveRecord::Base
9
9
  "Consonant"
10
10
  ).call(Product.arel_table)
11
11
  end
12
+
12
13
  has_mochigome_aggregations do |a|
13
14
  a.fields [
14
15
  :sum_price,
@@ -24,6 +25,10 @@ class Product < ActiveRecord::Base
24
25
  a.fields_in_ruby [ {"Count squared" => lambda{|row| row["Secret count"].try(:**, 2)}} ]
25
26
  end
26
27
 
28
+ has_mochigome_aggregations(:averaging) do |a|
29
+ a.fields [:average_price]
30
+ end
31
+
27
32
  belongs_to :category
28
33
  has_many :store_products
29
34
  has_many :stores, :through => :store_products
@@ -275,6 +275,15 @@ describe Mochigome::Query do
275
275
  assert_equal (2*@product_c.price).to_f.to_s, (data_node/1/0/0)['Gross'].to_f.to_s
276
276
  end
277
277
 
278
+ it "can use a named aggregate data setting" do
279
+ q = Mochigome::Query.new(
280
+ [Owner],
281
+ :aggregate_sources => [[Product, :averaging]]
282
+ )
283
+ data_node = q.run
284
+ assert_equal ((19.95*4 + 5)/5).to_f.to_s, data_node['Products average price'].to_f.to_s
285
+ end
286
+
278
287
  it "collects aggregate data in subgroups" do
279
288
  q = Mochigome::Query.new(
280
289
  [Mochigome::SubgroupModel.new(Owner, :last_name), Owner, Store, Product],
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: 7
4
+ hash: 5
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 14
10
- version: 0.1.14
9
+ - 15
10
+ version: 0.1.15
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-06-03 00:00:00 Z
18
+ date: 2012-06-04 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  version_requirements: &id001 !ruby/object:Gem::Requirement