hightop 0.1.4 → 0.2.4

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
- SHA1:
3
- metadata.gz: 19538edc7ac8f8cc81df7ad682c47ec6dfe0d38e
4
- data.tar.gz: 2f2bb4d909ead9b64fa293627a784c5adeaadd2d
2
+ SHA256:
3
+ metadata.gz: e986b06b74104ea5fb99fe92abdb061eab4cc225ba9fa4f34216eadcd704e556
4
+ data.tar.gz: 5ca8954b8ce39c1212e0bc0b651e22450ff26b17795665b561cc7e4bbb134067
5
5
  SHA512:
6
- metadata.gz: ac01a53983e69a760c745bcddd99287774ae73d7b743dcf4be327b252c0524e3147b6e815a1560b735f6cdf2252d651402ea9b775468bd93300d056fdcea18d3
7
- data.tar.gz: 37252ef2688c355c2aa327f36fd5025c7809986abfc256bb4f8ea0df48442c8add698d944261b2a0ee0d16ee5c3d52b352023ad7c334a6ec39fe80e80a3922f0
6
+ metadata.gz: e9d93d7b9edcce9dcfb6f3b7912ef3252454731bcc68d45cc9ff391df854a6fe49e5d7ca269780e55e98cf1481a17ef3472427de69694d6098cfdcacf9e61c7d
7
+ data.tar.gz: cd86dfd59b77d39482d06d0a6e9f59869ca15eaab6eef6e5cc62f754ad9d3addd781e21749a192a181385620b2508b520ee22da1f2c397566ac82159778a65d2
@@ -1,37 +1,59 @@
1
- ## 0.1.4
1
+ ## 0.2.4 (2020-09-07)
2
+
3
+ - Added warning for non-attribute argument
4
+ - Added deprecation warning for `uniq`
5
+
6
+ ## 0.2.3 (2020-06-18)
7
+
8
+ - Dropped support for Active Record 4.2 and Ruby 2.3
9
+ - Fixed deprecation warning in Ruby 2.7
10
+
11
+ ## 0.2.2 (2019-08-12)
12
+
13
+ - Added support for Mongoid
14
+
15
+ ## 0.2.1 (2019-08-04)
16
+
17
+ - Added support for arrays and hashes
18
+
19
+ ## 0.2.0 (2017-03-19)
20
+
21
+ - Use keyword arguments
22
+
23
+ ## 0.1.4 (2016-02-04)
2
24
 
3
25
  - Added `distinct` option to replace `uniq`
4
26
 
5
- ## 0.1.3
27
+ ## 0.1.3 (2015-06-18)
6
28
 
7
29
  - Fixed `min` option with `uniq`
8
30
 
9
- ## 0.1.2
31
+ ## 0.1.2 (2014-11-05)
10
32
 
11
33
  - Added `min` option
12
34
 
13
- ## 0.1.1
35
+ ## 0.1.1 (2014-07-02)
14
36
 
15
37
  - Added `uniq` option
16
38
  - Fixed `Model.limit(n).top`
17
39
 
18
- ## 0.1.0
40
+ ## 0.1.0 (2014-06-11)
19
41
 
20
42
  - No changes, just bump
21
43
 
22
- ## 0.0.4
44
+ ## 0.0.4 (2014-06-11)
23
45
 
24
46
  - Added support for multiple groups
25
47
  - Added `nil` option
26
48
 
27
- ## 0.0.3
49
+ ## 0.0.3 (2014-06-11)
28
50
 
29
51
  - Fixed escaping
30
52
 
31
- ## 0.0.2
53
+ ## 0.0.2 (2014-05-29)
32
54
 
33
55
  - Added `limit` parameter
34
56
 
35
- ## 0.0.1
57
+ ## 0.0.1 (2014-05-11)
36
58
 
37
59
  - First release
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014 Andrew Kane
1
+ Copyright (c) 2014-2020 Andrew Kane
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -2,19 +2,28 @@
2
2
 
3
3
  A nice shortcut for group count queries
4
4
 
