activerecord-mysql2rgeo-adapter 7.2.0 → 7.3.1
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 +29 -12
- data/lib/active_record/connection_adapters/mysql2rgeo/column_methods.rb +6 -0
- data/lib/active_record/connection_adapters/mysql2rgeo/schema_creation.rb +20 -0
- data/lib/active_record/connection_adapters/mysql2rgeo/schema_statements.rb +132 -5
- data/lib/active_record/connection_adapters/mysql2rgeo/spatial_column.rb +37 -6
- data/lib/active_record/connection_adapters/mysql2rgeo/spatial_column_info.rb +8 -3
- data/lib/active_record/connection_adapters/mysql2rgeo/spatial_table_definition.rb +101 -5
- data/lib/active_record/connection_adapters/mysql2rgeo/version.rb +1 -1
- data/lib/active_record/connection_adapters/mysql2rgeo_adapter.rb +86 -18
- data/lib/active_record/type/spatial.rb +64 -11
- data/lib/activerecord-mysql2rgeo-adapter.rb +0 -2
- metadata +27 -23
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 22e12f955f45c958cdf1d7482072dea06de6c23a55df0863d0e454cb3b2b4814
|
|
4
|
+
data.tar.gz: 594de2ab90c4ec8cc2ea126ad286eddbf7c44b3ff46a08b204ff92add1baefde
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5f41a95d660e6c21be4a2b3d653e0d47758d74432a36f1ac68075f2a2b079ec4d0da35e30fd83e6e2d7484abd8d9e8a664752aa397d0024690ae01b4afd84047
|
|
7
|
+
data.tar.gz: 2ff34f00366a8e5861ba4394f1b42d827f1b502e258defe09bd156b28eb9e13f53b7e4b617d8c283fcbe09909885f3002b8a04f8d101723d8c1b7c206975505a
|
|
@@ -28,12 +28,10 @@ module Arel # :nodoc:
|
|
|
28
28
|
|
|
29
29
|
def visit_String(node, collector)
|
|
30
30
|
node, srid = Mysql2Rgeo.parse_node(node)
|
|
31
|
-
collector <<
|
|
32
|
-
"#{st_func('ST_WKTToSQL')}(#{quote(node)})"
|
|
33
|
-
else
|
|
34
|
-
"#{st_func('ST_WKTToSQL')}(#{quote(node)}, #{srid})"
|
|
35
|
-
end
|
|
31
|
+
collector << spatial_constant_sql(node, srid)
|
|
36
32
|
end
|
|
33
|
+
alias visit_RGeo_Feature_Instance visit_String
|
|
34
|
+
alias visit_RGeo_Cartesian_BoundingBox visit_String
|
|
37
35
|
|
|
38
36
|
def visit_RGeo_ActiveRecord_SpatialNamedFunction(node, collector)
|
|
39
37
|
aggregate(st_func(node.name), node, collector)
|
|
@@ -43,21 +41,28 @@ module Arel # :nodoc:
|
|
|
43
41
|
case node
|
|
44
42
|
when String
|
|
45
43
|
node, srid = Mysql2Rgeo.parse_node(node)
|
|
46
|
-
collector <<
|
|
47
|
-
"#{st_func('ST_WKTToSQL')}(#{quote(node)})"
|
|
48
|
-
else
|
|
49
|
-
"#{st_func('ST_WKTToSQL')}(#{quote(node)}, #{srid})"
|
|
50
|
-
end
|
|
44
|
+
collector << spatial_constant_sql(node, srid)
|
|
51
45
|
when RGeo::Feature::Instance
|
|
52
|
-
|
|
46
|
+
visit_RGeo_Feature_Instance(node, collector)
|
|
53
47
|
when RGeo::Cartesian::BoundingBox
|
|
54
|
-
|
|
48
|
+
visit_RGeo_Cartesian_BoundingBox(node, collector)
|
|
55
49
|
else
|
|
56
50
|
visit(node, collector)
|
|
57
51
|
end
|
|
58
52
|
end
|
|
59
53
|
|
|
60
54
|
def self.parse_node(node)
|
|
55
|
+
if RGeo::Feature::Instance === node
|
|
56
|
+
wkt = RGeo::WKRep::WKTGenerator.new(tag_format: :wkt11, emit_ewkt_srid: false).generate(node)
|
|
57
|
+
return [wkt, node.srid]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
if RGeo::Cartesian::BoundingBox === node
|
|
61
|
+
geometry = node.to_geometry
|
|
62
|
+
wkt = RGeo::WKRep::WKTGenerator.new(tag_format: :wkt11, emit_ewkt_srid: false).generate(geometry)
|
|
63
|
+
return [wkt, geometry.srid]
|
|
64
|
+
end
|
|
65
|
+
|
|
61
66
|
value, srid = nil, 0
|
|
62
67
|
if node =~ /.*;.*$/i
|
|
63
68
|
params = Regexp.last_match(0).split(";")
|
|
@@ -76,6 +81,18 @@ module Arel # :nodoc:
|
|
|
76
81
|
end
|
|
77
82
|
[value, srid]
|
|
78
83
|
end
|
|
84
|
+
|
|
85
|
+
private
|
|
86
|
+
|
|
87
|
+
def spatial_constant_sql(node, srid)
|
|
88
|
+
if srid == 0
|
|
89
|
+
"#{st_func('ST_WKTToSQL')}(#{quote(node)})"
|
|
90
|
+
elsif srid == 4326
|
|
91
|
+
"#{st_func('ST_WKTToSQL')}(#{quote(node)}, #{srid}, 'axis-order=long-lat')"
|
|
92
|
+
else
|
|
93
|
+
"#{st_func('ST_WKTToSQL')}(#{quote(node)}, #{srid})"
|
|
94
|
+
end
|
|
95
|
+
end
|
|
79
96
|
end
|
|
80
97
|
end
|
|
81
98
|
end
|
|
@@ -14,6 +14,10 @@ module ActiveRecord
|
|
|
14
14
|
column(name, :geometry, **options)
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
+
def geography(name, options = {})
|
|
18
|
+
column(name, :geometry, geographic: true, **options)
|
|
19
|
+
end
|
|
20
|
+
|
|
17
21
|
def geometry_collection(name, options = {})
|
|
18
22
|
column(name, :geometrycollection, **options)
|
|
19
23
|
end
|
|
@@ -42,10 +46,12 @@ module ActiveRecord
|
|
|
42
46
|
def point(name, options = {})
|
|
43
47
|
column(name, :point, **options)
|
|
44
48
|
end
|
|
49
|
+
alias st_point point
|
|
45
50
|
|
|
46
51
|
def polygon(name, options = {})
|
|
47
52
|
column(name, :polygon, **options)
|
|
48
53
|
end
|
|
54
|
+
alias st_polygon polygon
|
|
49
55
|
end
|
|
50
56
|
end
|
|
51
57
|
|
|
@@ -5,14 +5,34 @@ 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
|
+
|
|
17
|
+
super
|
|
18
|
+
end
|
|
8
19
|
|
|
9
20
|
def add_column_options!(sql, options)
|
|
10
21
|
if options[:srid]
|
|
11
22
|
sql << " /*!80003 SRID #{options[:srid]} */"
|
|
23
|
+
options = options.except(:srid)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
if options_include_default?(options) && spatial_column_definition?(options[:column])
|
|
27
|
+
options = options.except(:default)
|
|
12
28
|
end
|
|
13
29
|
|
|
14
30
|
super
|
|
15
31
|
end
|
|
32
|
+
|
|
33
|
+
def spatial_column_definition?(column)
|
|
34
|
+
column.respond_to?(:type) && column.type && @conn.class.spatial_column_options(column.type.to_sym)
|
|
35
|
+
end
|
|
16
36
|
end
|
|
17
37
|
end
|
|
18
38
|
end
|
|
@@ -13,12 +13,39 @@ module ActiveRecord
|
|
|
13
13
|
# https://dev.mysql.com/doc/refman/5.6/en/create-index.html
|
|
14
14
|
indexes.select do |idx|
|
|
15
15
|
idx.type == :spatial
|
|
16
|
-
end.each
|
|
16
|
+
end.each do |idx|
|
|
17
|
+
if idx.is_a?(Struct)
|
|
18
|
+
idx.lengths = {}
|
|
19
|
+
idx.using = :gist if idx.members.include?(:using)
|
|
20
|
+
else
|
|
21
|
+
idx.instance_variable_set(:@lengths, {})
|
|
22
|
+
idx.instance_variable_set(:@using, :gist)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
17
25
|
indexes
|
|
18
26
|
end
|
|
19
27
|
|
|
28
|
+
def add_index(table_name, column_name, **options) # :nodoc:
|
|
29
|
+
if options[:using]&.to_sym == :gist
|
|
30
|
+
Array(column_name).each do |name|
|
|
31
|
+
column = columns(table_name).find { |col| col.name == name.to_s }
|
|
32
|
+
next unless column&.spatial? && column.null
|
|
33
|
+
|
|
34
|
+
column_options = column.limit.is_a?(Hash) ? column.limit.symbolize_keys.except(:type) : {}
|
|
35
|
+
column_options[:comment] = column.comment if column.comment.present?
|
|
36
|
+
change_column(table_name, name, column.limit[:type].to_sym, **column_options.merge(null: false))
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
super
|
|
41
|
+
end
|
|
42
|
+
|
|
20
43
|
# override
|
|
21
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
|
|
48
|
+
|
|
22
49
|
if (info = RGeo::ActiveRecord.geometric_type_from_name(type.to_s.delete("_")))
|
|
23
50
|
type = limit[:type] || type if limit.is_a?(::Hash)
|
|
24
51
|
type = type.to_s.delete("_").upcase
|
|
@@ -38,20 +65,67 @@ module ActiveRecord
|
|
|
38
65
|
Mysql2Rgeo::TableDefinition.new(self, *args, **options)
|
|
39
66
|
end
|
|
40
67
|
|
|
68
|
+
def update_table_definition(table_name, base)
|
|
69
|
+
Mysql2Rgeo::Table.new(table_name, base)
|
|
70
|
+
end
|
|
71
|
+
|
|
41
72
|
# override
|
|
42
73
|
def new_column_from_field(table_name, field, _definitions)
|
|
43
74
|
type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
|
|
44
75
|
default, default_function = field[:Default], nil
|
|
76
|
+
metadata = Mysql2Rgeo::ColumnDefinitionUtils.extract_metadata(field[:Comment])
|
|
77
|
+
comment = Mysql2Rgeo::ColumnDefinitionUtils.strip_metadata_comment(field[:Comment])
|
|
78
|
+
default = metadata[:default_hex] if default.nil? && metadata[:default_hex].present?
|
|
45
79
|
|
|
46
80
|
if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\([0-6]?\))?\z/i.match?(default)
|
|
47
81
|
default, default_function = nil, default
|
|
48
82
|
elsif type_metadata.extra == "DEFAULT_GENERATED"
|
|
49
|
-
default
|
|
50
|
-
|
|
83
|
+
if default == "NULL" && metadata[:default_hex].present?
|
|
84
|
+
default = metadata[:default_hex]
|
|
85
|
+
elsif default == "NULL"
|
|
86
|
+
default = generated_default_for(table_name, field[:Field])
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
if default&.match?(/\Ast_geomfromtext\(/i)
|
|
90
|
+
default = +"(#{default})" unless default.start_with?("(")
|
|
91
|
+
default, default_function = nil, default
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
if type_metadata.extra.to_s.match?(/(?:VIRTUAL|STORED|PERSISTENT)\s+GENERATED/i)
|
|
96
|
+
default_function = generation_expression_for(table_name, field[:Field])
|
|
51
97
|
end
|
|
52
98
|
|
|
53
99
|
# {:dimension=>2, :has_m=>false, :has_z=>false, :name=>"latlon", :srid=>0, :type=>"GEOMETRY"}
|
|
54
100
|
spatial = spatial_column_info(table_name).get(field[:Field], type_metadata.sql_type)
|
|
101
|
+
if spatial
|
|
102
|
+
spatial[:has_z] ||= metadata[:has_z]
|
|
103
|
+
spatial[:has_m] ||= metadata[:has_m]
|
|
104
|
+
spatial[:geographic] ||= metadata[:geographic]
|
|
105
|
+
geo_type = spatial[:type].camelize
|
|
106
|
+
geo_type = "#{geo_type}Z" if spatial[:has_z]
|
|
107
|
+
geo_type = "#{geo_type}M" if spatial[:has_m]
|
|
108
|
+
sql_type = if spatial[:geographic]
|
|
109
|
+
"geography(#{geo_type},#{spatial[:srid]})"
|
|
110
|
+
else
|
|
111
|
+
"geometry(#{geo_type},#{spatial[:srid]})"
|
|
112
|
+
end
|
|
113
|
+
type_metadata = MySQL::TypeMetadata.new(
|
|
114
|
+
ConnectionAdapters::SqlTypeMetadata.new(
|
|
115
|
+
sql_type: sql_type,
|
|
116
|
+
type: :geometry,
|
|
117
|
+
limit: nil,
|
|
118
|
+
precision: type_metadata.precision,
|
|
119
|
+
scale: type_metadata.scale,
|
|
120
|
+
),
|
|
121
|
+
extra: type_metadata.extra,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
if default_function&.match?(/\A\(?st_geomfromtext\(/i)
|
|
125
|
+
default = extract_spatial_default_hex(default_function, spatial)
|
|
126
|
+
default_function = nil
|
|
127
|
+
end
|
|
128
|
+
end
|
|
55
129
|
|
|
56
130
|
SpatialColumn.new(
|
|
57
131
|
field[:Field],
|
|
@@ -60,8 +134,9 @@ module ActiveRecord
|
|
|
60
134
|
field[:Null] == "YES",
|
|
61
135
|
default_function,
|
|
62
136
|
collation: field[:Collation],
|
|
63
|
-
comment:
|
|
64
|
-
spatial: spatial
|
|
137
|
+
comment: comment,
|
|
138
|
+
spatial: spatial,
|
|
139
|
+
array: metadata[:array]
|
|
65
140
|
)
|
|
66
141
|
end
|
|
67
142
|
|
|
@@ -70,6 +145,58 @@ module ActiveRecord
|
|
|
70
145
|
@spatial_column_info ||= {}
|
|
71
146
|
@spatial_column_info[table_name.to_sym] = SpatialColumnInfo.new(self, table_name.to_s)
|
|
72
147
|
end
|
|
148
|
+
|
|
149
|
+
def extract_spatial_default_hex(default_function, spatial)
|
|
150
|
+
default_sql = default_function.delete_prefix("(").delete_suffix(")").delete("\\")
|
|
151
|
+
match = default_sql.match(/\Ast_geomfromtext\(_utf8mb4'(.+?)',\s*(\d+)\)\z/i)
|
|
152
|
+
return unless match
|
|
153
|
+
|
|
154
|
+
wkt = match[1]
|
|
155
|
+
srid = match[2].to_i
|
|
156
|
+
type = ActiveRecord::Type::Spatial.new(
|
|
157
|
+
spatial[:geographic] ? "geography" : "geometry",
|
|
158
|
+
geo_type: ActiveRecord::Type::Spatial.normalize_geo_type(spatial[:type]),
|
|
159
|
+
srid: srid,
|
|
160
|
+
geographic: spatial[:geographic],
|
|
161
|
+
has_z: spatial[:has_z],
|
|
162
|
+
has_m: spatial[:has_m],
|
|
163
|
+
)
|
|
164
|
+
geometry = type.serialize(wkt)
|
|
165
|
+
return unless geometry
|
|
166
|
+
geometry = RGeo::Feature.cast(geometry, factory: type.send(:spatial_factory), project: true) if spatial[:geographic]
|
|
167
|
+
|
|
168
|
+
wkb = RGeo::WKRep::WKBGenerator.new(
|
|
169
|
+
hex_format: true,
|
|
170
|
+
little_endian: true,
|
|
171
|
+
type_format: :wkb11,
|
|
172
|
+
emit_ewkb_srid: false
|
|
173
|
+
).generate(geometry)
|
|
174
|
+
return wkb.upcase unless spatial[:geographic]
|
|
175
|
+
|
|
176
|
+
srid_hex = [spatial[:srid].to_i].pack("V").unpack1("H*")
|
|
177
|
+
"#{srid_hex}#{wkb}".upcase
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def generation_expression_for(table_name, column_name)
|
|
181
|
+
query_value(<<~SQL)&.gsub("`", "")
|
|
182
|
+
SELECT generation_expression
|
|
183
|
+
FROM information_schema.columns
|
|
184
|
+
WHERE table_schema = DATABASE()
|
|
185
|
+
AND table_name = #{quote(table_name)}
|
|
186
|
+
AND column_name = #{quote(column_name)}
|
|
187
|
+
SQL
|
|
188
|
+
&.gsub(/st_buffer\(([^,]+),\s*(\d+)\)/i, 'st_buffer(\1, (\2)::double precision)')
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def generated_default_for(table_name, column_name)
|
|
192
|
+
query_value(<<~SQL)
|
|
193
|
+
SELECT column_default
|
|
194
|
+
FROM information_schema.columns
|
|
195
|
+
WHERE table_schema = DATABASE()
|
|
196
|
+
AND table_name = #{quote(table_name)}
|
|
197
|
+
AND column_name = #{quote(column_name)}
|
|
198
|
+
SQL
|
|
199
|
+
end
|
|
73
200
|
end
|
|
74
201
|
end
|
|
75
202
|
end
|
|
@@ -4,12 +4,16 @@ 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, spatial: nil, **)
|
|
7
|
+
def initialize(name, default, sql_type_metadata = nil, null = true, default_function = nil, collation: nil, comment: nil, spatial: nil, array: false, **)
|
|
8
8
|
@sql_type_metadata = sql_type_metadata
|
|
9
|
+
@array = array
|
|
9
10
|
if spatial
|
|
10
11
|
# This case comes from an entry in the geometry_columns table
|
|
11
12
|
set_geometric_type_from_name(spatial[:type])
|
|
12
13
|
@srid = spatial[:srid].to_i
|
|
14
|
+
@has_z = spatial[:has_z]
|
|
15
|
+
@has_m = spatial[:has_m]
|
|
16
|
+
@geographic = spatial[:geographic]
|
|
13
17
|
elsif sql_type =~ /geometry|point|linestring|polygon/i
|
|
14
18
|
build_from_sql_type(sql_type_metadata.sql_type)
|
|
15
19
|
elsif sql_type_metadata.sql_type =~ /geometry|point|linestring|polygon/i
|
|
@@ -20,23 +24,31 @@ module ActiveRecord # :nodoc:
|
|
|
20
24
|
super(name, default, sql_type_metadata, null, default_function, collation: collation, comment: comment)
|
|
21
25
|
if spatial?
|
|
22
26
|
if @srid
|
|
23
|
-
@limit = { type:
|
|
27
|
+
@limit = { type: limit_type_name, srid: @srid }
|
|
28
|
+
@limit[:geographic] = true if geographic?
|
|
29
|
+
@limit[:has_z] = true if has_z?
|
|
30
|
+
@limit[:has_m] = true if has_m?
|
|
24
31
|
end
|
|
25
32
|
end
|
|
26
33
|
end
|
|
27
34
|
|
|
28
35
|
attr_reader :geometric_type, :srid
|
|
29
36
|
|
|
37
|
+
def array
|
|
38
|
+
@array || false
|
|
39
|
+
end
|
|
40
|
+
alias array? array
|
|
41
|
+
|
|
30
42
|
def has_z
|
|
31
|
-
false
|
|
43
|
+
spatial? ? (@has_z || false) : nil
|
|
32
44
|
end
|
|
33
45
|
|
|
34
46
|
def has_m
|
|
35
|
-
false
|
|
47
|
+
spatial? ? (@has_m || false) : nil
|
|
36
48
|
end
|
|
37
49
|
|
|
38
50
|
def geographic
|
|
39
|
-
false
|
|
51
|
+
spatial? ? (@geographic || false) : nil
|
|
40
52
|
end
|
|
41
53
|
|
|
42
54
|
alias geographic? geographic
|
|
@@ -59,12 +71,31 @@ module ActiveRecord # :nodoc:
|
|
|
59
71
|
|
|
60
72
|
def set_geometric_type_from_name(name)
|
|
61
73
|
@geometric_type = RGeo::ActiveRecord.geometric_type_from_name(name) || RGeo::Feature::Geometry
|
|
74
|
+
@geo_type_name = ActiveRecord::Type::Spatial.normalize_geo_type(name)
|
|
62
75
|
end
|
|
63
76
|
|
|
64
77
|
def build_from_sql_type(sql_type)
|
|
65
|
-
geo_type, @srid = Type::Spatial.parse_sql_type(sql_type)
|
|
78
|
+
geo_type, @srid, @has_z, @has_m, @geographic = Type::Spatial.parse_sql_type(sql_type)
|
|
66
79
|
set_geometric_type_from_name(geo_type)
|
|
67
80
|
end
|
|
81
|
+
|
|
82
|
+
def limit_type_name
|
|
83
|
+
type_name = @geo_type_name || geometric_type.type_name.underscore
|
|
84
|
+
case type_name
|
|
85
|
+
when "point", "polygon"
|
|
86
|
+
"st_#{type_name}"
|
|
87
|
+
when "linestring"
|
|
88
|
+
"line_string"
|
|
89
|
+
when "multilinestring"
|
|
90
|
+
"multi_line_string"
|
|
91
|
+
when "multipoint"
|
|
92
|
+
"multi_point"
|
|
93
|
+
when "multipolygon"
|
|
94
|
+
"multi_polygon"
|
|
95
|
+
else
|
|
96
|
+
type_name
|
|
97
|
+
end
|
|
98
|
+
end
|
|
68
99
|
end
|
|
69
100
|
end
|
|
70
101
|
end
|
|
@@ -13,11 +13,11 @@ module ActiveRecord # :nodoc:
|
|
|
13
13
|
def all
|
|
14
14
|
info = if @adapter.supports_expression_index?
|
|
15
15
|
@adapter.query(
|
|
16
|
-
"SELECT column_name, srs_id, column_type FROM INFORMATION_SCHEMA.Columns WHERE table_name='#{@table_name}'"
|
|
16
|
+
"SELECT column_name, srs_id, column_type, column_comment FROM INFORMATION_SCHEMA.Columns WHERE table_schema = DATABASE() AND table_name='#{@table_name}'"
|
|
17
17
|
)
|
|
18
18
|
else
|
|
19
19
|
@adapter.query(
|
|
20
|
-
"SELECT column_name, 0, column_type FROM INFORMATION_SCHEMA.Columns WHERE table_name='#{@table_name}'"
|
|
20
|
+
"SELECT column_name, 0, column_type, column_comment FROM INFORMATION_SCHEMA.Columns WHERE table_schema = DATABASE() AND table_name='#{@table_name}'"
|
|
21
21
|
)
|
|
22
22
|
end
|
|
23
23
|
|
|
@@ -25,11 +25,16 @@ module ActiveRecord # :nodoc:
|
|
|
25
25
|
info.each do |row|
|
|
26
26
|
name = row[0]
|
|
27
27
|
type = row[2]
|
|
28
|
-
|
|
28
|
+
column_comment = row[3].to_s
|
|
29
|
+
has_z = type.sub!(/z$/i, "").present?
|
|
30
|
+
has_m = type.sub!(/m$/i, "").present?
|
|
29
31
|
result[name] = {
|
|
30
32
|
name: name,
|
|
31
33
|
srid: row[1].to_i,
|
|
32
34
|
type: type,
|
|
35
|
+
has_z: has_z,
|
|
36
|
+
has_m: has_m,
|
|
37
|
+
geographic: column_comment.include?("mysql2rgeo:geographic"),
|
|
33
38
|
}
|
|
34
39
|
end
|
|
35
40
|
result
|
|
@@ -7,16 +7,43 @@ module ActiveRecord # :nodoc:
|
|
|
7
7
|
include ColumnMethods
|
|
8
8
|
# super: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
|
|
9
9
|
def new_column_definition(name, type, **options)
|
|
10
|
-
|
|
10
|
+
spatial_type = type.to_sym == :virtual ? options[:type]&.to_sym : type.to_sym
|
|
11
|
+
|
|
12
|
+
if spatial_type && (info = Mysql2RgeoAdapter.spatial_column_options(spatial_type))
|
|
11
13
|
if (limit = options.delete(:limit)) && limit.is_a?(::Hash)
|
|
12
14
|
options.merge!(limit)
|
|
13
15
|
end
|
|
14
16
|
|
|
15
|
-
geo_type =
|
|
17
|
+
geo_type = if type.to_sym == :virtual
|
|
18
|
+
"GEOMETRY"
|
|
19
|
+
else
|
|
20
|
+
ColumnDefinitionUtils.geo_type(options[:type] || spatial_type || info[:type])
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
unless type.to_sym == :virtual
|
|
24
|
+
options[:srid] ||= ColumnDefinitionUtils.default_srid(options)
|
|
25
|
+
options[:comment] = ColumnDefinitionUtils.add_metadata_comment(
|
|
26
|
+
options[:comment],
|
|
27
|
+
geographic: options[:geographic],
|
|
28
|
+
has_m: options[:has_m],
|
|
29
|
+
has_z: options[:has_z],
|
|
30
|
+
array: options[:array],
|
|
31
|
+
default: options[:default],
|
|
32
|
+
srid: options[:srid],
|
|
33
|
+
geo_type: geo_type
|
|
34
|
+
)
|
|
35
|
+
else
|
|
36
|
+
options.delete(:srid)
|
|
37
|
+
end
|
|
16
38
|
|
|
17
39
|
options[:spatial_type] = geo_type
|
|
18
|
-
|
|
40
|
+
if type.to_sym == :virtual
|
|
41
|
+
column = super(name, type, **options.merge(type: geo_type.downcase.to_sym))
|
|
42
|
+
else
|
|
43
|
+
column = super(name, geo_type.downcase.to_sym, **options)
|
|
44
|
+
end
|
|
19
45
|
else
|
|
46
|
+
options[:comment] = ColumnDefinitionUtils.add_metadata_comment(options[:comment], array: options[:array]) if options[:array]
|
|
20
47
|
column = super(name, type, **options)
|
|
21
48
|
end
|
|
22
49
|
|
|
@@ -24,19 +51,88 @@ module ActiveRecord # :nodoc:
|
|
|
24
51
|
end
|
|
25
52
|
|
|
26
53
|
def valid_column_definition_options
|
|
27
|
-
super + %i[geographic has_m spatial_type srid]
|
|
54
|
+
super + %i[array geographic has_m has_z spatial_type srid]
|
|
28
55
|
end
|
|
29
56
|
end
|
|
30
57
|
|
|
58
|
+
class Table < MySQL::Table # :nodoc:
|
|
59
|
+
include ColumnMethods
|
|
60
|
+
end
|
|
61
|
+
|
|
31
62
|
module ColumnDefinitionUtils
|
|
63
|
+
METADATA_TOKENS = {
|
|
64
|
+
geographic: "mysql2rgeo:geographic",
|
|
65
|
+
has_m: "mysql2rgeo:has_m",
|
|
66
|
+
has_z: "mysql2rgeo:has_z",
|
|
67
|
+
array: "mysql2rgeo:array",
|
|
68
|
+
default_prefix: "mysql2rgeo:default:"
|
|
69
|
+
}.freeze
|
|
70
|
+
|
|
32
71
|
class << self
|
|
33
72
|
def geo_type(type = "GEOMETRY")
|
|
34
|
-
type.to_s.delete("_").upcase
|
|
73
|
+
type.to_s.sub(/\Ast_/, "").delete("_").upcase
|
|
35
74
|
end
|
|
36
75
|
|
|
37
76
|
def default_srid(options)
|
|
38
77
|
options[:geographic] ? 4326 : Mysql2RgeoAdapter::DEFAULT_SRID
|
|
39
78
|
end
|
|
79
|
+
|
|
80
|
+
def add_metadata_comment(comment, geographic: false, has_m: false, has_z: false, array: false, default: nil, srid: nil, geo_type: nil)
|
|
81
|
+
values = [comment]
|
|
82
|
+
values << METADATA_TOKENS[:geographic] if geographic
|
|
83
|
+
values << METADATA_TOKENS[:has_m] if has_m
|
|
84
|
+
values << METADATA_TOKENS[:has_z] if has_z
|
|
85
|
+
values << METADATA_TOKENS[:array] if array
|
|
86
|
+
if default
|
|
87
|
+
values << "#{METADATA_TOKENS[:default_prefix]}#{encode_default(default, geographic: geographic, srid: srid, geo_type: geo_type, has_m: has_m, has_z: has_z)}"
|
|
88
|
+
end
|
|
89
|
+
values.compact_blank.join(" ")
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def extract_metadata(comment)
|
|
93
|
+
text = comment.to_s
|
|
94
|
+
default_hex = text[/#{Regexp.escape(METADATA_TOKENS[:default_prefix])}([0-9A-F]+)/i, 1]
|
|
95
|
+
{
|
|
96
|
+
geographic: text.include?(METADATA_TOKENS[:geographic]),
|
|
97
|
+
has_m: text.include?(METADATA_TOKENS[:has_m]),
|
|
98
|
+
has_z: text.include?(METADATA_TOKENS[:has_z]),
|
|
99
|
+
array: text.include?(METADATA_TOKENS[:array]),
|
|
100
|
+
default_hex: default_hex,
|
|
101
|
+
}
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def strip_metadata_comment(comment)
|
|
105
|
+
text = comment.to_s
|
|
106
|
+
METADATA_TOKENS.each_value do |token|
|
|
107
|
+
text = text.gsub(token, "")
|
|
108
|
+
end
|
|
109
|
+
text = text.gsub(/mysql2rgeo:default:[0-9A-F]+/i, "")
|
|
110
|
+
text.squeeze(" ").strip.presence
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def encode_default(default, geographic:, srid:, geo_type:, has_m:, has_z:)
|
|
114
|
+
type = ActiveRecord::Type::Spatial.new(
|
|
115
|
+
geographic ? "geography" : "geometry",
|
|
116
|
+
geo_type: ActiveRecord::Type::Spatial.normalize_geo_type(geo_type),
|
|
117
|
+
srid: srid,
|
|
118
|
+
geographic: geographic,
|
|
119
|
+
has_z: has_z,
|
|
120
|
+
has_m: has_m
|
|
121
|
+
)
|
|
122
|
+
geometry = type.serialize(default)
|
|
123
|
+
geometry = RGeo::Feature.cast(geometry, factory: type.send(:spatial_factory), project: true) if geographic
|
|
124
|
+
|
|
125
|
+
wkb = RGeo::WKRep::WKBGenerator.new(
|
|
126
|
+
hex_format: true,
|
|
127
|
+
little_endian: true,
|
|
128
|
+
type_format: :wkb11,
|
|
129
|
+
emit_ewkb_srid: false
|
|
130
|
+
).generate(geometry).upcase
|
|
131
|
+
return wkb unless geographic
|
|
132
|
+
|
|
133
|
+
srid_hex = [srid.to_i].pack("V").unpack1("H*").upcase
|
|
134
|
+
"#{srid_hex}#{wkb}"
|
|
135
|
+
end
|
|
40
136
|
end
|
|
41
137
|
end
|
|
42
138
|
end
|
|
@@ -47,27 +47,37 @@ module ActiveRecord
|
|
|
47
47
|
module ConnectionAdapters
|
|
48
48
|
class Mysql2RgeoAdapter < Mysql2Adapter
|
|
49
49
|
ADAPTER_NAME = "Mysql2Rgeo"
|
|
50
|
+
MINIMUM_SUPPORTED_VERSION = "8.0.0"
|
|
50
51
|
|
|
51
52
|
include Mysql2Rgeo::SchemaStatements
|
|
52
53
|
|
|
53
54
|
SPATIAL_COLUMN_OPTIONS =
|
|
54
55
|
{
|
|
56
|
+
geography: { type: "geometry", geographic: true },
|
|
55
57
|
geometry: {},
|
|
56
58
|
geometrycollection: {},
|
|
59
|
+
geometry_collection: { type: "geometrycollection" },
|
|
57
60
|
linestring: {},
|
|
61
|
+
line_string: { type: "linestring" },
|
|
58
62
|
multilinestring: {},
|
|
63
|
+
multi_line_string: { type: "multilinestring" },
|
|
59
64
|
multipoint: {},
|
|
65
|
+
multi_point: { type: "multipoint" },
|
|
60
66
|
multipolygon: {},
|
|
67
|
+
multi_polygon: { type: "multipolygon" },
|
|
61
68
|
spatial: { type: "geometry" },
|
|
62
69
|
point: {},
|
|
63
|
-
polygon: {}
|
|
70
|
+
polygon: {},
|
|
71
|
+
st_point: { type: "point" },
|
|
72
|
+
st_polygon: { type: "polygon" }
|
|
64
73
|
}.freeze
|
|
65
74
|
|
|
66
|
-
#
|
|
75
|
+
# MySQL uses SRID 0 when a spatial column does not declare one explicitly.
|
|
67
76
|
DEFAULT_SRID = 0
|
|
68
77
|
|
|
69
|
-
def initialize(
|
|
78
|
+
def initialize(connection, logger, connection_options, config)
|
|
70
79
|
super
|
|
80
|
+
verify_supported_database_version!
|
|
71
81
|
|
|
72
82
|
@visitor = Arel::Visitors::Mysql2Rgeo.new(self)
|
|
73
83
|
end
|
|
@@ -86,7 +96,10 @@ module ActiveRecord
|
|
|
86
96
|
super.merge(
|
|
87
97
|
geometry: { name: "geometry" },
|
|
88
98
|
geometrycollection: { name: "geometrycollection" },
|
|
99
|
+
line_string: { name: "linestring" },
|
|
89
100
|
linestring: { name: "linestring" },
|
|
101
|
+
st_point: { name: "point" },
|
|
102
|
+
st_polygon: { name: "polygon" },
|
|
90
103
|
multi_line_string: { name: "multilinestring" },
|
|
91
104
|
multi_point: { name: "multipoint" },
|
|
92
105
|
multi_polygon: { name: "multipolygon" },
|
|
@@ -102,20 +115,50 @@ module ActiveRecord
|
|
|
102
115
|
def initialize_type_map(m)
|
|
103
116
|
super
|
|
104
117
|
|
|
105
|
-
|
|
106
|
-
geometry
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
linestring
|
|
110
|
-
|
|
111
|
-
multipoint
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
118
|
+
{
|
|
119
|
+
"geography" => "geometry",
|
|
120
|
+
"geometry" => "geometry",
|
|
121
|
+
"geometry_collection" => "geometrycollection",
|
|
122
|
+
"line_string" => "linestring",
|
|
123
|
+
"multi_line_string" => "multilinestring",
|
|
124
|
+
"multi_point" => "multipoint",
|
|
125
|
+
"multi_polygon" => "multipolygon",
|
|
126
|
+
"st_point" => "point",
|
|
127
|
+
"st_polygon" => "polygon",
|
|
128
|
+
}.each do |registered_type, geo_type|
|
|
129
|
+
m.register_type(registered_type) do |sql_type|
|
|
130
|
+
Type::Spatial.new(sql_type.to_s, geo_type: geo_type)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
[
|
|
135
|
+
/\Ageometry(?:\(.*\))?\z/i,
|
|
136
|
+
/\Ageography(?:\(.*\))?\z/i,
|
|
137
|
+
/\Apoint(?:\s.*)?\z/i,
|
|
138
|
+
/\Alinestring(?:\s.*)?\z/i,
|
|
139
|
+
/\Apolygon(?:\s.*)?\z/i,
|
|
140
|
+
/\Amultipoint(?:\s.*)?\z/i,
|
|
141
|
+
/\Amultilinestring(?:\s.*)?\z/i,
|
|
142
|
+
/\Amultipolygon(?:\s.*)?\z/i,
|
|
143
|
+
/\Ageometrycollection(?:\s.*)?\z/i,
|
|
144
|
+
].each do |pattern|
|
|
145
|
+
m.register_type(pattern) do |sql_type|
|
|
116
146
|
Type::Spatial.new(sql_type.to_s)
|
|
117
147
|
end
|
|
118
148
|
end
|
|
149
|
+
|
|
150
|
+
{
|
|
151
|
+
st_point: "point",
|
|
152
|
+
st_polygon: "polygon",
|
|
153
|
+
line_string: "linestring",
|
|
154
|
+
multi_line_string: "multilinestring",
|
|
155
|
+
multi_point: "multipoint",
|
|
156
|
+
multi_polygon: "multipolygon",
|
|
157
|
+
}.each do |alias_type, geo_type|
|
|
158
|
+
ActiveRecord::Type.register(alias_type) do |_, **kwargs|
|
|
159
|
+
Type::Spatial.new(geo_type, geo_type: geo_type, **kwargs)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
119
162
|
end
|
|
120
163
|
end
|
|
121
164
|
|
|
@@ -125,23 +168,48 @@ module ActiveRecord
|
|
|
125
168
|
end
|
|
126
169
|
|
|
127
170
|
def supports_spatial?
|
|
128
|
-
!mariadb? &&
|
|
171
|
+
!mariadb? && database_version >= MINIMUM_SUPPORTED_VERSION
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def adapter_name
|
|
175
|
+
ADAPTER_NAME
|
|
129
176
|
end
|
|
130
177
|
|
|
131
178
|
def quote(value)
|
|
132
179
|
dbval = value.try(:value_for_database) || value
|
|
133
180
|
if RGeo::Feature::Geometry.check_type(dbval)
|
|
134
|
-
|
|
181
|
+
wkt = RGeo::WKRep::WKTGenerator.new(tag_format: :wkt11, emit_ewkt_srid: false).generate(dbval)
|
|
182
|
+
if dbval.srid == 4326
|
|
183
|
+
"ST_GeomFromText(#{super(wkt)}, #{dbval.srid}, 'axis-order=long-lat')"
|
|
184
|
+
else
|
|
185
|
+
"ST_GeomFromText(#{super(wkt)}, #{dbval.srid})"
|
|
186
|
+
end
|
|
135
187
|
else
|
|
136
188
|
super
|
|
137
189
|
end
|
|
138
190
|
end
|
|
139
191
|
|
|
140
|
-
def
|
|
141
|
-
|
|
192
|
+
def quote_default_expression(value, column) # :nodoc:
|
|
193
|
+
return super unless column.respond_to?(:spatial?) && column.spatial?
|
|
194
|
+
|
|
195
|
+
value = lookup_cast_type(column.sql_type).serialize(value)
|
|
196
|
+
hex = RGeo::WKRep::WKBGenerator.new(
|
|
197
|
+
hex_format: true,
|
|
198
|
+
little_endian: true,
|
|
199
|
+
type_format: :wkb11,
|
|
200
|
+
emit_ewkb_srid: false
|
|
201
|
+
).generate(value).upcase
|
|
202
|
+
"(ST_GeomFromWKB(x'#{hex}', #{value.srid}))"
|
|
142
203
|
end
|
|
143
204
|
|
|
144
205
|
private
|
|
206
|
+
def verify_supported_database_version!
|
|
207
|
+
return if database_version >= MINIMUM_SUPPORTED_VERSION
|
|
208
|
+
|
|
209
|
+
raise ActiveRecord::ConnectionNotEstablished,
|
|
210
|
+
"#{ADAPTER_NAME} supports MySQL #{MINIMUM_SUPPORTED_VERSION}+ only (detected #{database_version})"
|
|
211
|
+
end
|
|
212
|
+
|
|
145
213
|
def type_map
|
|
146
214
|
emulate_booleans ? TYPE_MAP_WITH_BOOLEAN : TYPE_MAP
|
|
147
215
|
end
|
|
@@ -9,9 +9,14 @@ module ActiveRecord
|
|
|
9
9
|
# "geography"
|
|
10
10
|
# "geometry NOT NULL"
|
|
11
11
|
# "geometry"
|
|
12
|
-
def initialize(sql_type = "geometry")
|
|
13
|
-
@sql_type = sql_type
|
|
14
|
-
|
|
12
|
+
def initialize(sql_type = "geometry", geo_type: nil, srid: nil, geographic: false, has_z: false, has_m: false, **_options)
|
|
13
|
+
@sql_type = geographic ? "geography" : sql_type
|
|
14
|
+
parsed_geo_type, parsed_srid, parsed_has_z, parsed_has_m, parsed_geographic = self.class.parse_sql_type(@sql_type)
|
|
15
|
+
@geo_type = self.class.normalize_geo_type(geo_type || parsed_geo_type)
|
|
16
|
+
@srid = srid || parsed_srid
|
|
17
|
+
@has_z = has_z || parsed_has_z
|
|
18
|
+
@has_m = has_m || parsed_has_m
|
|
19
|
+
@geographic = geographic || parsed_geographic
|
|
15
20
|
end
|
|
16
21
|
|
|
17
22
|
# sql_type: geometry, geometry(Point), geometry(Point,4326), ...
|
|
@@ -20,23 +25,51 @@ module ActiveRecord
|
|
|
20
25
|
# geo_type: geography, geometry, point, line_string, polygon, ...
|
|
21
26
|
# srid: 1234
|
|
22
27
|
def self.parse_sql_type(sql_type)
|
|
23
|
-
geo_type
|
|
28
|
+
geo_type = nil
|
|
29
|
+
srid = 0
|
|
30
|
+
has_z = false
|
|
31
|
+
has_m = false
|
|
32
|
+
geographic = false
|
|
33
|
+
|
|
24
34
|
if sql_type =~ /(geography|geometry)\((.*)\)$/i
|
|
25
35
|
# geometry(Point)
|
|
26
36
|
# geometry(Point,4326)
|
|
37
|
+
geographic = Regexp.last_match(1).casecmp("geography").zero?
|
|
27
38
|
params = Regexp.last_match(2).split(",")
|
|
28
39
|
if params.first =~ /([a-z]+[^zm])(z?)(m?)/i
|
|
29
40
|
geo_type = Regexp.last_match(1)
|
|
41
|
+
has_z = Regexp.last_match(2).casecmp("z").zero?
|
|
42
|
+
has_m = Regexp.last_match(3).casecmp("m").zero?
|
|
30
43
|
end
|
|
31
44
|
if params.last =~ /(\d+)/
|
|
32
45
|
srid = Regexp.last_match(1).to_i
|
|
33
46
|
end
|
|
47
|
+
elsif sql_type =~ /\A(geography|geometry)\z/i
|
|
48
|
+
geographic = Regexp.last_match(1).casecmp("geography").zero?
|
|
49
|
+
geo_type = Regexp.last_match(1)
|
|
34
50
|
else
|
|
35
51
|
# geometry
|
|
36
52
|
# otherType(a,b)
|
|
37
53
|
geo_type = sql_type
|
|
38
54
|
end
|
|
39
|
-
[geo_type, srid]
|
|
55
|
+
[geo_type, srid, has_z, has_m, geographic]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.normalize_geo_type(geo_type)
|
|
59
|
+
case geo_type.to_s.underscore.delete("_")
|
|
60
|
+
when "geometrycollection"
|
|
61
|
+
"geometry_collection"
|
|
62
|
+
when "linestring"
|
|
63
|
+
"line_string"
|
|
64
|
+
when "multilinestring"
|
|
65
|
+
"multi_line_string"
|
|
66
|
+
when "multipoint"
|
|
67
|
+
"multi_point"
|
|
68
|
+
when "multipolygon"
|
|
69
|
+
"multi_polygon"
|
|
70
|
+
else
|
|
71
|
+
geo_type.to_s.underscore.presence
|
|
72
|
+
end
|
|
40
73
|
end
|
|
41
74
|
|
|
42
75
|
def spatial_factory
|
|
@@ -45,7 +78,9 @@ module ActiveRecord
|
|
|
45
78
|
@spatial_factories[@srid] ||=
|
|
46
79
|
RGeo::ActiveRecord::SpatialFactoryStore.instance.factory(
|
|
47
80
|
geo_type: @geo_type,
|
|
48
|
-
|
|
81
|
+
has_m: @has_m,
|
|
82
|
+
has_z: @has_z,
|
|
83
|
+
sql_type: @geographic ? "geography" : "geometry",
|
|
49
84
|
srid: @srid
|
|
50
85
|
)
|
|
51
86
|
end
|
|
@@ -67,6 +102,9 @@ module ActiveRecord
|
|
|
67
102
|
return if value.nil?
|
|
68
103
|
|
|
69
104
|
geo_value = cast_value(value)
|
|
105
|
+
if geo_value && !@geographic && @srid.to_i.zero? && geo_value.srid != @srid
|
|
106
|
+
geo_value = RGeo::Feature.cast(geo_value, factory: spatial_factory, project: true)
|
|
107
|
+
end
|
|
70
108
|
|
|
71
109
|
# TODO: - only valid types should be allowed
|
|
72
110
|
# e.g. linestring is not valid for point column
|
|
@@ -89,12 +127,27 @@ module ActiveRecord
|
|
|
89
127
|
if ["\x00", "\x01"].include?(marker)
|
|
90
128
|
@srid = string[0, 4].unpack1(marker == "\x01" ? "V" : "N")
|
|
91
129
|
RGeo::WKRep::WKBParser.new(spatial_factory, support_ewkb: true, default_srid: @srid).parse(string[4..-1])
|
|
92
|
-
elsif string[0
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
130
|
+
elsif string.match?(/\A[0-9a-fA-F]+\z/)
|
|
131
|
+
original_srid = @srid
|
|
132
|
+
parser = RGeo::WKRep::WKBParser.new(spatial_factory, support_ewkb: true, default_srid: @srid)
|
|
133
|
+
|
|
134
|
+
begin
|
|
135
|
+
return parser.parse([string].pack("H*"))
|
|
136
|
+
rescue RGeo::Error::ParseError, RGeo::Error::InvalidGeometry
|
|
137
|
+
@srid = original_srid
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
if string[0, 10] =~ /[0-9a-fA-F]{8}0[01]/
|
|
141
|
+
@srid = string[0, 8].to_i(16)
|
|
142
|
+
@srid = [@srid].pack("V").unpack("N").first if string[9, 1] == "1"
|
|
143
|
+
parser = RGeo::WKRep::WKBParser.new(spatial_factory, support_ewkb: true, default_srid: @srid)
|
|
144
|
+
return parser.parse([string[8..-1]].pack("H*"))
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
parser.parse([string].pack("H*"))
|
|
96
148
|
else
|
|
97
|
-
string,
|
|
149
|
+
string, srid = Arel::Visitors::Mysql2Rgeo.parse_node(string)
|
|
150
|
+
@srid = srid.zero? ? @srid : srid
|
|
98
151
|
RGeo::WKRep::WKTParser.new(spatial_factory, support_ewkt: true, default_srid: @srid).parse(string)
|
|
99
152
|
end
|
|
100
153
|
rescue RGeo::Error::ParseError, RGeo::Error::InvalidGeometry
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: activerecord-mysql2rgeo-adapter
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 7.
|
|
4
|
+
version: 7.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yongdae Hwang
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-03-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|
|
@@ -16,14 +16,14 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: 7.
|
|
19
|
+
version: 7.1.0
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: 7.
|
|
26
|
+
version: 7.1.0
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: rgeo-activerecord
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -39,78 +39,79 @@ dependencies:
|
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: 7.0.0
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
42
|
+
name: rake
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
45
|
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '
|
|
48
|
-
type: :
|
|
47
|
+
version: '13.0'
|
|
48
|
+
type: :development
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: '
|
|
54
|
+
version: '13.0'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
|
-
name:
|
|
56
|
+
name: minitest
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
59
|
- - "~>"
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '
|
|
61
|
+
version: '5.4'
|
|
62
62
|
type: :development
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
66
|
- - "~>"
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '
|
|
68
|
+
version: '5.4'
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
|
-
name:
|
|
70
|
+
name: mocha
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
72
72
|
requirements:
|
|
73
73
|
- - "~>"
|
|
74
74
|
- !ruby/object:Gem::Version
|
|
75
|
-
version: '
|
|
75
|
+
version: '1.1'
|
|
76
76
|
type: :development
|
|
77
77
|
prerelease: false
|
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
79
|
requirements:
|
|
80
80
|
- - "~>"
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
|
-
version: '
|
|
82
|
+
version: '1.1'
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
|
-
name:
|
|
84
|
+
name: benchmark-ips
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
86
86
|
requirements:
|
|
87
87
|
- - "~>"
|
|
88
88
|
- !ruby/object:Gem::Version
|
|
89
|
-
version: '2.
|
|
89
|
+
version: '2.12'
|
|
90
90
|
type: :development
|
|
91
91
|
prerelease: false
|
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
93
|
requirements:
|
|
94
94
|
- - "~>"
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
|
-
version: '2.
|
|
96
|
+
version: '2.12'
|
|
97
97
|
- !ruby/object:Gem::Dependency
|
|
98
|
-
name:
|
|
98
|
+
name: rubocop
|
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
|
100
100
|
requirements:
|
|
101
101
|
- - "~>"
|
|
102
102
|
- !ruby/object:Gem::Version
|
|
103
|
-
version: '
|
|
103
|
+
version: '1.50'
|
|
104
104
|
type: :development
|
|
105
105
|
prerelease: false
|
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
107
|
requirements:
|
|
108
108
|
- - "~>"
|
|
109
109
|
- !ruby/object:Gem::Version
|
|
110
|
-
version: '
|
|
110
|
+
version: '1.50'
|
|
111
111
|
description: ActiveRecord connection adapter for MySQL. It is based on the stock MySQL
|
|
112
112
|
adapter, and adds built-in support for the spatial extensions provided by MySQL.
|
|
113
|
-
It uses the RGeo library to represent spatial data in Ruby.
|
|
113
|
+
It uses the RGeo library to represent spatial data in Ruby. This gem is maintained
|
|
114
|
+
for MySQL 8.0 and 8.4.
|
|
114
115
|
email: stadia@gmail.com
|
|
115
116
|
executables: []
|
|
116
117
|
extensions: []
|
|
@@ -132,7 +133,10 @@ files:
|
|
|
132
133
|
homepage: http://github.com/stadia/activerecord-mysql2rgeo-adapter
|
|
133
134
|
licenses:
|
|
134
135
|
- BSD-3-Clause
|
|
135
|
-
metadata:
|
|
136
|
+
metadata:
|
|
137
|
+
source_code_uri: https://github.com/stadia/activerecord-mysql2rgeo-adapter
|
|
138
|
+
documentation_uri: https://github.com/stadia/activerecord-mysql2rgeo-adapter/blob/main/README.md
|
|
139
|
+
rubygems_mfa_required: 'true'
|
|
136
140
|
post_install_message:
|
|
137
141
|
rdoc_options: []
|
|
138
142
|
require_paths:
|
|
@@ -141,7 +145,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
141
145
|
requirements:
|
|
142
146
|
- - ">="
|
|
143
147
|
- !ruby/object:Gem::Version
|
|
144
|
-
version:
|
|
148
|
+
version: 3.0.0
|
|
145
149
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
146
150
|
requirements:
|
|
147
151
|
- - ">="
|