rgeo-activerecord 6.2.2 → 7.0.0
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 +4 -4
- data/History.md +5 -0
- data/README.md +52 -26
- data/lib/rgeo/active_record/arel_spatial_queries.rb +13 -17
- data/lib/rgeo/active_record/spatial_factory_store.rb +52 -12
- data/lib/rgeo/active_record/version.rb +1 -1
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9c1442b0141a1655c582e412962a3328b702e52da302e3a4874a3d22ee3f8fbc
|
4
|
+
data.tar.gz: 86933cf076e3c728ea34d3918bff61f56baef30c7e31dce99e56093a2049a5cd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d4b10c1f4ab732aa52545bce0f920fd36511e68c4c560b5f29f3b5907243e82cc8723bb54abd7ce1277a1857d2783749e0d1bc8a452117d4b9b7f5f6da1262ea
|
7
|
+
data.tar.gz: 46b20c80597ca7dd822987fcf2592c56d68c0f413684eb5e87de012a5139f77a8b6ded059553001b5791c7f6be867a9897b01b4aca4ef5dda361d4259482d79b
|
data/History.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
### 7.0.0 / 2020-12-15
|
2
|
+
|
3
|
+
* Update visit_* methods and Arel interface to support RGeo features.
|
4
|
+
* Rework SpatialFactoryStore to support hierarchical matches and fallbacks.
|
5
|
+
|
1
6
|
### 6.2.2 / 2020-11-20
|
2
7
|
|
3
8
|
* Removed `Arel::Visitor::DepthFirst` for ActiveRecord 6.1 compatibility (kamipo)
|
data/README.md
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
## RGeo::ActiveRecord
|
2
2
|
|
3
|
-
[](https://rubygems.org/gems/rgeo-activerecord)
|
4
|
+
[](https://github.com/rgeo/rgeo-activerecord/actions?query=workflow%3A%22Tests%22)
|
5
5
|
[](https://codeclimate.com/github/rgeo/rgeo-activerecord)
|
6
6
|
|
7
|
-
RGeo::ActiveRecord is an optional [RGeo](http://github.com/
|
7
|
+
RGeo::ActiveRecord is an optional [RGeo](http://github.com/rgeo/rgeo) module
|
8
8
|
providing spatial extensions for ActiveRecord, as well as a set of helpers for
|
9
9
|
writing spatial ActiveRecord adapters based on RGeo.
|
10
10
|
|
@@ -28,6 +28,7 @@ Gemfile:
|
|
28
28
|
```ruby
|
29
29
|
gem 'rgeo-activerecord'
|
30
30
|
```
|
31
|
+
|
31
32
|
Version `6.1` supports ActiveRecord 5.x and 6.0 with `rgeo` 1.0+.
|
32
33
|
|
33
34
|
Version `6.0` supports ActiveRecord 5.x with `rgeo` 1.x.
|
@@ -40,32 +41,28 @@ Version `1.1.0` supports ActiveRecord 4.0 and 4.1
|
|
40
41
|
|
41
42
|
Version `0.6.0` supports earlier versions of ruby and ActiveRecord:
|
42
43
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
- Ruby 1.8.7 or later
|
45
|
+
- ActiveRecord 3.0.3 - 3.2.x
|
46
|
+
- rgeo 0.3.20 or later
|
47
|
+
- arel 2.0.6 or later
|
47
48
|
|
48
49
|
### Spatial Factories for Columns
|
49
50
|
|
50
|
-
|
51
|
-
are no longer tied to their database column in ActiveRecord 4.2.
|
51
|
+
**_This is an introduction. More details are available in the [wiki entry](https://github.com/rgeo/rgeo-activerecord/wiki/Spatial-Factory-Store)._**
|
52
52
|
|
53
|
-
Register spatial factories in the `SpatialFactoryStore` singleton class. Each spatial
|
54
|
-
in your
|
55
|
-
a factory matching the properties of its type. For example, you can set a different
|
56
|
-
spatial factory for point types, or for types matching a specific SRID, or having
|
53
|
+
Register spatial factories in the `SpatialFactoryStore` singleton class to parse spatial data. Each spatial column
|
54
|
+
in your models will use the `SpatialFactoryStore` to parse the stored WKB into an RGeo Feature. The factory from the `SpatialFactoryStore` is chosen based on metadata from the spatial column and the attributes with which the factory was registered to the store. For example, you can set a factory for point types, for types matching a specific SRID, having
|
57
55
|
a Z coordinate, or any combination of attributes.
|
58
56
|
|
59
|
-
The supported keys when registering a spatial type are listed here with their
|
60
|
-
and other allowed values:
|
57
|
+
The supported keys when registering a spatial type are listed here with their expected values:
|
61
58
|
|
62
59
|
```
|
63
|
-
geo_type:
|
64
|
-
|
65
|
-
has_m:
|
66
|
-
has_z:
|
67
|
-
sql_type:
|
68
|
-
srid:
|
60
|
+
geo_type: string # geometry, point, polygon, line_string, geometry_collection,
|
61
|
+
# multi_line_string, multi_point, multi_polygon
|
62
|
+
has_m: boolean # true, false
|
63
|
+
has_z: boolean # true, false
|
64
|
+
sql_type: string # geometry, geography
|
65
|
+
srid: int # (any valid SRID)
|
69
66
|
```
|
70
67
|
|
71
68
|
The default factories are `RGeo::Geographic.spherical_factory` for
|
@@ -73,7 +70,7 @@ geographic types, and `RGeo::Cartesian.preferred_factory` for geometric types.
|
|
73
70
|
|
74
71
|
Here is an example setup:
|
75
72
|
|
76
|
-
```
|
73
|
+
```rb
|
77
74
|
RGeo::ActiveRecord::SpatialFactoryStore.instance.tap do |config|
|
78
75
|
# By default, use the GEOS implementation for spatial columns.
|
79
76
|
config.default = RGeo::Geos.factory_generator
|
@@ -83,6 +80,33 @@ RGeo::ActiveRecord::SpatialFactoryStore.instance.tap do |config|
|
|
83
80
|
end
|
84
81
|
```
|
85
82
|
|
83
|
+
_NOTE: `rgeo_factory_generator` and related methods were removed in version 4.0, since column types
|
84
|
+
are no longer tied to their database column in ActiveRecord 4.2._
|
85
|
+
|
86
|
+
### Spatial Queries
|
87
|
+
|
88
|
+
RGeo-ActiveRecord provides an Arel interface to use functions commonly found in spatial databases. The interface also allows for the creation of your own spatial functions if they are not defined.
|
89
|
+
|
90
|
+
Here is an example using `st_contains`:
|
91
|
+
|
92
|
+
```rb
|
93
|
+
point = RGeo::Geos.factory(srid: 0).point(1,1)
|
94
|
+
|
95
|
+
buildings = Building.arel_table
|
96
|
+
containing_buiildings = Building.where(buildings[:geom].st_contains(point))
|
97
|
+
```
|
98
|
+
|
99
|
+
or using the `Arel.spatial` node:
|
100
|
+
|
101
|
+
```rb
|
102
|
+
point = "SRID=0;POINT(1,1)"
|
103
|
+
|
104
|
+
buildings = Building.arel_table
|
105
|
+
containing_buiildings = Building.where(buildings[:geom].st_contains(Arel.spatial(point)))
|
106
|
+
```
|
107
|
+
|
108
|
+
_Note: If you pass a WKT representation into an st_function, you should prepend the string with SRID=your_srid, otherwise the database will assume SRID=0 which may cause errors on certain operations._
|
109
|
+
|
86
110
|
### RGeo Dependency
|
87
111
|
|
88
112
|
See the README for the [rgeo](https://github.com/rgeo/rgeo) gem, a dependency, for further
|
@@ -107,15 +131,17 @@ http://groups.google.com/group/rgeo-users
|
|
107
131
|
### Acknowledgments
|
108
132
|
|
109
133
|
[Daniel Azuma](http://www.daniel-azuma.com) created RGeo.
|
110
|
-
[Tee Parham](http://twitter.com/teeparham) is
|
134
|
+
[Tee Parham](http://twitter.com/teeparham) is a former maintainer.
|
135
|
+
[Keith Doggett](http://www.github.com/keithdoggett) is a current maintainer.
|
136
|
+
[Ulysse Buonomo](http://www.github.com/BuonOmo) is a current maintainer.
|
111
137
|
|
112
138
|
Development is supported by:
|
113
139
|
|
114
|
-
|
115
|
-
|
140
|
+
- [Klaxit](https://www.klaxit.com)
|
141
|
+
- Goldfish Ads
|
116
142
|
|
117
143
|
### License
|
118
144
|
|
119
|
-
Copyright
|
145
|
+
Copyright 2020 Daniel Azuma, Tee Parham
|
120
146
|
|
121
147
|
https://github.com/rgeo/rgeo-activerecord/blob/master/LICENSE.txt
|
@@ -24,14 +24,13 @@ module RGeo
|
|
24
24
|
|
25
25
|
def visit_RGeo_ActiveRecord_SpatialNamedFunction(node, collector)
|
26
26
|
name = st_func(node.name)
|
27
|
-
exprs = []
|
28
|
-
node.expressions.each_with_index do |expr, index|
|
29
|
-
exprs << (node.spatial_argument?(index) ? visit_in_spatial_context(expr, collector) : visit(expr, collector))
|
30
|
-
end
|
31
27
|
collector << name
|
32
28
|
collector << "("
|
33
29
|
collector << "DISTINCT " if node.distinct
|
34
|
-
|
30
|
+
node.expressions.each_with_index do |expr, index|
|
31
|
+
node.spatial_argument?(index) ? visit_in_spatial_context(expr, collector) : visit(expr, collector)
|
32
|
+
collector << ", " unless index == node.expressions.size - 1
|
33
|
+
end
|
35
34
|
collector << ")"
|
36
35
|
collector << " AS #{visit(node.alias, collector)}" if node.alias
|
37
36
|
collector
|
@@ -41,13 +40,15 @@ module RGeo
|
|
41
40
|
# The node must be a string (in which case it is treated as WKT),
|
42
41
|
# an RGeo feature, or a spatial attribute.
|
43
42
|
def visit_in_spatial_context(node, collector)
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
collector <<
|
49
|
-
|
50
|
-
|
43
|
+
if node.is_a?(String)
|
44
|
+
collector << "#{st_func('ST_GeomFromText')}(#{quote(node)})"
|
45
|
+
elsif node.is_a?(RGeo::Feature::Instance)
|
46
|
+
srid = node.srid
|
47
|
+
collector << "#{st_func('ST_GeomFromText')}(#{quote(node.to_s)}, #{srid})"
|
48
|
+
elsif node.is_a?(RGeo::Cartesian::BoundingBox)
|
49
|
+
geom = node.to_geometry
|
50
|
+
srid = geom.srid
|
51
|
+
collector << "#{st_func('ST_GeomFromText')}(#{quote(geom.to_s)}, #{srid})"
|
51
52
|
else
|
52
53
|
visit(node, collector)
|
53
54
|
end
|
@@ -86,11 +87,6 @@ module RGeo
|
|
86
87
|
alias :visit_RGeo_Cartesian_BoundingBox :visit_String
|
87
88
|
end
|
88
89
|
|
89
|
-
Arel::Visitors::ToSql.class_eval do
|
90
|
-
alias :visit_RGeo_Feature_Instance :visit_String
|
91
|
-
alias :visit_RGeo_Cartesian_BoundingBox :visit_String
|
92
|
-
end
|
93
|
-
|
94
90
|
# A NamedFunction subclass that keeps track of the spatial-ness of
|
95
91
|
# the arguments and return values, so that it can provide context to
|
96
92
|
# visitors that want to interpret syntax differently when dealing with
|
@@ -4,16 +4,17 @@ module RGeo
|
|
4
4
|
module ActiveRecord
|
5
5
|
class SpatialFactoryStore
|
6
6
|
include Singleton
|
7
|
+
Entry = Struct.new(:attrs, :factory)
|
7
8
|
|
8
9
|
attr_accessor :registry
|
9
10
|
|
10
11
|
def initialize
|
11
|
-
@registry =
|
12
|
+
@registry = []
|
12
13
|
@default = nil
|
13
14
|
end
|
14
15
|
|
15
16
|
def register(factory, attrs = {})
|
16
|
-
registry
|
17
|
+
registry.push(Entry.new(filter_attrs(attrs), factory))
|
17
18
|
end
|
18
19
|
|
19
20
|
def default(attrs = {})
|
@@ -25,11 +26,11 @@ module RGeo
|
|
25
26
|
end
|
26
27
|
|
27
28
|
def factory(attrs)
|
28
|
-
|
29
|
+
closest_factory(attrs) || default(attrs)
|
29
30
|
end
|
30
31
|
|
31
32
|
def clear
|
32
|
-
@registry =
|
33
|
+
@registry = []
|
33
34
|
end
|
34
35
|
|
35
36
|
private
|
@@ -50,14 +51,53 @@ module RGeo
|
|
50
51
|
}
|
51
52
|
end
|
52
53
|
|
53
|
-
def
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
54
|
+
def filter_attrs(attrs)
|
55
|
+
attrs.slice(:geo_type, :has_m, :has_z, :sql_type, :srid)
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# Match attrs to the closest equal to or less specific factory
|
60
|
+
#
|
61
|
+
# That means that attrs can at most be matched to an Entry with the same
|
62
|
+
# number of keys as it. But could match with a factory with only 1 key
|
63
|
+
# in its attrs.
|
64
|
+
#
|
65
|
+
# Examples:
|
66
|
+
# attrs = {sql_type: "geometry" }, entry_attrs = {sql_type: "geometry", geo_type: "point"}
|
67
|
+
# is not a match because the entry is more specific than attrs
|
68
|
+
#
|
69
|
+
# attrs = {sql_type: "geometry", geo_type: "point"}, entry_attrs = {sql_type: "geometry"}
|
70
|
+
# is a match because the entry is less specific than attrs and would be the fallback for all "geometry" types
|
71
|
+
#
|
72
|
+
# attrs = {sql_type: "geometry", geo_type: "point"}, entry_attrs = {sql_type: "geometry", geo_type: "linestring"}
|
73
|
+
# is not a match because there are mismatched keys
|
74
|
+
#
|
75
|
+
# If there is no match, nil is returned
|
76
|
+
def closest_factory(attrs)
|
77
|
+
max_matches = 0
|
78
|
+
registry.reduce(nil) do |selected_fac, entry|
|
79
|
+
cmp = cmp_attrs(attrs, entry.attrs)
|
80
|
+
if cmp > max_matches
|
81
|
+
max_matches = cmp
|
82
|
+
entry.factory
|
83
|
+
else
|
84
|
+
selected_fac
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
##
|
90
|
+
# Returns number of common key/values
|
91
|
+
# or -1 if oth is bigger than attrs, or they have a mismatched key/value pair
|
92
|
+
def cmp_attrs(attrs, oth)
|
93
|
+
return -1 if oth.size > attrs.size
|
94
|
+
matches = 0
|
95
|
+
attrs.each do |k, v|
|
96
|
+
next if oth[k].nil?
|
97
|
+
return -1 unless v == oth[k]
|
98
|
+
matches += 1
|
99
|
+
end
|
100
|
+
matches
|
61
101
|
end
|
62
102
|
end
|
63
103
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rgeo-activerecord
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 7.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Azuma
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2020-12-
|
12
|
+
date: 2020-12-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -123,6 +123,20 @@ dependencies:
|
|
123
123
|
- - ">="
|
124
124
|
- !ruby/object:Gem::Version
|
125
125
|
version: 1.0.0
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: simplecov
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: 0.20.0
|
133
|
+
type: :development
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: 0.20.0
|
126
140
|
description: RGeo is a geospatial data library for Ruby. RGeo::ActiveRecord is an
|
127
141
|
optional RGeo module providing some spatial extensions to ActiveRecord, as well
|
128
142
|
as common tools used by RGeo-based spatial adapters.
|
@@ -164,7 +178,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
164
178
|
- !ruby/object:Gem::Version
|
165
179
|
version: '0'
|
166
180
|
requirements: []
|
167
|
-
rubygems_version: 3.0.
|
181
|
+
rubygems_version: 3.0.8
|
168
182
|
signing_key:
|
169
183
|
specification_version: 4
|
170
184
|
summary: An RGeo module providing spatial extensions to ActiveRecord.
|