cubicle 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,10 @@
1
+ ==0.1.5
2
+ * Added duration_since (aliased as elapsed, age_since) to calculate the time elapsed since any
3
+ given timestamp and the current execution time of the query.
4
+
5
+ == 0.1.4
6
+ * Cached aggregations were being stored on disk, but not properly utilized. This is now fixed.
7
+
1
8
  == 0.1.3
2
9
  * Formalized flat (Cubicle::Data::Table) and hierarchical (Cubicle::Data::Hierarchy) data results from cubicle queries,
3
10
  and added client side support for rolling up measure values in hierarchical data so that no matter how a given
data/cubicle.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{cubicle}
8
- s.version = "0.1.4"
8
+ s.version = "0.1.5"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Nathan Stults"]
12
- s.date = %q{2010-03-25}
12
+ s.date = %q{2010-03-29}
13
13
  s.description = %q{Cubicle provides a dsl and aggregation caching framework for automating the generation, execution and caching of map reduce queries when using MongoDB in Ruby. Cubicle also includes a MongoMapper plugin for quickly performing ad-hoc, multi-level group-by queries against a MongoMapper model.}
14
14
  s.email = %q{hereiam@sonic.net}
15
15
  s.extra_rdoc_files = [
@@ -1,108 +1,117 @@
1
- module Cubicle
2
- module Aggregation
3
- module Dsl
4
-
5
- def source_collection_name(collection_name = nil)
6
- return @source_collection = collection_name if collection_name
7
- @source_collection ||= name.chomp("Cubicle").chomp("Cube").chomp("Aggregation").underscore.pluralize
8
- end
9
- alias source_collection_name= source_collection_name
10
-
11
- def target_collection_name(collection_name = nil)
12
- return nil if transient?
13
- return @target_name = collection_name if collection_name
14
- @target_name ||= "#{name.blank? ? source_collection_name : name.underscore.pluralize}_cubicle"
15
- end
16
- alias target_collection_name= target_collection_name
17
-
18
- def dimension(*args)
19
- dimensions << Cubicle::Dimension.new(*args)
20
- dimensions[-1]
21
- end
22
-
23
- def dimensions(*args)
24
- return (@dimensions ||= Cubicle::MemberList.new) if args.length < 1
25
- args = args[0] if args.length == 1 && args[0].is_a?(Array)
26
- args.each {|dim| dimension dim }
27
- @dimensions
28
- end
29
-
30
- def measure(*args)
31
- measures << Measure.new(*args)
32
- measures[-1]
33
- end
34
-
35
- def measures(*args)
36
- return (@measures ||= Cubicle::MemberList.new) if args.length < 1
37
- args = args[0] if args.length == 1 && args[0].is_a?(Array)
38
- args.each {|m| measure m}
39
- @measures
40
- end
41
-
42
- def count(*args)
43
- options = args.extract_options!
44
- options[:aggregation_method] = :count
45
- measure(*(args << options))
46
- end
47
-
48
- def average(*args)
49
- options = args.extract_options!
50
- options[:aggregation_method] = :average
51
- measure(*(args << options))
52
- #Averaged fields need a count of non-null values to properly calculate the average
53
- args[0] = "#{args[0]}_count".to_sym
54
- count *args
55
- end
56
- alias avg average
57
-
58
- def sum(*args)
59
- options = args.extract_options!
60
- options[:aggregation_method] = :sum
61
- measure(*(args << options))
62
- end
63
-
64
- def duration(*args)
65
- options = args.extract_options!
66
- options[:in] ||= durations_in
67
- args << options
68
- measures << (dur = Duration.new(*args))
69
- count("#{dur.name}_count".to_sym, :expression=>dur.expression) if dur.aggregation_method == :average
70
- end
71
-
72
- def average_duration(*args)
73
- duration(*args)
74
- end
75
- alias avg_duration average_duration
76
-
77
- def total_duration(*args)
78
- options = args.extract_options!
79
- options[:aggregation_method] = :sum
80
- duration(*(args<<options))
81
- end
82
-
83
- def durations_in(unit_of_time = nil)
84
- return (@duration_unit ||= :seconds) unless unit_of_time
85
- @duration_unit = unit_of_time.to_s.pluralize.to_sym
86
- end
87
- alias :duration_unit :durations_in
88
-
89
-
90
- def ratio(member_name, numerator, denominator)
91
- measures << Ratio.new(member_name, numerator, denominator)
92
- end
93
-
94
- def aggregation(*member_list)
95
- member_list = member_list[0] if member_list[0].is_a?(Array)
96
- aggregations << member_list
97
- end
98
-
99
- def time_dimension(*args)
100
- return (@time_dimension ||= nil) unless args.length > 0
101
- @time_dimension = dimension(*args)
102
- end
103
- alias time_dimension= time_dimension
104
- alias date time_dimension
105
- alias time time_dimension
106
- end
107
- end
1
+ module Cubicle
2
+ module Aggregation
3
+ module Dsl
4
+
5
+ def source_collection_name(collection_name = nil)
6
+ return @source_collection = collection_name if collection_name
7
+ @source_collection ||= name.chomp("Cubicle").chomp("Cube").chomp("Aggregation").underscore.pluralize
8
+ end
9
+ alias source_collection_name= source_collection_name
10
+
11
+ def target_collection_name(collection_name = nil)
12
+ return nil if transient?
13
+ return @target_name = collection_name if collection_name
14
+ @target_name ||= "#{name.blank? ? source_collection_name : name.underscore.pluralize}_cubicle"
15
+ end
16
+ alias target_collection_name= target_collection_name
17
+
18
+ def dimension(*args)
19
+ dimensions << Cubicle::Dimension.new(*args)
20
+ dimensions[-1]
21
+ end
22
+
23
+ def dimensions(*args)
24
+ return (@dimensions ||= Cubicle::MemberList.new) if args.length < 1
25
+ args = args[0] if args.length == 1 && args[0].is_a?(Array)
26
+ args.each {|dim| dimension dim }
27
+ @dimensions
28
+ end
29
+
30
+ def measure(*args)
31
+ measures << Measure.new(*args)
32
+ measures[-1]
33
+ end
34
+
35
+ def measures(*args)
36
+ return (@measures ||= Cubicle::MemberList.new) if args.length < 1
37
+ args = args[0] if args.length == 1 && args[0].is_a?(Array)
38
+ args.each {|m| measure m}
39
+ @measures
40
+ end
41
+
42
+ def count(*args)
43
+ options = args.extract_options!
44
+ options[:aggregation_method] = :count
45
+ measure(*(args << options))
46
+ end
47
+
48
+ def average(*args)
49
+ options = args.extract_options!
50
+ options[:aggregation_method] = :average
51
+ measure(*(args << options))
52
+ #Averaged fields need a count of non-null values to properly calculate the average
53
+ args[0] = "#{args[0]}_count".to_sym
54
+ count *args
55
+ end
56
+ alias avg average
57
+
58
+ def sum(*args)
59
+ options = args.extract_options!
60
+ options[:aggregation_method] = :sum
61
+ measure(*(args << options))
62
+ end
63
+
64
+ def duration(*args)
65
+ options = args.extract_options!
66
+ options[:in] ||= durations_in
67
+ args << options
68
+ measures << (dur = Duration.new(*args))
69
+ count("#{dur.name}_count".to_sym, :expression=>dur.expression) if dur.aggregation_method == :average
70
+ end
71
+
72
+ def average_duration(*args)
73
+ duration(*args)
74
+ end
75
+ alias avg_duration average_duration
76
+
77
+ def total_duration(*args)
78
+ options = args.extract_options!
79
+ options[:aggregation_method] = :sum
80
+ duration(*(args<<options))
81
+ end
82
+
83
+ def duration_since(*args)
84
+ options = args.extract_options!
85
+ ms1 = args.length > 1 ? args.delete_at(1) : args.shift
86
+ options[ms1] = :now
87
+ duration(*(args<<options))
88
+ end
89
+ alias age_since duration_since
90
+ alias elapsed duration_since
91
+
92
+ def durations_in(unit_of_time = nil)
93
+ return (@duration_unit ||= :seconds) unless unit_of_time
94
+ @duration_unit = unit_of_time.to_s.pluralize.to_sym
95
+ end
96
+ alias :duration_unit :durations_in
97
+
98
+
99
+ def ratio(member_name, numerator, denominator)
100
+ measures << Ratio.new(member_name, numerator, denominator)
101
+ end
102
+
103
+ def aggregation(*member_list)
104
+ member_list = member_list[0] if member_list[0].is_a?(Array)
105
+ aggregations << member_list
106
+ end
107
+
108
+ def time_dimension(*args)
109
+ return (@time_dimension ||= nil) unless args.length > 0
110
+ @time_dimension = dimension(*args)
111
+ end
112
+ alias time_dimension= time_dimension
113
+ alias date time_dimension
114
+ alias time time_dimension
115
+ end
116
+ end
108
117
  end
@@ -23,7 +23,7 @@ module Cubicle
23
23
  cond = " && (#{self.condition})" unless self.condition.blank?
24
24
  #prefix these names for the expression
25
25
  prefix = "#{self.timestamp_prefix}#{self.timestamp_prefix.blank? ? '' : '.'}"
26
- ms1,ms2 = [self.begin_milestone,self.end_milestone].map{|ms|"this.#{prefix}#{ms}"}
26
+ ms1,ms2 = [self.begin_milestone,self.end_milestone].map{|ms|ms.to_s=='now' ? "new Date(#{Time.now.to_i*1000})" : "this.#{prefix}#{ms}"}
27
27
  @expression = "(#{ms1} && #{ms2}#{cond}) ? (#{ms2}-#{ms1})/#{denominator} : null"
28
28
  end
29
29
 
@@ -1,3 +1,3 @@
1
1
  module Cubicle
2
- VERSION = '0.1.4'
2
+ VERSION = '0.1.5'
3
3
  end
@@ -1,47 +1,69 @@
1
- require "test_helper"
2
-
3
- class DurationTest < ActiveSupport::TestCase
4
- context "Querying a cubicle with durations" do
5
- setup do
6
- #record 1, ms1 = 1/1/2000, ms2 = 1/2/2000, ms3=1/4/2000
7
- #record 2, ms1 = 1/1/2000, ms2 = 1/3/2000, ms3=1/5/2000
8
- Defect.create_duration_test_data
9
- end
10
- should "correctly calculate durations for each activity" do
11
- results = DefectCubicle.query do
12
- select :all
13
- by :operator
14
- end
15
- a1 = results["a"][0]
16
- a2 = results["b"][0]
17
-
18
- assert_equal 1 * 60 * 60 * 24, a1["ms1_to_ms2_average"]
19
- assert_equal 2 * 60 * 60 * 24, a1["ms2_to_ms3_sum"]
20
- assert_equal 3, a1["total_duration"]
21
-
22
- assert_equal 2 * 60 * 60 * 24, a2["ms1_to_ms2_average"]
23
- assert_equal 2 * 60 * 60 * 24, a2["ms2_to_ms3_sum"]
24
- assert_equal 4, a2["total_duration"]
25
- end
26
- should "correctly aggregate durations" do
27
- results = DefectCubicle.query do
28
- select :all_measures, :product
29
- end
30
- results = results[0]
31
-
32
- assert_equal 1.5 * 60 * 60 * 24, results["ms1_to_ms2_average"]
33
- assert_equal 4 * 60 * 60 * 24, results["ms2_to_ms3_sum"]
34
- assert_equal 3.5, results["total_duration"]
35
-
36
- end
37
- should "respect the condition argument" do
38
- results = DefectCubicle.query do
39
- select :all_measures, :product
40
- end
41
- results = results[0]
42
-
43
- assert_equal 3, results["conditional_duration"]
44
- end
45
- end
46
-
1
+ require "test_helper"
2
+
3
+ class DurationTest < ActiveSupport::TestCase
4
+ context "Querying a cubicle with durations" do
5
+ setup do
6
+ #record 1, ms1 = 1/1/2000, ms2 = 1/2/2000, ms3=1/4/2000
7
+ #record 2, ms1 = 1/1/2000, ms2 = 1/3/2000, ms3=1/5/2000
8
+ Defect.create_duration_test_data
9
+ end
10
+ should "correctly calculate durations for each activity" do
11
+ results = DefectCubicle.query do
12
+ select :all
13
+ by :operator
14
+ end
15
+ a1 = results["a"][0]
16
+ a2 = results["b"][0]
17
+
18
+ assert_equal 1 * 60 * 60 * 24, a1["ms1_to_ms2_average"]
19
+ assert_equal 2 * 60 * 60 * 24, a1["ms2_to_ms3_sum"]
20
+ assert_equal 3, a1["total_duration"]
21
+
22
+ assert_equal 2 * 60 * 60 * 24, a2["ms1_to_ms2_average"]
23
+ assert_equal 2 * 60 * 60 * 24, a2["ms2_to_ms3_sum"]
24
+ assert_equal 4, a2["total_duration"]
25
+ end
26
+ should "correctly aggregate durations" do
27
+ results = DefectCubicle.query do
28
+ select :all_measures, :product
29
+ end
30
+ results = results[0]
31
+
32
+ assert_equal 1.5 * 60 * 60 * 24, results["ms1_to_ms2_average"]
33
+ assert_equal 4 * 60 * 60 * 24, results["ms2_to_ms3_sum"]
34
+ assert_equal 3.5, results["total_duration"]
35
+
36
+ end
37
+ should "respect the condition argument" do
38
+ results = DefectCubicle.query do
39
+ select :all_measures, :product
40
+ end
41
+ results = results[0]
42
+
43
+ assert_equal 3, results["conditional_duration"]
44
+ end
45
+ should "calculate duration_since via elapsed" do
46
+ Time.now = "1/10/2000"
47
+ results = DefectCubicle.query do
48
+ select :all_measures, :product
49
+ end
50
+ puts results.inspect
51
+ results = results[0]
52
+
53
+ assert_equal((6+5)/2.0, results["ms3_to_now_average"])
54
+
55
+ end
56
+ should "calculate named duration_since via age_since" do
57
+ Time.now = "1/10/2000"
58
+ results = DefectCubicle.query do
59
+ select :all_measures, :product
60
+ end
61
+ puts results.inspect
62
+ results = results[0]
63
+
64
+ assert_equal((6+5)/2.0, results["avg_time_since_ms3"])
65
+
66
+ end
67
+ end
68
+
47
69
  end
@@ -1,32 +1,34 @@
1
- class DefectCubicle
2
- extend Cubicle::Aggregation
3
-
4
- date :manufacture_date, :field_name=>'manufacture_date', :alias=>:date
5
- dimension :month, :expression=>'this.manufacture_date.substring(0,7)'
6
- dimension :year, :expression=>'this.manufacture_date.substring(0,4)'
7
-
8
- dimension :manufacture_time
9
-
10
- dimension :product, :field_name=>'product.name'
11
- dimension :region, :field_name=>'plant.address.region'
12
-
13
- dimensions :operator, :outcome
14
-
15
- count :total_defects, :field_name=>'defect_id'
16
- count :preventable_defects, :expression=>'this.root_cause != "act_of_god"'
17
- sum :total_cost, :field_name=>'cost'
18
- avg :avg_cost, :field_name=>'cost'
19
-
20
- #calculated fields
21
- ratio :preventable_pct, :preventable_defects, :total_defects
22
-
23
- #durations
24
- average_duration :ms1 => :ms2
25
- total_duration :ms2 => :ms3
26
- duration :total_duration, :ms1 => :ms3, :in=>:days
27
- duration :conditional_duration, :ms1 => :ms3, :in=>:days, :condition=>"this.defect_id != 2"
28
-
29
- #pre-cached aggregations
30
- aggregation :month, :year, :product
31
- aggregation :month, :region
1
+ class DefectCubicle
2
+ extend Cubicle::Aggregation
3
+
4
+ date :manufacture_date, :field_name=>'manufacture_date', :alias=>:date
5
+ dimension :month, :expression=>'this.manufacture_date.substring(0,7)'
6
+ dimension :year, :expression=>'this.manufacture_date.substring(0,4)'
7
+
8
+ dimension :manufacture_time
9
+
10
+ dimension :product, :field_name=>'product.name'
11
+ dimension :region, :field_name=>'plant.address.region'
12
+
13
+ dimensions :operator, :outcome
14
+
15
+ count :total_defects, :field_name=>'defect_id'
16
+ count :preventable_defects, :expression=>'this.root_cause != "act_of_god"'
17
+ sum :total_cost, :field_name=>'cost'
18
+ avg :avg_cost, :field_name=>'cost'
19
+
20
+ #calculated fields
21
+ ratio :preventable_pct, :preventable_defects, :total_defects
22
+
23
+ #durations
24
+ average_duration :ms1 => :ms2
25
+ total_duration :ms2 => :ms3
26
+ duration :total_duration, :ms1 => :ms3, :in=>:days
27
+ duration :conditional_duration, :ms1 => :ms3, :in=>:days, :condition=>"this.defect_id != 2"
28
+ elapsed :ms3, :in=>:days
29
+ age_since :avg_time_since_ms3, :ms3, :in=>:days
30
+
31
+ #pre-cached aggregations
32
+ aggregation :month, :year, :product
33
+ aggregation :month, :region
32
34
  end