active_median 0.1.0 → 0.1.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.
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: