Armg
Add MySQL geometry type to Active Record.
Installation
Add this line to your application's Gemfile:
gem 'armg'
And then execute:
$ bundle
Or install it yourself as:
$ gem install armg
Usage
require 'active_record'
require 'armg'
ActiveRecord::Base.establish_connection(adapter: 'mysql2', database: 'my_db')
ActiveRecord::Migration.create_table :geoms, options: 'ENGINE=MyISAM' do |t|
t.geometry 'location', null: false
t.index ['location'], name: 'idx_location', type: :spatial
end
class Geom < ActiveRecord::Base; end
wkt_parser = RGeo::WKRep::WKTParser.new(nil, support_ewkt: true)
point = wkt_parser.parse('SRID=4326;Point(-122.1 47.3)')
Geom.create!(location: point)
Geom.first
#=> #<Geom id: 1, location: #<RGeo::Cartesian::PointImpl:0x... "POINT (-122.1 47.3)">>
Using WKT
Armg.deserializer = Armg::WktDeserializer.new
Armg.serializer = Armg::WktSerializer.new
Geom.create!(location: 'Point(-122.1 47.3)')
Geom.first
#=> #<Geom id: 1, location: "Point (-122.1 47.3)">
Using custom deserializer
class CustomDeserializer
def initialize
factory = RGeo::Geographic.spherical_factory(srid: 0)
@wkb_parser = RGeo::WKRep::WKBParser.new(factory, support_ewkb: true)
end
def deserialize(wkb)
wkb_without_srid = wkb.b.slice(4..-1)
@wkb_parser.parse(wkb_without_srid)
end
end
Armg.deserializer = CustomDeserializer.new
Geom.take
#=> #<Geom id: 1, location: #<RGeo::Geographic::SphericalPointImpl:0x... "POINT (-122.1 47.3)">>
Using custom serializer
class CustomSerializer
def initialize
@wkt_parser = RGeo::WKRep::WKTParser.new(nil, support_ewkt: true)
@wkb_generator = RGeo::WKRep::WKBGenerator.new(type_format: :ewkb, little_endian: true)
end
def serialize(value)
if value.is_a?(String)
value = @wkt_parser.parse(value)
end
srid = "\x00\x00\x00\x00"
srid + @wkb_generator.generate(value)
end
end
Armg.serializer = CustomSerializer.new
Geom.create!(id: 4, location: 'Point(-122.1 47.3)')
Running tests
docker-compose up -d
bundle install
bundle exec appraisal install
bundle exec appraisal ar61 rake
# bundle exec appraisal ar60 rake
# ARMG_TEST_MYSQL_PORT=10057 bundle exec appraisal ar61 rake # MySQL 5.7
# ARMG_TEST_MYSQL_PORT=10057 ARMG_TEST_MYSQL_ENGINE=InnoDB bundle exec appraisal ar61 rake
Using with Ridgepole
You need to extend the TableDefinition class.
# ridgepole-geo.rb
module TableDefinitionExtForGeometry
def geometry(*args)
= args.
column_names = args
column_names.each { |name| column(name, :geometry, ) }
end
end
Ridgepole::DSLParser::TableDefinition.prepend(TableDefinitionExtForGeometry)
module DiffExtForGeometry
def (opts)
super
opts.delete(:length) if opts[:type] == :spatial
end
end
Ridgepole::Diff.prepend(DiffExtForGeometry)
$ ridgepole -c 'mysql2://[email protected]:10057/armg_test' -r armg -e > Schemafile
$ cat Schemafile
# Export Schema
create_table "geoms", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
t.geometry "location", null: false
t.string "name"
t.index ["location"], name: "idx_location", length: 32, type: :spatial
t.index ["name"], name: "idx_name", length: 10
end
$ ridgepole -c 'mysql2://[email protected]:10057/armg_test' -r armg,ridgepole-geo -a
Apply `Schemafile`
No change
Limitation on MySQL 8.0
At the moment, armg gem supports only SRIDs with long-lat axis order in MySQL 8.0. e.g. SRID=3857 (WGS 84 / Pseudo-Mercator -- Spherical Mercator, Google Maps, OpenStreetMap, Bing, ArcGIS, ESRI)
That is, armg does not support SRIDs with lat-long axis order. e.g. SRID=4326 (WGS 84 -- WGS84 - World Geodetic System 1984, used in GPS)