activerecord-postgres-postgis 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +24 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +22 -0
  5. data/Gemfile +23 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +29 -0
  8. data/Rakefile +6 -0
  9. data/activerecord-postgres-postgis.gemspec +29 -0
  10. data/lib/activerecord-postgres-postgis.rb +10 -0
  11. data/lib/activerecord-postgres-postgis/active_record.rb +3 -0
  12. data/lib/activerecord-postgres-postgis/active_record/connection_adapters/column.rb +53 -0
  13. data/lib/activerecord-postgres-postgis/active_record/connection_adapters/oid.rb +33 -0
  14. data/lib/activerecord-postgres-postgis/active_record/connection_adapters/postgresql_adapter.rb +29 -0
  15. data/lib/activerecord-postgres-postgis/active_record/connection_adapters/quoting.rb +17 -0
  16. data/lib/activerecord-postgres-postgis/active_record/connection_adapters/schema_definitions.rb +49 -0
  17. data/lib/activerecord-postgres-postgis/active_record/connection_adapters/schema_statements.rb +42 -0
  18. data/lib/activerecord-postgres-postgis/arel/visitors/to_sql.rb +9 -0
  19. data/lib/activerecord-postgres-postgis/model.rb +35 -0
  20. data/lib/activerecord-postgres-postgis/railtie.rb +18 -0
  21. data/lib/activerecord-postgres-postgis/version.rb +7 -0
  22. data/lib/generators/postgis/setup_generator.rb +25 -0
  23. data/lib/tasks/postgis.rake +12 -0
  24. data/lib/templates/rails4/setup_postgis.rb +9 -0
  25. data/lib/templates/setup_postgis.rb +9 -0
  26. data/spec/dummy/rails-4.1.0/.gitignore +16 -0
  27. data/spec/dummy/rails-4.1.0/README.rdoc +28 -0
  28. data/spec/dummy/rails-4.1.0/Rakefile +6 -0
  29. data/spec/dummy/rails-4.1.0/app/assets/images/.keep +0 -0
  30. data/spec/dummy/rails-4.1.0/app/assets/javascripts/application.js +16 -0
  31. data/spec/dummy/rails-4.1.0/app/assets/stylesheets/application.css +15 -0
  32. data/spec/dummy/rails-4.1.0/app/controllers/application_controller.rb +5 -0
  33. data/spec/dummy/rails-4.1.0/app/controllers/concerns/.keep +0 -0
  34. data/spec/dummy/rails-4.1.0/app/helpers/application_helper.rb +2 -0
  35. data/spec/dummy/rails-4.1.0/app/mailers/.keep +0 -0
  36. data/spec/dummy/rails-4.1.0/app/models/.keep +0 -0
  37. data/spec/dummy/rails-4.1.0/app/models/concerns/.keep +0 -0
  38. data/spec/dummy/rails-4.1.0/app/models/foo.rb +5 -0
  39. data/spec/dummy/rails-4.1.0/app/views/layouts/application.html.erb +14 -0
  40. data/spec/dummy/rails-4.1.0/bin/bundle +3 -0
  41. data/spec/dummy/rails-4.1.0/bin/rails +8 -0
  42. data/spec/dummy/rails-4.1.0/bin/rake +8 -0
  43. data/spec/dummy/rails-4.1.0/bin/spring +18 -0
  44. data/spec/dummy/rails-4.1.0/config.ru +4 -0
  45. data/spec/dummy/rails-4.1.0/config/application.rb +32 -0
  46. data/spec/dummy/rails-4.1.0/config/boot.rb +4 -0
  47. data/spec/dummy/rails-4.1.0/config/database.yml +11 -0
  48. data/spec/dummy/rails-4.1.0/config/environment.rb +5 -0
  49. data/spec/dummy/rails-4.1.0/config/environments/development.rb +37 -0
  50. data/spec/dummy/rails-4.1.0/config/environments/production.rb +82 -0
  51. data/spec/dummy/rails-4.1.0/config/environments/test.rb +39 -0
  52. data/spec/dummy/rails-4.1.0/config/initializers/assets.rb +8 -0
  53. data/spec/dummy/rails-4.1.0/config/initializers/backtrace_silencers.rb +7 -0
  54. data/spec/dummy/rails-4.1.0/config/initializers/cookies_serializer.rb +3 -0
  55. data/spec/dummy/rails-4.1.0/config/initializers/filter_parameter_logging.rb +4 -0
  56. data/spec/dummy/rails-4.1.0/config/initializers/inflections.rb +16 -0
  57. data/spec/dummy/rails-4.1.0/config/initializers/mime_types.rb +4 -0
  58. data/spec/dummy/rails-4.1.0/config/initializers/session_store.rb +3 -0
  59. data/spec/dummy/rails-4.1.0/config/initializers/wrap_parameters.rb +14 -0
  60. data/spec/dummy/rails-4.1.0/config/locales/en.yml +23 -0
  61. data/spec/dummy/rails-4.1.0/config/routes.rb +56 -0
  62. data/spec/dummy/rails-4.1.0/config/secrets.yml +22 -0
  63. data/spec/dummy/rails-4.1.0/db/migrate/20140628210427_setup_postgis.rb +9 -0
  64. data/spec/dummy/rails-4.1.0/db/migrate/20140628230435_create_foos.rb +10 -0
  65. data/spec/dummy/rails-4.1.0/db/schema.rb +35 -0
  66. data/spec/dummy/rails-4.1.0/db/seeds.rb +7 -0
  67. data/spec/dummy/rails-4.1.0/lib/assets/.keep +0 -0
  68. data/spec/dummy/rails-4.1.0/lib/tasks/.keep +0 -0
  69. data/spec/dummy/rails-4.1.0/log/.keep +0 -0
  70. data/spec/dummy/rails-4.1.0/public/404.html +67 -0
  71. data/spec/dummy/rails-4.1.0/public/422.html +67 -0
  72. data/spec/dummy/rails-4.1.0/public/500.html +66 -0
  73. data/spec/dummy/rails-4.1.0/public/favicon.ico +0 -0
  74. data/spec/dummy/rails-4.1.0/public/robots.txt +5 -0
  75. data/spec/dummy/rails-4.1.0/vendor/assets/javascripts/.keep +0 -0
  76. data/spec/dummy/rails-4.1.0/vendor/assets/stylesheets/.keep +0 -0
  77. data/spec/migration_spec.rb +39 -0
  78. data/spec/model_spec.rb +16 -0
  79. data/spec/setup_generator_spec.rb +65 -0
  80. data/spec/spatial_spec.rb +51 -0
  81. data/spec/spec_helper.rb +114 -0
  82. data/spec/support/migration.rb +11 -0
  83. metadata +280 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f9aa50c6ce6da9571d94f676d2858022c24b7266
4
+ data.tar.gz: 1f6f2362576751d97bdcd4f363758126c6be436f
5
+ SHA512:
6
+ metadata.gz: cd380b3ac160df3eb0c03e2da64c22a0c79d833aaef7783810e84a4ca0b27a7a44476a999f9be5fbaf939567e6238bee9aa0ad6eb92fce8a5f832bb99c542784
7
+ data.tar.gz: cd73d7d4fb3c4ddc92ed4556c304c77ea475593ac454c85943835c2d1f46cb9e6376245dbd112df56066af4e921850362ba189b3baf535be6751ed82d67b80e7
@@ -0,0 +1,24 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+ .rbenv*
24
+ .rvmrc
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1,22 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ - 2.1.0
6
+ - ruby-head
7
+ - rbx-2
8
+ - rbx-head
9
+ addons:
10
+ postgresql: "9.3"
11
+ env:
12
+ - "RAILS_VERSION=4.1.0"
13
+ matrix:
14
+ allow_failures:
15
+ - env: "RAILS_VERSION=master"
16
+ - rvm: ruby-head
17
+ - rvm: rbx-head
18
+ script:
19
+ - cd spec/dummy/rails-$RAILS_VERSION; bundle exec rake db:migrate
20
+ - cd ../../../; bundle exec rake spec
21
+ before_script:
22
+ - psql -c 'create database activerecord_postgresql_postgis_test;' -U postgres
data/Gemfile ADDED
@@ -0,0 +1,23 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in activerecord-postgres-postgis.gemspec
4
+ gemspec
5
+
6
+ rails_version = ENV['RAILS_VERSION'] || 'default'
7
+
8
+ rails = case rails_version
9
+ when 'master'
10
+ { github: 'rails/rails' }
11
+ when 'default'
12
+ '>= 4.1.0'
13
+ else
14
+ "~> #{rails_version}"
15
+ end
16
+
17
+ gem 'rails', rails
18
+
19
+ gem 'coveralls', require: false
20
+
21
+ platforms :ruby do
22
+ gem 'pg'
23
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Anthony Smith
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # Activerecord::Postgres::Postgis
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'activerecord-postgres-postgis'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install activerecord-postgres-postgis
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( https://github.com/[my-github-username]/activerecord-postgres-postgis/fork )
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create a new Pull Request
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new :spec
5
+
6
+ task default: :spec
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'activerecord-postgres-postgis/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'activerecord-postgres-postgis'
8
+ spec.version = ActiveRecord::Postgres::Postgis::VERSION
9
+ spec.authors = ['Anthony Smith']
10
+ spec.email = ['anthony@sticksnleaves.com']
11
+ spec.summary = %q{Write a short summary. Required.}
12
+ spec.description = %q{Write a longer description. Optional.}
13
+ spec.homepage = ''
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_dependency 'activerecord', '>= 3.2'
22
+ spec.add_dependency 'rake'
23
+ spec.add_dependency 'rgeo', '~> 0.3'
24
+
25
+ spec.add_development_dependency 'bundler', '~> 1.6'
26
+ spec.add_development_dependency 'database_cleaner'
27
+ spec.add_development_dependency 'generator_spec'
28
+ spec.add_development_dependency 'rspec-rails'
29
+ end
@@ -0,0 +1,10 @@
1
+ require 'active_support'
2
+ require 'rgeo'
3
+
4
+ if defined?(Rails)
5
+ require 'activerecord-postgres-postgis/railtie'
6
+ else
7
+ ActiveSupport.on_load :active_record do
8
+ require File.expand_path('../lib/activerecord-postgres-postgis/active_record', __FILE__)
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ Dir["#{File.dirname(__FILE__)}/**/*.rb"].each { |f| require f }
2
+
3
+ ActiveRecord::Base.extend(ActiveRecord::Postgres::Postgis::Model)
@@ -0,0 +1,53 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ class PostgreSQLColumn < Column
4
+ attr_reader :spatial_type, :srid
5
+
6
+ attr_accessor :oid_type
7
+
8
+ def initialize_with_spatial(name, default, oid_type, sql_type = nil, null = true)
9
+ initialize_without_spatial(name, default, oid_type, sql_type, null)
10
+
11
+ @spatial_type = extract_spatial_type(sql_type)
12
+ @srid = extract_srid(sql_type)
13
+
14
+ if spatial?
15
+ oid_type.srid = @srid
16
+ end
17
+ end
18
+
19
+ alias_method_chain :initialize, :spatial
20
+
21
+ def simplified_type_with_spatial(field_type)
22
+ if field_type =~ /^(?:geometry)/
23
+ :geometry
24
+ elsif field_type =~ /^(?:geography)/
25
+ :geography
26
+ else
27
+ simplified_type_without_spatial(field_type)
28
+ end
29
+ end
30
+
31
+ alias_method_chain :simplified_type, :spatial
32
+
33
+ def spatial?
34
+ !sql_type.match(/^(geometry|geography)/).nil?
35
+ end
36
+
37
+ private
38
+ def extract_spatial_type(sql_type)
39
+ if sql_type =~ /^(geometry|geography)\(([a-z]+)(,\d+)?\)/i
40
+ @limit = nil
41
+ "'#{$2.upcase}'"
42
+ end
43
+ end
44
+
45
+ def extract_srid(sql_type)
46
+ if sql_type =~ /^(geometry|geography)\(([a-z]+)(,(\d+))\)/i
47
+ @limit = nil
48
+ $4.to_i
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,33 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ class PostgreSQLAdapter < AbstractAdapter
4
+ module OID
5
+ class Spatial < Type
6
+ attr_accessor :factory_generator, :srid
7
+
8
+ def initialize(factory_generator = nil)
9
+ @factory_generator = factory_generator
10
+ end
11
+
12
+ def type_cast(value)
13
+ if value.kind_of?(RGeo::Feature::Geometry)
14
+ RGeo::Feature.cast(value, @factory)
15
+ elsif value && value.respond_to?(:to_s)
16
+ marker = value[0, 1]
17
+ if marker == "\x00" || marker == "\x01" || value[0,4] =~ /[0-9a-fA-F]{4}/
18
+ RGeo::WKRep::WKBParser.new(@factory_generator, support_ewkb: true, default_srid: srid).parse(value)
19
+ else
20
+ RGeo::WKRep::WKTParser.new(@factory_generator, support_ewkt: true, default_srid: srid).parse(value)
21
+ end
22
+ else
23
+ nil
24
+ end
25
+ end
26
+ end
27
+
28
+ register_type('geometry', Spatial.new)
29
+ register_type('geography', Spatial.new(RGeo::Geographic.method(:spherical_factory)))
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,29 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ class PostgreSQLAdapter < AbstractAdapter
4
+ def prepare_column_options_with_spatial(column, types)
5
+ spec = prepare_column_options_without_spatial(column, types)
6
+ spec[:spatial_type] = column.spatial_type if column.respond_to?(:spatial_type) && column.spatial_type
7
+ spec[:srid] = column.srid.to_s if column.respond_to?(:srid) && column.srid
8
+ spec
9
+ end
10
+
11
+ alias_method_chain :prepare_column_options, :spatial
12
+
13
+ def migration_keys_with_spatial
14
+ migration_keys_without_spatial + [:spatial_type, :srid]
15
+ end
16
+
17
+ alias_method_chain :migration_keys, :spatial
18
+
19
+ def native_database_types_with_spatial
20
+ native_database_types_without_spatial.merge({
21
+ geometry: { name: 'geometry' },
22
+ geography: { name: 'geography' }
23
+ })
24
+ end
25
+
26
+ alias_method_chain :native_database_types, :spatial
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,17 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ class PostgreSQLAdapter < AbstractAdapter
4
+ module Quoting
5
+ def type_cast_with_spatial(value, column, array_member = false)
6
+ if value.kind_of?(RGeo::Feature::Geometry)
7
+ RGeo::WKRep::WKBGenerator.new(hex_format: true, type_format: :ewkb, emit_ewkb_srid: true).generate(value)
8
+ else
9
+ type_cast_without_spatial(value, column, array_member)
10
+ end
11
+ end
12
+
13
+ alias_method_chain :type_cast, :spatial
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,49 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module ColumnMethods
4
+ # Adds geometry type for migrations. So you can add column to a table like:
5
+ # create_table :locations do |t|
6
+ # ...
7
+ # t.geometry :geom, srid: 423, type: 'LINESTRING'
8
+ # ...
9
+ # end
10
+ #
11
+ def geometry(name, options = {})
12
+ column(name, :geometry, options)
13
+ end
14
+
15
+ # Adds geography type for migrations. So you can add column to a table
16
+ # like:
17
+ # create_table :locations do |t|
18
+ # ...
19
+ # t.geography :geog, type: 'LINESTRING'
20
+ # ...
21
+ # end
22
+ #
23
+ def geography(name, options = {})
24
+ column(name, :geography, options)
25
+ end
26
+ end
27
+
28
+ class PostgreSQLAdapter::ColumnDefinition < ActiveRecord::ConnectionAdapters::ColumnDefinition
29
+ attr_accessor :spatial_type, :srid
30
+ end
31
+
32
+ class PostgreSQLAdapter::TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
33
+ include ColumnMethods
34
+
35
+ def column_with_spatial(name, type = nil, options = {})
36
+ column = column_without_spatial(name, type, options)[name]
37
+ column.spatial_type = options[:spatial_type]
38
+ column.srid = options[:srid]
39
+ self
40
+ end
41
+
42
+ alias_method_chain :column, :spatial
43
+ end
44
+
45
+ class PostgreSQLAdapter::Table < ActiveRecord::ConnectionAdapters::Table
46
+ include ColumnMethods
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,42 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ class PostgreSQLAdapter::SchemaCreation < ActiveRecord::ConnectionAdapters::AbstractAdapter::SchemaCreation
4
+ def add_column_options_with_spatial!(sql, options)
5
+ column = options.fetch(:column) { return super }
6
+ if column.type == :geometry
7
+ if column.spatial_type || column.srid
8
+ sql_params = column.spatial_type
9
+ sql_params << ',' if sql_params && column.srid
10
+ sql_params = column.srid.to_s.prepend(sql_params || '') if column.srid
11
+ sql << "(#{sql_params})" if sql_params
12
+ end
13
+ elsif column.type == :geography
14
+ if column.spatial_type || column.srid
15
+ sql_params = column.spatial_type
16
+ sql_params << ',' if sql_params
17
+ sql_params = 4326.to_s.prepend(sql_params || '')
18
+ sql << "(#{sql_params})" if sql_params
19
+ end
20
+ else
21
+ add_column_options_without_spatial!(sql, options)
22
+ end
23
+ end
24
+
25
+ alias_method_chain :add_column_options!, :spatial
26
+ end
27
+
28
+ module SchemaStatements
29
+ # Adds a spatial column to the table using the PostGIS
30
+ # "AddGeometryColumn()" function.
31
+ #
32
+ # This method exists for backwards compatability with PostGIS 1.x.
33
+ #
34
+ # Example:
35
+ # add_geometry_column :roads, :geom, srid: 423, spatial_type: 'LINESTRING', dimension: 2
36
+ #
37
+ def add_geometry_column(table_name, column_name, options = {})
38
+ execute "SELECT AddGeometryColumn('#{table_name}', '#{column_name}', #{options[:srid]}, '#{options[:spatial_type]}', #{options[:dimension]})"
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,9 @@
1
+ module Arel
2
+ module Visitors
3
+ class ToSql < Arel::Visitors::Visitor
4
+ def visit_RGeo_Feature_Geometry(o, a)
5
+ quote(RGeo::WKRep::WKTGenerator.new(type_format: :ewkt, emit_ewkt_srid: true).generate(o))
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,35 @@
1
+ module ActiveRecord
2
+ module Postgres
3
+ module Postgis
4
+ FACTORY_GENERATORS = {
5
+ geometry: {
6
+ preferred: :preferred_factory,
7
+ simple: :simple_factory
8
+ },
9
+ geography: {
10
+ spherical: :spherical_factory,
11
+ simple_mercator: :simple_mercator_factory,
12
+ projected: :projected_factory
13
+ }
14
+ }
15
+
16
+ module Model
17
+ def spatial(column_name, factory, options = {})
18
+ column = columns_hash[column_name.to_s]
19
+ return unless column
20
+
21
+ column.oid_type.factory_generator = factory_generator_class(column.type).send(FACTORY_GENERATORS[column.type][factory], { srid: column.srid }.merge(options))
22
+ end
23
+
24
+ private
25
+ def factory_generator_class(column_type)
26
+ if column_type == :geometry
27
+ RGeo::Cartesian
28
+ elsif column_type == :geography
29
+ RGeo::Geographic
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end