activerecord-mysql2rgeo-adapter 1.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 +7 -0
- data/LICENSE.txt +29 -0
- data/lib/active_record/connection_adapters/mysql2rgeo/arel_tosql.rb +60 -0
- data/lib/active_record/connection_adapters/mysql2rgeo/column_methods.rb +51 -0
- data/lib/active_record/connection_adapters/mysql2rgeo/create_connection.rb +49 -0
- data/lib/active_record/connection_adapters/mysql2rgeo/schema_statements.rb +62 -0
- data/lib/active_record/connection_adapters/mysql2rgeo/spatial_column.rb +75 -0
- data/lib/active_record/connection_adapters/mysql2rgeo/spatial_table_definition.rb +74 -0
- data/lib/active_record/connection_adapters/mysql2rgeo/version.rb +7 -0
- data/lib/active_record/connection_adapters/mysql2rgeo_adapter.rb +96 -0
- data/lib/active_record/type/spatial.rb +110 -0
- data/lib/activerecord-mysql2rgeo-adapter.rb +1 -0
- metadata +140 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1d0b0c732c20c79a3c0b43cfb579062910095e02
|
4
|
+
data.tar.gz: b177970830c534be704dffd1947226dd60fda3b8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 80a6789fabf449fd1492e68736235fa28f9c83b307cf126f4473cec5deea2b7390ef73c0e7652a534045f84370917be06ba2eb8cb245e2d149bd87da8c26630e
|
7
|
+
data.tar.gz: 2ae5516787390b36e96c79d9312c1b91f94be7d8d4adfa0d2241d8f879ffdee1ae0ed5f09da8bae8985d43b32cf28851d80c693d938f87421420c5965d4b0593
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
# Copyright 2012 Daniel Azuma
|
3
|
+
#
|
4
|
+
# All rights reserved.
|
5
|
+
#
|
6
|
+
# Redistribution and use in source and binary forms, with or without
|
7
|
+
# modification, are permitted provided that the following conditions are met:
|
8
|
+
#
|
9
|
+
# * Redistributions of source code must retain the above copyright notice,
|
10
|
+
# this list of conditions and the following disclaimer.
|
11
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
# this list of conditions and the following disclaimer in the documentation
|
13
|
+
# and/or other materials provided with the distribution.
|
14
|
+
# * Neither the name of the copyright holder, nor the names of any other
|
15
|
+
# contributors to this software, may be used to endorse or promote products
|
16
|
+
# derived from this software without specific prior written permission.
|
17
|
+
#
|
18
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
19
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
20
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
21
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
22
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
23
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
24
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
25
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
26
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
27
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
28
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
# -----------------------------------------------------------------------------
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Arel # :nodoc:
|
2
|
+
module Visitors # :nodoc:
|
3
|
+
# Different super-class under JRuby JDBC adapter.
|
4
|
+
MySQLSuperclass = if defined?(::ArJdbc::MySQL::BindSubstitution)
|
5
|
+
::ArJdbc::MySQL::BindSubstitution
|
6
|
+
else
|
7
|
+
MySQL
|
8
|
+
end
|
9
|
+
|
10
|
+
class Mysql2Rgeo < MySQLSuperclass # :nodoc:
|
11
|
+
include RGeo::ActiveRecord::SpatialToSql
|
12
|
+
|
13
|
+
if ::Arel::Visitors.const_defined?(:BindVisitor)
|
14
|
+
include ::Arel::Visitors::BindVisitor
|
15
|
+
end
|
16
|
+
|
17
|
+
FUNC_MAP = {
|
18
|
+
"st_wkttosql" => "ST_GeomFromText",
|
19
|
+
"st_wkbtosql" => "ST_GeomFromWKB",
|
20
|
+
"st_length" => "ST_Length"
|
21
|
+
}.freeze
|
22
|
+
|
23
|
+
def st_func(standard_name)
|
24
|
+
FUNC_MAP[standard_name.downcase] || standard_name
|
25
|
+
end
|
26
|
+
|
27
|
+
def visit_Arel_Nodes_SelectCore(o, collector)
|
28
|
+
len = o.projections.length - 1
|
29
|
+
if len == 0
|
30
|
+
if !o.projections.first.nil? && o.projections.first.respond_to?(:relation)
|
31
|
+
projections = []
|
32
|
+
column_cache(o.projections.first.relation.name).keys.each do |x|
|
33
|
+
projections << o.projections.first.relation[x.to_sym]
|
34
|
+
end
|
35
|
+
o.projections = projections
|
36
|
+
end
|
37
|
+
end
|
38
|
+
super
|
39
|
+
end
|
40
|
+
|
41
|
+
def visit_Arel_Attributes_Attribute(o, collector)
|
42
|
+
join_name = o.relation.table_alias || o.relation.name
|
43
|
+
|
44
|
+
collector << if (!column_for(o).nil? && column_for(o).type == :geometry) && !collector.value.include?(" WHERE ")
|
45
|
+
"ST_AsText(#{quote_table_name join_name}.#{quote_column_name o.name}) as #{quote_column_name o.name}"
|
46
|
+
else
|
47
|
+
"#{quote_table_name join_name}.#{quote_column_name o.name}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def visit_String(node, collector)
|
52
|
+
collector << "#{st_func('ST_WKTToSQL')}(#{quote(node)})"
|
53
|
+
end
|
54
|
+
|
55
|
+
def visit_RGeo_ActiveRecord_SpatialNamedFunction(node, collector)
|
56
|
+
aggregate(st_func(node.name), node, collector)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module Mysql2Rgeo
|
4
|
+
module ColumnMethods
|
5
|
+
def spatial(name, options = {})
|
6
|
+
raise "You must set a type. For example: 't.spatial :object1, limit: { type: 'point' }'" if options[:limit].blank? || options[:limit][:type].blank?
|
7
|
+
column(name, options[:limit][:type], options)
|
8
|
+
end
|
9
|
+
|
10
|
+
def geometry(*args, multi: false, **options)
|
11
|
+
multi ? multi_geometry(*args, **options) : args.each { |name| column(name, :geometry, options) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def geometrycollection(*args, **options)
|
15
|
+
args.each { |name| column(name, :geometrycollection, options) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def point(*args, multi: false, **options)
|
19
|
+
multi ? multi_point(*args, **options) : args.each { |name| column(name, :point, options) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def multipoint(*args, **options)
|
23
|
+
args.each { |name| column(name, :multipoint, options) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def linestring(*args, multi: false, **options)
|
27
|
+
multi ? multi_linestring(*args, **options) : args.each { |name| column(name, :linestring, options) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def multilinestring(*args, **options)
|
31
|
+
args.each { |name| column(name, :multilinestring, options) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def polygon(*args, multi: false, **options)
|
35
|
+
multi ? multipolygon(*args, **options) : args.each { |name| column(name, :polygon, options) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def multipolygon(*args, **options)
|
39
|
+
args.each { |name| column(name, :multipolygon, options) }
|
40
|
+
end
|
41
|
+
|
42
|
+
alias multi_point multipoint
|
43
|
+
alias multi_geometry geometrycollection
|
44
|
+
alias multi_linestring multilinestring
|
45
|
+
alias multi_polygon multipolygon
|
46
|
+
end
|
47
|
+
|
48
|
+
MySQL::Table.send(:include, ColumnMethods)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
if RUBY_ENGINE == "jruby"
|
2
|
+
require "active_record/connection_adapters/jdbcmysql_adapter"
|
3
|
+
else
|
4
|
+
require "mysql2"
|
5
|
+
end
|
6
|
+
|
7
|
+
module ActiveRecord # :nodoc:
|
8
|
+
module ConnectionHandling # :nodoc:
|
9
|
+
if RUBY_ENGINE == "jruby"
|
10
|
+
|
11
|
+
def jdbcmysql2rgeo_connection(config)
|
12
|
+
config[:adapter_class] = ConnectionAdapters::Mysql2RgeoAdapter
|
13
|
+
mysql2_connection(config)
|
14
|
+
end
|
15
|
+
|
16
|
+
alias jdbcmysql2rgeo_connection mysql2rgeo_connection
|
17
|
+
|
18
|
+
else
|
19
|
+
|
20
|
+
# Based on the default <tt>mysql2_connection</tt> definition from ActiveRecord.
|
21
|
+
# https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
|
22
|
+
# FULL REPLACEMENT because we need to create a different class.
|
23
|
+
|
24
|
+
def mysql2rgeo_connection(config)
|
25
|
+
config = config.symbolize_keys
|
26
|
+
|
27
|
+
config[:username] = "root" if config[:username].nil?
|
28
|
+
config[:flags] ||= 0
|
29
|
+
|
30
|
+
if Mysql2::Client.const_defined? :FOUND_ROWS
|
31
|
+
if config[:flags].is_a? Array
|
32
|
+
config[:flags].push "FOUND_ROWS".freeze
|
33
|
+
else
|
34
|
+
config[:flags] |= Mysql2::Client::FOUND_ROWS
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
client = Mysql2::Client.new(config)
|
39
|
+
ConnectionAdapters::Mysql2RgeoAdapter.new(client, logger, nil, config)
|
40
|
+
rescue Mysql2::Error => error
|
41
|
+
if error.message.include?("Unknown database")
|
42
|
+
raise ActiveRecord::NoDatabaseError
|
43
|
+
else
|
44
|
+
raise
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module Mysql2Rgeo
|
4
|
+
module SchemaStatements
|
5
|
+
# override
|
6
|
+
def new_column(*args)
|
7
|
+
SpatialColumn.new(*args)
|
8
|
+
end
|
9
|
+
|
10
|
+
def type_to_sql(type, limit = nil, precision = nil, scale = nil, array = nil)
|
11
|
+
if (info = spatial_column_constructor(type.to_sym))
|
12
|
+
type = limit[:type] || type if limit.is_a?(::Hash)
|
13
|
+
type = "geometry" if type.to_s == "spatial"
|
14
|
+
type = type.to_s.delete("_").upcase
|
15
|
+
end
|
16
|
+
super(type, limit, precision, scale, array)
|
17
|
+
end
|
18
|
+
|
19
|
+
def spatial_column_constructor(name)
|
20
|
+
RGeo::ActiveRecord::DEFAULT_SPATIAL_COLUMN_CONSTRUCTORS[name]
|
21
|
+
end
|
22
|
+
|
23
|
+
# override
|
24
|
+
def native_database_types
|
25
|
+
# Add spatial types
|
26
|
+
super.merge(
|
27
|
+
geometry: { name: "geometry" },
|
28
|
+
point: { name: "point" },
|
29
|
+
linestring: { name: "linestring" },
|
30
|
+
polygon: { name: "polygon" },
|
31
|
+
multi_geometry: { name: "geometrycollection" },
|
32
|
+
multi_point: { name: "multipoint" },
|
33
|
+
multi_linestring: { name: "multilinestring" },
|
34
|
+
multi_polygon: { name: "multipolygon" },
|
35
|
+
spatial: { name: "geometry", limit: { type: :point } }
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
# override
|
40
|
+
def create_table_definition(*args)
|
41
|
+
Mysql2Rgeo::TableDefinition.new(*args)
|
42
|
+
end
|
43
|
+
|
44
|
+
def initialize_type_map(m)
|
45
|
+
super
|
46
|
+
%w(
|
47
|
+
geometry
|
48
|
+
point
|
49
|
+
linestring
|
50
|
+
polygon
|
51
|
+
geometrycollection
|
52
|
+
multipoint
|
53
|
+
multilinestring
|
54
|
+
multipolygon
|
55
|
+
).each do |geo_type|
|
56
|
+
m.register_type(geo_type, Type::Spatial.new(geo_type))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module ActiveRecord # :nodoc:
|
2
|
+
module ConnectionAdapters # :nodoc:
|
3
|
+
module Mysql2Rgeo # :nodoc:
|
4
|
+
class SpatialColumn < ConnectionAdapters::MySQL::Column # :nodoc:
|
5
|
+
def initialize(name, default, sql_type_metadata = nil, null = true, table_name = nil, default_function = nil, collation = nil, comment: nil)
|
6
|
+
@geometric_type = nil
|
7
|
+
if sql_type =~ /geometry|point|linestring|polygon/i
|
8
|
+
build_from_sql_type(sql_type_metadata.sql_type)
|
9
|
+
elsif sql_type_metadata.sql_type =~ /geometry|point|linestring|polygon/i
|
10
|
+
# A geometry column with no geometry_columns entry.
|
11
|
+
# @geometric_type = geo_type_from_sql_type(sql_type)
|
12
|
+
build_from_sql_type(sql_type_metadata.sql_type)
|
13
|
+
end
|
14
|
+
super(name, default, sql_type_metadata, null, table_name, default_function, collation)
|
15
|
+
@comment = comment
|
16
|
+
if spatial?
|
17
|
+
if @srid
|
18
|
+
@limit = { type: @geometric_type.type_name.underscore }
|
19
|
+
@limit[:srid] = @srid if @srid
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
attr_reader :geometric_type, :srid
|
25
|
+
|
26
|
+
def has_z
|
27
|
+
false
|
28
|
+
end
|
29
|
+
|
30
|
+
def has_m
|
31
|
+
false
|
32
|
+
end
|
33
|
+
|
34
|
+
def geographic
|
35
|
+
false
|
36
|
+
end
|
37
|
+
|
38
|
+
alias :has_z? :has_z
|
39
|
+
alias :has_m? :has_m
|
40
|
+
alias :geographic? :geographic
|
41
|
+
|
42
|
+
def limit
|
43
|
+
if spatial?
|
44
|
+
@limit
|
45
|
+
else
|
46
|
+
super
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def klass
|
51
|
+
type == :spatial ? RGeo::Feature::Geometry : super
|
52
|
+
end
|
53
|
+
|
54
|
+
def spatial?
|
55
|
+
!@geometric_type.nil?
|
56
|
+
end
|
57
|
+
|
58
|
+
def multi?
|
59
|
+
/^(geometrycollection|multi)/i.match?(sql_type)
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def set_geometric_type_from_name(name)
|
65
|
+
@geometric_type = RGeo::ActiveRecord.geometric_type_from_name(name) || RGeo::Feature::Geometry
|
66
|
+
end
|
67
|
+
|
68
|
+
def build_from_sql_type(sql_type)
|
69
|
+
geo_type, @srid, @has_z, @has_m = Type::Spatial.parse_sql_type(sql_type)
|
70
|
+
set_geometric_type_from_name(geo_type)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module ActiveRecord # :nodoc:
|
2
|
+
module ConnectionAdapters # :nodoc:
|
3
|
+
module Mysql2Rgeo # :nodoc:
|
4
|
+
class TableDefinition < MySQL::TableDefinition # :nodoc:
|
5
|
+
include ColumnMethods
|
6
|
+
|
7
|
+
# super: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
|
8
|
+
def new_column_definition(name, type, options)
|
9
|
+
if (info = Mysql2RgeoAdapter.spatial_column_options(type.to_sym))
|
10
|
+
if (limit = options.delete(:limit))
|
11
|
+
options.merge!(limit) if limit.is_a?(::Hash)
|
12
|
+
end
|
13
|
+
|
14
|
+
geo_type = ColumnDefinition.geo_type(options[:type] || type || info[:type])
|
15
|
+
base_type = info[:type] || :geometry
|
16
|
+
|
17
|
+
# puts name.dup << " - " << type.to_s << " - " << options.to_s << " :: " << geo_type.to_s << " - " << base_type.to_s
|
18
|
+
|
19
|
+
column = super(name, geo_type.downcase.to_sym, options)
|
20
|
+
column.spatial_type = geo_type
|
21
|
+
column.srid = options[:srid]
|
22
|
+
else
|
23
|
+
column = super(name, type, options)
|
24
|
+
end
|
25
|
+
|
26
|
+
column
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def create_column_definition(name, type)
|
32
|
+
if Mysql2RgeoAdapter.spatial_column_options(type.to_sym)
|
33
|
+
Mysql2Rgeo::ColumnDefinition.new(name, type)
|
34
|
+
else
|
35
|
+
super
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class ColumnDefinition < MySQL::ColumnDefinition
|
41
|
+
# needs to accept the spatial type? or figure out from limit ?
|
42
|
+
|
43
|
+
def self.geo_type(type = "GEOMETRY")
|
44
|
+
g_type = type.to_s.delete("_").upcase
|
45
|
+
return "POINT" if g_type == "POINT"
|
46
|
+
return "POLYGON" if g_type == "POLYGON"
|
47
|
+
g_type
|
48
|
+
end
|
49
|
+
|
50
|
+
def spatial_type
|
51
|
+
@spatial_type
|
52
|
+
end
|
53
|
+
|
54
|
+
def spatial_type=(value)
|
55
|
+
@spatial_type = value.to_s
|
56
|
+
end
|
57
|
+
|
58
|
+
def srid
|
59
|
+
if @srid
|
60
|
+
@srid.to_i
|
61
|
+
else
|
62
|
+
Mysql2RgeoAdapter::DEFAULT_SRID
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def srid=(value)
|
67
|
+
@srid = value
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
SpatialIndexDefinition = Struct.new(*IndexDefinition.members, :spatial)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# The activerecord-mysql2rgeo-adapter gem installs the *mysql2rgeo*
|
2
|
+
# connection adapter into ActiveRecord.
|
3
|
+
|
4
|
+
# :stopdoc:
|
5
|
+
|
6
|
+
require "active_record/connection_adapters/mysql2_adapter"
|
7
|
+
require "rgeo/active_record"
|
8
|
+
require "active_record/connection_adapters/mysql2rgeo/version"
|
9
|
+
require "active_record/connection_adapters/mysql2rgeo/column_methods"
|
10
|
+
require "active_record/connection_adapters/mysql2rgeo/schema_statements"
|
11
|
+
require "active_record/connection_adapters/mysql2rgeo/spatial_table_definition"
|
12
|
+
require "active_record/connection_adapters/mysql2rgeo/spatial_column"
|
13
|
+
require "active_record/connection_adapters/mysql2rgeo/arel_tosql"
|
14
|
+
require "active_record/type/spatial"
|
15
|
+
require "active_record/connection_adapters/mysql2rgeo/create_connection"
|
16
|
+
|
17
|
+
# :startdoc:
|
18
|
+
|
19
|
+
module ActiveRecord
|
20
|
+
module ConnectionAdapters
|
21
|
+
class Mysql2RgeoAdapter < Mysql2Adapter
|
22
|
+
include Mysql2Rgeo::SchemaStatements
|
23
|
+
|
24
|
+
SPATIAL_COLUMN_OPTIONS =
|
25
|
+
{
|
26
|
+
geometry: {},
|
27
|
+
geometrycollection: {},
|
28
|
+
linestring: {},
|
29
|
+
spatial: { type: "geometry" }.freeze,
|
30
|
+
point: {},
|
31
|
+
polygon: {},
|
32
|
+
multilinestring: {},
|
33
|
+
multipoint: {},
|
34
|
+
multipolygon: {},
|
35
|
+
}.freeze
|
36
|
+
|
37
|
+
# http://postgis.17.x6.nabble.com/Default-SRID-td5001115.html
|
38
|
+
DEFAULT_SRID = 0
|
39
|
+
|
40
|
+
ADAPTER_NAME = "Mysql2Rgeo".freeze
|
41
|
+
|
42
|
+
def initialize(connection, logger, connection_options, config)
|
43
|
+
super
|
44
|
+
|
45
|
+
@visitor = Arel::Visitors::Mysql2Rgeo.new(self)
|
46
|
+
@visitor.extend(DetermineIfPreparableVisitor) if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.spatial_column_options(key)
|
50
|
+
SPATIAL_COLUMN_OPTIONS[key]
|
51
|
+
end
|
52
|
+
|
53
|
+
def default_srid
|
54
|
+
DEFAULT_SRID
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns an array of indexes for the given table.
|
58
|
+
def indexes(table_name, _name = nil) #:nodoc:
|
59
|
+
indexes = []
|
60
|
+
current_index = nil
|
61
|
+
execute_and_free("SHOW KEYS FROM #{quote_table_name(table_name)}", "SCHEMA") do |result|
|
62
|
+
each_hash(result) do |row|
|
63
|
+
if current_index != row[:Key_name]
|
64
|
+
next if row[:Key_name] == "PRIMARY" # skip the primary key
|
65
|
+
current_index = row[:Key_name]
|
66
|
+
|
67
|
+
mysql_index_type = row[:Index_type].downcase.to_sym
|
68
|
+
index_type = INDEX_TYPES.include?(mysql_index_type) ? mysql_index_type : nil
|
69
|
+
index_using = INDEX_USINGS.include?(mysql_index_type) ? mysql_index_type : nil
|
70
|
+
options = [row[:Table], row[:Key_name], row[:Non_unique].to_i == 0, [], [], nil, nil, index_type, index_using, row[:Index_comment].presence]
|
71
|
+
indexes << if mysql_index_type == :spatial
|
72
|
+
options.push(true)
|
73
|
+
Mysql2Rgeo::SpatialIndexDefinition.new(*options)
|
74
|
+
else
|
75
|
+
IndexDefinition.new(*options)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
indexes.last.columns << row[:Column_name]
|
80
|
+
indexes.last.lengths.merge!(row[:Column_name] => row[:Sub_part].to_i) if row[:Sub_part] && mysql_index_type != :spatial
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
indexes
|
85
|
+
end
|
86
|
+
|
87
|
+
def quote(value, column = nil)
|
88
|
+
if RGeo::Feature::Geometry.check_type(value)
|
89
|
+
"ST_GeomFromWKB(0x#{RGeo::WKRep::WKBGenerator.new(hex_format: true, little_endian: true).generate(value)},#{value.srid})"
|
90
|
+
else
|
91
|
+
super
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Type
|
3
|
+
class Spatial < Value # :nodoc:
|
4
|
+
# sql_type is a string that comes from the database definition
|
5
|
+
# examples:
|
6
|
+
# "geometry"
|
7
|
+
# "geography"
|
8
|
+
# "geometry NOT NULL"
|
9
|
+
# "geometry"
|
10
|
+
def initialize(sql_type = "geometry")
|
11
|
+
@sql_type = sql_type
|
12
|
+
@geo_type, @srid = self.class.parse_sql_type(sql_type)
|
13
|
+
end
|
14
|
+
|
15
|
+
# sql_type: geometry, geometry(Point), geometry(Point,4326), ...
|
16
|
+
#
|
17
|
+
# returns [geo_type, srid, has_z, has_m]
|
18
|
+
# geo_type: geography, geometry, point, line_string, polygon, ...
|
19
|
+
# srid: 1234
|
20
|
+
# has_z: false
|
21
|
+
# has_m: false
|
22
|
+
def self.parse_sql_type(sql_type)
|
23
|
+
geo_type, srid, has_z, has_m = nil, 0, false, false
|
24
|
+
|
25
|
+
if sql_type =~ /[geography,geometry]\((.*)\)$/i
|
26
|
+
# geometry(Point,4326)
|
27
|
+
params = Regexp.last_match(1).split(",")
|
28
|
+
if params.size > 1
|
29
|
+
if params.first =~ /([a-z]+[^zm])(z?)(m?)/i
|
30
|
+
has_z = !Regexp.last_match(2).empty?
|
31
|
+
has_m = !Regexp.last_match(3).empty?
|
32
|
+
geo_type = Regexp.last_match(1)
|
33
|
+
end
|
34
|
+
if params.last =~ /(\d+)/
|
35
|
+
srid = Regexp.last_match(1).to_i
|
36
|
+
end
|
37
|
+
else
|
38
|
+
# geometry(Point)
|
39
|
+
geo_type = params[0]
|
40
|
+
end
|
41
|
+
else
|
42
|
+
# geometry
|
43
|
+
geo_type = sql_type
|
44
|
+
end
|
45
|
+
[geo_type, srid, has_z, has_m]
|
46
|
+
end
|
47
|
+
|
48
|
+
def klass
|
49
|
+
type == :geometry ? RGeo::Feature::Geometry : super
|
50
|
+
end
|
51
|
+
|
52
|
+
def type
|
53
|
+
:geometry
|
54
|
+
end
|
55
|
+
|
56
|
+
def spatial?
|
57
|
+
true
|
58
|
+
end
|
59
|
+
|
60
|
+
def spatial_factory
|
61
|
+
@spatial_factory ||=
|
62
|
+
RGeo::ActiveRecord::SpatialFactoryStore.instance.factory(
|
63
|
+
geo_type: @geo_type,
|
64
|
+
sql_type: @sql_type,
|
65
|
+
srid: @srid
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
# support setting an RGeo object or a WKT string
|
70
|
+
def serialize(value)
|
71
|
+
return if value.nil?
|
72
|
+
geo_value = cast_value(value)
|
73
|
+
geo_value
|
74
|
+
# TODO: - only valid types should be allowed
|
75
|
+
# e.g. linestring is not valid for point column
|
76
|
+
# raise "maybe should raise" unless RGeo::Feature::Geometry.check_type(geo_value)
|
77
|
+
# RGeo::WKRep::WKBGenerator.new(hex_format: true, type_format: :ewkb, emit_ewkb_srid: true).generate(geo_value)
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
# Convenience method for types which do not need separate type casting
|
83
|
+
# behavior for user and database inputs. Called by Value#cast for
|
84
|
+
# values except +nil+.
|
85
|
+
def cast_value(value) # :doc:
|
86
|
+
return if value.nil?
|
87
|
+
value.class === "String" ? parse_wkt(value) : parse_wkt(value.to_s)
|
88
|
+
end
|
89
|
+
|
90
|
+
# convert WKT string into RGeo object
|
91
|
+
def parse_wkt(string)
|
92
|
+
wkt_parser(string).parse(string)
|
93
|
+
rescue RGeo::Error::ParseError
|
94
|
+
nil
|
95
|
+
end
|
96
|
+
|
97
|
+
def binary_string?(string)
|
98
|
+
string[0] == "\x00" || string[0] == "\x01" || string[0, 4] =~ /[0-9a-fA-F]{4}/
|
99
|
+
end
|
100
|
+
|
101
|
+
def wkt_parser(string)
|
102
|
+
if binary_string?(string)
|
103
|
+
RGeo::WKRep::WKBParser.new(spatial_factory, support_ewkb: true, default_srid: @srid)
|
104
|
+
else
|
105
|
+
RGeo::WKRep::WKTParser.new(spatial_factory, support_ewkt: true, default_srid: @srid)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require "active_record/connection_adapters/mysql2rgeo_adapter.rb"
|
metadata
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: activerecord-mysql2rgeo-adapter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Yongdae Hwang
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-02-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activerecord
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 5.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 5.0.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rgeo-activerecord
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 5.0.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 5.0.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '12.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '12.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '5.4'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '5.4'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: mocha
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.1'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.1'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: appraisal
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '2.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '2.0'
|
97
|
+
description: ActiveRecord connection adapter for MySQL. It is based on the stock MySQL
|
98
|
+
adapter, and adds built-in support for the spatial extensions provided by MySQL.
|
99
|
+
It uses the RGeo library to represent spatial data in Ruby.
|
100
|
+
email: stadia@gmail.com
|
101
|
+
executables: []
|
102
|
+
extensions: []
|
103
|
+
extra_rdoc_files: []
|
104
|
+
files:
|
105
|
+
- LICENSE.txt
|
106
|
+
- lib/active_record/connection_adapters/mysql2rgeo/arel_tosql.rb
|
107
|
+
- lib/active_record/connection_adapters/mysql2rgeo/column_methods.rb
|
108
|
+
- lib/active_record/connection_adapters/mysql2rgeo/create_connection.rb
|
109
|
+
- lib/active_record/connection_adapters/mysql2rgeo/schema_statements.rb
|
110
|
+
- lib/active_record/connection_adapters/mysql2rgeo/spatial_column.rb
|
111
|
+
- lib/active_record/connection_adapters/mysql2rgeo/spatial_table_definition.rb
|
112
|
+
- lib/active_record/connection_adapters/mysql2rgeo/version.rb
|
113
|
+
- lib/active_record/connection_adapters/mysql2rgeo_adapter.rb
|
114
|
+
- lib/active_record/type/spatial.rb
|
115
|
+
- lib/activerecord-mysql2rgeo-adapter.rb
|
116
|
+
homepage: http://github.com/stadia/activerecord-mysql2rgeo-adapter
|
117
|
+
licenses:
|
118
|
+
- BSD
|
119
|
+
metadata: {}
|
120
|
+
post_install_message:
|
121
|
+
rdoc_options: []
|
122
|
+
require_paths:
|
123
|
+
- lib
|
124
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
125
|
+
requirements:
|
126
|
+
- - ">="
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: 2.2.2
|
129
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
requirements: []
|
135
|
+
rubyforge_project:
|
136
|
+
rubygems_version: 2.6.10
|
137
|
+
signing_key:
|
138
|
+
specification_version: 4
|
139
|
+
summary: ActiveRecord adapter for MySQL, based on RGeo.
|
140
|
+
test_files: []
|