activerecord-mysql2rgeo-adapter 7.3.1 → 8.0.5
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/lib/active_record/connection_adapters/mysql2rgeo/arel_tosql.rb +6 -7
- data/lib/active_record/connection_adapters/mysql2rgeo/schema_creation.rb +21 -22
- data/lib/active_record/connection_adapters/mysql2rgeo/schema_statements.rb +29 -22
- data/lib/active_record/connection_adapters/mysql2rgeo/spatial_column.rb +41 -12
- data/lib/active_record/connection_adapters/mysql2rgeo/spatial_column_info.rb +5 -5
- data/lib/active_record/connection_adapters/mysql2rgeo/spatial_table_definition.rb +26 -14
- data/lib/active_record/connection_adapters/mysql2rgeo/version.rb +1 -1
- data/lib/active_record/connection_adapters/mysql2rgeo_adapter.rb +90 -89
- data/lib/active_record/type/spatial.rb +6 -8
- metadata +12 -14
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c7c7868e390a06f088a15fbc05edcf4191cd4234da8d0d3a2946f92870a4ce3e
|
|
4
|
+
data.tar.gz: e6ccf5ee308dfbefd8b0997b67c17b895e7346d14be5ca36a86782b73e80d73f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e0109fb5a4f7a6afcaa3b8bb3a698239de3c2e211be0d776e5135b0c45cf36cc66ed0ecd9208c41477784391664f10c7e5596e3d1abe3fe498c76da26332a0be
|
|
7
|
+
data.tar.gz: 3974d1716e3446e6addf1edcdc7ed8ce31c7367f1b9a12eaa45944f0e57aaceb57526b3ed79e63e4365b7f87ab5e12b6a66a465a7fd41db197ce4316ab486e02
|
|
@@ -9,12 +9,10 @@ module Arel # :nodoc:
|
|
|
9
9
|
MySQL
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
class Mysql2Rgeo < MySQLSuperclass
|
|
12
|
+
class Mysql2Rgeo < MySQLSuperclass # :nodoc:
|
|
13
13
|
include RGeo::ActiveRecord::SpatialToSql
|
|
14
14
|
|
|
15
|
-
if ::Arel::Visitors.const_defined?(:BindVisitor)
|
|
16
|
-
include ::Arel::Visitors::BindVisitor
|
|
17
|
-
end
|
|
15
|
+
include ::Arel::Visitors::BindVisitor if ::Arel::Visitors.const_defined?(:BindVisitor)
|
|
18
16
|
|
|
19
17
|
FUNC_MAP = {
|
|
20
18
|
"st_wkttosql" => "ST_GeomFromText",
|
|
@@ -52,18 +50,19 @@ module Arel # :nodoc:
|
|
|
52
50
|
end
|
|
53
51
|
|
|
54
52
|
def self.parse_node(node)
|
|
55
|
-
if RGeo::Feature::Instance
|
|
53
|
+
if node.is_a?(RGeo::Feature::Instance)
|
|
56
54
|
wkt = RGeo::WKRep::WKTGenerator.new(tag_format: :wkt11, emit_ewkt_srid: false).generate(node)
|
|
57
55
|
return [wkt, node.srid]
|
|
58
56
|
end
|
|
59
57
|
|
|
60
|
-
if RGeo::Cartesian::BoundingBox
|
|
58
|
+
if node.is_a?(RGeo::Cartesian::BoundingBox)
|
|
61
59
|
geometry = node.to_geometry
|
|
62
60
|
wkt = RGeo::WKRep::WKTGenerator.new(tag_format: :wkt11, emit_ewkt_srid: false).generate(geometry)
|
|
63
61
|
return [wkt, geometry.srid]
|
|
64
62
|
end
|
|
65
63
|
|
|
66
|
-
value
|
|
64
|
+
value = nil
|
|
65
|
+
srid = 0
|
|
67
66
|
if node =~ /.*;.*$/i
|
|
68
67
|
params = Regexp.last_match(0).split(";")
|
|
69
68
|
if params.first =~ /(srid|SRID)=\d*/
|
|
@@ -5,34 +5,33 @@ module ActiveRecord
|
|
|
5
5
|
module Mysql2Rgeo
|
|
6
6
|
class SchemaCreation < MySQL::SchemaCreation # :nodoc:
|
|
7
7
|
private
|
|
8
|
-
def visit_IndexDefinition(o, create = false)
|
|
9
|
-
if o.using&.to_sym == :gist
|
|
10
|
-
sql = create ? ["CREATE SPATIAL INDEX"] : ["SPATIAL INDEX"]
|
|
11
|
-
sql << quote_column_name(o.name)
|
|
12
|
-
sql << "ON #{quote_table_name(o.table)}" if create
|
|
13
|
-
sql << "(#{quoted_columns(o)})"
|
|
14
|
-
return sql.join(" ")
|
|
15
|
-
end
|
|
16
8
|
|
|
17
|
-
|
|
9
|
+
def visit_IndexDefinition(o, create = false)
|
|
10
|
+
if o.using&.to_sym == :gist
|
|
11
|
+
sql = create ? ["CREATE SPATIAL INDEX"] : ["SPATIAL INDEX"]
|
|
12
|
+
sql << quote_column_name(o.name)
|
|
13
|
+
sql << "ON #{quote_table_name(o.table)}" if create
|
|
14
|
+
sql << "(#{quoted_columns(o)})"
|
|
15
|
+
return sql.join(" ")
|
|
18
16
|
end
|
|
19
17
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
sql << " /*!80003 SRID #{options[:srid]} */"
|
|
23
|
-
options = options.except(:srid)
|
|
24
|
-
end
|
|
18
|
+
super
|
|
19
|
+
end
|
|
25
20
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
super
|
|
21
|
+
def add_column_options!(sql, options)
|
|
22
|
+
if options[:srid]
|
|
23
|
+
sql << " /*!80003 SRID #{options[:srid]} */"
|
|
24
|
+
options = options.except(:srid)
|
|
31
25
|
end
|
|
32
26
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
options = options.except(:default) if options_include_default?(options) && spatial_column_definition?(options[:column])
|
|
28
|
+
|
|
29
|
+
super
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def spatial_column_definition?(column)
|
|
33
|
+
column.respond_to?(:type) && column.type && @conn.class.spatial_column_options(column.type.to_sym)
|
|
34
|
+
end
|
|
36
35
|
end
|
|
37
36
|
end
|
|
38
37
|
end
|
|
@@ -7,7 +7,7 @@ module ActiveRecord
|
|
|
7
7
|
# super: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/mysql/schema_statements.rb
|
|
8
8
|
|
|
9
9
|
# override
|
|
10
|
-
def indexes(table_name)
|
|
10
|
+
def indexes(table_name) # :nodoc:
|
|
11
11
|
indexes = super
|
|
12
12
|
# HACK(aleks, 06/15/18): MySQL 5 does not support prefix lengths for spatial indexes
|
|
13
13
|
# https://dev.mysql.com/doc/refman/5.6/en/create-index.html
|
|
@@ -33,7 +33,7 @@ module ActiveRecord
|
|
|
33
33
|
|
|
34
34
|
column_options = column.limit.is_a?(Hash) ? column.limit.symbolize_keys.except(:type) : {}
|
|
35
35
|
column_options[:comment] = column.comment if column.comment.present?
|
|
36
|
-
change_column(table_name, name, column.limit[:type].to_sym, **column_options
|
|
36
|
+
change_column(table_name, name, column.limit[:type].to_sym, **column_options, null: false)
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
|
|
@@ -42,17 +42,19 @@ module ActiveRecord
|
|
|
42
42
|
|
|
43
43
|
# override
|
|
44
44
|
def type_to_sql(type, limit: nil, precision: nil, scale: nil, unsigned: nil, **) # :nodoc:
|
|
45
|
-
if type.to_sym == :geometry && limit.is_a?(String)
|
|
46
|
-
return "geometry(#{limit})"
|
|
47
|
-
end
|
|
45
|
+
return "geometry(#{limit})" if type.to_sym == :geometry && limit.is_a?(String)
|
|
48
46
|
|
|
49
|
-
if
|
|
47
|
+
if RGeo::ActiveRecord.geometric_type_from_name(type.to_s.delete("_"))
|
|
50
48
|
type = limit[:type] || type if limit.is_a?(::Hash)
|
|
51
49
|
type = type.to_s.delete("_").upcase
|
|
52
50
|
end
|
|
53
51
|
super
|
|
54
52
|
end
|
|
55
53
|
|
|
54
|
+
def update_table_definition(table_name, base)
|
|
55
|
+
Mysql2Rgeo::Table.new(table_name, base)
|
|
56
|
+
end
|
|
57
|
+
|
|
56
58
|
private
|
|
57
59
|
|
|
58
60
|
# override
|
|
@@ -65,20 +67,18 @@ module ActiveRecord
|
|
|
65
67
|
Mysql2Rgeo::TableDefinition.new(self, *args, **options)
|
|
66
68
|
end
|
|
67
69
|
|
|
68
|
-
def update_table_definition(table_name, base)
|
|
69
|
-
Mysql2Rgeo::Table.new(table_name, base)
|
|
70
|
-
end
|
|
71
|
-
|
|
72
70
|
# override
|
|
73
71
|
def new_column_from_field(table_name, field, _definitions)
|
|
74
72
|
type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
|
|
75
|
-
default
|
|
73
|
+
default = field[:Default]
|
|
74
|
+
default_function = nil
|
|
76
75
|
metadata = Mysql2Rgeo::ColumnDefinitionUtils.extract_metadata(field[:Comment])
|
|
77
76
|
comment = Mysql2Rgeo::ColumnDefinitionUtils.strip_metadata_comment(field[:Comment])
|
|
78
77
|
default = metadata[:default_hex] if default.nil? && metadata[:default_hex].present?
|
|
79
78
|
|
|
80
79
|
if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\([0-6]?\))?\z/i.match?(default)
|
|
81
|
-
|
|
80
|
+
default_function = default
|
|
81
|
+
default = nil
|
|
82
82
|
elsif type_metadata.extra == "DEFAULT_GENERATED"
|
|
83
83
|
if default == "NULL" && metadata[:default_hex].present?
|
|
84
84
|
default = metadata[:default_hex]
|
|
@@ -87,8 +87,9 @@ module ActiveRecord
|
|
|
87
87
|
end
|
|
88
88
|
|
|
89
89
|
if default&.match?(/\Ast_geomfromtext\(/i)
|
|
90
|
-
default =
|
|
91
|
-
|
|
90
|
+
default = "(#{default})" unless default.start_with?("(")
|
|
91
|
+
default_function = default
|
|
92
|
+
default = nil
|
|
92
93
|
end
|
|
93
94
|
end
|
|
94
95
|
|
|
@@ -116,9 +117,9 @@ module ActiveRecord
|
|
|
116
117
|
type: :geometry,
|
|
117
118
|
limit: nil,
|
|
118
119
|
precision: type_metadata.precision,
|
|
119
|
-
scale: type_metadata.scale
|
|
120
|
+
scale: type_metadata.scale
|
|
120
121
|
),
|
|
121
|
-
extra: type_metadata.extra
|
|
122
|
+
extra: type_metadata.extra
|
|
122
123
|
)
|
|
123
124
|
|
|
124
125
|
if default_function&.match?(/\A\(?st_geomfromtext\(/i)
|
|
@@ -159,10 +160,11 @@ module ActiveRecord
|
|
|
159
160
|
srid: srid,
|
|
160
161
|
geographic: spatial[:geographic],
|
|
161
162
|
has_z: spatial[:has_z],
|
|
162
|
-
has_m: spatial[:has_m]
|
|
163
|
+
has_m: spatial[:has_m]
|
|
163
164
|
)
|
|
164
165
|
geometry = type.serialize(wkt)
|
|
165
166
|
return unless geometry
|
|
167
|
+
|
|
166
168
|
geometry = RGeo::Feature.cast(geometry, factory: type.send(:spatial_factory), project: true) if spatial[:geographic]
|
|
167
169
|
|
|
168
170
|
wkb = RGeo::WKRep::WKBGenerator.new(
|
|
@@ -171,10 +173,15 @@ module ActiveRecord
|
|
|
171
173
|
type_format: :wkb11,
|
|
172
174
|
emit_ewkb_srid: false
|
|
173
175
|
).generate(geometry)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
176
|
+
wkb = wkb.upcase
|
|
177
|
+
return wkb unless spatial[:geographic]
|
|
178
|
+
|
|
179
|
+
endian = wkb[0, 2]
|
|
180
|
+
type_hex = wkb[2, 8]
|
|
181
|
+
body = wkb[10..]
|
|
182
|
+
type = [type_hex].pack("H*").unpack1("V") | 0x20000000
|
|
183
|
+
srid_hex = [spatial[:srid].to_i].pack("V").unpack1("H*").upcase
|
|
184
|
+
"#{endian}#{[type].pack('V').unpack1('H*').upcase}#{srid_hex}#{body}"
|
|
178
185
|
end
|
|
179
186
|
|
|
180
187
|
def generation_expression_for(table_name, column_name)
|
|
@@ -185,7 +192,7 @@ module ActiveRecord
|
|
|
185
192
|
AND table_name = #{quote(table_name)}
|
|
186
193
|
AND column_name = #{quote(column_name)}
|
|
187
194
|
SQL
|
|
188
|
-
|
|
195
|
+
&.gsub(/st_buffer\(([^,]+),\s*(\d+)\)/i, 'st_buffer(\1, (\2)::double precision)')
|
|
189
196
|
end
|
|
190
197
|
|
|
191
198
|
def generated_default_for(table_name, column_name)
|
|
@@ -4,16 +4,22 @@ module ActiveRecord # :nodoc:
|
|
|
4
4
|
module ConnectionAdapters # :nodoc:
|
|
5
5
|
module Mysql2Rgeo # :nodoc:
|
|
6
6
|
class SpatialColumn < ConnectionAdapters::MySQL::Column # :nodoc:
|
|
7
|
-
def initialize(name, default, sql_type_metadata = nil, null = true, default_function = nil, collation: nil, comment: nil,
|
|
7
|
+
def initialize(name, default, sql_type_metadata = nil, null = true, default_function = nil, collation: nil, comment: nil,
|
|
8
|
+
spatial: nil, array: false, **)
|
|
8
9
|
@sql_type_metadata = sql_type_metadata
|
|
9
10
|
@array = array
|
|
11
|
+
@geographic = !!(sql_type_metadata&.sql_type =~ /geography\(/i)
|
|
10
12
|
if spatial
|
|
11
13
|
# This case comes from an entry in the geometry_columns table
|
|
12
14
|
set_geometric_type_from_name(spatial[:type])
|
|
13
15
|
@srid = spatial[:srid].to_i
|
|
14
|
-
@has_z = spatial[:has_z]
|
|
15
|
-
@has_m = spatial[:has_m]
|
|
16
|
-
@geographic = spatial[:geographic]
|
|
16
|
+
@has_z = !!spatial[:has_z]
|
|
17
|
+
@has_m = !!spatial[:has_m]
|
|
18
|
+
@geographic = !!spatial[:geographic] || @geographic
|
|
19
|
+
elsif @geographic
|
|
20
|
+
@srid = 4326
|
|
21
|
+
@has_z = @has_m = false
|
|
22
|
+
build_from_sql_type(sql_type_metadata.sql_type)
|
|
17
23
|
elsif sql_type =~ /geometry|point|linestring|polygon/i
|
|
18
24
|
build_from_sql_type(sql_type_metadata.sql_type)
|
|
19
25
|
elsif sql_type_metadata.sql_type =~ /geometry|point|linestring|polygon/i
|
|
@@ -22,14 +28,13 @@ module ActiveRecord # :nodoc:
|
|
|
22
28
|
build_from_sql_type(sql_type_metadata.sql_type)
|
|
23
29
|
end
|
|
24
30
|
super(name, default, sql_type_metadata, null, default_function, collation: collation, comment: comment)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
end
|
|
31
|
+
return unless spatial?
|
|
32
|
+
return unless @srid
|
|
33
|
+
|
|
34
|
+
@limit = { type: limit_type_name, srid: @srid }
|
|
35
|
+
@limit[:geographic] = true if geographic?
|
|
36
|
+
@limit[:has_z] = true if has_z?
|
|
37
|
+
@limit[:has_m] = true if has_m?
|
|
33
38
|
end
|
|
34
39
|
|
|
35
40
|
attr_reader :geometric_type, :srid
|
|
@@ -67,6 +72,30 @@ module ActiveRecord # :nodoc:
|
|
|
67
72
|
%i[geometry geography].include?(@sql_type_metadata.type)
|
|
68
73
|
end
|
|
69
74
|
|
|
75
|
+
SPATIAL_ATTRIBUTES = %w[geographic geometric_type has_m has_z srid limit].freeze
|
|
76
|
+
|
|
77
|
+
def init_with(coder)
|
|
78
|
+
SPATIAL_ATTRIBUTES.each { |attr| instance_variable_set(:"@#{attr}", coder[attr]) }
|
|
79
|
+
super
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def encode_with(coder)
|
|
83
|
+
SPATIAL_ATTRIBUTES.each { |attr| coder[attr] = instance_variable_get(:"@#{attr}") }
|
|
84
|
+
super
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def ==(other)
|
|
88
|
+
other.is_a?(SpatialColumn) &&
|
|
89
|
+
super &&
|
|
90
|
+
array == other.array &&
|
|
91
|
+
SPATIAL_ATTRIBUTES.all? { |attr| public_send(attr) == other.public_send(attr) }
|
|
92
|
+
end
|
|
93
|
+
alias eql? ==
|
|
94
|
+
|
|
95
|
+
def hash
|
|
96
|
+
SPATIAL_ATTRIBUTES.reduce(SpatialColumn.hash ^ super.hash ^ array.hash) { |h, attr| h ^ public_send(attr).hash }
|
|
97
|
+
end
|
|
98
|
+
|
|
70
99
|
private
|
|
71
100
|
|
|
72
101
|
def set_geometric_type_from_name(name)
|
|
@@ -29,11 +29,11 @@ module ActiveRecord # :nodoc:
|
|
|
29
29
|
has_z = type.sub!(/z$/i, "").present?
|
|
30
30
|
has_m = type.sub!(/m$/i, "").present?
|
|
31
31
|
result[name] = {
|
|
32
|
-
name:
|
|
33
|
-
srid:
|
|
34
|
-
type:
|
|
35
|
-
has_z:
|
|
36
|
-
has_m:
|
|
32
|
+
name: name,
|
|
33
|
+
srid: row[1].to_i,
|
|
34
|
+
type: type,
|
|
35
|
+
has_z: has_z,
|
|
36
|
+
has_m: has_m,
|
|
37
37
|
geographic: column_comment.include?("mysql2rgeo:geographic"),
|
|
38
38
|
}
|
|
39
39
|
end
|
|
@@ -5,6 +5,7 @@ module ActiveRecord # :nodoc:
|
|
|
5
5
|
module Mysql2Rgeo # :nodoc:
|
|
6
6
|
class TableDefinition < MySQL::TableDefinition # :nodoc:
|
|
7
7
|
include ColumnMethods
|
|
8
|
+
|
|
8
9
|
# super: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
|
|
9
10
|
def new_column_definition(name, type, **options)
|
|
10
11
|
spatial_type = type.to_sym == :virtual ? options[:type]&.to_sym : type.to_sym
|
|
@@ -20,7 +21,9 @@ module ActiveRecord # :nodoc:
|
|
|
20
21
|
ColumnDefinitionUtils.geo_type(options[:type] || spatial_type || info[:type])
|
|
21
22
|
end
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
if type.to_sym == :virtual
|
|
25
|
+
options.delete(:srid)
|
|
26
|
+
else
|
|
24
27
|
options[:srid] ||= ColumnDefinitionUtils.default_srid(options)
|
|
25
28
|
options[:comment] = ColumnDefinitionUtils.add_metadata_comment(
|
|
26
29
|
options[:comment],
|
|
@@ -32,19 +35,20 @@ module ActiveRecord # :nodoc:
|
|
|
32
35
|
srid: options[:srid],
|
|
33
36
|
geo_type: geo_type
|
|
34
37
|
)
|
|
35
|
-
else
|
|
36
|
-
options.delete(:srid)
|
|
37
38
|
end
|
|
38
39
|
|
|
39
40
|
options[:spatial_type] = geo_type
|
|
40
|
-
if type.to_sym == :virtual
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
column = if type.to_sym == :virtual
|
|
42
|
+
super(name, type, **options.merge(type: geo_type.downcase.to_sym))
|
|
43
|
+
else
|
|
44
|
+
super(name, geo_type.downcase.to_sym, **options)
|
|
45
|
+
end
|
|
45
46
|
else
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
if options[:array]
|
|
48
|
+
options[:comment] =
|
|
49
|
+
ColumnDefinitionUtils.add_metadata_comment(options[:comment], array: options[:array])
|
|
50
|
+
end
|
|
51
|
+
column = super
|
|
48
52
|
end
|
|
49
53
|
|
|
50
54
|
column
|
|
@@ -77,14 +81,16 @@ module ActiveRecord # :nodoc:
|
|
|
77
81
|
options[:geographic] ? 4326 : Mysql2RgeoAdapter::DEFAULT_SRID
|
|
78
82
|
end
|
|
79
83
|
|
|
80
|
-
def add_metadata_comment(comment, geographic: false, has_m: false, has_z: false, array: false, default: nil, srid: nil,
|
|
84
|
+
def add_metadata_comment(comment, geographic: false, has_m: false, has_z: false, array: false, default: nil, srid: nil,
|
|
85
|
+
geo_type: nil)
|
|
81
86
|
values = [comment]
|
|
82
87
|
values << METADATA_TOKENS[:geographic] if geographic
|
|
83
88
|
values << METADATA_TOKENS[:has_m] if has_m
|
|
84
89
|
values << METADATA_TOKENS[:has_z] if has_z
|
|
85
90
|
values << METADATA_TOKENS[:array] if array
|
|
86
91
|
if default
|
|
87
|
-
values << "#{METADATA_TOKENS[:default_prefix]}#{encode_default(default, geographic: geographic, srid: srid,
|
|
92
|
+
values << "#{METADATA_TOKENS[:default_prefix]}#{encode_default(default, geographic: geographic, srid: srid,
|
|
93
|
+
geo_type: geo_type, has_m: has_m, has_z: has_z)}"
|
|
88
94
|
end
|
|
89
95
|
values.compact_blank.join(" ")
|
|
90
96
|
end
|
|
@@ -128,10 +134,16 @@ module ActiveRecord # :nodoc:
|
|
|
128
134
|
type_format: :wkb11,
|
|
129
135
|
emit_ewkb_srid: false
|
|
130
136
|
).generate(geometry).upcase
|
|
131
|
-
|
|
137
|
+
geographic ? with_ewkb_srid(wkb, srid) : wkb
|
|
138
|
+
end
|
|
132
139
|
|
|
140
|
+
def with_ewkb_srid(wkb, srid)
|
|
141
|
+
endian = wkb[0, 2]
|
|
142
|
+
type_hex = wkb[2, 8]
|
|
143
|
+
body = wkb[10..]
|
|
144
|
+
type = [type_hex].pack("H*").unpack1("V") | 0x20000000
|
|
133
145
|
srid_hex = [srid.to_i].pack("V").unpack1("H*").upcase
|
|
134
|
-
"#{srid_hex}#{
|
|
146
|
+
"#{endian}#{[type].pack('V').unpack1('H*').upcase}#{srid_hex}#{body}"
|
|
135
147
|
end
|
|
136
148
|
end
|
|
137
149
|
end
|
|
@@ -22,6 +22,12 @@ require "active_record/type/spatial"
|
|
|
22
22
|
|
|
23
23
|
# :startdoc:
|
|
24
24
|
|
|
25
|
+
ActiveRecord::ConnectionAdapters.register(
|
|
26
|
+
"mysql2rgeo",
|
|
27
|
+
"ActiveRecord::ConnectionAdapters::Mysql2RgeoAdapter",
|
|
28
|
+
"active_record/connection_adapters/mysql2rgeo_adapter"
|
|
29
|
+
)
|
|
30
|
+
|
|
25
31
|
module ActiveRecord
|
|
26
32
|
module ConnectionHandling # :nodoc:
|
|
27
33
|
# Establishes a connection to the database that's used by all Active Record objects.
|
|
@@ -29,7 +35,7 @@ module ActiveRecord
|
|
|
29
35
|
config = config.symbolize_keys
|
|
30
36
|
config[:flags] ||= 0
|
|
31
37
|
|
|
32
|
-
if config[:flags].
|
|
38
|
+
if config[:flags].is_a? Array
|
|
33
39
|
config[:flags].push "FOUND_ROWS"
|
|
34
40
|
else
|
|
35
41
|
config[:flags] |= Mysql2::Client::FOUND_ROWS
|
|
@@ -39,7 +45,7 @@ module ActiveRecord
|
|
|
39
45
|
ConnectionAdapters::Mysql2RgeoAdapter.new_client(config),
|
|
40
46
|
logger,
|
|
41
47
|
nil,
|
|
42
|
-
config
|
|
48
|
+
config
|
|
43
49
|
)
|
|
44
50
|
end
|
|
45
51
|
end
|
|
@@ -47,37 +53,34 @@ module ActiveRecord
|
|
|
47
53
|
module ConnectionAdapters
|
|
48
54
|
class Mysql2RgeoAdapter < Mysql2Adapter
|
|
49
55
|
ADAPTER_NAME = "Mysql2Rgeo"
|
|
50
|
-
MINIMUM_SUPPORTED_VERSION = "8.0.0"
|
|
51
56
|
|
|
52
57
|
include Mysql2Rgeo::SchemaStatements
|
|
53
58
|
|
|
54
59
|
SPATIAL_COLUMN_OPTIONS =
|
|
55
60
|
{
|
|
56
|
-
geography:
|
|
57
|
-
geometry:
|
|
58
|
-
geometrycollection:
|
|
61
|
+
geography: { type: "geometry", geographic: true },
|
|
62
|
+
geometry: {},
|
|
63
|
+
geometrycollection: {},
|
|
59
64
|
geometry_collection: { type: "geometrycollection" },
|
|
60
|
-
linestring:
|
|
61
|
-
line_string:
|
|
62
|
-
multilinestring:
|
|
63
|
-
multi_line_string:
|
|
64
|
-
multipoint:
|
|
65
|
-
multi_point:
|
|
66
|
-
multipolygon:
|
|
67
|
-
multi_polygon:
|
|
68
|
-
spatial:
|
|
69
|
-
point:
|
|
70
|
-
polygon:
|
|
71
|
-
st_point:
|
|
72
|
-
st_polygon:
|
|
65
|
+
linestring: {},
|
|
66
|
+
line_string: { type: "linestring" },
|
|
67
|
+
multilinestring: {},
|
|
68
|
+
multi_line_string: { type: "multilinestring" },
|
|
69
|
+
multipoint: {},
|
|
70
|
+
multi_point: { type: "multipoint" },
|
|
71
|
+
multipolygon: {},
|
|
72
|
+
multi_polygon: { type: "multipolygon" },
|
|
73
|
+
spatial: { type: "geometry" },
|
|
74
|
+
point: {},
|
|
75
|
+
polygon: {},
|
|
76
|
+
st_point: { type: "point" },
|
|
77
|
+
st_polygon: { type: "polygon" }
|
|
73
78
|
}.freeze
|
|
74
79
|
|
|
75
|
-
# MySQL uses SRID 0 when a spatial column does not declare one explicitly.
|
|
76
80
|
DEFAULT_SRID = 0
|
|
77
81
|
|
|
78
|
-
def initialize(
|
|
82
|
+
def initialize(...)
|
|
79
83
|
super
|
|
80
|
-
verify_supported_database_version!
|
|
81
84
|
|
|
82
85
|
@visitor = Arel::Visitors::Mysql2Rgeo.new(self)
|
|
83
86
|
end
|
|
@@ -94,85 +97,89 @@ module ActiveRecord
|
|
|
94
97
|
# Add spatial types
|
|
95
98
|
# Reference: https://dev.mysql.com/doc/refman/5.6/en/spatial-type-overview.html
|
|
96
99
|
super.merge(
|
|
97
|
-
geometry:
|
|
98
|
-
geometrycollection:
|
|
99
|
-
line_string:
|
|
100
|
-
linestring:
|
|
101
|
-
st_point:
|
|
102
|
-
st_polygon:
|
|
103
|
-
multi_line_string:
|
|
104
|
-
multi_point:
|
|
105
|
-
multi_polygon:
|
|
106
|
-
spatial:
|
|
107
|
-
point:
|
|
108
|
-
polygon:
|
|
100
|
+
geometry: { name: "geometry" },
|
|
101
|
+
geometrycollection: { name: "geometrycollection" },
|
|
102
|
+
line_string: { name: "linestring" },
|
|
103
|
+
linestring: { name: "linestring" },
|
|
104
|
+
st_point: { name: "point" },
|
|
105
|
+
st_polygon: { name: "polygon" },
|
|
106
|
+
multi_line_string: { name: "multilinestring" },
|
|
107
|
+
multi_point: { name: "multipoint" },
|
|
108
|
+
multi_polygon: { name: "multipolygon" },
|
|
109
|
+
spatial: { name: "geometry" },
|
|
110
|
+
point: { name: "point" },
|
|
111
|
+
polygon: { name: "polygon" }
|
|
109
112
|
)
|
|
110
113
|
end
|
|
111
114
|
|
|
112
115
|
class << self
|
|
113
|
-
|
|
114
116
|
private
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
117
|
+
|
|
118
|
+
def initialize_type_map(m)
|
|
119
|
+
super
|
|
120
|
+
|
|
121
|
+
{
|
|
122
|
+
"geography" => "geometry",
|
|
123
|
+
"geometry" => "geometry",
|
|
124
|
+
"geometry_collection" => "geometrycollection",
|
|
125
|
+
"line_string" => "linestring",
|
|
126
|
+
"multi_line_string" => "multilinestring",
|
|
127
|
+
"multi_point" => "multipoint",
|
|
128
|
+
"multi_polygon" => "multipolygon",
|
|
129
|
+
"st_point" => "point",
|
|
130
|
+
"st_polygon" => "polygon",
|
|
131
|
+
}.each do |registered_type, geo_type|
|
|
132
|
+
m.register_type(registered_type) do |sql_type|
|
|
133
|
+
Type::Spatial.new(sql_type.to_s, geo_type: geo_type)
|
|
132
134
|
end
|
|
135
|
+
end
|
|
133
136
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
end
|
|
137
|
+
[
|
|
138
|
+
/\Ageometry(?:\(.*\))?\z/i,
|
|
139
|
+
/\Ageography(?:\(.*\))?\z/i,
|
|
140
|
+
/\Apoint(?:\s.*)?\z/i,
|
|
141
|
+
/\Alinestring(?:\s.*)?\z/i,
|
|
142
|
+
/\Apolygon(?:\s.*)?\z/i,
|
|
143
|
+
/\Amultipoint(?:\s.*)?\z/i,
|
|
144
|
+
/\Amultilinestring(?:\s.*)?\z/i,
|
|
145
|
+
/\Amultipolygon(?:\s.*)?\z/i,
|
|
146
|
+
/\Ageometrycollection(?:\s.*)?\z/i,
|
|
147
|
+
].each do |pattern|
|
|
148
|
+
m.register_type(pattern) do |sql_type|
|
|
149
|
+
Type::Spatial.new(sql_type.to_s)
|
|
148
150
|
end
|
|
151
|
+
end
|
|
149
152
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
end
|
|
153
|
+
{
|
|
154
|
+
st_point: "point",
|
|
155
|
+
st_polygon: "polygon",
|
|
156
|
+
line_string: "linestring",
|
|
157
|
+
multi_line_string: "multilinestring",
|
|
158
|
+
multi_point: "multipoint",
|
|
159
|
+
multi_polygon: "multipolygon",
|
|
160
|
+
}.each do |alias_type, geo_type|
|
|
161
|
+
ActiveRecord::Type.register(alias_type) do |_, **kwargs|
|
|
162
|
+
Type::Spatial.new(geo_type, geo_type: geo_type, **kwargs)
|
|
161
163
|
end
|
|
162
164
|
end
|
|
165
|
+
end
|
|
163
166
|
end
|
|
164
167
|
|
|
165
168
|
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
|
|
166
169
|
TYPE_MAP_WITH_BOOLEAN = Type::TypeMap.new(TYPE_MAP).tap do |m|
|
|
167
|
-
m.register_type
|
|
170
|
+
m.register_type(/^tinyint\(1\)/i, Type::Boolean.new)
|
|
168
171
|
end
|
|
169
172
|
|
|
170
173
|
def supports_spatial?
|
|
171
|
-
!mariadb? &&
|
|
174
|
+
!mariadb? && version >= "5.7.6"
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def supports_partitioned_indexes?
|
|
178
|
+
false
|
|
172
179
|
end
|
|
173
180
|
|
|
174
181
|
def adapter_name
|
|
175
|
-
|
|
182
|
+
"Mysql2Rgeo"
|
|
176
183
|
end
|
|
177
184
|
|
|
178
185
|
def quote(value)
|
|
@@ -203,16 +210,10 @@ module ActiveRecord
|
|
|
203
210
|
end
|
|
204
211
|
|
|
205
212
|
private
|
|
206
|
-
def verify_supported_database_version!
|
|
207
|
-
return if database_version >= MINIMUM_SUPPORTED_VERSION
|
|
208
213
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
def type_map
|
|
214
|
-
emulate_booleans ? TYPE_MAP_WITH_BOOLEAN : TYPE_MAP
|
|
215
|
-
end
|
|
214
|
+
def type_map
|
|
215
|
+
emulate_booleans ? TYPE_MAP_WITH_BOOLEAN : TYPE_MAP
|
|
216
|
+
end
|
|
216
217
|
end
|
|
217
218
|
end
|
|
218
219
|
end
|
|
@@ -41,9 +41,7 @@ module ActiveRecord
|
|
|
41
41
|
has_z = Regexp.last_match(2).casecmp("z").zero?
|
|
42
42
|
has_m = Regexp.last_match(3).casecmp("m").zero?
|
|
43
43
|
end
|
|
44
|
-
if params.last =~ /(\d+)/
|
|
45
|
-
srid = Regexp.last_match(1).to_i
|
|
46
|
-
end
|
|
44
|
+
srid = Regexp.last_match(1).to_i if params.last =~ /(\d+)/
|
|
47
45
|
elsif sql_type =~ /\A(geography|geometry)\z/i
|
|
48
46
|
geographic = Regexp.last_match(1).casecmp("geography").zero?
|
|
49
47
|
geo_type = Regexp.last_match(1)
|
|
@@ -82,7 +80,7 @@ module ActiveRecord
|
|
|
82
80
|
has_z: @has_z,
|
|
83
81
|
sql_type: @geographic ? "geography" : "geometry",
|
|
84
82
|
srid: @srid
|
|
85
|
-
|
|
83
|
+
)
|
|
86
84
|
end
|
|
87
85
|
|
|
88
86
|
def klass
|
|
@@ -118,7 +116,7 @@ module ActiveRecord
|
|
|
118
116
|
def cast_value(value)
|
|
119
117
|
return if value.nil?
|
|
120
118
|
|
|
121
|
-
::String
|
|
119
|
+
value.is_a?(::String) ? parse_wkt(value) : value
|
|
122
120
|
end
|
|
123
121
|
|
|
124
122
|
# convert WKT string into RGeo object
|
|
@@ -126,7 +124,7 @@ module ActiveRecord
|
|
|
126
124
|
marker = string[4, 1]
|
|
127
125
|
if ["\x00", "\x01"].include?(marker)
|
|
128
126
|
@srid = string[0, 4].unpack1(marker == "\x01" ? "V" : "N")
|
|
129
|
-
RGeo::WKRep::WKBParser.new(spatial_factory, support_ewkb: true, default_srid: @srid).parse(string[4
|
|
127
|
+
RGeo::WKRep::WKBParser.new(spatial_factory, support_ewkb: true, default_srid: @srid).parse(string[4..])
|
|
130
128
|
elsif string.match?(/\A[0-9a-fA-F]+\z/)
|
|
131
129
|
original_srid = @srid
|
|
132
130
|
parser = RGeo::WKRep::WKBParser.new(spatial_factory, support_ewkb: true, default_srid: @srid)
|
|
@@ -139,9 +137,9 @@ module ActiveRecord
|
|
|
139
137
|
|
|
140
138
|
if string[0, 10] =~ /[0-9a-fA-F]{8}0[01]/
|
|
141
139
|
@srid = string[0, 8].to_i(16)
|
|
142
|
-
@srid = [@srid].pack("V").
|
|
140
|
+
@srid = [@srid].pack("V").unpack1("N") if string[9, 1] == "1"
|
|
143
141
|
parser = RGeo::WKRep::WKBParser.new(spatial_factory, support_ewkb: true, default_srid: @srid)
|
|
144
|
-
return parser.parse([string[8
|
|
142
|
+
return parser.parse([string[8..]].pack("H*"))
|
|
145
143
|
end
|
|
146
144
|
|
|
147
145
|
parser.parse([string].pack("H*"))
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: activerecord-mysql2rgeo-adapter
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 8.0.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yongdae Hwang
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: activerecord
|
|
@@ -16,28 +15,28 @@ dependencies:
|
|
|
16
15
|
requirements:
|
|
17
16
|
- - "~>"
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: 7.
|
|
18
|
+
version: '7.2'
|
|
20
19
|
type: :runtime
|
|
21
20
|
prerelease: false
|
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
22
|
requirements:
|
|
24
23
|
- - "~>"
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: 7.
|
|
25
|
+
version: '7.2'
|
|
27
26
|
- !ruby/object:Gem::Dependency
|
|
28
27
|
name: rgeo-activerecord
|
|
29
28
|
requirement: !ruby/object:Gem::Requirement
|
|
30
29
|
requirements:
|
|
31
30
|
- - "~>"
|
|
32
31
|
- !ruby/object:Gem::Version
|
|
33
|
-
version:
|
|
32
|
+
version: 8.0.0
|
|
34
33
|
type: :runtime
|
|
35
34
|
prerelease: false
|
|
36
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
36
|
requirements:
|
|
38
37
|
- - "~>"
|
|
39
38
|
- !ruby/object:Gem::Version
|
|
40
|
-
version:
|
|
39
|
+
version: 8.0.0
|
|
41
40
|
- !ruby/object:Gem::Dependency
|
|
42
41
|
name: rake
|
|
43
42
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -67,19 +66,19 @@ dependencies:
|
|
|
67
66
|
- !ruby/object:Gem::Version
|
|
68
67
|
version: '5.4'
|
|
69
68
|
- !ruby/object:Gem::Dependency
|
|
70
|
-
name:
|
|
69
|
+
name: minitest-excludes
|
|
71
70
|
requirement: !ruby/object:Gem::Requirement
|
|
72
71
|
requirements:
|
|
73
72
|
- - "~>"
|
|
74
73
|
- !ruby/object:Gem::Version
|
|
75
|
-
version: '
|
|
74
|
+
version: '2.0'
|
|
76
75
|
type: :development
|
|
77
76
|
prerelease: false
|
|
78
77
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
78
|
requirements:
|
|
80
79
|
- - "~>"
|
|
81
80
|
- !ruby/object:Gem::Version
|
|
82
|
-
version: '
|
|
81
|
+
version: '2.0'
|
|
83
82
|
- !ruby/object:Gem::Dependency
|
|
84
83
|
name: benchmark-ips
|
|
85
84
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -134,10 +133,10 @@ homepage: http://github.com/stadia/activerecord-mysql2rgeo-adapter
|
|
|
134
133
|
licenses:
|
|
135
134
|
- BSD-3-Clause
|
|
136
135
|
metadata:
|
|
136
|
+
funding_uri: https://opencollective.com/rgeo
|
|
137
137
|
source_code_uri: https://github.com/stadia/activerecord-mysql2rgeo-adapter
|
|
138
138
|
documentation_uri: https://github.com/stadia/activerecord-mysql2rgeo-adapter/blob/main/README.md
|
|
139
139
|
rubygems_mfa_required: 'true'
|
|
140
|
-
post_install_message:
|
|
141
140
|
rdoc_options: []
|
|
142
141
|
require_paths:
|
|
143
142
|
- lib
|
|
@@ -145,15 +144,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
145
144
|
requirements:
|
|
146
145
|
- - ">="
|
|
147
146
|
- !ruby/object:Gem::Version
|
|
148
|
-
version: 3.
|
|
147
|
+
version: 3.1.0
|
|
149
148
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
150
149
|
requirements:
|
|
151
150
|
- - ">="
|
|
152
151
|
- !ruby/object:Gem::Version
|
|
153
152
|
version: '0'
|
|
154
153
|
requirements: []
|
|
155
|
-
rubygems_version:
|
|
156
|
-
signing_key:
|
|
154
|
+
rubygems_version: 4.0.20
|
|
157
155
|
specification_version: 4
|
|
158
156
|
summary: ActiveRecord adapter for MySQL, based on RGeo.
|
|
159
157
|
test_files: []
|