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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c7c7868e390a06f088a15fbc05edcf4191cd4234da8d0d3a2946f92870a4ce3e
4
- data.tar.gz: e6ccf5ee308dfbefd8b0997b67c17b895e7346d14be5ca36a86782b73e80d73f
3
+ metadata.gz: 3f886ffec9c1cc39dd75d324940ebb386a49b5a8b23d65f3e2016e9610dd0c23
4
+ data.tar.gz: ba5b9e5e18655b6a52f0e73a612679efd55f5a097e8eeaf6d13736631c9dcaf9
5
5
  SHA512:
6
- metadata.gz: e0109fb5a4f7a6afcaa3b8bb3a698239de3c2e211be0d776e5135b0c45cf36cc66ed0ecd9208c41477784391664f10c7e5596e3d1abe3fe498c76da26332a0be
7
- data.tar.gz: 3974d1716e3446e6addf1edcdc7ed8ce31c7367f1b9a12eaa45944f0e57aaceb57526b3ed79e63e4365b7f87ab5e12b6a66a465a7fd41db197ce4316ab486e02
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 visit_String(node, collector)
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 visit_String
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(*args, **options)
67
- Mysql2Rgeo::TableDefinition.new(self, *args, **options)
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
- type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
73
- default = field[:Default]
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
- metadata = Mysql2Rgeo::ColumnDefinitionUtils.extract_metadata(field[:Comment])
76
- comment = Mysql2Rgeo::ColumnDefinitionUtils.strip_metadata_comment(field[:Comment])
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, field[:Field])
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, field[:Field])
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(field[:Field], type_metadata.sql_type)
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
- field[:Field],
134
+ field_name,
135
+ lookup_cast_type(type_metadata.sql_type),
133
136
  default,
134
137
  type_metadata,
135
- field[:Null] == "YES",
138
+ field_value(field, "Null") == "YES",
136
139
  default_function,
137
- collation: field[:Collation],
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
- def initialize(name, default, sql_type_metadata = nil, null = true, default_function = nil, collation: nil, comment: nil,
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
- super(name, default, sql_type_metadata, null, default_function, collation: collation, comment: comment)
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
 
@@ -3,7 +3,7 @@
3
3
  module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module Mysql2Rgeo
6
- VERSION = "8.0.5"
6
+ VERSION = "9.0.0"
7
7
  end
8
8
  end
9
9
  end
@@ -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
- super.merge(
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
- emulate_booleans ? TYPE_MAP_WITH_BOOLEAN : TYPE_MAP
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
- @spatial_factories ||= {}
75
-
76
- @spatial_factories[@srid] ||=
77
- RGeo::ActiveRecord::SpatialFactoryStore.instance.factory(
78
- geo_type: @geo_type,
79
- has_m: @has_m,
80
- has_z: @has_z,
81
- sql_type: @geographic ? "geography" : "geometry",
82
- srid: @srid
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
- @srid = string[0, 4].unpack1(marker == "\x01" ? "V" : "N")
127
- RGeo::WKRep::WKBParser.new(spatial_factory, support_ewkb: true, default_srid: @srid).parse(string[4..])
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
- @srid = string[0, 8].to_i(16)
140
- @srid = [@srid].pack("V").unpack1("N") if string[9, 1] == "1"
141
- parser = RGeo::WKRep::WKBParser.new(spatial_factory, support_ewkb: true, default_srid: @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
- @srid = srid.zero? ? @srid : srid
149
- RGeo::WKRep::WKTParser.new(spatial_factory, support_ewkt: true, default_srid: @srid).parse(string)
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
@@ -1,3 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_record/connection_adapters/mysql2rgeo_adapter"
4
+
5
+ ActiveRecord::ConnectionAdapters.register("mysql2rgeo", "ActiveRecord::ConnectionAdapters::Mysql2RgeoAdapter",
6
+ "active_record/connection_adapters/mysql2rgeo_adapter")
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: 8.0.5
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: '7.2'
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: '7.2'
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.1.0
147
+ version: 3.2.0
148
148
  required_rubygems_version: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - ">="