active_record_calculator 0.0.1
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/.gitignore +4 -0
- data/Gemfile +4 -0
- data/Rakefile +1 -0
- data/active_record_calculator.gemspec +31 -0
- data/lib/active_record_calculator/calculator_proxy.rb +71 -0
- data/lib/active_record_calculator/operation.rb +36 -0
- data/lib/active_record_calculator/version.rb +3 -0
- data/lib/active_record_calculator.rb +21 -0
- metadata +100 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "active_record_calculator/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "active_record_calculator"
|
7
|
+
s.version = ActiveRecordCalculator::VERSION
|
8
|
+
s.authors = ["Grady Griffin"]
|
9
|
+
s.email = ["gradyg@izea.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{ActiveRecord Calculations done faster}
|
12
|
+
s.description = %q{active_record_calculator does groupable aggregate functions in one sql call for better performance}
|
13
|
+
|
14
|
+
s.rubyforge_project = "active_record_calculator"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
# s.add_runtime_dependency "rest-client"
|
24
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
25
|
+
s.add_runtime_dependency('activerecord')
|
26
|
+
s.add_development_dependency("rspec")
|
27
|
+
else
|
28
|
+
s.add_dependency('activerecord')
|
29
|
+
s.add_development_dependency("rspec")
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module ActiveRecordCalculator
|
2
|
+
class CalculatorProxy
|
3
|
+
def initialize(klass, finder_options = {})
|
4
|
+
@klass = klass
|
5
|
+
@operations = []
|
6
|
+
@columns = []
|
7
|
+
@finder_options = finder_options.except(:order, :select)
|
8
|
+
end
|
9
|
+
|
10
|
+
def col(column_name, as = nil)
|
11
|
+
add_column(column_name, as)
|
12
|
+
end
|
13
|
+
alias :column :col
|
14
|
+
|
15
|
+
def cnt(column_name, as, options = {})
|
16
|
+
add_operation(:count, column_name, as, options)
|
17
|
+
end
|
18
|
+
alias :count :cnt
|
19
|
+
|
20
|
+
def sum(column_name, as, conditions = {})
|
21
|
+
add_operation(:sum, column_name, as, options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def avg(column_name, as, conditions = {})
|
25
|
+
add_operation(:avg, column_name, as, options)
|
26
|
+
end
|
27
|
+
alias :average :avg
|
28
|
+
|
29
|
+
def max(column_name, as, conditions = {})
|
30
|
+
add_operation(:max, column_name, as, options)
|
31
|
+
end
|
32
|
+
alias :maximum :max
|
33
|
+
|
34
|
+
def min(column_name, as, conditions = {})
|
35
|
+
add_operation(:min, column_name, as, options)
|
36
|
+
end
|
37
|
+
alias :minimum :min
|
38
|
+
|
39
|
+
def calculate
|
40
|
+
sql = @klass.send(:construct_finder_sql, @finder_options)
|
41
|
+
sql.gsub!(/^SELECT \*/, select)
|
42
|
+
@operations = []
|
43
|
+
@klass.find_by_sql(sql)
|
44
|
+
end
|
45
|
+
|
46
|
+
def set_finder_options(finder_options = {})
|
47
|
+
@finder_options = finder_options.except(:select)
|
48
|
+
end
|
49
|
+
|
50
|
+
def select
|
51
|
+
s = ["SELECT\n"]
|
52
|
+
s += @columns.join(', ') + "\n"
|
53
|
+
s += @operations.collect {|op| op.build_select(@klass)}.join(",\n")
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def add_column(column_name, as)
|
59
|
+
if as
|
60
|
+
@columns << column_name
|
61
|
+
else
|
62
|
+
@columns << "#{column_name} AS #{as}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def add_operation(op, column_name, as, options)
|
67
|
+
options = {:conditions => options} if options.is_a?(String)
|
68
|
+
@operations << Operation.new(op, column_name, as, options)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module ActiveRecordCalculator
|
2
|
+
class Operation
|
3
|
+
|
4
|
+
def initialize(op, column, as, options)
|
5
|
+
@op = op
|
6
|
+
@column = column
|
7
|
+
@as = as
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def build_select(klass)
|
12
|
+
mock = klass.send(:construct_calculation_sql, @op, @column, @options)
|
13
|
+
all, sel, cond = if mock =~ /\s+WHERE\s+/
|
14
|
+
mock.match(/^SELECT\s+(.*)\s+AS.*\s+WHERE\s?(.*)/).to_a
|
15
|
+
else
|
16
|
+
mock.match(/^SELECT\s+(.*)\s+AS/).to_a
|
17
|
+
end
|
18
|
+
return "#{sel} AS #{@as}" unless cond
|
19
|
+
i = sel.index('(')
|
20
|
+
start = sel[0..i]
|
21
|
+
mid = "CASE #{cond} WHEN 1 THEN #{sel[i+1..-2]} ELSE #{default} END"
|
22
|
+
fin = ") AS #{@as}"
|
23
|
+
"#{start}#{mid}#{fin}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def inspect
|
27
|
+
"#{@as} => #{@op}"
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def default
|
33
|
+
@op == :sum ? 0 : 'NULL'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "active_record_calculator/version"
|
2
|
+
|
3
|
+
module ActiveRecordCalculator
|
4
|
+
def self.included(base)
|
5
|
+
base.extend ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def calculate_many(options = {}, &blk)
|
10
|
+
calculator = CalculatorProxy.new(self, options)
|
11
|
+
yield calculator
|
12
|
+
calculator.calculate
|
13
|
+
end
|
14
|
+
|
15
|
+
def calculator
|
16
|
+
CalculatorProxy.new(self)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
::ActiveRecord::Base.send :include, ActiveRecordCalculator
|
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: active_record_calculator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Grady Griffin
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-01-27 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: activerecord
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
version: "0"
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: rspec
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
hash: 3
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
version: "0"
|
46
|
+
type: :development
|
47
|
+
version_requirements: *id002
|
48
|
+
description: active_record_calculator does groupable aggregate functions in one sql call for better performance
|
49
|
+
email:
|
50
|
+
- gradyg@izea.com
|
51
|
+
executables: []
|
52
|
+
|
53
|
+
extensions: []
|
54
|
+
|
55
|
+
extra_rdoc_files: []
|
56
|
+
|
57
|
+
files:
|
58
|
+
- .gitignore
|
59
|
+
- Gemfile
|
60
|
+
- Rakefile
|
61
|
+
- active_record_calculator.gemspec
|
62
|
+
- lib/active_record_calculator.rb
|
63
|
+
- lib/active_record_calculator/calculator_proxy.rb
|
64
|
+
- lib/active_record_calculator/operation.rb
|
65
|
+
- lib/active_record_calculator/version.rb
|
66
|
+
homepage: ""
|
67
|
+
licenses: []
|
68
|
+
|
69
|
+
post_install_message:
|
70
|
+
rdoc_options: []
|
71
|
+
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
hash: 3
|
80
|
+
segments:
|
81
|
+
- 0
|
82
|
+
version: "0"
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
hash: 3
|
89
|
+
segments:
|
90
|
+
- 0
|
91
|
+
version: "0"
|
92
|
+
requirements: []
|
93
|
+
|
94
|
+
rubyforge_project: active_record_calculator
|
95
|
+
rubygems_version: 1.8.15
|
96
|
+
signing_key:
|
97
|
+
specification_version: 3
|
98
|
+
summary: ActiveRecord Calculations done faster
|
99
|
+
test_files: []
|
100
|
+
|