rgeo-activerecord 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +5 -0
- data/lib/rgeo/active_record/ar_factory_settings.rb +40 -43
- data/lib/rgeo/active_record/arel_spatial_queries.rb +29 -30
- data/lib/rgeo/active_record/common_adapter_elements.rb +51 -43
- data/lib/rgeo/active_record/geometry_mixin.rb +11 -12
- data/lib/rgeo/active_record/spatial_expressions.rb +55 -55
- data/lib/rgeo/active_record/version.rb +1 -1
- data/test/basic_test.rb +75 -0
- data/test/test_helper.rb +0 -4
- metadata +5 -5
- data/test/tc_basic.rb +0 -74
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 11ad920c01d1f944cd3d7f4f658b4138a1954284
|
4
|
+
data.tar.gz: 184abfc52e1c1708726c344bc66842133381949d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6bffb41f789ef87f8557cbdbc786a3c2070c7d193e9fe819467397b556a613ac8a9b9e363def43a0f09afcfdfae8fdddeaf4b1584f5166901dbd59be2c6af1f8
|
7
|
+
data.tar.gz: 7254fcac74eb52b88152d27f8f452045f376202462365822432e0cda43c35ffa6f0df65516ad85f63e9f6b9a2af5eabc8d60e25da28bc7f5136b1b28c59745b2
|
data/History.md
CHANGED
@@ -2,11 +2,11 @@ module RGeo
|
|
2
2
|
module ActiveRecord
|
3
3
|
# The default factory generator for ActiveRecord::Base.
|
4
4
|
|
5
|
-
DEFAULT_FACTORY_GENERATOR = ::Proc.new do |
|
6
|
-
if
|
7
|
-
::RGeo::Geographic.spherical_factory(
|
5
|
+
DEFAULT_FACTORY_GENERATOR = ::Proc.new do |config|
|
6
|
+
if config.delete(:geographic)
|
7
|
+
::RGeo::Geographic.spherical_factory(config)
|
8
8
|
else
|
9
|
-
::RGeo::Cartesian.preferred_factory(
|
9
|
+
::RGeo::Cartesian.preferred_factory(config)
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
@@ -19,40 +19,38 @@ module RGeo
|
|
19
19
|
end
|
20
20
|
|
21
21
|
# Get the default factory generator for the given table
|
22
|
-
def get_factory_generator(
|
23
|
-
@factory_generators[
|
22
|
+
def get_factory_generator(table_name)
|
23
|
+
@factory_generators[table_name.to_s] || ::RGeo::ActiveRecord::DEFAULT_FACTORY_GENERATOR
|
24
24
|
end
|
25
25
|
|
26
26
|
# Set the default factory generator for the given table
|
27
|
-
def set_factory_generator(
|
28
|
-
@factory_generators[
|
27
|
+
def set_factory_generator(table_name, generator)
|
28
|
+
@factory_generators[table_name.to_s] = generator
|
29
29
|
end
|
30
30
|
|
31
|
-
# Get the factory or factory generator for the given table name
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
result_ = result_.call(params_)
|
31
|
+
# Get the factory or factory generator for the given table name and column name.
|
32
|
+
def get_column_factory(table_name, column_name, params = nil)
|
33
|
+
table_name = table_name.to_s
|
34
|
+
column_name = column_name.to_s
|
35
|
+
result = (@column_factories[table_name] ||= {})[column_name] ||
|
36
|
+
@factory_generators[table_name] || ::RGeo::ActiveRecord::DEFAULT_FACTORY_GENERATOR
|
37
|
+
if params && !result.kind_of?(::RGeo::Feature::Factory::Instance)
|
38
|
+
result = result.call(params)
|
40
39
|
end
|
41
|
-
|
40
|
+
result
|
42
41
|
end
|
43
42
|
|
44
|
-
# Set the factory or factory generator for the given table name
|
45
|
-
|
46
|
-
|
47
|
-
(@column_factories[table_name_.to_s] ||= {})[column_name_.to_s] = factory_
|
43
|
+
# Set the factory or factory generator for the given table name and column name.
|
44
|
+
def set_column_factory(table_name, column_name, factory)
|
45
|
+
(@column_factories[table_name.to_s] ||= {})[column_name.to_s] = factory
|
48
46
|
end
|
49
47
|
|
50
48
|
# Clear settings for the given table name, or for all tables
|
51
|
-
def clear!(
|
52
|
-
if
|
53
|
-
|
54
|
-
@factory_generators.delete(
|
55
|
-
@column_factories.delete(
|
49
|
+
def clear!(table_name = nil)
|
50
|
+
if table_name
|
51
|
+
table_name = table_name.to_s
|
52
|
+
@factory_generators.delete(table_name)
|
53
|
+
@column_factories.delete(table_name)
|
56
54
|
else
|
57
55
|
@factory_generators.clear
|
58
56
|
@column_factories.clear
|
@@ -65,15 +63,14 @@ module RGeo
|
|
65
63
|
# Additional class methods on ::ActiveRecord::Base that provide
|
66
64
|
# a way to control the RGeo factory used for ActiveRecord objects.
|
67
65
|
module ActiveRecordBaseFactorySettings
|
68
|
-
# Return the RGeoFactorySettings object associated with this
|
69
|
-
# class's connection.
|
66
|
+
# Return the RGeoFactorySettings object associated with this class's connection.
|
70
67
|
def rgeo_factory_settings
|
71
|
-
|
68
|
+
pool = begin
|
72
69
|
connection_pool
|
73
70
|
rescue ::ActiveRecord::ConnectionNotEstablished
|
74
71
|
nil
|
75
72
|
end
|
76
|
-
|
73
|
+
pool ? pool.rgeo_factory_settings : RGeoFactorySettings::DEFAULT
|
77
74
|
end
|
78
75
|
|
79
76
|
# The value of this attribute is a RGeo::Feature::FactoryGenerator
|
@@ -92,21 +89,21 @@ module RGeo
|
|
92
89
|
end
|
93
90
|
|
94
91
|
# Set the rgeo_factory_generator attribute
|
95
|
-
def rgeo_factory_generator=(
|
96
|
-
rgeo_factory_settings.set_factory_generator(table_name,
|
92
|
+
def rgeo_factory_generator=(generator)
|
93
|
+
rgeo_factory_settings.set_factory_generator(table_name, generator)
|
97
94
|
end
|
98
95
|
|
99
96
|
# This is a convenient way to set the rgeo_factory_generator by
|
100
97
|
# passing a block.
|
101
|
-
def to_generate_rgeo_factory(&
|
102
|
-
rgeo_factory_settings.set_factory_generator(table_name,
|
98
|
+
def to_generate_rgeo_factory(&block)
|
99
|
+
rgeo_factory_settings.set_factory_generator(table_name, block)
|
103
100
|
end
|
104
101
|
|
105
102
|
# Set a specific factory for this ActiveRecord class and the given
|
106
103
|
# column name. This setting, if present, overrides the result of the
|
107
104
|
# rgeo_factory_generator.
|
108
|
-
def set_rgeo_factory_for_column(
|
109
|
-
rgeo_factory_settings.set_column_factory(table_name,
|
105
|
+
def set_rgeo_factory_for_column(column_name, factory)
|
106
|
+
rgeo_factory_settings.set_column_factory(table_name, column_name, factory)
|
110
107
|
end
|
111
108
|
|
112
109
|
# Returns the factory generator or specific factory to use for this
|
@@ -116,8 +113,8 @@ module RGeo
|
|
116
113
|
# rgeo_factory_generator for this class, and returns the resulting
|
117
114
|
# factory. Otherwise, if no params hash is given, just returns the
|
118
115
|
# rgeo_factory_generator for this class.
|
119
|
-
def rgeo_factory_for_column(
|
120
|
-
rgeo_factory_settings.get_column_factory(table_name,
|
116
|
+
def rgeo_factory_for_column(column_name, params = nil)
|
117
|
+
rgeo_factory_settings.get_column_factory(table_name, column_name, params)
|
121
118
|
end
|
122
119
|
end
|
123
120
|
|
@@ -135,11 +132,11 @@ module RGeo
|
|
135
132
|
|
136
133
|
alias_method :new_connection_without_rgeo_modification, :new_connection
|
137
134
|
def new_connection
|
138
|
-
|
139
|
-
if
|
140
|
-
|
135
|
+
result = new_connection_without_rgeo_modification
|
136
|
+
if result.respond_to?(:set_rgeo_factory_settings)
|
137
|
+
result.set_rgeo_factory_settings(rgeo_factory_settings)
|
141
138
|
end
|
142
|
-
|
139
|
+
result
|
143
140
|
end
|
144
141
|
end
|
145
142
|
|
@@ -12,8 +12,8 @@ module RGeo
|
|
12
12
|
# a particular database. This method should take a name and
|
13
13
|
# return either the changed name or the original name.
|
14
14
|
|
15
|
-
def st_func(
|
16
|
-
|
15
|
+
def st_func(standard_name)
|
16
|
+
standard_name
|
17
17
|
end
|
18
18
|
|
19
19
|
# Visit the SpatialNamedFunction node. This operates similarly to
|
@@ -21,40 +21,39 @@ module RGeo
|
|
21
21
|
# mapping for the database, and it also uses the type information
|
22
22
|
# in the node to determine when to cast string arguments to WKT,
|
23
23
|
|
24
|
-
def visit_RGeo_ActiveRecord_SpatialNamedFunction(
|
25
|
-
name_ = st_func(
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
def visit_RGeo_ActiveRecord_SpatialNamedFunction(node, *args)
|
25
|
+
name_ = st_func(node.name)
|
26
|
+
exprs = []
|
27
|
+
node.expressions.each_with_index do |expr, index|
|
28
|
+
exprs << (node.spatial_argument?(index) ? visit_in_spatial_context(expr, *args) : visit(expr, *args))
|
29
29
|
end
|
30
|
-
"#{name_}(#{
|
30
|
+
"#{name_}(#{node.distinct ? 'DISTINCT ' : ''}#{exprs.join(', ')})#{node.alias ? " AS #{visit(node.alias, *args)}" : ''}"
|
31
31
|
end
|
32
32
|
|
33
33
|
# Generates SQL for a spatial node.
|
34
34
|
# The node must be a string (in which case it is treated as WKT),
|
35
35
|
# an RGeo feature, or a spatial attribute.
|
36
|
-
def visit_in_spatial_context(
|
37
|
-
case
|
36
|
+
def visit_in_spatial_context(node, *args)
|
37
|
+
case node
|
38
38
|
when ::String
|
39
|
-
"#{st_func('ST_WKTToSQL')}(#{quote(
|
39
|
+
"#{st_func('ST_WKTToSQL')}(#{quote(node)})"
|
40
40
|
when ::RGeo::Feature::Instance
|
41
|
-
visit_RGeo_Feature_Instance(
|
41
|
+
visit_RGeo_Feature_Instance(node, *args)
|
42
42
|
when ::RGeo::Cartesian::BoundingBox
|
43
|
-
visit_RGeo_Cartesian_BoundingBox(
|
43
|
+
visit_RGeo_Cartesian_BoundingBox(node, *args)
|
44
44
|
else
|
45
|
-
visit(
|
45
|
+
visit(node, *args)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
-
# This node wraps an RGeo feature and gives it spatial expression
|
51
|
-
# constructors.
|
50
|
+
# This node wraps an RGeo feature and gives it spatial expression constructors.
|
52
51
|
class SpatialConstantNode
|
53
52
|
include ::RGeo::ActiveRecord::SpatialExpressions
|
54
53
|
|
55
54
|
# The delegate should be the RGeo feature.
|
56
|
-
def initialize(
|
57
|
-
@delegate =
|
55
|
+
def initialize(delegate)
|
56
|
+
@delegate = delegate
|
58
57
|
end
|
59
58
|
|
60
59
|
# Return the RGeo feature
|
@@ -63,32 +62,33 @@ module RGeo
|
|
63
62
|
|
64
63
|
# :stopdoc:
|
65
64
|
|
66
|
-
# Make sure the standard Arel visitors can handle RGeo feature objects
|
67
|
-
# by default.
|
65
|
+
# Make sure the standard Arel visitors can handle RGeo feature objects by default.
|
68
66
|
|
69
67
|
::Arel::Visitors::Visitor.class_eval do
|
70
|
-
def visit_RGeo_ActiveRecord_SpatialConstantNode(
|
68
|
+
def visit_RGeo_ActiveRecord_SpatialConstantNode(node, *args)
|
71
69
|
if respond_to?(:visit_in_spatial_context)
|
72
|
-
visit_in_spatial_context(
|
70
|
+
visit_in_spatial_context(node.delegate, *args)
|
73
71
|
else
|
74
|
-
visit(
|
72
|
+
visit(node.delegate, *args)
|
75
73
|
end
|
76
74
|
end
|
77
75
|
end
|
76
|
+
|
78
77
|
::Arel::Visitors::Dot.class_eval do
|
79
78
|
alias :visit_RGeo_Feature_Instance :visit_String
|
80
79
|
alias :visit_RGeo_Cartesian_BoundingBox :visit_String
|
81
80
|
end
|
81
|
+
|
82
82
|
::Arel::Visitors::DepthFirst.class_eval do
|
83
83
|
alias :visit_RGeo_Feature_Instance :terminal
|
84
84
|
alias :visit_RGeo_Cartesian_BoundingBox :terminal
|
85
85
|
end
|
86
|
+
|
86
87
|
::Arel::Visitors::ToSql.class_eval do
|
87
88
|
alias :visit_RGeo_Feature_Instance :visit_String
|
88
89
|
alias :visit_RGeo_Cartesian_BoundingBox :visit_String
|
89
90
|
end
|
90
91
|
|
91
|
-
|
92
92
|
# A NamedFunction subclass that keeps track of the spatial-ness of
|
93
93
|
# the arguments and return values, so that it can provide context to
|
94
94
|
# visitors that want to interpret syntax differently when dealing with
|
@@ -96,19 +96,18 @@ module RGeo
|
|
96
96
|
class SpatialNamedFunction < ::Arel::Nodes::NamedFunction
|
97
97
|
include ::RGeo::ActiveRecord::SpatialExpressions
|
98
98
|
|
99
|
-
def initialize(
|
100
|
-
super(
|
101
|
-
@spatial_flags =
|
99
|
+
def initialize(name, expr, spatial_flags = [], aliaz = nil)
|
100
|
+
super(name, expr, aliaz)
|
101
|
+
@spatial_flags = spatial_flags
|
102
102
|
end
|
103
103
|
|
104
104
|
def spatial_result?
|
105
105
|
@spatial_flags.first
|
106
106
|
end
|
107
107
|
|
108
|
-
def spatial_argument?(
|
109
|
-
@spatial_flags[
|
108
|
+
def spatial_argument?(index)
|
109
|
+
@spatial_flags[index + 1]
|
110
110
|
end
|
111
|
-
|
112
111
|
end
|
113
112
|
|
114
113
|
# :startdoc:
|
@@ -6,26 +6,26 @@ module RGeo
|
|
6
6
|
# Some default column constructors specifications for most spatial
|
7
7
|
# databases. Individual adapters may add to or override this list.
|
8
8
|
DEFAULT_SPATIAL_COLUMN_CONSTRUCTORS = {
|
9
|
-
:
|
10
|
-
:
|
11
|
-
:
|
12
|
-
:
|
13
|
-
:
|
14
|
-
:
|
15
|
-
:
|
16
|
-
:
|
17
|
-
:
|
9
|
+
spatial: { type: 'geometry' }.freeze,
|
10
|
+
geometry: {}.freeze,
|
11
|
+
point: {}.freeze,
|
12
|
+
line_string: {}.freeze,
|
13
|
+
polygon: {}.freeze,
|
14
|
+
geometry_collection: {}.freeze,
|
15
|
+
multi_line_string: {}.freeze,
|
16
|
+
multi_point: {}.freeze,
|
17
|
+
multi_polygon: {}.freeze,
|
18
18
|
}.freeze
|
19
19
|
|
20
20
|
# Index definition struct with a spatial flag field.
|
21
21
|
|
22
|
-
class SpatialIndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths, :orders, :where, :spatial)
|
22
|
+
class SpatialIndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths, :orders, :where, :using, :type, :spatial)
|
23
23
|
end
|
24
24
|
|
25
25
|
# Returns a feature type module given a string type.
|
26
26
|
|
27
|
-
def self.geometric_type_from_name(
|
28
|
-
case
|
27
|
+
def self.geometric_type_from_name(name)
|
28
|
+
case name.to_s
|
29
29
|
when /^geometry/i then ::RGeo::Feature::Geometry
|
30
30
|
when /^point/i then ::RGeo::Feature::Point
|
31
31
|
when /^linestring/i then ::RGeo::Feature::LineString
|
@@ -49,16 +49,16 @@ module RGeo
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
-
def method_missing_with_rgeo(
|
53
|
-
if @base.respond_to?(:spatial_column_constructor) && (
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
column(
|
52
|
+
def method_missing_with_rgeo(method_name, *args, &block)
|
53
|
+
if @base.respond_to?(:spatial_column_constructor) && (info = @base.spatial_column_constructor(method_name))
|
54
|
+
info = info.dup
|
55
|
+
type = (info.delete(:type) || method_name).to_s
|
56
|
+
opts = args.extract_options!.merge(info)
|
57
|
+
args.each do |name|
|
58
|
+
column(name, type, opts)
|
59
59
|
end
|
60
60
|
else
|
61
|
-
method_missing_without_rgeo(
|
61
|
+
method_missing_without_rgeo(method_name, *args, &block)
|
62
62
|
end
|
63
63
|
end
|
64
64
|
end
|
@@ -75,16 +75,16 @@ module RGeo
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
-
def method_missing_with_rgeo(
|
79
|
-
if @base.respond_to?(:
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
@base.add_column(@table_name,
|
78
|
+
def method_missing_with_rgeo(method_name, *args, &block)
|
79
|
+
if @base.respond_to?(:spatial_column_construcor) && (info = @base.spatial_column_constructor(method_name))
|
80
|
+
info = info.dup
|
81
|
+
type = (info.delete(:type) || method_name).to_s
|
82
|
+
opts = args.extract_options!.merge(info)
|
83
|
+
args.each do |name|
|
84
|
+
@base.add_column(@table_name, name, type, opts)
|
85
85
|
end
|
86
86
|
else
|
87
|
-
method_missing_without_rgeo(
|
87
|
+
method_missing_without_rgeo(method_name, *args, &block)
|
88
88
|
end
|
89
89
|
end
|
90
90
|
end
|
@@ -103,22 +103,30 @@ module RGeo
|
|
103
103
|
|
104
104
|
private
|
105
105
|
|
106
|
-
def indexes_with_rgeo(
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
106
|
+
def indexes_with_rgeo(table, stream)
|
107
|
+
indexes = @connection.indexes(table)
|
108
|
+
if indexes.any?
|
109
|
+
add_index_statements = indexes.map do |index|
|
110
|
+
statement = [
|
111
|
+
("add_index #{index.table.inspect}"),
|
112
|
+
index.columns.inspect,
|
113
|
+
("name: #{index.name.inspect}"),
|
114
|
+
]
|
115
|
+
statement << 'unique: true' if index.unique
|
116
|
+
statement << 'spatial: true' if index.respond_to?(:spatial) && index.spatial
|
117
|
+
index_lengths = (index.lengths || []).compact
|
118
|
+
statement << ("length: #{::Hash[*index.columns.zip(index.lengths).flatten].inspect}") if index_lengths.any?
|
119
|
+
|
120
|
+
index_orders = index.orders || {}
|
121
|
+
statement << "order: #{index.orders.inspect}" if index_orders.any?
|
122
|
+
statement << "where: #{index.where.inspect}" if index.where
|
123
|
+
statement << "using: #{index.using.inspect}" if index.using
|
124
|
+
statement << "type: #{index.type.inspect}" if index.type
|
125
|
+
|
126
|
+
" #{statement.join(', ')}"
|
119
127
|
end
|
120
|
-
|
121
|
-
|
128
|
+
stream.puts add_index_statements.sort.join("\n")
|
129
|
+
stream.puts
|
122
130
|
end
|
123
131
|
end
|
124
132
|
end
|
@@ -6,7 +6,7 @@ module RGeo
|
|
6
6
|
|
7
7
|
module GeometryMixin
|
8
8
|
# The default JSON generator Proc. Renders geometry fields as WKT.
|
9
|
-
DEFAULT_JSON_GENERATOR = ::Proc.new{ |
|
9
|
+
DEFAULT_JSON_GENERATOR = ::Proc.new{ |geom| geom.to_s }
|
10
10
|
|
11
11
|
@json_generator = DEFAULT_JSON_GENERATOR
|
12
12
|
|
@@ -22,15 +22,15 @@ module RGeo
|
|
22
22
|
# <tt>:geojson</tt>::
|
23
23
|
# GeoJSON format. Requires the rgeo-geojson gem.
|
24
24
|
|
25
|
-
def self.set_json_generator(
|
26
|
-
if
|
27
|
-
|
28
|
-
elsif
|
25
|
+
def self.set_json_generator(value = nil, &block)
|
26
|
+
if block && !value
|
27
|
+
value = block
|
28
|
+
elsif value == :geojson
|
29
29
|
require 'rgeo/geo_json'
|
30
|
-
|
30
|
+
value = ::Proc.new{ |geom_| ::RGeo::GeoJSON.encode(geom_) }
|
31
31
|
end
|
32
|
-
if
|
33
|
-
@json_generator =
|
32
|
+
if value.is_a?(::Proc)
|
33
|
+
@json_generator = value
|
34
34
|
else
|
35
35
|
@json_generator = DEFAULT_JSON_GENERATOR
|
36
36
|
end
|
@@ -41,14 +41,13 @@ module RGeo
|
|
41
41
|
# This is used to generate JSON for geometry-valued ActiveRecord
|
42
42
|
# fields by default.
|
43
43
|
|
44
|
-
def self.generate_json(
|
45
|
-
@json_generator.call(
|
44
|
+
def self.generate_json(geom)
|
45
|
+
@json_generator.call(geom)
|
46
46
|
end
|
47
47
|
|
48
|
-
|
49
48
|
# Serializes this object as JSON for ActiveRecord.
|
50
49
|
|
51
|
-
def as_json(
|
50
|
+
def as_json(opts = nil)
|
52
51
|
GeometryMixin.generate_json(self)
|
53
52
|
end
|
54
53
|
end
|
@@ -18,9 +18,9 @@ module RGeo
|
|
18
18
|
# Generic functions
|
19
19
|
#++
|
20
20
|
|
21
|
-
def st_function(
|
22
|
-
|
23
|
-
::RGeo::ActiveRecord::SpatialNamedFunction.new(
|
21
|
+
def st_function(function, *args)
|
22
|
+
spatial_info = args.last.is_a?(::Array) ? args.pop : []
|
23
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new(function, [self] + args, spatial_info)
|
24
24
|
end
|
25
25
|
|
26
26
|
#--
|
@@ -63,70 +63,70 @@ module RGeo
|
|
63
63
|
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Envelope', [self], [true, true])
|
64
64
|
end
|
65
65
|
|
66
|
-
def st_equals(
|
67
|
-
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Equals', [self,
|
66
|
+
def st_equals(rhs)
|
67
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Equals', [self, rhs], [false, true, true])
|
68
68
|
end
|
69
69
|
|
70
|
-
def st_disjoint(
|
71
|
-
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Disjoint', [self,
|
70
|
+
def st_disjoint(rhs)
|
71
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Disjoint', [self, rhs], [false, true, true])
|
72
72
|
end
|
73
73
|
|
74
|
-
def st_intersects(
|
75
|
-
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Intersects', [self,
|
74
|
+
def st_intersects(rhs)
|
75
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Intersects', [self, rhs], [false, true, true])
|
76
76
|
end
|
77
77
|
|
78
|
-
def st_touches(
|
79
|
-
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Touches', [self,
|
78
|
+
def st_touches(rhs)
|
79
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Touches', [self, rhs], [false, true, true])
|
80
80
|
end
|
81
81
|
|
82
|
-
def st_crosses(
|
83
|
-
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Crosses', [self,
|
82
|
+
def st_crosses(rhs)
|
83
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Crosses', [self, rhs], [false, true, true])
|
84
84
|
end
|
85
85
|
|
86
|
-
def st_within(
|
87
|
-
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Within', [self,
|
86
|
+
def st_within(rhs)
|
87
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Within', [self, rhs], [false, true, true])
|
88
88
|
end
|
89
89
|
|
90
|
-
def st_contains(
|
91
|
-
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Contains', [self,
|
90
|
+
def st_contains(rhs)
|
91
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Contains', [self, rhs], [false, true, true])
|
92
92
|
end
|
93
93
|
|
94
|
-
def st_overlaps(
|
95
|
-
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Overlaps', [self,
|
94
|
+
def st_overlaps(rhs)
|
95
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Overlaps', [self, rhs], [false, true, true])
|
96
96
|
end
|
97
97
|
|
98
|
-
def st_relate(
|
99
|
-
|
100
|
-
|
101
|
-
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Relate',
|
98
|
+
def st_relate(rhs, matrix = nil)
|
99
|
+
args = [self, rhs]
|
100
|
+
args << matrix.to_s if matrix
|
101
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Relate', args, [false, true, true, false])
|
102
102
|
end
|
103
103
|
|
104
|
-
def st_distance(
|
105
|
-
|
106
|
-
|
107
|
-
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Distance',
|
104
|
+
def st_distance(rhs, units = nil)
|
105
|
+
args = [self, rhs]
|
106
|
+
args << units.to_s if units
|
107
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Distance', args, [false, true, true, false])
|
108
108
|
end
|
109
109
|
|
110
|
-
def st_intersection(
|
111
|
-
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Intersection', [self,
|
110
|
+
def st_intersection(rhs)
|
111
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Intersection', [self, rhs], [true, true, true])
|
112
112
|
end
|
113
113
|
|
114
|
-
def st_difference(
|
115
|
-
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Difference', [self,
|
114
|
+
def st_difference(rhs)
|
115
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Difference', [self, rhs], [true, true, true])
|
116
116
|
end
|
117
117
|
|
118
|
-
def st_union(
|
119
|
-
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Union', [self,
|
118
|
+
def st_union(rhs)
|
119
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Union', [self, rhs], [true, true, true])
|
120
120
|
end
|
121
121
|
|
122
|
-
def st_symdifference(
|
123
|
-
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_SymDifference', [self,
|
122
|
+
def st_symdifference(rhs)
|
123
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_SymDifference', [self, rhs], [true, true, true])
|
124
124
|
end
|
125
125
|
|
126
|
-
def st_buffer(
|
127
|
-
|
128
|
-
|
129
|
-
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Buffer',
|
126
|
+
def st_buffer(distance, units = nil)
|
127
|
+
args = [self, distance.to_f]
|
128
|
+
args << units.to_s if units
|
129
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Buffer', args, [true, true, false])
|
130
130
|
end
|
131
131
|
|
132
132
|
def st_convexhull
|
@@ -175,10 +175,10 @@ module RGeo
|
|
175
175
|
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_IsRing', [self], [false, true])
|
176
176
|
end
|
177
177
|
|
178
|
-
def st_length(
|
179
|
-
|
180
|
-
|
181
|
-
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Length',
|
178
|
+
def st_length(units = nil)
|
179
|
+
args = [self]
|
180
|
+
args << units.to_s if units
|
181
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Length', args, [false, true, false])
|
182
182
|
end
|
183
183
|
|
184
184
|
|
@@ -190,8 +190,8 @@ module RGeo
|
|
190
190
|
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_NumPoints', [self], [false, true])
|
191
191
|
end
|
192
192
|
|
193
|
-
def st_pointn(
|
194
|
-
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_PointN', [self,
|
193
|
+
def st_pointn(n)
|
194
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_PointN', [self, n.to_i], [true, true, false])
|
195
195
|
end
|
196
196
|
|
197
197
|
|
@@ -199,10 +199,10 @@ module RGeo
|
|
199
199
|
# Surface functions
|
200
200
|
#++
|
201
201
|
|
202
|
-
def st_area(
|
203
|
-
|
204
|
-
|
205
|
-
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_StartPoint',
|
202
|
+
def st_area(units = nil)
|
203
|
+
args = [self]
|
204
|
+
args << units.to_s if units
|
205
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_StartPoint', args, [false, true, false])
|
206
206
|
end
|
207
207
|
|
208
208
|
def st_centroid
|
@@ -227,8 +227,8 @@ module RGeo
|
|
227
227
|
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_NumInteriorRing', [self], [false, true])
|
228
228
|
end
|
229
229
|
|
230
|
-
def st_interiorringn(
|
231
|
-
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_InteriorRingN', [self,
|
230
|
+
def st_interiorringn(n)
|
231
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_InteriorRingN', [self, n.to_i], [true, true, false])
|
232
232
|
end
|
233
233
|
|
234
234
|
#--
|
@@ -239,8 +239,8 @@ module RGeo
|
|
239
239
|
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_NumGeometries', [self], [false, true])
|
240
240
|
end
|
241
241
|
|
242
|
-
def st_geometryn(
|
243
|
-
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_GeometryN', [self,
|
242
|
+
def st_geometryn(n)
|
243
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_GeometryN', [self, n.to_i], [true, true, false])
|
244
244
|
end
|
245
245
|
|
246
246
|
end
|
@@ -263,8 +263,8 @@ module Arel
|
|
263
263
|
#
|
264
264
|
# Requires Arel 2.1 or later.
|
265
265
|
|
266
|
-
def self.spatial(
|
267
|
-
::RGeo::ActiveRecord::SpatialConstantNode.new(
|
266
|
+
def self.spatial(arg)
|
267
|
+
::RGeo::ActiveRecord::SpatialConstantNode.new(arg)
|
268
268
|
end
|
269
269
|
|
270
270
|
end
|
data/test/basic_test.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class BasicTest < MINITEST_CLASS # :nodoc:
|
4
|
+
class MyTable < ::ActiveRecord::Base
|
5
|
+
end
|
6
|
+
|
7
|
+
def test_has_version
|
8
|
+
assert RGeo::ActiveRecord::VERSION
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_default_factory_generator
|
12
|
+
MyTable.rgeo_factory_generator = nil
|
13
|
+
factory = MyTable.rgeo_factory_for_column(:hello).call(has_z_coordinate: true, srid: 4326)
|
14
|
+
assert_equal true, factory.property(:has_z_coordinate)
|
15
|
+
assert_equal true, factory.property(:is_cartesian)
|
16
|
+
assert_nil factory.property(:is_geographic)
|
17
|
+
assert_equal 4326, factory.srid
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_set_factory_generator
|
21
|
+
MyTable.rgeo_factory_generator = RGeo::Geographic.method(:spherical_factory)
|
22
|
+
factory = MyTable.rgeo_factory_for_column(:hello, has_z_coordinate: true, srid: 4326)
|
23
|
+
assert_equal true, factory.property(:has_z_coordinate)
|
24
|
+
assert_equal true, factory.property(:is_geographic)
|
25
|
+
assert_nil factory.property(:is_cartesian)
|
26
|
+
assert_equal false, factory.has_projection?
|
27
|
+
assert_equal 4326, factory.srid
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_specific_factory_for_column
|
31
|
+
MyTable.rgeo_factory_generator = nil
|
32
|
+
MyTable.set_rgeo_factory_for_column(:foo, RGeo::Geographic.simple_mercator_factory(has_z_coordinate: true))
|
33
|
+
factory = MyTable.rgeo_factory_for_column(:foo)
|
34
|
+
assert_equal true, factory.property(:has_z_coordinate)
|
35
|
+
assert_equal true, factory.property(:is_geographic)
|
36
|
+
assert_nil factory.property(:is_cartesian)
|
37
|
+
assert_equal true, factory.has_projection?
|
38
|
+
assert_equal 4326, factory.srid
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_default_as_json_wkt
|
42
|
+
RGeo::ActiveRecord::GeometryMixin.set_json_generator(nil)
|
43
|
+
factory = RGeo::Cartesian.preferred_factory
|
44
|
+
point = factory.point(1, 2)
|
45
|
+
assert_equal "POINT (1.0 2.0)", point.as_json
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_default_as_json_geojson
|
49
|
+
RGeo::ActiveRecord::GeometryMixin.set_json_generator(:geojson)
|
50
|
+
factory = RGeo::Cartesian.preferred_factory
|
51
|
+
point = factory.point(1, 2)
|
52
|
+
assert_equal({'type' => 'Point', 'coordinates' => [1.0, 2.0]}, point.as_json)
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_arel_visit_spatial_constant_node
|
56
|
+
visitor = arel_visitor
|
57
|
+
|
58
|
+
# :accept API changed in Arel 6.0:
|
59
|
+
# https://github.com/rails/arel/commit/fcd11dcb99d69d
|
60
|
+
sql = if Arel::VERSION > "6.0.0"
|
61
|
+
visitor.accept(Arel.spatial('POINT (1.0 2.0)'), Arel::Collectors::PlainString.new)
|
62
|
+
else
|
63
|
+
visitor.accept(Arel.spatial('POINT (1.0 2.0)'))
|
64
|
+
end
|
65
|
+
|
66
|
+
assert_equal("ST_WKTToSQL('POINT (1.0 2.0)')", sql)
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def arel_visitor
|
72
|
+
Arel::Visitors::PostgreSQL.new(Arel::Table.engine.connection)
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -10,7 +10,3 @@ MINITEST_CLASS = if defined?(::Minitest::Test)
|
|
10
10
|
|
11
11
|
Arel::Visitors::PostgreSQL.send(:include, ::RGeo::ActiveRecord::SpatialToSql)
|
12
12
|
Arel::Table.engine = FakeRecord::Base.new
|
13
|
-
|
14
|
-
def arel_visitor
|
15
|
-
Arel::Visitors::PostgreSQL.new(Arel::Table.engine.connection)
|
16
|
-
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rgeo-activerecord
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Azuma
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-07-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rgeo
|
@@ -86,8 +86,8 @@ files:
|
|
86
86
|
- lib/rgeo/active_record/geometry_mixin.rb
|
87
87
|
- lib/rgeo/active_record/spatial_expressions.rb
|
88
88
|
- lib/rgeo/active_record/version.rb
|
89
|
+
- test/basic_test.rb
|
89
90
|
- test/support/fake_record.rb
|
90
|
-
- test/tc_basic.rb
|
91
91
|
- test/test_helper.rb
|
92
92
|
homepage: http://github.com/rgeo/rgeo-activerecord
|
93
93
|
licenses: []
|
@@ -108,12 +108,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
108
108
|
version: '0'
|
109
109
|
requirements: []
|
110
110
|
rubyforge_project:
|
111
|
-
rubygems_version: 2.
|
111
|
+
rubygems_version: 2.6.12
|
112
112
|
signing_key:
|
113
113
|
specification_version: 4
|
114
114
|
summary: An RGeo module providing spatial extensions to ActiveRecord.
|
115
115
|
test_files:
|
116
|
+
- test/basic_test.rb
|
116
117
|
- test/support/fake_record.rb
|
117
|
-
- test/tc_basic.rb
|
118
118
|
- test/test_helper.rb
|
119
119
|
has_rdoc:
|
data/test/tc_basic.rb
DELETED
@@ -1,74 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
module RGeo
|
4
|
-
module ActiveRecord
|
5
|
-
module Tests # :nodoc:
|
6
|
-
class TestBasic < MINITEST_CLASS # :nodoc:
|
7
|
-
class MyTable < ::ActiveRecord::Base
|
8
|
-
end
|
9
|
-
|
10
|
-
def test_has_version
|
11
|
-
assert ::RGeo::ActiveRecord::VERSION
|
12
|
-
end
|
13
|
-
|
14
|
-
def test_default_factory_generator
|
15
|
-
MyTable.rgeo_factory_generator = nil
|
16
|
-
factory_ = MyTable.rgeo_factory_for_column(:hello).call(:has_z_coordinate => true, :srid => 4326)
|
17
|
-
assert_equal(true, factory_.property(:has_z_coordinate))
|
18
|
-
assert_equal(true, factory_.property(:is_cartesian))
|
19
|
-
assert_nil(factory_.property(:is_geographic))
|
20
|
-
assert_equal(4326, factory_.srid)
|
21
|
-
end
|
22
|
-
|
23
|
-
def test_set_factory_generator
|
24
|
-
MyTable.rgeo_factory_generator = ::RGeo::Geographic.method(:spherical_factory)
|
25
|
-
factory_ = MyTable.rgeo_factory_for_column(:hello, :has_z_coordinate => true, :srid => 4326)
|
26
|
-
assert_equal(true, factory_.property(:has_z_coordinate))
|
27
|
-
assert_equal(true, factory_.property(:is_geographic))
|
28
|
-
assert_nil(factory_.property(:is_cartesian))
|
29
|
-
assert_equal(false, factory_.has_projection?)
|
30
|
-
assert_equal(4326, factory_.srid)
|
31
|
-
end
|
32
|
-
|
33
|
-
def test_specific_factory_for_column
|
34
|
-
MyTable.rgeo_factory_generator = nil
|
35
|
-
MyTable.set_rgeo_factory_for_column(:foo, ::RGeo::Geographic.simple_mercator_factory(:has_z_coordinate => true))
|
36
|
-
factory_ = MyTable.rgeo_factory_for_column(:foo)
|
37
|
-
assert_equal(true, factory_.property(:has_z_coordinate))
|
38
|
-
assert_equal(true, factory_.property(:is_geographic))
|
39
|
-
assert_nil(factory_.property(:is_cartesian))
|
40
|
-
assert_equal(true, factory_.has_projection?)
|
41
|
-
assert_equal(4326, factory_.srid)
|
42
|
-
end
|
43
|
-
|
44
|
-
def test_default_as_json_wkt
|
45
|
-
GeometryMixin.set_json_generator(nil)
|
46
|
-
factory_ = ::RGeo::Cartesian.preferred_factory
|
47
|
-
p_ = factory_.point(1, 2)
|
48
|
-
assert_equal("POINT (1.0 2.0)", p_.as_json)
|
49
|
-
end
|
50
|
-
|
51
|
-
def test_default_as_json_geojson
|
52
|
-
GeometryMixin.set_json_generator(:geojson)
|
53
|
-
factory_ = ::RGeo::Cartesian.preferred_factory
|
54
|
-
p_ = factory_.point(1, 2)
|
55
|
-
assert_equal({'type' => 'Point', 'coordinates' => [1.0, 2.0]}, p_.as_json)
|
56
|
-
end
|
57
|
-
|
58
|
-
def test_arel_visit_SpatialConstantNode
|
59
|
-
visitor = arel_visitor
|
60
|
-
|
61
|
-
# :accept API changed in Arel 6.0:
|
62
|
-
# https://github.com/rails/arel/commit/fcd11dcb99d69d
|
63
|
-
sql = if Arel::VERSION > "6.0.0"
|
64
|
-
visitor.accept(Arel.spatial('POINT (1.0 2.0)'), Arel::Collectors::PlainString.new)
|
65
|
-
else
|
66
|
-
visitor.accept(Arel.spatial('POINT (1.0 2.0)'))
|
67
|
-
end
|
68
|
-
|
69
|
-
assert_equal("ST_WKTToSQL('POINT (1.0 2.0)')", sql)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|