activerecord-postgres-earthdistance 0.4.4 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +20 -0
- data/Gemfile.lock +20 -12
- data/README.md +22 -9
- data/Rakefile +10 -11
- data/activerecord-postgres-earthdistance.gemspec +12 -5
- data/lib/activerecord-postgres-earthdistance.rb +1 -1
- data/lib/activerecord-postgres-earthdistance/activerecord.rb +5 -6
- data/lib/activerecord-postgres-earthdistance/acts_as_geolocated.rb +64 -25
- data/lib/activerecord-postgres-earthdistance/railties.rb +8 -10
- data/spec/act_as_geolocated_spec.rb +101 -39
- data/spec/fixtures/job.rb +4 -0
- data/spec/spec_helper.rb +31 -22
- metadata +21 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 837c44a62054d3207412a8426a108d91c3ee565a
|
4
|
+
data.tar.gz: 51eb68df69f6259f9ed85cfa01a8b699bdfdc59d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bc1e1bb9e5ee4f5abf5d282cc0580ddde5994a7011e0948413b1191549fe78850835eb9aee996fa4a5faa12534124848371c327e82a0b36e24f07d934881f86d
|
7
|
+
data.tar.gz: b0a529f93d2adcba785c74c7440ac7ef45eae07175b7ac7a670e388046dc589c6082c9dc63b0d698c7070d97d91cfb3da8ae61afab4a1531151090341f3711ee
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Metrics/LineLength:
|
2
|
+
Max: 100
|
3
|
+
|
4
|
+
Metrics/BlockLength:
|
5
|
+
Enabled: false
|
6
|
+
|
7
|
+
Metrics/MethodLength:
|
8
|
+
Enabled: false
|
9
|
+
|
10
|
+
Style/Documentation:
|
11
|
+
Enabled: false
|
12
|
+
|
13
|
+
Style/FileName:
|
14
|
+
Enabled: false
|
15
|
+
|
16
|
+
Style/StringLiterals:
|
17
|
+
EnforcedStyle: double_quotes
|
18
|
+
|
19
|
+
Style/VariableNumber:
|
20
|
+
EnforcedStyle: normalcase
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
activerecord-postgres-earthdistance (0.
|
4
|
+
activerecord-postgres-earthdistance (0.5.0)
|
5
5
|
activerecord (>= 3.1)
|
6
6
|
pg
|
7
7
|
rake
|
@@ -9,25 +9,31 @@ PATH
|
|
9
9
|
GEM
|
10
10
|
remote: http://rubygems.org/
|
11
11
|
specs:
|
12
|
-
activemodel (5.0.0)
|
13
|
-
activesupport (= 5.0.0)
|
14
|
-
activerecord (5.0.0)
|
15
|
-
activemodel (= 5.0.0)
|
16
|
-
activesupport (= 5.0.0)
|
12
|
+
activemodel (5.0.0.1)
|
13
|
+
activesupport (= 5.0.0.1)
|
14
|
+
activerecord (5.0.0.1)
|
15
|
+
activemodel (= 5.0.0.1)
|
16
|
+
activesupport (= 5.0.0.1)
|
17
17
|
arel (~> 7.0)
|
18
|
-
activesupport (5.0.0)
|
18
|
+
activesupport (5.0.0.1)
|
19
19
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
20
20
|
i18n (~> 0.7)
|
21
21
|
minitest (~> 5.1)
|
22
22
|
tzinfo (~> 1.1)
|
23
|
-
arel (7.1.
|
23
|
+
arel (7.1.4)
|
24
|
+
coderay (1.1.1)
|
24
25
|
concurrent-ruby (1.0.2)
|
25
26
|
diff-lcs (1.2.5)
|
26
27
|
i18n (0.7.0)
|
27
28
|
json (1.8.3)
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
method_source (0.8.2)
|
30
|
+
minitest (5.9.1)
|
31
|
+
pg (0.19.0)
|
32
|
+
pry (0.10.4)
|
33
|
+
coderay (~> 1.1.0)
|
34
|
+
method_source (~> 0.8.1)
|
35
|
+
slop (~> 3.4)
|
36
|
+
rake (11.3.0)
|
31
37
|
rdoc (4.2.1)
|
32
38
|
json (~> 1.4)
|
33
39
|
rspec (2.99.0)
|
@@ -38,6 +44,7 @@ GEM
|
|
38
44
|
rspec-expectations (2.99.2)
|
39
45
|
diff-lcs (>= 1.1.3, < 2.0)
|
40
46
|
rspec-mocks (2.99.4)
|
47
|
+
slop (3.6.0)
|
41
48
|
thread_safe (0.3.5)
|
42
49
|
tzinfo (1.2.2)
|
43
50
|
thread_safe (~> 0.1)
|
@@ -48,8 +55,9 @@ PLATFORMS
|
|
48
55
|
DEPENDENCIES
|
49
56
|
activerecord-postgres-earthdistance!
|
50
57
|
bundler
|
58
|
+
pry
|
51
59
|
rdoc
|
52
60
|
rspec (~> 2.11)
|
53
61
|
|
54
62
|
BUNDLED WITH
|
55
|
-
1.
|
63
|
+
1.13.1
|
data/README.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
#ActiveRecord + PostgreSQL Earthdistance [![Build Status](https://travis-ci.org/diogob/activerecord-postgres-earthdistance.svg?branch=master)](https://travis-ci.org/diogob/activerecord-postgres-earthdistance)
|
1
|
+
# ActiveRecord + PostgreSQL Earthdistance [![Build Status](https://travis-ci.org/diogob/activerecord-postgres-earthdistance.svg?branch=master)](https://travis-ci.org/diogob/activerecord-postgres-earthdistance) [![Code Climate](https://codeclimate.com/github/diogob/activerecord-postgres-earthdistance/badges/gpa.svg)](https://codeclimate.com/github/diogob/activerecord-postgres-earthdistance)
|
2
2
|
|
3
3
|
Check distances with latitude and longitude using PostgreSQL special indexes.
|
4
4
|
This gem enables your model to query the database using the earthdistance extension. This should be much faster than using trigonometry functions over standard indexes.
|
5
5
|
|
6
|
-
##Requirements
|
6
|
+
## Requirements
|
7
7
|
|
8
8
|
Postgresql 9.1+ with contrib and Rails 3.1+
|
9
9
|
On Ubuntu, this is easy: `sudo apt-get install postgresql-contrib-9.1`
|
@@ -14,7 +14,7 @@ On Mac you have a couple of options:
|
|
14
14
|
* [Homebrew’s](https://github.com/mxcl/homebrew) Postgres installation also includes the contrib packages: `brew install postgres`
|
15
15
|
* [Postgres.app](http://postgresapp.com/)
|
16
16
|
|
17
|
-
##Install
|
17
|
+
## Install
|
18
18
|
|
19
19
|
|
20
20
|
Earthdistance is a PostgreSQL contrib module, [check it out first](http://www.postgresql.org/docs/9.2/static/earthdistance.html).
|
@@ -60,7 +60,7 @@ This will create the index with a SQL like this:
|
|
60
60
|
CREATE INDEX places_earthdistance_ix ON places USING GIST (ll_to_earth(lat, lng));
|
61
61
|
```
|
62
62
|
|
63
|
-
##Usage
|
63
|
+
## Usage
|
64
64
|
|
65
65
|
This gem only provides a custom serialization coder.
|
66
66
|
If you want to use it just put in your Gemfile:
|
@@ -86,7 +86,15 @@ class Place < ActiveRecord::Base
|
|
86
86
|
end
|
87
87
|
```
|
88
88
|
|
89
|
-
|
89
|
+
You can also locale other entities through an geolocated association as in:
|
90
|
+
```ruby
|
91
|
+
class Job < ActiveRecord::Base
|
92
|
+
belongs_to :job
|
93
|
+
acts_as_geolocated through: :job
|
94
|
+
end
|
95
|
+
```
|
96
|
+
|
97
|
+
### Querying the database
|
90
98
|
|
91
99
|
To query for all places within a given radius of 100 meters from the origin -22.951916,-43.210487 just use:
|
92
100
|
```ruby
|
@@ -98,6 +106,11 @@ You can also order the records based on the distance from a point
|
|
98
106
|
Place.within_radius(100, -22.951916,-43.210487).order_by_distance(-22.951916,-43.210487)
|
99
107
|
```
|
100
108
|
|
109
|
+
To query on associated models (the joins will be included for you):
|
110
|
+
```ruby
|
111
|
+
Job.within_radius(100, -22.951916,-43.210487)
|
112
|
+
```
|
113
|
+
|
101
114
|
The `within_radius` query performs two checks: first against the *bounding box*, followed by computing the exact distance for
|
102
115
|
all contained elements. The latter might be computationally expensive for big ranges.
|
103
116
|
So if precision is not an issue but query speed is, you might want to query against the bounding box only:
|
@@ -112,7 +125,7 @@ closest = Place.within_radius(100, *point).order_by_distance(*point).selecting_d
|
|
112
125
|
closest.distance
|
113
126
|
```
|
114
127
|
|
115
|
-
##Test Database
|
128
|
+
## Test Database
|
116
129
|
|
117
130
|
To have earthdistance enabled when you load your database schema (as happens in rake db:test:prepare), you
|
118
131
|
have two options.
|
@@ -128,12 +141,12 @@ This will change your schema dumps from Ruby to SQL. If you're
|
|
128
141
|
unsure about the implications of this change, we suggest reading this
|
129
142
|
[Rails Guide](http://guides.rubyonrails.org/migrations.html#schema-dumping-and-you).
|
130
143
|
|
131
|
-
##Help
|
144
|
+
## Help
|
132
145
|
|
133
146
|
You can use issues in github for that. Or else you can reach us at
|
134
147
|
twitter: [@dbiazus](https://twitter.com/#!/dbiazus)
|
135
148
|
|
136
|
-
##Note on Patches/Pull Requests
|
149
|
+
## Note on Patches/Pull Requests
|
137
150
|
|
138
151
|
|
139
152
|
* Fork the project.
|
@@ -142,6 +155,6 @@ twitter: [@dbiazus](https://twitter.com/#!/dbiazus)
|
|
142
155
|
* Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
143
156
|
* Send me a pull request. Bonus points for topic branches.
|
144
157
|
|
145
|
-
##Copyright
|
158
|
+
## Copyright
|
146
159
|
|
147
160
|
Copyright © 2010 Diogo Biazus. See LICENSE for details.
|
data/Rakefile
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
2
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "rubygems"
|
5
|
+
require "rspec/core/rake_task"
|
6
|
+
require "rdoc/task"
|
7
7
|
|
8
|
-
task :
|
8
|
+
task default: :spec
|
9
9
|
|
10
10
|
begin
|
11
11
|
Bundler.setup(:default, :development)
|
@@ -18,10 +18,9 @@ end
|
|
18
18
|
RSpec::Core::RakeTask.new(:spec)
|
19
19
|
|
20
20
|
RDoc::Task.new do |rdoc|
|
21
|
-
version = File.exist?(
|
22
|
-
rdoc.rdoc_dir =
|
21
|
+
version = File.exist?("VERSION") ? File.read("VERSION") : ""
|
22
|
+
rdoc.rdoc_dir = "rdoc"
|
23
23
|
rdoc.title = "activerecord-postgres-hstore #{version}"
|
24
|
-
rdoc.rdoc_files.include(
|
25
|
-
rdoc.rdoc_files.include(
|
24
|
+
rdoc.rdoc_files.include("README*")
|
25
|
+
rdoc.rdoc_files.include("lib/**/*.rb")
|
26
26
|
end
|
27
|
-
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
lib = File.expand_path(
|
3
|
-
|
2
|
+
lib = File.expand_path("../lib/", __FILE__)
|
3
|
+
$LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib)
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = "activerecord-postgres-earthdistance"
|
7
|
-
s.version = "0.
|
7
|
+
s.version = "0.5.0"
|
8
8
|
|
9
9
|
s.platform = Gem::Platform::RUBY
|
10
10
|
s.license = "MIT"
|
@@ -12,7 +12,9 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.email = "diogo@biazus.me"
|
13
13
|
s.homepage = "http://github.com/diogob/activerecord-postgres-earthdistance"
|
14
14
|
s.summary = "Check distances with latitude and longitude using PostgreSQL special indexes"
|
15
|
-
s.description = "This gem enables your model to query the database using the earthdistance
|
15
|
+
s.description = "This gem enables your model to query the database using the earthdistance \
|
16
|
+
extension. This should be much faster than using trigonometry functions over\
|
17
|
+
standart indexs."
|
16
18
|
s.required_ruby_version = ">= 1.8.7"
|
17
19
|
s.required_rubygems_version = ">= 1.3.6"
|
18
20
|
|
@@ -22,8 +24,13 @@ Gem::Specification.new do |s|
|
|
22
24
|
s.add_development_dependency "bundler"
|
23
25
|
s.add_development_dependency "rdoc"
|
24
26
|
s.add_development_dependency "rspec", "~> 2.11"
|
27
|
+
s.add_development_dependency "pry"
|
25
28
|
|
26
|
-
git_files =
|
29
|
+
git_files = begin
|
30
|
+
`git ls-files`.split("\n")
|
31
|
+
rescue
|
32
|
+
""
|
33
|
+
end
|
27
34
|
s.files = git_files
|
28
35
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
29
36
|
s.executables = []
|
@@ -3,14 +3,13 @@ require "activerecord-postgres-earthdistance/acts_as_geolocated"
|
|
3
3
|
module ActiveRecord
|
4
4
|
module ConnectionAdapters
|
5
5
|
module SchemaStatements
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
[table_name, table_name, (options[:lat] || 'lat'), (options[:lng] || 'lng')]
|
6
|
+
def add_earthdistance_index(table_name, options = {})
|
7
|
+
execute("CREATE INDEX %s_earthdistance_ix ON %s USING gist (ll_to_earth(%s, %s));")
|
8
|
+
.format([table_name, table_name, (options[:lat] || "lat"), (options[:lng] || "lng")])
|
10
9
|
end
|
11
10
|
|
12
|
-
def remove_earthdistance_index
|
13
|
-
execute
|
11
|
+
def remove_earthdistance_index(table_name)
|
12
|
+
execute("DROP INDEX %s_earthdistance_ix;").format([table_name])
|
14
13
|
end
|
15
14
|
end
|
16
15
|
end
|
@@ -4,57 +4,96 @@ module ActiveRecordPostgresEarthdistance
|
|
4
4
|
|
5
5
|
module ClassMethods
|
6
6
|
def acts_as_geolocated(options = {})
|
7
|
-
cattr_accessor :latitude_column, :longitude_column
|
7
|
+
cattr_accessor :latitude_column, :longitude_column, :through_table
|
8
8
|
self.latitude_column = options[:lat] || (column_names.include?("lat") ? "lat" : "latitude")
|
9
|
-
self.longitude_column = options[:lng] ||
|
9
|
+
self.longitude_column = options[:lng] ||
|
10
|
+
(column_names.include?("lng") ? "lng" : "longitude")
|
11
|
+
self.through_table = options[:through]
|
10
12
|
end
|
11
13
|
|
12
14
|
def within_box(radius, lat, lng)
|
13
|
-
earth_box = Arel::Nodes::NamedFunction.new(
|
14
|
-
|
15
|
+
earth_box = Arel::Nodes::NamedFunction.new(
|
16
|
+
"earth_box",
|
17
|
+
[Utils.ll_to_earth_coords(lat, lng), Utils.quote_value(radius)]
|
18
|
+
)
|
19
|
+
joins(through_table)
|
20
|
+
.where(
|
21
|
+
Arel::Nodes::InfixOperation.new(
|
22
|
+
"<@",
|
23
|
+
Utils.ll_to_earth_columns(through_table_klass),
|
24
|
+
earth_box
|
25
|
+
)
|
26
|
+
)
|
15
27
|
end
|
16
28
|
|
17
29
|
def within_radius(radius, lat, lng)
|
18
|
-
earth_distance =
|
19
|
-
within_box(radius, lat, lng)
|
30
|
+
earth_distance = Utils.earth_distance(through_table_klass, lat, lng)
|
31
|
+
within_box(radius, lat, lng)
|
32
|
+
.where(Arel::Nodes::InfixOperation.new("<=", earth_distance, Utils.quote_value(radius)))
|
20
33
|
end
|
21
34
|
|
22
35
|
def order_by_distance(lat, lng, order = "ASC")
|
23
|
-
earth_distance =
|
24
|
-
order("#{earth_distance.to_sql} #{order
|
36
|
+
earth_distance = Utils.earth_distance(through_table_klass, lat, lng)
|
37
|
+
joins(through_table).order("#{earth_distance.to_sql} #{order}")
|
25
38
|
end
|
26
|
-
end
|
27
39
|
|
28
|
-
|
29
|
-
def self.ll_to_earth_columns(klass)
|
30
|
-
Arel::Nodes::NamedFunction.new('ll_to_earth', [klass.arel_table[klass.latitude_column], klass.arel_table[klass.longitude_column]])
|
31
|
-
end
|
40
|
+
private
|
32
41
|
|
33
|
-
def
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
def self.quote_value value
|
38
|
-
if Arel::Nodes.respond_to?(:build_quoted) # for arel >= 6.0.0
|
39
|
-
Arel::Nodes.build_quoted(value)
|
42
|
+
def through_table_klass
|
43
|
+
if through_table.present?
|
44
|
+
reflections[through_table.to_s].klass
|
40
45
|
else
|
41
|
-
|
46
|
+
self
|
42
47
|
end
|
43
48
|
end
|
44
49
|
end
|
45
50
|
end
|
46
51
|
|
52
|
+
module Utils
|
53
|
+
def self.earth_distance(through_table_klass, lat, lng, aliaz = nil)
|
54
|
+
Arel::Nodes::NamedFunction.new(
|
55
|
+
"earth_distance",
|
56
|
+
[
|
57
|
+
ll_to_earth_columns(through_table_klass),
|
58
|
+
ll_to_earth_coords(lat, lng)
|
59
|
+
],
|
60
|
+
aliaz
|
61
|
+
)
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.ll_to_earth_columns(klass)
|
65
|
+
Arel::Nodes::NamedFunction.new(
|
66
|
+
"ll_to_earth",
|
67
|
+
[klass.arel_table[klass.latitude_column], klass.arel_table[klass.longitude_column]]
|
68
|
+
)
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.ll_to_earth_coords(lat, lng)
|
72
|
+
Arel::Nodes::NamedFunction.new("ll_to_earth", [quote_value(lat), quote_value(lng)])
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.quote_value(value)
|
76
|
+
if Arel::Nodes.respond_to?(:build_quoted) # for arel >= 6.0.0
|
77
|
+
Arel::Nodes.build_quoted(value)
|
78
|
+
else
|
79
|
+
value
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
47
84
|
module QueryMethods
|
48
|
-
def selecting_distance_from
|
85
|
+
def selecting_distance_from(lat, lng, name = "distance", include_default_columns = true)
|
49
86
|
clone.tap do |relation|
|
50
87
|
values = []
|
51
|
-
|
52
|
-
|
88
|
+
if relation.select_values.empty? && include_default_columns
|
89
|
+
values << relation.arel_table[Arel.star]
|
90
|
+
end
|
91
|
+
values << Utils.earth_distance(self, lat, lng, name)
|
92
|
+
|
53
93
|
relation.select_values = values
|
54
94
|
end
|
55
95
|
end
|
56
96
|
end
|
57
|
-
|
58
97
|
end
|
59
98
|
|
60
99
|
ActiveRecord::Base.send :include, ActiveRecordPostgresEarthdistance::ActsAsGeolocated
|
@@ -1,13 +1,13 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
1
|
+
require "rails"
|
2
|
+
require "rails/generators"
|
3
|
+
require "rails/generators/migration"
|
4
|
+
require "active_record"
|
5
5
|
# = Earth Distance Railtie
|
6
6
|
#
|
7
7
|
# Creates a new railtie for 2 reasons:
|
8
8
|
#
|
9
9
|
# * Initialize ActiveRecord properly
|
10
|
-
# * Add earthdistance:setup generator
|
10
|
+
# * Add earthdistance:setup generator
|
11
11
|
class EarthDistance < Rails::Railtie
|
12
12
|
# Creates the earthdistance:setup generator. This generator creates a migration that
|
13
13
|
# adds earthdistance support for your database. If fact, it's just the sql from the
|
@@ -20,21 +20,19 @@ class EarthDistance < Rails::Railtie
|
|
20
20
|
include Rails::Generators::Migration
|
21
21
|
|
22
22
|
def self.source_root
|
23
|
-
@source_root ||= File.join(File.dirname(__FILE__),
|
23
|
+
@source_root ||= File.join(File.dirname(__FILE__), "..", "templates")
|
24
24
|
end
|
25
25
|
|
26
26
|
def self.next_migration_number(dirname)
|
27
27
|
if ActiveRecord::Base.timestamped_migrations
|
28
28
|
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
29
29
|
else
|
30
|
-
"%.3d"
|
30
|
+
"%.3d".format(current_migration_number(dirname) + 1)
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
34
|
def create_migration_file
|
35
|
-
migration_template
|
35
|
+
migration_template "setup_earthdistance.rb", "db/migrate/setup_earthdistance.rb"
|
36
36
|
end
|
37
|
-
|
38
37
|
end
|
39
38
|
end
|
40
|
-
|
@@ -1,10 +1,10 @@
|
|
1
|
-
require
|
1
|
+
require "spec_helper"
|
2
2
|
|
3
3
|
describe "ActiveRecord::Base.act_as_geolocated" do
|
4
|
-
describe
|
4
|
+
describe "ActiveRecord::Base" do
|
5
5
|
context "when using .where with a model instance as a placeholder" do
|
6
6
|
let(:place) { Place.create! }
|
7
|
-
subject { Place.where(
|
7
|
+
subject { Place.where("id = ?", place).first }
|
8
8
|
after { place.destroy! }
|
9
9
|
|
10
10
|
it { should == place }
|
@@ -16,7 +16,7 @@ describe "ActiveRecord::Base.act_as_geolocated" do
|
|
16
16
|
|
17
17
|
subject { Place.within_box(test_data[:radius], test_data[:lat], test_data[:lng]) }
|
18
18
|
|
19
|
-
before(:all) { @place = Place.create!(:
|
19
|
+
before(:all) { @place = Place.create!(lat: -30.0277041, lng: -51.2287346) }
|
20
20
|
after(:all) { @place.destroy }
|
21
21
|
|
22
22
|
context "when query with null data" do
|
@@ -24,19 +24,19 @@ describe "ActiveRecord::Base.act_as_geolocated" do
|
|
24
24
|
end
|
25
25
|
|
26
26
|
context "when query for the exact same point with radius 0" do
|
27
|
-
let(:test_data) { { lat: -30.0277041, lng: -51.2287346
|
27
|
+
let(:test_data) { { lat: -30.0277041, lng: -51.2287346, radius: 0 } }
|
28
28
|
|
29
29
|
it { should == [@place] }
|
30
30
|
end
|
31
31
|
|
32
32
|
context "when query for place within the box" do
|
33
|
-
let(:test_data) { { radius:
|
33
|
+
let(:test_data) { { radius: 4_000_000, lat: -27.5969039, lng: -48.5494544 } }
|
34
34
|
|
35
35
|
it { should == [@place] }
|
36
36
|
end
|
37
37
|
|
38
38
|
context "when query for place within the box, but outside the radius" do
|
39
|
-
let(:test_data) { { radius:
|
39
|
+
let(:test_data) { { radius: 300_000, lat: -27.5969039, lng: -48.5494544 } }
|
40
40
|
|
41
41
|
it "the place shouldn't be within the radius" do
|
42
42
|
Place.within_radius(test_data[:radius], test_data[:lat], test_data[:lng]).should be_empty
|
@@ -56,21 +56,28 @@ describe "ActiveRecord::Base.act_as_geolocated" do
|
|
56
56
|
subject { Place.within_box(test_data[:radius], test_data[:lat], test_data[:lng]) }
|
57
57
|
|
58
58
|
it "should work with objects having columns with the same name" do
|
59
|
-
expect
|
60
|
-
|
59
|
+
expect do
|
60
|
+
Place
|
61
|
+
.joins(:events)
|
62
|
+
.within_radius(test_data[:radius], test_data[:lat], test_data[:lng]).to_a
|
63
|
+
end.to_not raise_error
|
61
64
|
end
|
62
65
|
|
63
66
|
it "should work with nested associations" do
|
64
|
-
expect
|
67
|
+
expect do
|
68
|
+
Event
|
69
|
+
.joins(:events)
|
70
|
+
.within_radius(test_data[:radius], test_data[:lat], test_data[:lng]).to_a
|
71
|
+
end.to_not raise_error
|
65
72
|
end
|
66
73
|
end
|
67
74
|
end
|
68
75
|
|
69
76
|
describe "#within_radius" do
|
70
|
-
let(:test_data){ {lat: nil, lng: nil, radius: nil} }
|
71
|
-
subject{ Place.within_radius(test_data[:radius], test_data[:lat], test_data[:lng]) }
|
77
|
+
let(:test_data) { { lat: nil, lng: nil, radius: nil } }
|
78
|
+
subject { Place.within_radius(test_data[:radius], test_data[:lat], test_data[:lng]) }
|
72
79
|
before(:all) do
|
73
|
-
@place = Place.create!(:
|
80
|
+
@place = Place.create!(lat: -30.0277041, lng: -51.2287346)
|
74
81
|
end
|
75
82
|
|
76
83
|
after(:all) do
|
@@ -78,66 +85,121 @@ describe "ActiveRecord::Base.act_as_geolocated" do
|
|
78
85
|
end
|
79
86
|
|
80
87
|
context "when query with null data" do
|
81
|
-
it{ should == [] }
|
88
|
+
it { should == [] }
|
82
89
|
end
|
83
90
|
|
84
91
|
context "when query for the exact same point with radius 0" do
|
85
|
-
let(:test_data){{lat: -30.0277041, lng: -51.2287346
|
86
|
-
it{ should == [@place] }
|
92
|
+
let(:test_data) { { lat: -30.0277041, lng: -51.2287346, radius: 0 } }
|
93
|
+
it { should == [@place] }
|
87
94
|
end
|
88
95
|
|
89
96
|
context "when query for place within radius" do
|
90
|
-
let(:test_data){ {radius:
|
91
|
-
it{ should == [@place] }
|
97
|
+
let(:test_data) { { radius: 4_000_000, lat: -27.5969039, lng: -48.5494544 } }
|
98
|
+
it { should == [@place] }
|
92
99
|
end
|
93
100
|
|
94
101
|
context "when query for place outside the radius" do
|
95
|
-
let(:test_data){ {radius: 1000, lat: -27.5969039, lng: -48.5494544} }
|
96
|
-
it{ should == [] }
|
102
|
+
let(:test_data) { { radius: 1000, lat: -27.5969039, lng: -48.5494544 } }
|
103
|
+
it { should == [] }
|
104
|
+
end
|
105
|
+
|
106
|
+
context "uses lat and long of through table" do
|
107
|
+
subject do
|
108
|
+
Job.within_radius(test_data[:radius], test_data[:lat], test_data[:lng])
|
109
|
+
end
|
110
|
+
|
111
|
+
before(:all) do
|
112
|
+
@event = Event.create!(lat: -30.0277041, lng: -51.2287346)
|
113
|
+
@job = Job.create!(event: @event)
|
114
|
+
end
|
115
|
+
|
116
|
+
after(:all) do
|
117
|
+
@event.destroy
|
118
|
+
@job.destroy
|
119
|
+
end
|
120
|
+
|
121
|
+
context "when query with null data" do
|
122
|
+
it { should == [] }
|
123
|
+
end
|
124
|
+
|
125
|
+
context "when query for the exact same point with radius 0" do
|
126
|
+
let(:test_data) { { lat: -30.0277041, lng: -51.2287346, radius: 0 } }
|
127
|
+
it { should == [@job] }
|
128
|
+
end
|
129
|
+
|
130
|
+
context "when query for place within radius" do
|
131
|
+
let(:test_data) { { radius: 4_000_000, lat: -27.5969039, lng: -48.5494544 } }
|
132
|
+
it { should == [@job] }
|
133
|
+
end
|
134
|
+
|
135
|
+
context "when query for place outside the radius" do
|
136
|
+
let(:test_data) { { radius: 1000, lat: -27.5969039, lng: -48.5494544 } }
|
137
|
+
it { should == [] }
|
138
|
+
end
|
97
139
|
end
|
98
140
|
end
|
99
141
|
|
100
142
|
describe "#order_by_distance" do
|
101
|
-
let(:current_location){ {lat: nil, lng: nil, radius: nil} }
|
102
|
-
|
143
|
+
let(:current_location) { { lat: nil, lng: nil, radius: nil } }
|
144
|
+
|
145
|
+
subject { Place.order_by_distance(current_location[:lat], current_location[:lng]) }
|
146
|
+
|
103
147
|
before(:all) do
|
104
|
-
@
|
105
|
-
@
|
148
|
+
@amsterdam = Place.create!(lat: 52.370216, lng: 4.895168)
|
149
|
+
@berlin = Place.create!(lat: 52.520007, lng: 13.404954) # Berlin
|
150
|
+
@event_in_amsterdam = Event.create!(lat: 52.370216, lng: 4.895168)
|
151
|
+
@event_in_berlin = Event.create!(lat: 52.520007, lng: 13.404954)
|
152
|
+
@amsterdam_job = Job.create!(event: @event_in_amsterdam)
|
153
|
+
@berlin_job = Job.create!(event: @event_in_berlin)
|
106
154
|
end
|
155
|
+
|
107
156
|
after(:all) do
|
108
|
-
@
|
109
|
-
@
|
157
|
+
@amsterdam.destroy
|
158
|
+
@berlin.destroy
|
159
|
+
@event_in_amsterdam.destroy
|
160
|
+
@event_in_berlin.destroy
|
161
|
+
@amsterdam_job.destroy
|
162
|
+
@berlin_job.destroy
|
163
|
+
end
|
164
|
+
|
165
|
+
context "uses lat and long of through table" do
|
166
|
+
subject do
|
167
|
+
Job.order_by_distance(current_location[:lat], current_location[:lng])
|
168
|
+
end
|
169
|
+
|
170
|
+
let(:current_location) { { lat: 51.511214, lng: 0.119824 } } # London
|
171
|
+
it { should == [@amsterdam_job, @berlin_job] }
|
110
172
|
end
|
111
173
|
|
112
174
|
context "when sorting on distance" do
|
113
|
-
let(:current_location){{lat: 51.511214, lng: 0.119824}} #London
|
114
|
-
it{ should == [@
|
175
|
+
let(:current_location) { { lat: 51.511214, lng: 0.119824 } } # London
|
176
|
+
it { should == [@amsterdam, @berlin] }
|
115
177
|
end
|
116
178
|
|
117
179
|
context "when sorting on distance from another location" do
|
118
|
-
let(:current_location){{lat: 52.229676, lng: 21.012229}} #Warsaw
|
119
|
-
it{ should == [@
|
180
|
+
let(:current_location) { { lat: 52.229676, lng: 21.012229 } } # Warsaw
|
181
|
+
it { should == [@berlin, @amsterdam] }
|
120
182
|
end
|
121
183
|
end
|
122
184
|
|
123
185
|
describe "#selecting_distance_from" do
|
124
|
-
let(:current_location){ {lat: nil, lng: nil, radius: nil} }
|
186
|
+
let(:current_location) { { lat: nil, lng: nil, radius: nil } }
|
125
187
|
subject do
|
126
|
-
Place
|
127
|
-
order_by_distance(current_location[:lat], current_location[:lng])
|
128
|
-
selecting_distance_from(current_location[:lat], current_location[:lng])
|
129
|
-
first
|
130
|
-
try{|p| [p.data, p.distance.to_f] }
|
188
|
+
Place
|
189
|
+
.order_by_distance(current_location[:lat], current_location[:lng])
|
190
|
+
.selecting_distance_from(current_location[:lat], current_location[:lng])
|
191
|
+
.first
|
192
|
+
.try { |p| [p.data, p.distance.to_f] }
|
131
193
|
end
|
132
194
|
before(:all) do
|
133
|
-
@place = Place.create!(:
|
195
|
+
@place = Place.create!(data: "Amsterdam", lat: 52.370216, lng: 4.895168) # Amsterdam
|
134
196
|
end
|
135
197
|
after(:all) do
|
136
198
|
@place.destroy
|
137
199
|
end
|
138
200
|
context "when selecting distance" do
|
139
|
-
let(:current_location){{lat: 52.229676, lng: 21.012229}} #Warsaw
|
140
|
-
it{ should == ["Amsterdam",
|
201
|
+
let(:current_location) { { lat: 52.229676, lng: 21.012229 } } # Warsaw
|
202
|
+
it { should == ["Amsterdam", 1_095_013.87438311] }
|
141
203
|
end
|
142
204
|
end
|
143
205
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__),
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
3
|
+
require "rspec"
|
4
|
+
require "rspec/autorun"
|
5
|
+
require "activerecord-postgres-earthdistance"
|
6
|
+
require "active_record"
|
7
7
|
|
8
8
|
RSpec.configure do |config|
|
9
9
|
config.before(:suite) do
|
@@ -11,12 +11,12 @@ RSpec.configure do |config|
|
|
11
11
|
# I do not use database users or password for the tests, using ident authentication instead
|
12
12
|
begin
|
13
13
|
ActiveRecord::Base.establish_connection(
|
14
|
-
:
|
15
|
-
:
|
16
|
-
:
|
17
|
-
:
|
18
|
-
:
|
19
|
-
:
|
14
|
+
adapter: "postgresql",
|
15
|
+
host: "localhost",
|
16
|
+
username: "postgres",
|
17
|
+
password: "postgres",
|
18
|
+
port: 5432,
|
19
|
+
database: "ar_pg_earthdistance_test"
|
20
20
|
)
|
21
21
|
ActiveRecord::Base.connection.execute %{
|
22
22
|
SET client_min_messages TO warning;
|
@@ -24,26 +24,35 @@ RSpec.configure do |config|
|
|
24
24
|
CREATE EXTENSION IF NOT EXISTS earthdistance;
|
25
25
|
DROP TABLE IF EXISTS places;
|
26
26
|
DROP TABLE IF EXISTS events;
|
27
|
+
DROP TABLE IF EXISTS jobs;
|
27
28
|
CREATE TABLE places (id serial PRIMARY KEY, data text, lat float8, lng float8);
|
28
|
-
CREATE TABLE events (
|
29
|
+
CREATE TABLE events (
|
30
|
+
id serial PRIMARY KEY,
|
31
|
+
event_id integer,
|
32
|
+
place_id integer,
|
33
|
+
data text,
|
34
|
+
lat float8,
|
35
|
+
lng float8
|
36
|
+
);
|
37
|
+
CREATE TABLE jobs (id serial PRIMARY KEY, event_id integer);
|
29
38
|
}
|
30
|
-
rescue
|
39
|
+
rescue StandardError => e
|
31
40
|
puts "Exception: #{e}"
|
32
41
|
ActiveRecord::Base.establish_connection(
|
33
|
-
:
|
34
|
-
:
|
35
|
-
:
|
36
|
-
:
|
37
|
-
:
|
38
|
-
:
|
42
|
+
adapter: "postgresql",
|
43
|
+
host: "localhost",
|
44
|
+
username: "postgres",
|
45
|
+
password: "postgres",
|
46
|
+
port: 5432,
|
47
|
+
database: "postgres"
|
39
48
|
)
|
40
49
|
ActiveRecord::Base.connection.execute "CREATE DATABASE ar_pg_earthdistance_test"
|
41
50
|
retry
|
42
51
|
end
|
43
52
|
|
44
53
|
# Load models used in spec
|
45
|
-
require
|
46
|
-
require
|
54
|
+
require "fixtures/place"
|
55
|
+
require "fixtures/event"
|
56
|
+
require "fixtures/job"
|
47
57
|
end
|
48
|
-
|
49
58
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-postgres-earthdistance
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Diogo Biazus
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-11-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -94,8 +94,22 @@ dependencies:
|
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '2.11'
|
97
|
-
|
98
|
-
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: pry
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: This gem enables your model to query the database using the earthdistance extension.
|
112
|
+
This should be much faster than using trigonometry functions over standart
|
99
113
|
indexs.
|
100
114
|
email: diogo@biazus.me
|
101
115
|
executables: []
|
@@ -105,6 +119,7 @@ files:
|
|
105
119
|
- ".document"
|
106
120
|
- ".gitignore"
|
107
121
|
- ".rspec"
|
122
|
+
- ".rubocop.yml"
|
108
123
|
- ".travis.yml"
|
109
124
|
- Gemfile
|
110
125
|
- Gemfile.lock
|
@@ -121,6 +136,7 @@ files:
|
|
121
136
|
- lib/templates/setup_earthdistance.rb
|
122
137
|
- spec/act_as_geolocated_spec.rb
|
123
138
|
- spec/fixtures/event.rb
|
139
|
+
- spec/fixtures/job.rb
|
124
140
|
- spec/fixtures/place.rb
|
125
141
|
- spec/spec_helper.rb
|
126
142
|
homepage: http://github.com/diogob/activerecord-postgres-earthdistance
|
@@ -150,5 +166,6 @@ summary: Check distances with latitude and longitude using PostgreSQL special in
|
|
150
166
|
test_files:
|
151
167
|
- spec/act_as_geolocated_spec.rb
|
152
168
|
- spec/fixtures/event.rb
|
169
|
+
- spec/fixtures/job.rb
|
153
170
|
- spec/fixtures/place.rb
|
154
171
|
- spec/spec_helper.rb
|