5
- [![Build Status](https://travis-ci.org/ankane/hightop.svg)](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
- instead of
14
+ Works with Active Record, Mongoid, arrays and hashes
15
+
16
+ [![Build Status](https://travis-ci.org/ankane/hightop.svg?branch=master)](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
- Visit.group(:browser).where("browser IS NOT NULL").order("count_all DESC, browser").count
23
+ gem 'hightop'
15
24
  ```
16
25
 
17
- Be sure to [sanitize user input](http://rails-sqli.org/) like you must with `group`.
26
+ ## Options
18
27
 
19
28
  Limit the results
20
29
 
@@ -37,7 +46,7 @@ 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
@@ -52,18 +61,49 @@ And min count
52
61
  Visit.top(:city, min: 10)
53
62
  ```
54
63
 
55
- ## Installation
64
+ ## User Input
56
65
 
57
- Add this line to your application’s Gemfile:
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
- gem 'hightop'
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
- And then execute:
77
+ ## Arrays and Hashes
64
78
 
65
- ```sh
66
- bundle
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
+ ```
@@ -1,41 +1,17 @@
1
- require "hightop/version"
2
- require "active_record"
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
- distinct = options[:distinct] || options[:uniq]
12
- order_str = column.is_a?(Array) ? column.map(&:to_s).join(", ") : column
13
- relation = group(column).order("count_#{distinct || 'all'} DESC, #{order_str}")
14
- if limit
15
- relation = relation.limit(limit)
16
- end
1
+ # dependencies
2
+ require "active_support"
17
3
 
18
- unless options[:nil]
19
- (column.is_a?(Array) ? column : [column]).each do |c|
20
- relation = relation.where("#{c} IS NOT NULL")
21
- end
22
- end
23
-
24
- if options[:min]
25
- relation = relation.having("COUNT(#{distinct ? "DISTINCT #{distinct}" : '*'}) >= #{options[:min].to_i}")
26
- end
4
+ # modules
5
+ require "hightop/enumerable"
6
+ require "hightop/version"
27
7
 
28
- if distinct
29
- # since relation.respond_to?(:distinct) can't be used
30
- if ActiveRecord::VERSION::MAJOR > 3
31
- relation.distinct.count(distinct)
32
- else
33
- relation.uniq.count(distinct)
34
- end
35
- else
36
- relation.count
37
- end
38
- end
8
+ ActiveSupport.on_load(:active_record) do
9
+ require "hightop/utils"
10
+ require "hightop/kicks"
11
+ extend Hightop::Kicks
39
12
  end
40
13
 
41
- ActiveRecord::Base.send :extend, Hightop
14
+ ActiveSupport.on_load(:mongoid) do
15
+ require "hightop/mongoid"
16
+ Mongoid::Document::ClassMethods.include(Hightop::Mongoid)
17
+ 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,41 @@
1
+ module Hightop
2
+ module Kicks
3
+ def top(column, limit = nil, distinct: nil, uniq: nil, min: nil, nil: nil)
4
+ warn "[hightop] uniq is deprecated. Use distinct instead" if uniq
5
+
6
+ columns = column.is_a?(Array) ? column : [column]
7
+ columns.each { |c| Utils.validate_column(c) }
8
+
9
+ distinct ||= uniq
10
+ Utils.validate_column(distinct) if distinct
11
+
12
+ relation = group(*columns).order("1 DESC", *columns)
13
+ if limit
14
+ relation = relation.limit(limit)
15
+ end
16
+
17
+ # terribly named option
18
+ unless binding.local_variable_get(:nil)
19
+ columns.each do |c|
20
+ c = Utils.resolve_column(self, c)
21
+ relation = relation.where("#{c} IS NOT NULL")
22
+ end
23
+ end
24
+
25
+ if min
26
+ if distinct
27
+ d = Utils.resolve_column(self, distinct)
28
+ relation = relation.having("COUNT(DISTINCT #{d}) >= #{min.to_i}")
29
+ else
30
+ relation = relation.having("COUNT(*) >= #{min.to_i}")
31
+ end
32
+ end
33
+
34
+ if distinct
35
+ relation.distinct.count(distinct)
36
+ else
37
+ relation.count
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,56 @@
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
+ warn "[hightop] uniq is deprecated. Use distinct instead" if uniq
7
+
8
+ columns = column.is_a?(Array) ? column : [column]
9
+
10
+ distinct ||= uniq
11
+
12
+ relation = all
13
+
14
+ # terribly named option
15
+ unless binding.local_variable_get(:nil)
16
+ columns.each do |c|
17
+ relation = relation.and(c.ne => nil)
18
+ end
19
+ end
20
+
21
+ ids = {}
22
+ columns.each_with_index do |c, i|
23
+ ids["c#{i}"] = "$#{c}"
24
+ end
25
+
26
+ if distinct
27
+ # group with distinct column first, then group without it
28
+ # https://stackoverflow.com/questions/24761266/select-group-by-count-and-distinct-count-in-same-mongodb-query/24770233#24770233
29
+ distinct_ids = ids.merge("c#{ids.size}" => "$#{distinct}")
30
+ relation = relation.group(_id: distinct_ids, count: {"$sum" => 1})
31
+ ids.each_key do |k|
32
+ ids[k] = "$_id.#{k}"
33
+ end
34
+ end
35
+
36
+ relation = relation.group(_id: ids, count: {"$sum" => 1})
37
+
38
+ if min
39
+ relation.pipeline.push("$match" => {"count" => {"$gte" => min}})
40
+ end
41
+
42
+ relation = relation.desc(:count)
43
+ if limit
44
+ relation = relation.limit(limit)
45
+ end
46
+
47
+ result = {}
48
+ collection.aggregate(relation.pipeline).each do |doc|
49
+ key = doc["_id"].values
50
+ key = key[0] if key.size == 1
51
+ result[key] = doc["count"]
52
+ end
53
+ result
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,21 @@
1
+ module Hightop
2
+ module Utils
3
+ class << self
4
+ # basic version of Active Record disallow_raw_sql!
5
+ # symbol = column (safe), Arel node = SQL (safe), other = untrusted
6
+ # matches table.column and column
7
+ def validate_column(column)
8
+ unless column.is_a?(Symbol) || column.is_a?(Arel::Nodes::SqlLiteral) || /\A\w+(\.\w+)?\z/i.match(column.to_s)
9
+ warn "[hightop] Non-attribute argument: #{column}. Use Arel.sql() for known-safe values. This will raise an error in Hightop 0.3.0"
10
+ end
11
+ end
12
+
13
+ # resolves eagerly
14
+ def resolve_column(relation, column)
15
+ node = relation.send(:relation).send(:arel_columns, [column]).first
16
+ node = Arel::Nodes::SqlLiteral.new(node) if node.is_a?(String)
17
+ relation.connection.visitor.accept(node, Arel::Collectors::SQLString.new).value
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,3 +1,3 @@
1
1
  module Hightop
2
- VERSION = "0.1.4"
2
+ VERSION = "0.2.4"
3
3
  end
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.1.4
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-04 00:00:00.000000000 Z
11
+ date: 2020-09-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: activerecord
14
+ name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
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: '0'
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: '1.6'
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: '1.6'
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: '0'
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: '0'
68
+ version: '5'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: sqlite3
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -80,25 +80,21 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
- description: A nice shortcut for group count queries
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
96
+ - lib/hightop/utils.rb
99
97
  - lib/hightop/version.rb
100
- - test/hightop_test.rb
101
- - test/test_helper.rb
102
98
  homepage: https://github.com/ankane/hightop
103
99
  licenses:
104
100
  - MIT
@@ -111,19 +107,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
111
107
  requirements:
112
108
  - - ">="
113
109
  - !ruby/object:Gem::Version
114
- version: '0'
110
+ version: '2.4'
115
111
  required_rubygems_version: !ruby/object:Gem::Requirement
116
112
  requirements:
117
113
  - - ">="
118
114
  - !ruby/object:Gem::Version
119
115
  version: '0'
120
116
  requirements: []
121
- rubyforge_project:
122
- rubygems_version: 2.4.5.1
117
+ rubygems_version: 3.1.2
123
118
  signing_key:
124
119
  specification_version: 4
125
120
  summary: A nice shortcut for group count queries
126
- test_files:
127
- - test/hightop_test.rb
128
- - test/test_helper.rb
129
- has_rdoc:
121
+ 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
@@ -1,12 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.1
4
- gemfile:
5
- - Gemfile
6
- sudo: false
7
- before_install: gem install bundler
8
- script: bundle exec rake test
9
- notifications:
10
- email:
11
- on_success: never
12
- on_failure: change
data/Gemfile DELETED
@@ -1,4 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- # Specify your gem's dependencies in hightop.gemspec
4
- gemspec
data/Rakefile DELETED
@@ -1,8 +0,0 @@
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
@@ -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
@@ -1,111 +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_distinct
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, distinct: :user_id)
72
- end
73
-
74
- def test_uniq
75
- create(city: "San Francisco", user_id: 1)
76
- create(city: "San Francisco", user_id: 1)
77
- expected = {
78
- "San Francisco" => 1
79
- }
80
- assert_equal expected, Visit.top(:city, uniq: :user_id)
81
- end
82
-
83
- def test_min
84
- create_city("San Francisco", 3)
85
- create_city("Chicago", 2)
86
- expected = {
87
- "San Francisco" => 3
88
- }
89
- assert_equal expected, Visit.top(:city, min: 3)
90
- end
91
-
92
- def test_min_distinct
93
- create(city: "San Francisco", user_id: 1)
94
- create(city: "San Francisco", user_id: 1)
95
- create(city: "San Francisco", user_id: 2)
96
- create(city: "Chicago", user_id: 1)
97
- create(city: "Chicago", user_id: 1)
98
- expected = {
99
- "San Francisco" => 2
100
- }
101
- assert_equal expected, Visit.top(:city, min: 2, distinct: :user_id)
102
- end
103
-
104
- def create_city(city, count = 1)
105
- create({city: city}, count)
106
- end
107
-
108
- def create(attributes, count = 1)
109
- count.times { Visit.create!(attributes) }
110
- end
111
- end
@@ -1,21 +0,0 @@
1
- require "bundler/setup"
2
- Bundler.require(:default)
3
- require "minitest/autorun"
4
- require "minitest/pride"
5
- require "logger"
6
-
7
- Minitest::Test = Minitest::Unit::TestCase unless defined?(Minitest::Test)
8
-
9
- # for debugging
10
- # ActiveRecord::Base.logger = Logger.new(STDOUT)
11
-
12
- # migrations
13
- ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
14
-
15
- ActiveRecord::Migration.create_table :visits do |t|
16
- t.string :city
17
- t.string :user_id
18
- end
19
-
20
- class Visit < ActiveRecord::Base
21
- end