active_median 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/Rakefile +7 -0
- data/active_median.gemspec +3 -0
- data/lib/active_median.rb +27 -37
- data/lib/active_median/version.rb +1 -1
- data/test/active_median_test.rb +34 -0
- data/test/test_helper.rb +15 -0
- metadata +38 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2b6d9c75498f9e09937bf9198f7b67249b2bf122
|
4
|
+
data.tar.gz: 49de0d0b1f1ba1e0509cf982ed97b3abebb19cf8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f93d25e49d3e9e1dbb2ba51cde3f54a8233ce9fae30710c30b76edc859b02b49eb9baa33034ecf6a97fd2569111903405fc63ffc323e2034965e81f29a6ad6f0
|
7
|
+
data.tar.gz: 589c9c118009bf1258aed61fcace805476549e9ca05504a0c4f21276d58e4cc97e960b4497ee3cd061d94d2a9f9d08029f114f698f55c7d5555fec6aae8290da
|
data/CHANGELOG.md
ADDED
data/Rakefile
CHANGED
data/active_median.gemspec
CHANGED
@@ -18,6 +18,9 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
+
spec.add_dependency "activerecord"
|
22
|
+
|
21
23
|
spec.add_development_dependency "bundler", "~> 1.3"
|
22
24
|
spec.add_development_dependency "rake"
|
25
|
+
spec.add_development_dependency "pg"
|
23
26
|
end
|
data/lib/active_median.rb
CHANGED
@@ -4,50 +4,40 @@ require "active_record"
|
|
4
4
|
module ActiveMedian
|
5
5
|
def self.create_function
|
6
6
|
# create median method
|
7
|
-
# http://
|
7
|
+
# http://wiki.postgresql.org/wiki/Aggregate_Median
|
8
8
|
ActiveRecord::Base.connection.execute <<-SQL
|
9
|
-
CREATE OR REPLACE FUNCTION
|
10
|
-
|
9
|
+
CREATE OR REPLACE FUNCTION median(anyarray)
|
10
|
+
RETURNS float8 AS
|
11
11
|
$$
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
12
|
+
WITH q AS
|
13
|
+
(
|
14
|
+
SELECT val
|
15
|
+
FROM unnest($1) val
|
16
|
+
WHERE VAL IS NOT NULL
|
17
|
+
ORDER BY 1
|
18
|
+
),
|
19
|
+
cnt AS
|
20
|
+
(
|
21
|
+
SELECT COUNT(*) AS c FROM q
|
22
|
+
)
|
23
|
+
SELECT AVG(val)::float8
|
24
|
+
FROM
|
25
|
+
(
|
26
|
+
SELECT val FROM q
|
27
|
+
LIMIT 2 - MOD((SELECT c FROM cnt), 2)
|
28
|
+
OFFSET GREATEST(CEIL((SELECT c FROM cnt) / 2.0) - 1,0)
|
29
|
+
) q2;
|
28
30
|
$$
|
29
|
-
|
31
|
+
LANGUAGE sql IMMUTABLE;
|
30
32
|
|
31
33
|
DROP AGGREGATE IF EXISTS median(numeric);
|
32
|
-
CREATE AGGREGATE median(numeric) (
|
33
|
-
SFUNC=array_append,
|
34
|
-
STYPE=numeric[],
|
35
|
-
FINALFUNC=array_median
|
36
|
-
);
|
37
|
-
SQL
|
38
|
-
ActiveRecord::Base.connection.execute <<-SQL
|
39
|
-
CREATE OR REPLACE FUNCTION array_median(double precision[])
|
40
|
-
RETURNS double precision AS
|
41
|
-
$$
|
42
|
-
SELECT array_median($1::numeric[])::double precision;
|
43
|
-
$$
|
44
|
-
LANGUAGE SQL;
|
45
|
-
|
46
34
|
DROP AGGREGATE IF EXISTS median(double precision);
|
47
|
-
|
35
|
+
DROP AGGREGATE IF EXISTS median(anyelement);
|
36
|
+
CREATE AGGREGATE median(anyelement) (
|
48
37
|
SFUNC=array_append,
|
49
|
-
STYPE=
|
50
|
-
FINALFUNC=
|
38
|
+
STYPE=anyarray,
|
39
|
+
FINALFUNC=median,
|
40
|
+
INITCOND='{}'
|
51
41
|
);
|
52
42
|
SQL
|
53
43
|
true
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class TestActiveMedian < Minitest::Test
|
4
|
+
|
5
|
+
def setup
|
6
|
+
ActiveMedian.create_function
|
7
|
+
User.delete_all
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_even
|
11
|
+
6.times {|n| User.create!(visits_count: n) }
|
12
|
+
assert_equal 2.5, User.median(:visits_count)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_odd
|
16
|
+
5.times {|n| User.create!(visits_count: n) }
|
17
|
+
assert_equal 2, User.median(:visits_count)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_empty
|
21
|
+
assert_nil User.median(:visits_count)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_decimal
|
25
|
+
6.times {|n| User.create!(latitude: n * 0.1) }
|
26
|
+
assert_equal 0.25, User.median(:latitude)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_float
|
30
|
+
6.times {|n| User.create!(rating: n * 0.1) }
|
31
|
+
assert_equal 0.25, User.median(:rating)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "bundler/setup"
|
2
|
+
Bundler.require :default
|
3
|
+
require "minitest/autorun"
|
4
|
+
require "minitest/pride"
|
5
|
+
|
6
|
+
ActiveRecord::Base.establish_connection adapter: "postgresql", database: "active_median_test"
|
7
|
+
|
8
|
+
ActiveRecord::Migration.create_table :users, force: true do |t|
|
9
|
+
t.integer :visits_count
|
10
|
+
t.decimal :latitude
|
11
|
+
t.float :rating
|
12
|
+
end
|
13
|
+
|
14
|
+
class User < ActiveRecord::Base
|
15
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_median
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-08-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activerecord
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,6 +52,20 @@ dependencies:
|
|
38
52
|
- - ">="
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pg
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
41
69
|
description: Median for ActiveRecord
|
42
70
|
email:
|
43
71
|
- acekane1@gmail.com
|
@@ -46,6 +74,7 @@ extensions: []
|
|
46
74
|
extra_rdoc_files: []
|
47
75
|
files:
|
48
76
|
- ".gitignore"
|
77
|
+
- CHANGELOG.md
|
49
78
|
- Gemfile
|
50
79
|
- LICENSE.txt
|
51
80
|
- README.md
|
@@ -53,6 +82,8 @@ files:
|
|
53
82
|
- active_median.gemspec
|
54
83
|
- lib/active_median.rb
|
55
84
|
- lib/active_median/version.rb
|
85
|
+
- test/active_median_test.rb
|
86
|
+
- test/test_helper.rb
|
56
87
|
homepage: https://github.com/ankane/active_median
|
57
88
|
licenses:
|
58
89
|
- MIT
|
@@ -73,8 +104,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
73
104
|
version: '0'
|
74
105
|
requirements: []
|
75
106
|
rubyforge_project:
|
76
|
-
rubygems_version: 2.2.
|
107
|
+
rubygems_version: 2.2.2
|
77
108
|
signing_key:
|
78
109
|
specification_version: 4
|
79
110
|
summary: Median for ActiveRecord
|
80
|
-
test_files:
|
111
|
+
test_files:
|
112
|
+
- test/active_median_test.rb
|
113
|
+
- test/test_helper.rb
|
114
|
+
has_rdoc:
|