hightop 0.1.3 → 0.2.3
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 +5 -5
- data/CHANGELOG.md +29 -8
- data/LICENSE.txt +1 -1
- data/README.md +62 -13
- data/lib/hightop.rb +12 -31
- data/lib/hightop/enumerable.rb +24 -0
- data/lib/hightop/kicks.rb +29 -0
- data/lib/hightop/mongoid.rb +52 -0
- data/lib/hightop/version.rb +1 -1
- metadata +19 -28
- data/.gitignore +0 -22
- data/.travis.yml +0 -10
- data/Gemfile +0 -4
- data/Rakefile +0 -8
- data/hightop.gemspec +0 -27
- data/test/hightop_test.rb +0 -90
- data/test/test_helper.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 340c609cb491de09f5c69f80b3e237126c081a8167565c78d6f28cac692cc34b
|
4
|
+
data.tar.gz: 0aa4d15e3ac6503a73f664602d0d07f1a0e956202f93411ec51d663dcca9b2ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 31bcc5dcc655886f5dad2ebe27f33a7f56702b0503883bac779a944b502dc9bf1f27694c1eb83e4d36ca908fbb1bbe5e9b09706b5536f1ba53616e555204c579
|
7
|
+
data.tar.gz: 1e4d59093c22c49d3166368d8b23386ca7366dd9fc1b31e813e9df81bdd5d3b3e7d87ece4d36bf6b94deef69d2cd093927c0d9eeb62582fd357feed0c381564d
|
data/CHANGELOG.md
CHANGED
@@ -1,33 +1,54 @@
|
|
1
|
-
## 0.
|
1
|
+
## 0.2.3 (2020-06-18)
|
2
|
+
|
3
|
+
- Dropped support for Rails 4.2 and Ruby 2.3
|
4
|
+
- Fixed deprecation warning in Ruby 2.7
|
5
|
+
|
6
|
+
## 0.2.2 (2019-08-12)
|
7
|
+
|
8
|
+
- Added support for Mongoid
|
9
|
+
|
10
|
+
## 0.2.1 (2019-08-04)
|
11
|
+
|
12
|
+
- Added support for arrays and hashes
|
13
|
+
|
14
|
+
## 0.2.0 (2017-03-19)
|
15
|
+
|
16
|
+
- Use keyword arguments
|
17
|
+
|
18
|
+
## 0.1.4 (2016-02-04)
|
19
|
+
|
20
|
+
- Added `distinct` option to replace `uniq`
|
21
|
+
|
22
|
+
## 0.1.3 (2015-06-18)
|
2
23
|
|
3
24
|
- Fixed `min` option with `uniq`
|
4
25
|
|
5
|
-
## 0.1.2
|
26
|
+
## 0.1.2 (2014-11-05)
|
6
27
|
|
7
28
|
- Added `min` option
|
8
29
|
|
9
|
-
## 0.1.1
|
30
|
+
## 0.1.1 (2014-07-02)
|
10
31
|
|
11
32
|
- Added `uniq` option
|
12
33
|
- Fixed `Model.limit(n).top`
|
13
34
|
|
14
|
-
## 0.1.0
|
35
|
+
## 0.1.0 (2014-06-11)
|
15
36
|
|
16
37
|
- No changes, just bump
|
17
38
|
|
18
|
-
## 0.0.4
|
39
|
+
## 0.0.4 (2014-06-11)
|
19
40
|
|
20
41
|
- Added support for multiple groups
|
21
42
|
- Added `nil` option
|
22
43
|
|
23
|
-
## 0.0.3
|
44
|
+
## 0.0.3 (2014-06-11)
|
24
45
|
|
25
46
|
- Fixed escaping
|
26
47
|
|
27
|
-
## 0.0.2
|
48
|
+
## 0.0.2 (2014-05-29)
|
28
49
|
|
29
50
|
- Added `limit` parameter
|
30
51
|
|
31
|
-
## 0.0.1
|
52
|
+
## 0.0.1 (2014-05-11)
|
32
53
|
|
33
54
|
- First release
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -2,19 +2,28 @@
|
|
2
2
|
|
3
3
|
A nice shortcut for group count queries
|
4
4
|
|
5
|
-
[](https://travis-ci.org/ankane/hightop)
|
6
|
-
|
7
5
|
```ruby
|
8
6
|
Visit.top(:browser)
|
7
|
+
# {
|
8
|
+
# "Chrome" => 63,
|
9
|
+
# "Safari" => 50,
|
10
|
+
# "Firefox" => 34
|
11
|
+
# }
|
9
12
|
```
|
10
13
|
|
11
|
-
|
14
|
+
Works with Active Record, Mongoid, arrays and hashes
|
15
|
+
|
16
|
+
[](https://travis-ci.org/ankane/hightop)
|
17
|
+
|
18
|
+
## Installation
|
19
|
+
|
20
|
+
Add this line to your application’s Gemfile:
|
12
21
|
|
13
22
|
```ruby
|
14
|
-
|
23
|
+
gem 'hightop'
|
15
24
|
```
|
16
25
|
|
17
|
-
|
26
|
+
## Options
|
18
27
|
|
19
28
|
Limit the results
|
20
29
|
|
@@ -37,13 +46,13 @@ Visit.top([:city, :browser])
|
|
37
46
|
And expressions
|
38
47
|
|
39
48
|
```ruby
|
40
|
-
Visit.top("LOWER(referring_domain)")
|
49
|
+
Visit.top(Arel.sql("LOWER(referring_domain)"))
|
41
50
|
```
|
42
51
|
|
43
52
|
And distinct
|
44
53
|
|
45
54
|
```ruby
|
46
|
-
Visit.top(:city,
|
55
|
+
Visit.top(:city, distinct: :user_id)
|
47
56
|
```
|
48
57
|
|
49
58
|
And min count
|
@@ -52,18 +61,49 @@ And min count
|
|
52
61
|
Visit.top(:city, min: 10)
|
53
62
|
```
|
54
63
|
|
55
|
-
##
|
64
|
+
## User Input
|
56
65
|
|
57
|
-
|
66
|
+
If passing user input as the column, be sure to sanitize it first [like you must](https://rails-sqli.org/) with `group`.
|
58
67
|
|
59
68
|
```ruby
|
60
|
-
|
69
|
+
column = params[:column]
|
70
|
+
|
71
|
+
# check against permitted columns
|
72
|
+
raise "Unpermitted column" unless ["column_a", "column_b"].include?(column)
|
73
|
+
|
74
|
+
User.top(column)
|
61
75
|
```
|
62
76
|
|
63
|
-
|
77
|
+
## Arrays and Hashes
|
64
78
|
|
65
|
-
|
66
|
-
|
79
|
+
Arrays
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
["up", "up", "down"].top
|
83
|
+
```
|
84
|
+
|
85
|
+
Hashes
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
{a: "up", b: "up", c: "down"}.top { |k, v| v }
|
89
|
+
```
|
90
|
+
|
91
|
+
Limit the results
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
["up", "up", "down"].top(1)
|
95
|
+
```
|
96
|
+
|
97
|
+
Include nil values
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
[nil, nil, "down"].top(nil: true)
|
101
|
+
```
|
102
|
+
|
103
|
+
Min count
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
["up", "up", "down"].top(min: 2)
|
67
107
|
```
|
68
108
|
|
69
109
|
## History
|
@@ -78,3 +118,12 @@ Everyone is encouraged to help improve this project. Here are a few ways you can
|
|
78
118
|
- Fix bugs and [submit pull requests](https://github.com/ankane/hightop/pulls)
|
79
119
|
- Write, clarify, or fix documentation
|
80
120
|
- Suggest or add new features
|
121
|
+
|
122
|
+
To get started with development and testing:
|
123
|
+
|
124
|
+
```sh
|
125
|
+
git clone https://github.com/ankane/hightop.git
|
126
|
+
cd hightop
|
127
|
+
bundle install
|
128
|
+
bundle exec rake test
|
129
|
+
```
|
data/lib/hightop.rb
CHANGED
@@ -1,35 +1,16 @@
|
|
1
|
-
|
2
|
-
require "
|
3
|
-
|
4
|
-
module Hightop
|
5
|
-
def top(column, limit = nil, options = {})
|
6
|
-
if limit.is_a?(Hash)
|
7
|
-
options = limit
|
8
|
-
limit = nil
|
9
|
-
end
|
10
|
-
|
11
|
-
order_str = column.is_a?(Array) ? column.map(&:to_s).join(", ") : column
|
12
|
-
relation = group(column).order("count_#{options[:uniq] || 'all'} DESC, #{order_str}")
|
13
|
-
if limit
|
14
|
-
relation = relation.limit(limit)
|
15
|
-
end
|
1
|
+
# dependencies
|
2
|
+
require "active_support"
|
16
3
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
if options[:min]
|
24
|
-
relation = relation.having("COUNT(#{options[:uniq] ? "DISTINCT #{options[:uniq]}" : '*'}) >= #{options[:min].to_i}")
|
25
|
-
end
|
4
|
+
# modules
|
5
|
+
require "hightop/enumerable"
|
6
|
+
require "hightop/version"
|
26
7
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
relation.count
|
31
|
-
end
|
32
|
-
end
|
8
|
+
ActiveSupport.on_load(:active_record) do
|
9
|
+
require "hightop/kicks"
|
10
|
+
extend Hightop::Kicks
|
33
11
|
end
|
34
12
|
|
35
|
-
|
13
|
+
ActiveSupport.on_load(:mongoid) do
|
14
|
+
require "hightop/mongoid"
|
15
|
+
Mongoid::Document::ClassMethods.include(Hightop::Mongoid)
|
16
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Enumerable
|
2
|
+
def top(*args, **options, &block)
|
3
|
+
if block || !(respond_to?(:scoping) || respond_to?(:with_scope))
|
4
|
+
# TODO raise error if too many arguments
|
5
|
+
limit = args[0]
|
6
|
+
min = options[:min]
|
7
|
+
|
8
|
+
counts = Hash.new(0)
|
9
|
+
map(&block).each do |v|
|
10
|
+
counts[v] += 1
|
11
|
+
end
|
12
|
+
counts.delete(nil) unless options[:nil]
|
13
|
+
counts.select! { |_, v| v >= min } if min
|
14
|
+
|
15
|
+
arr = counts.sort_by { |_, v| -v }
|
16
|
+
arr = arr[0...limit] if limit
|
17
|
+
Hash[arr]
|
18
|
+
elsif respond_to?(:scoping)
|
19
|
+
scoping { @klass.send(:top, *args, **options, &block) }
|
20
|
+
else
|
21
|
+
with_scope(self) { klass.send(:top, *args, **options, &block) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Hightop
|
2
|
+
module Kicks
|
3
|
+
def top(column, limit = nil, distinct: nil, uniq: nil, min: nil, nil: nil)
|
4
|
+
distinct ||= uniq
|
5
|
+
order_str = column.is_a?(Array) ? column.map(&:to_s).join(", ") : column
|
6
|
+
relation = group(column).order(["count_#{distinct || 'all'} DESC", order_str])
|
7
|
+
if limit
|
8
|
+
relation = relation.limit(limit)
|
9
|
+
end
|
10
|
+
|
11
|
+
# terribly named option
|
12
|
+
unless binding.local_variable_get(:nil)
|
13
|
+
(column.is_a?(Array) ? column : [column]).each do |c|
|
14
|
+
relation = relation.where("#{c} IS NOT NULL")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
if min
|
19
|
+
relation = relation.having("COUNT(#{distinct ? "DISTINCT #{distinct}" : '*'}) >= #{min.to_i}")
|
20
|
+
end
|
21
|
+
|
22
|
+
if distinct
|
23
|
+
relation.distinct.count(distinct)
|
24
|
+
else
|
25
|
+
relation.count
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Hightop
|
2
|
+
module Mongoid
|
3
|
+
# super helpful article
|
4
|
+
# https://maximomussini.com/posts/mongoid-aggregation-dsl/
|
5
|
+
def top(column, limit = nil, distinct: nil, uniq: nil, min: nil, nil: nil)
|
6
|
+
distinct ||= uniq
|
7
|
+
|
8
|
+
relation = all
|
9
|
+
|
10
|
+
# terribly named option
|
11
|
+
unless binding.local_variable_get(:nil)
|
12
|
+
(column.is_a?(Array) ? column : [column]).each do |c|
|
13
|
+
relation = relation.and(c.ne => nil)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
ids = {}
|
18
|
+
Array(column).each_with_index do |c, i|
|
19
|
+
ids["c#{i}"] = "$#{c}"
|
20
|
+
end
|
21
|
+
|
22
|
+
if distinct
|
23
|
+
# group with distinct column first, then group without it
|
24
|
+
# https://stackoverflow.com/questions/24761266/select-group-by-count-and-distinct-count-in-same-mongodb-query/24770233#24770233
|
25
|
+
distinct_ids = ids.merge("c#{ids.size}" => "$#{distinct}")
|
26
|
+
relation = relation.group(_id: distinct_ids, count: {"$sum" => 1})
|
27
|
+
ids.each_key do |k|
|
28
|
+
ids[k] = "$_id.#{k}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
relation = relation.group(_id: ids, count: {"$sum" => 1})
|
33
|
+
|
34
|
+
if min
|
35
|
+
relation.pipeline.push("$match" => {"count" => {"$gte" => min}})
|
36
|
+
end
|
37
|
+
|
38
|
+
relation = relation.desc(:count)
|
39
|
+
if limit
|
40
|
+
relation = relation.limit(limit)
|
41
|
+
end
|
42
|
+
|
43
|
+
result = {}
|
44
|
+
collection.aggregate(relation.pipeline).each do |doc|
|
45
|
+
key = doc["_id"].values
|
46
|
+
key = key[0] if key.size == 1
|
47
|
+
result[key] = doc["count"]
|
48
|
+
end
|
49
|
+
result
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/hightop/version.rb
CHANGED
metadata
CHANGED
@@ -1,43 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hightop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-06-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: activesupport
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '5'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '5'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,14 +58,14 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '5'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '5'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: sqlite3
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,25 +80,20 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
-
description:
|
84
|
-
email:
|
85
|
-
- andrew@chartkick.com
|
83
|
+
description:
|
84
|
+
email: andrew@chartkick.com
|
86
85
|
executables: []
|
87
86
|
extensions: []
|
88
87
|
extra_rdoc_files: []
|
89
88
|
files:
|
90
|
-
- ".gitignore"
|
91
|
-
- ".travis.yml"
|
92
89
|
- CHANGELOG.md
|
93
|
-
- Gemfile
|
94
90
|
- LICENSE.txt
|
95
91
|
- README.md
|
96
|
-
- Rakefile
|
97
|
-
- hightop.gemspec
|
98
92
|
- lib/hightop.rb
|
93
|
+
- lib/hightop/enumerable.rb
|
94
|
+
- lib/hightop/kicks.rb
|
95
|
+
- lib/hightop/mongoid.rb
|
99
96
|
- lib/hightop/version.rb
|
100
|
-
- test/hightop_test.rb
|
101
|
-
- test/test_helper.rb
|
102
97
|
homepage: https://github.com/ankane/hightop
|
103
98
|
licenses:
|
104
99
|
- MIT
|
@@ -111,19 +106,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
111
106
|
requirements:
|
112
107
|
- - ">="
|
113
108
|
- !ruby/object:Gem::Version
|
114
|
-
version: '
|
109
|
+
version: '2.4'
|
115
110
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
111
|
requirements:
|
117
112
|
- - ">="
|
118
113
|
- !ruby/object:Gem::Version
|
119
114
|
version: '0'
|
120
115
|
requirements: []
|
121
|
-
|
122
|
-
rubygems_version: 2.4.5
|
116
|
+
rubygems_version: 3.1.2
|
123
117
|
signing_key:
|
124
118
|
specification_version: 4
|
125
119
|
summary: A nice shortcut for group count queries
|
126
|
-
test_files:
|
127
|
-
- test/hightop_test.rb
|
128
|
-
- test/test_helper.rb
|
129
|
-
has_rdoc:
|
120
|
+
test_files: []
|
data/.gitignore
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
*.gem
|
2
|
-
*.rbc
|
3
|
-
.bundle
|
4
|
-
.config
|
5
|
-
.yardoc
|
6
|
-
Gemfile.lock
|
7
|
-
InstalledFiles
|
8
|
-
_yardoc
|
9
|
-
coverage
|
10
|
-
doc/
|
11
|
-
lib/bundler/man
|
12
|
-
pkg
|
13
|
-
rdoc
|
14
|
-
spec/reports
|
15
|
-
test/tmp
|
16
|
-
test/version_tmp
|
17
|
-
tmp
|
18
|
-
*.bundle
|
19
|
-
*.so
|
20
|
-
*.o
|
21
|
-
*.a
|
22
|
-
mkmf.log
|
data/.travis.yml
DELETED
data/Gemfile
DELETED
data/Rakefile
DELETED
data/hightop.gemspec
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
lib = File.expand_path("../lib", __FILE__)
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require "hightop/version"
|
5
|
-
|
6
|
-
Gem::Specification.new do |spec|
|
7
|
-
spec.name = "hightop"
|
8
|
-
spec.version = Hightop::VERSION
|
9
|
-
spec.authors = ["Andrew Kane"]
|
10
|
-
spec.email = ["andrew@chartkick.com"]
|
11
|
-
spec.summary = "A nice shortcut for group count queries"
|
12
|
-
spec.description = "A nice shortcut for group count queries"
|
13
|
-
spec.homepage = "https://github.com/ankane/hightop"
|
14
|
-
spec.license = "MIT"
|
15
|
-
|
16
|
-
spec.files = `git ls-files -z`.split("\x0")
|
17
|
-
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
-
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = ["lib"]
|
20
|
-
|
21
|
-
spec.add_dependency "activerecord"
|
22
|
-
|
23
|
-
spec.add_development_dependency "bundler", "~> 1.6"
|
24
|
-
spec.add_development_dependency "rake"
|
25
|
-
spec.add_development_dependency "minitest"
|
26
|
-
spec.add_development_dependency "sqlite3"
|
27
|
-
end
|
data/test/hightop_test.rb
DELETED
@@ -1,90 +0,0 @@
|
|
1
|
-
require_relative "test_helper"
|
2
|
-
|
3
|
-
class TestHightop < Minitest::Test
|
4
|
-
def setup
|
5
|
-
Visit.delete_all
|
6
|
-
end
|
7
|
-
|
8
|
-
def test_top
|
9
|
-
create_city("San Francisco", 3)
|
10
|
-
create_city("Chicago", 2)
|
11
|
-
expected = {
|
12
|
-
"San Francisco" => 3,
|
13
|
-
"Chicago" => 2
|
14
|
-
}
|
15
|
-
assert_equal expected, Visit.top(:city)
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_limit
|
19
|
-
create_city("San Francisco", 3)
|
20
|
-
create_city("Chicago", 2)
|
21
|
-
create_city("Boston", 1)
|
22
|
-
expected = {
|
23
|
-
"San Francisco" => 3,
|
24
|
-
"Chicago" => 2
|
25
|
-
}
|
26
|
-
assert_equal expected, Visit.top(:city, 2)
|
27
|
-
assert_equal expected, Visit.limit(2).top(:city)
|
28
|
-
end
|
29
|
-
|
30
|
-
def test_nil_values
|
31
|
-
create_city("San Francisco", 3)
|
32
|
-
create_city(nil, 2)
|
33
|
-
expected = {
|
34
|
-
"San Francisco" => 3
|
35
|
-
}
|
36
|
-
assert_equal expected, Visit.top(:city)
|
37
|
-
end
|
38
|
-
|
39
|
-
def test_nil_option
|
40
|
-
create_city("San Francisco", 3)
|
41
|
-
create_city(nil, 2)
|
42
|
-
expected = {
|
43
|
-
"San Francisco" => 3,
|
44
|
-
nil => 2
|
45
|
-
}
|
46
|
-
assert_equal expected, Visit.top(:city, nil: true)
|
47
|
-
end
|
48
|
-
|
49
|
-
def test_multiple_groups
|
50
|
-
create_city("San Francisco")
|
51
|
-
expected = {
|
52
|
-
["San Francisco", "San Francisco"] => 1
|
53
|
-
}
|
54
|
-
assert_equal expected, Visit.top([:city, :city])
|
55
|
-
end
|
56
|
-
|
57
|
-
def test_expressions
|
58
|
-
create_city("San Francisco")
|
59
|
-
expected = {
|
60
|
-
"san francisco" => 1
|
61
|
-
}
|
62
|
-
assert_equal expected, Visit.top("LOWER(city)")
|
63
|
-
end
|
64
|
-
|
65
|
-
def test_uniq
|
66
|
-
create(city: "San Francisco", user_id: 1)
|
67
|
-
create(city: "San Francisco", user_id: 1)
|
68
|
-
expected = {
|
69
|
-
"San Francisco" => 1
|
70
|
-
}
|
71
|
-
assert_equal expected, Visit.top(:city, uniq: :user_id)
|
72
|
-
end
|
73
|
-
|
74
|
-
def test_min
|
75
|
-
create_city("San Francisco", 3)
|
76
|
-
create_city("Chicago", 2)
|
77
|
-
expected = {
|
78
|
-
"San Francisco" => 3
|
79
|
-
}
|
80
|
-
assert_equal expected, Visit.top(:city, min: 3)
|
81
|
-
end
|
82
|
-
|
83
|
-
def create_city(city, count = 1)
|
84
|
-
create({city: city}, count)
|
85
|
-
end
|
86
|
-
|
87
|
-
def create(attributes, count = 1)
|
88
|
-
count.times { Visit.create!(attributes) }
|
89
|
-
end
|
90
|
-
end
|
data/test/test_helper.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
require "bundler/setup"
|
2
|
-
Bundler.require(:default)
|
3
|
-
require "minitest/autorun"
|
4
|
-
require "minitest/pride"
|
5
|
-
require "logger"
|
6
|
-
|
7
|
-
# for debugging
|
8
|
-
# ActiveRecord::Base.logger = Logger.new(STDOUT)
|
9
|
-
|
10
|
-
# migrations
|
11
|
-
ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
|
12
|
-
|
13
|
-
ActiveRecord::Migration.create_table :visits do |t|
|
14
|
-
t.string :city
|
15
|
-
t.string :user_id
|
16
|
-
end
|
17
|
-
|
18
|
-
class Visit < ActiveRecord::Base
|
19
|
-
end
|