activerecord-mysql2rgeo-adapter 8.0.5 → 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/active_record/connection_adapters/mysql2rgeo/arel_tosql.rb +2 -7
- data/lib/active_record/connection_adapters/mysql2rgeo/schema_statements.rb +19 -12
- data/lib/active_record/connection_adapters/mysql2rgeo/spatial_column.rb +16 -2
- data/lib/active_record/connection_adapters/mysql2rgeo/version.rb +1 -1
- data/lib/active_record/connection_adapters/mysql2rgeo_adapter.rb +36 -15
- data/lib/active_record/type/spatial.rb +31 -22
- data/lib/activerecord-mysql2rgeo-adapter.rb +3 -0
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3f886ffec9c1cc39dd75d324940ebb386a49b5a8b23d65f3e2016e9610dd0c23
|
|
4
|
+
data.tar.gz: ba5b9e5e18655b6a52f0e73a612679efd55f5a097e8eeaf6d13736631c9dcaf9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cd759c023b7736b538039efbb1ebe0e289f77532758df317b6c7273269cc22d5888a662365cc5dafcfb5eade82732f6e531cba88df7df652c15e085b9d839a9d
|
|
7
|
+
data.tar.gz: 6e6b9e64f3662ed48fd16a18fa9fcb4741d70748c306a2ad07abf8e72eddb8819c4f0a3c47f185c743c8b5a336aac8910d0affff618a94258c8eac23887d97a6
|
|
@@ -24,16 +24,11 @@ module Arel # :nodoc:
|
|
|
24
24
|
FUNC_MAP[standard_name.downcase] || standard_name
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
def
|
|
27
|
+
def visit_RGeo_Feature_Instance(node, collector)
|
|
28
28
|
node, srid = Mysql2Rgeo.parse_node(node)
|
|
29
29
|
collector << spatial_constant_sql(node, srid)
|
|
30
30
|
end
|
|
31
|
-
alias visit_RGeo_Feature_Instance
|
|
32
|
-
alias visit_RGeo_Cartesian_BoundingBox visit_String
|
|
33
|
-
|
|
34
|
-
def visit_RGeo_ActiveRecord_SpatialNamedFunction(node, collector)
|
|
35
|
-
aggregate(st_func(node.name), node, collector)
|
|
36
|
-
end
|
|
31
|
+
alias visit_RGeo_Cartesian_BoundingBox visit_RGeo_Feature_Instance
|
|
37
32
|
|
|
38
33
|
def visit_in_spatial_context(node, collector)
|
|
39
34
|
case node
|
|
@@ -63,17 +63,19 @@ module ActiveRecord
|
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
# override
|
|
66
|
-
def create_table_definition(
|
|
67
|
-
Mysql2Rgeo::TableDefinition.new(self,
|
|
66
|
+
def create_table_definition(*, **)
|
|
67
|
+
Mysql2Rgeo::TableDefinition.new(self, *, **)
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
# override
|
|
71
71
|
def new_column_from_field(table_name, field, _definitions)
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
field_name = field_value(field, "Field")
|
|
73
|
+
type_metadata = fetch_type_metadata(field_value(field, "Type"), field_value(field, "Extra"))
|
|
74
|
+
default = field_value(field, "Default")
|
|
74
75
|
default_function = nil
|
|
75
|
-
|
|
76
|
-
|
|
76
|
+
metadata_comment = field_value(field, "Comment")
|
|
77
|
+
metadata = Mysql2Rgeo::ColumnDefinitionUtils.extract_metadata(metadata_comment)
|
|
78
|
+
comment = Mysql2Rgeo::ColumnDefinitionUtils.strip_metadata_comment(metadata_comment)
|
|
77
79
|
default = metadata[:default_hex] if default.nil? && metadata[:default_hex].present?
|
|
78
80
|
|
|
79
81
|
if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\([0-6]?\))?\z/i.match?(default)
|
|
@@ -83,7 +85,7 @@ module ActiveRecord
|
|
|
83
85
|
if default == "NULL" && metadata[:default_hex].present?
|
|
84
86
|
default = metadata[:default_hex]
|
|
85
87
|
elsif default == "NULL"
|
|
86
|
-
default = generated_default_for(table_name,
|
|
88
|
+
default = generated_default_for(table_name, field_name)
|
|
87
89
|
end
|
|
88
90
|
|
|
89
91
|
if default&.match?(/\Ast_geomfromtext\(/i)
|
|
@@ -94,11 +96,11 @@ module ActiveRecord
|
|
|
94
96
|
end
|
|
95
97
|
|
|
96
98
|
if type_metadata.extra.to_s.match?(/(?:VIRTUAL|STORED|PERSISTENT)\s+GENERATED/i)
|
|
97
|
-
default_function = generation_expression_for(table_name,
|
|
99
|
+
default_function = generation_expression_for(table_name, field_name)
|
|
98
100
|
end
|
|
99
101
|
|
|
100
102
|
# {:dimension=>2, :has_m=>false, :has_z=>false, :name=>"latlon", :srid=>0, :type=>"GEOMETRY"}
|
|
101
|
-
spatial = spatial_column_info(table_name).get(
|
|
103
|
+
spatial = spatial_column_info(table_name).get(field_name, type_metadata.sql_type)
|
|
102
104
|
if spatial
|
|
103
105
|
spatial[:has_z] ||= metadata[:has_z]
|
|
104
106
|
spatial[:has_m] ||= metadata[:has_m]
|
|
@@ -129,12 +131,13 @@ module ActiveRecord
|
|
|
129
131
|
end
|
|
130
132
|
|
|
131
133
|
SpatialColumn.new(
|
|
132
|
-
|
|
134
|
+
field_name,
|
|
135
|
+
lookup_cast_type(type_metadata.sql_type),
|
|
133
136
|
default,
|
|
134
137
|
type_metadata,
|
|
135
|
-
field
|
|
138
|
+
field_value(field, "Null") == "YES",
|
|
136
139
|
default_function,
|
|
137
|
-
collation: field
|
|
140
|
+
collation: field_value(field, "Collation"),
|
|
138
141
|
comment: comment,
|
|
139
142
|
spatial: spatial,
|
|
140
143
|
array: metadata[:array]
|
|
@@ -147,6 +150,10 @@ module ActiveRecord
|
|
|
147
150
|
@spatial_column_info[table_name.to_sym] = SpatialColumnInfo.new(self, table_name.to_s)
|
|
148
151
|
end
|
|
149
152
|
|
|
153
|
+
def field_value(field, key)
|
|
154
|
+
field[key] || field[key.to_sym]
|
|
155
|
+
end
|
|
156
|
+
|
|
150
157
|
def extract_spatial_default_hex(default_function, spatial)
|
|
151
158
|
default_sql = default_function.delete_prefix("(").delete_suffix(")").delete("\\")
|
|
152
159
|
match = default_sql.match(/\Ast_geomfromtext\(_utf8mb4'(.+?)',\s*(\d+)\)\z/i)
|
|
@@ -4,8 +4,18 @@ module ActiveRecord # :nodoc:
|
|
|
4
4
|
module ConnectionAdapters # :nodoc:
|
|
5
5
|
module Mysql2Rgeo # :nodoc:
|
|
6
6
|
class SpatialColumn < ConnectionAdapters::MySQL::Column # :nodoc:
|
|
7
|
-
|
|
7
|
+
# ActiveRecord 8.1 added cast_type as Column#initialize's second argument.
|
|
8
|
+
COLUMN_TAKES_CAST_TYPE = ActiveRecord.gem_version >= Gem::Version.new("8.1")
|
|
9
|
+
|
|
10
|
+
def initialize(name, cast_type, default, sql_type_metadata = nil, null = true, default_function = nil, collation: nil, comment: nil,
|
|
8
11
|
spatial: nil, array: false, **)
|
|
12
|
+
if default.respond_to?(:sql_type) && (sql_type_metadata.nil? || sql_type_metadata == true || sql_type_metadata == false)
|
|
13
|
+
null = sql_type_metadata unless sql_type_metadata.nil?
|
|
14
|
+
sql_type_metadata = default
|
|
15
|
+
default = cast_type
|
|
16
|
+
cast_type = nil
|
|
17
|
+
end
|
|
18
|
+
|
|
9
19
|
@sql_type_metadata = sql_type_metadata
|
|
10
20
|
@array = array
|
|
11
21
|
@geographic = !!(sql_type_metadata&.sql_type =~ /geography\(/i)
|
|
@@ -27,7 +37,11 @@ spatial: nil, array: false, **)
|
|
|
27
37
|
# @geometric_type = geo_type_from_sql_type(sql_type)
|
|
28
38
|
build_from_sql_type(sql_type_metadata.sql_type)
|
|
29
39
|
end
|
|
30
|
-
|
|
40
|
+
if COLUMN_TAKES_CAST_TYPE
|
|
41
|
+
super(name, cast_type, default, sql_type_metadata, null, default_function, collation: collation, comment: comment)
|
|
42
|
+
else
|
|
43
|
+
super(name, default, sql_type_metadata, null, default_function, collation: collation, comment: comment)
|
|
44
|
+
end
|
|
31
45
|
return unless spatial?
|
|
32
46
|
return unless @srid
|
|
33
47
|
|
|
@@ -34,6 +34,7 @@ module ActiveRecord
|
|
|
34
34
|
def mysql2rgeo_connection(config)
|
|
35
35
|
config = config.symbolize_keys
|
|
36
36
|
config[:flags] ||= 0
|
|
37
|
+
config[:database_timezone] ||= ConnectionAdapters::AbstractAdapter.validate_default_timezone(config[:default_timezone])
|
|
37
38
|
|
|
38
39
|
if config[:flags].is_a? Array
|
|
39
40
|
config[:flags].push "FOUND_ROWS"
|
|
@@ -96,23 +97,37 @@ module ActiveRecord
|
|
|
96
97
|
def native_database_types
|
|
97
98
|
# Add spatial types
|
|
98
99
|
# Reference: https://dev.mysql.com/doc/refman/5.6/en/spatial-type-overview.html
|
|
99
|
-
|
|
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" }
|
|
112
|
-
)
|
|
100
|
+
self.class.native_database_types
|
|
113
101
|
end
|
|
114
102
|
|
|
115
103
|
class << self
|
|
104
|
+
def native_database_types
|
|
105
|
+
# ActiveRecord < 8.1 only has the instance method, backed by NATIVE_DATABASE_TYPES.
|
|
106
|
+
(defined?(super) ? super : self::NATIVE_DATABASE_TYPES).merge(
|
|
107
|
+
geography: { name: "geometry" },
|
|
108
|
+
geometry: { name: "geometry" },
|
|
109
|
+
geometrycollection: { name: "geometrycollection" },
|
|
110
|
+
line_string: { name: "linestring" },
|
|
111
|
+
linestring: { name: "linestring" },
|
|
112
|
+
st_point: { name: "point" },
|
|
113
|
+
st_polygon: { name: "polygon" },
|
|
114
|
+
multi_line_string: { name: "multilinestring" },
|
|
115
|
+
multi_point: { name: "multipoint" },
|
|
116
|
+
multi_polygon: { name: "multipolygon" },
|
|
117
|
+
spatial: { name: "geometry" },
|
|
118
|
+
point: { name: "point" },
|
|
119
|
+
polygon: { name: "polygon" }
|
|
120
|
+
)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def extended_type_map(emulate_booleans:, default_timezone: nil)
|
|
124
|
+
Type::TypeMap.new(emulate_booleans ? TYPE_MAP_WITH_BOOLEAN : TYPE_MAP).tap do |m|
|
|
125
|
+
register_class_with_precision m, /\A[^(]*time/i, Type::Time, timezone: default_timezone
|
|
126
|
+
register_class_with_precision m, /\A[^(]*datetime/i, Type::DateTime, timezone: default_timezone
|
|
127
|
+
m.alias_type(/\A[^(]*timestamp/i, "datetime")
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
116
131
|
private
|
|
117
132
|
|
|
118
133
|
def initialize_type_map(m)
|
|
@@ -212,7 +227,13 @@ module ActiveRecord
|
|
|
212
227
|
private
|
|
213
228
|
|
|
214
229
|
def type_map
|
|
215
|
-
|
|
230
|
+
if (key = extended_type_map_key)
|
|
231
|
+
self.class::EXTENDED_TYPE_MAPS.compute_if_absent(key) do
|
|
232
|
+
self.class.extended_type_map(**key)
|
|
233
|
+
end
|
|
234
|
+
else
|
|
235
|
+
emulate_booleans ? TYPE_MAP_WITH_BOOLEAN : TYPE_MAP
|
|
236
|
+
end
|
|
216
237
|
end
|
|
217
238
|
end
|
|
218
239
|
end
|
|
@@ -10,13 +10,14 @@ module ActiveRecord
|
|
|
10
10
|
# "geometry NOT NULL"
|
|
11
11
|
# "geometry"
|
|
12
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
|
|
13
|
+
@sql_type = -(geographic ? "geography" : sql_type.to_s)
|
|
14
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)
|
|
15
|
+
@geo_type = -self.class.normalize_geo_type(geo_type || parsed_geo_type).to_s
|
|
16
16
|
@srid = srid || parsed_srid
|
|
17
17
|
@has_z = has_z || parsed_has_z
|
|
18
18
|
@has_m = has_m || parsed_has_m
|
|
19
19
|
@geographic = geographic || parsed_geographic
|
|
20
|
+
freeze
|
|
20
21
|
end
|
|
21
22
|
|
|
22
23
|
# sql_type: geometry, geometry(Point), geometry(Point,4326), ...
|
|
@@ -70,17 +71,17 @@ module ActiveRecord
|
|
|
70
71
|
end
|
|
71
72
|
end
|
|
72
73
|
|
|
73
|
-
def spatial_factory
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
74
|
+
def spatial_factory(srid = @srid)
|
|
75
|
+
# Don't use instance variable caching since Type objects are frozen in Rails 8.1+
|
|
76
|
+
# The SpatialFactoryStore already caches factories internally
|
|
77
|
+
# Use provided srid or fall back to instance srid
|
|
78
|
+
RGeo::ActiveRecord::SpatialFactoryStore.instance.factory(
|
|
79
|
+
geo_type: @geo_type,
|
|
80
|
+
has_m: @has_m,
|
|
81
|
+
has_z: @has_z,
|
|
82
|
+
sql_type: @geographic ? "geography" : "geometry",
|
|
83
|
+
srid: srid
|
|
84
|
+
)
|
|
84
85
|
end
|
|
85
86
|
|
|
86
87
|
def klass
|
|
@@ -123,30 +124,28 @@ module ActiveRecord
|
|
|
123
124
|
def parse_wkt(string)
|
|
124
125
|
marker = string[4, 1]
|
|
125
126
|
if ["\x00", "\x01"].include?(marker)
|
|
126
|
-
|
|
127
|
-
RGeo::WKRep::WKBParser.new(spatial_factory, support_ewkb: true, default_srid:
|
|
127
|
+
srid = string[0, 4].unpack1(marker == "\x01" ? "V" : "N")
|
|
128
|
+
RGeo::WKRep::WKBParser.new(spatial_factory(srid), support_ewkb: true, default_srid: srid).parse(string[4..])
|
|
128
129
|
elsif string.match?(/\A[0-9a-fA-F]+\z/)
|
|
129
|
-
original_srid = @srid
|
|
130
130
|
parser = RGeo::WKRep::WKBParser.new(spatial_factory, support_ewkb: true, default_srid: @srid)
|
|
131
131
|
|
|
132
132
|
begin
|
|
133
133
|
return parser.parse([string].pack("H*"))
|
|
134
134
|
rescue RGeo::Error::ParseError, RGeo::Error::InvalidGeometry
|
|
135
|
-
@srid = original_srid
|
|
136
135
|
end
|
|
137
136
|
|
|
138
137
|
if string[0, 10] =~ /[0-9a-fA-F]{8}0[01]/
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
parser = RGeo::WKRep::WKBParser.new(spatial_factory, support_ewkb: true, default_srid:
|
|
138
|
+
srid = string[0, 8].to_i(16)
|
|
139
|
+
srid = [srid].pack("V").unpack1("N") if string[9, 1] == "1"
|
|
140
|
+
parser = RGeo::WKRep::WKBParser.new(spatial_factory(srid), support_ewkb: true, default_srid: srid)
|
|
142
141
|
return parser.parse([string[8..]].pack("H*"))
|
|
143
142
|
end
|
|
144
143
|
|
|
145
144
|
parser.parse([string].pack("H*"))
|
|
146
145
|
else
|
|
147
146
|
string, srid = Arel::Visitors::Mysql2Rgeo.parse_node(string)
|
|
148
|
-
|
|
149
|
-
RGeo::WKRep::WKTParser.new(spatial_factory, support_ewkt: true, default_srid:
|
|
147
|
+
srid = @srid if srid.zero?
|
|
148
|
+
RGeo::WKRep::WKTParser.new(spatial_factory(srid), support_ewkt: true, default_srid: srid).parse(string)
|
|
150
149
|
end
|
|
151
150
|
rescue RGeo::Error::ParseError, RGeo::Error::InvalidGeometry
|
|
152
151
|
nil
|
|
@@ -154,3 +153,13 @@ module ActiveRecord
|
|
|
154
153
|
end
|
|
155
154
|
end
|
|
156
155
|
end
|
|
156
|
+
|
|
157
|
+
module ActiveRecord
|
|
158
|
+
module ConnectionAdapters
|
|
159
|
+
module Mysql2Rgeo
|
|
160
|
+
module OID
|
|
161
|
+
Spatial = ActiveRecord::Type::Spatial
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: activerecord-mysql2rgeo-adapter
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 9.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yongdae Hwang
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version:
|
|
18
|
+
version: 8.0.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version:
|
|
25
|
+
version: 8.0.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: rgeo-activerecord
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -144,7 +144,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
144
144
|
requirements:
|
|
145
145
|
- - ">="
|
|
146
146
|
- !ruby/object:Gem::Version
|
|
147
|
-
version: 3.
|
|
147
|
+
version: 3.2.0
|
|
148
148
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
149
149
|
requirements:
|
|
150
150
|
- - ">="
|