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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cd1078e7f04565325bc6055502adad0c3703eec5
4
- data.tar.gz: 02266f10162a9dec2779790bb926adc0e95ae696
3
+ metadata.gz: 2b6d9c75498f9e09937bf9198f7b67249b2bf122
4
+ data.tar.gz: 49de0d0b1f1ba1e0509cf982ed97b3abebb19cf8
5
5
  SHA512:
6
- metadata.gz: 99455884b48f4b78a35524fc95c8912a33cec9e3b92745577ce6583ba7acc70d4e70beddf2c9173dfc7756f79eb5a335a75d5ca36a54cdad23ceec44bf767157
7
- data.tar.gz: 147c1b11f376a34407407ccc7b901a1533b4f8b1312f9142e51eab3e3d2b3ef4e21ab108f226772d7c22f2354242193fdd3b9ce4e308c4acd4897d1d204bc70a
6
+ metadata.gz: f93d25e49d3e9e1dbb2ba51cde3f54a8233ce9fae30710c30b76edc859b02b49eb9baa33034ecf6a97fd2569111903405fc63ffc323e2034965e81f29a6ad6f0
7
+ data.tar.gz: 589c9c118009bf1258aed61fcace805476549e9ca05504a0c4f21276d58e4cc97e960b4497ee3cd061d94d2a9f9d08029f114f698f55c7d5555fec6aae8290da
@@ -0,0 +1,8 @@
1
+ ## 0.1.1
2
+
3
+ - 10x faster median
4
+ - Added tests
5
+
6
+ ## 0.1.0
7
+
8
+ - First release
data/Rakefile CHANGED
@@ -1 +1,8 @@
1
1
  require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ task :default => :test
5
+ Rake::TestTask.new do |t|
6
+ t.libs << "test"
7
+ t.pattern = "test/**/*_test.rb"
8
+ end
@@ -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
@@ -4,50 +4,40 @@ require "active_record"
4
4
  module ActiveMedian
5
5
  def self.create_function
6
6
  # create median method
7
- # http://www.postgresonline.com/journal/archives/67-Build-Median-Aggregate-Function-in-SQL.html
7
+ # http://wiki.postgresql.org/wiki/Aggregate_Median
8
8
  ActiveRecord::Base.connection.execute <<-SQL
9
- CREATE OR REPLACE FUNCTION array_median(numeric[])
10
- RETURNS numeric AS
9
+ CREATE OR REPLACE FUNCTION median(anyarray)
10
+ RETURNS float8 AS
11
11
  $$
12
- SELECT CASE
13
- WHEN array_upper($1, 1) = 0 THEN null
14
- WHEN mod(array_upper($1, 1), 2) = 1 THEN asorted[ceiling(array_upper(asorted, 1) / 2.0)]
15
- ELSE (
16
- (
17
- asorted[ceiling(array_upper(asorted, 1) / 2.0)] +
18
- asorted[ceiling(array_upper(asorted, 1) / 2.0) + 1]
19
- ) / 2.0
20
- )
21
- END
22
- FROM (
23
- SELECT ARRAY(
24
- SELECT ($1)[n] FROM generate_series(1, array_upper($1, 1)) AS n
25
- WHERE ($1)[n] IS NOT NULL ORDER BY ($1)[n]
26
- ) AS asorted
27
- ) AS foo;
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
- LANGUAGE SQL;
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
- CREATE AGGREGATE median(double precision) (
35
+ DROP AGGREGATE IF EXISTS median(anyelement);
36
+ CREATE AGGREGATE median(anyelement) (
48
37
  SFUNC=array_append,
49
- STYPE=double precision[],
50
- FINALFUNC=array_median
38
+ STYPE=anyarray,
39
+ FINALFUNC=median,
40
+ INITCOND='{}'
51
41
  );
52
42
  SQL
53
43
  true
@@ -1,3 +1,3 @@
1
1
  module ActiveMedian
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -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
@@ -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.0
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-03-13 00:00:00.000000000 Z
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.0
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: