spatial_features 3.4.8 → 3.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9407d9a0f72fe25d714ee781b2902f387c77837c8deb3b1c1df8cdaa7be97b35
4
- data.tar.gz: af6a1f4386fcb85adb7b0c17925f13ff11f0730fd4fe407cdbf1c8efdcfbbdee
3
+ metadata.gz: c477982103b4f48e410ff562a0bf0e16ec24e4cd3b42584aa5015cde9d380264
4
+ data.tar.gz: 9982438597418015427e05f060ac060f2a3ab803930c06d8a5e9a7578153129f
5
5
  SHA512:
6
- metadata.gz: 22acdcc935004caaf2783679b0e0126ddfe679cd7f51c29f0eb6f358746c9cfb01c67dd5f67db4bfa26f975aec7da783d6e3ad45312e292081677ff194761552
7
- data.tar.gz: 84fd0dcfd2a158bd7612df2da14b6124bc9b5a4b668779057037cf1c17a4be03eda6641ee9204d3eef696766e446c3764fcb6976ea3387ad660e8fef63285c13
6
+ metadata.gz: 4aa2e8cdb7a59b4bf113489055c0d3018b3fb01ce5e18d6a03ec77d865e177b84231715abab3c410d5aba837db2fc0f0ebf2dd6ab70d5892567aaeda7b6e4e0a
7
+ data.tar.gz: 9a823d0703242fff4b790428b531a52d6017aa28e5922d87052066ff72e8056fa841825566e4feb0d48f10b238ca0be5570393ffe126108cf8c057efac3dbfba
data/README.md CHANGED
@@ -106,7 +106,8 @@ Person.new(:features => [Feature.new(:geog => 'some binary PostGIS Geography str
106
106
  ### Import
107
107
 
108
108
  You can specify multiple import sources for geometry. Each key is a method that returns the data for the Importer, and
109
- each value is the Importer to use to parse the data. See each Importer for more details.
109
+ each value is the Importer to use to parse the data. Options can be passed in place of the Importer name, but must still
110
+ include a `name` key with the name of the importer. See each Importer for more details.
110
111
  ```ruby
111
112
  def ImageImporter
112
113
  def self.call(feature, image_paths)
@@ -117,8 +118,11 @@ def ImageImporter
117
118
  end
118
119
 
119
120
  class Location < ActiveRecord::Base
120
- has_spatial_features :import => { :remote_kml_url => 'KMLFile', :file => 'File', :geojson => 'ESRIGeoJSON' },
121
- :image_handlers => ['ImageImporter']
121
+ has_spatial_features :image_handlers => ['ImageImporter'],
122
+ :import => {
123
+ :remote_kml_url => { :name => 'KMLFile', :feature_name => lambda {|source_feature| source_feature.metadata['shapeID'] },
124
+ :file => 'File', :geojson => 'ESRIGeoJSON' }
125
+ }
122
126
 
123
127
  def remote_kml_url
124
128
  "www.test.com/kml/#{id}.kml"
@@ -200,6 +204,23 @@ add_index :features, :source_identifier
200
204
  MyModel.update_features!(:force => true) # Force an `update_features!` will populate the source_identifier column.
201
205
  ```
202
206
 
207
+ ## Upgrading From 3.4 to 3.5
208
+ The gem now relies on virtual columns to set a number of derived column values.
209
+ ```ruby
210
+ change_table :features do |t|
211
+ t.remove :tilegeom, :feature_type, :centroid, :area, :north, :east, :south, :west
212
+
213
+ t.virtual :tilegeom, :type => 'geometry(Geometry,3857)', as: "ST_Transform(geom, 3857)", stored: true, :index => { :using => :gist }
214
+ t.virtual :feature_type, :type => :string, as: "CASE GeometryType(geog) WHEN 'POLYGON' THEN 'polygon' WHEN 'MULTIPOLYGON' THEN 'polygon' WHEN 'GEOMETRYCOLLECTION' THEN 'polygon' WHEN 'LINESTRING' THEN 'line' WHEN 'MULTILINESTRING' THEN 'line' WHEN 'POINT' THEN 'point' WHEN 'MULTIPOINT' THEN 'point' END", stored: true, :index => true
215
+ t.virtual :centroid, :type => :geography, as: "ST_PointOnSurface(geog::geometry)", stored: true
216
+ t.virtual :area, :type => :decimal, as: "ST_Area(geog)", stored: true
217
+ t.virtual :north, :type => :decimal, as: "ST_YMax(geog::geometry)", stored: true
218
+ t.virtual :east, :type => :decimal, as: "ST_XMax(geog::geometry)", stored: true
219
+ t.virtual :south, :type => :decimal, as: "ST_YMin(geog::geometry)", stored: true
220
+ t.virtual :west, :type => :decimal, as: "ST_XMin(geog::geometry)", stored: true
221
+ end
222
+ ```
223
+
203
224
  ## Testing
204
225
 
205
226
  Create a postgres database:
@@ -13,7 +13,6 @@ class AbstractFeature < ActiveRecord::Base
13
13
 
14
14
  FEATURE_TYPES = %w(polygon point line)
15
15
 
16
- before_validation :sanitize_feature_type
17
16
  validates_presence_of :geog
18
17
  validate :validate_geometry, if: :will_save_change_to_geog?
19
18
  before_save :sanitize, if: :will_save_change_to_geog?
@@ -113,13 +112,7 @@ class AbstractFeature < ActiveRecord::Base
113
112
 
114
113
  def self.cache_derivatives(options = {})
115
114
  update_all <<-SQL.squish
116
- geom = ST_Transform(geog::geometry, #{detect_srid('geom')}),
117
- north = ST_YMax(geog::geometry),
118
- east = ST_XMax(geog::geometry),
119
- south = ST_YMin(geog::geometry),
120
- west = ST_XMin(geog::geometry),
121
- area = ST_Area(geog),
122
- centroid = ST_PointOnSurface(geog::geometry)
115
+ geom = ST_Transform(geog::geometry, #{detect_srid('geom')})
123
116
  SQL
124
117
 
125
118
  invalid('geom').update_all <<-SQL.squish
@@ -127,8 +120,7 @@ class AbstractFeature < ActiveRecord::Base
127
120
  SQL
128
121
 
129
122
  update_all <<-SQL.squish
130
- geom_lowres = ST_SimplifyPreserveTopology(geom, #{options.fetch(:lowres_simplification, lowres_simplification)}),
131
- tilegeom = ST_Transform(geom, 3857)
123
+ geom_lowres = ST_SimplifyPreserveTopology(geom, #{options.fetch(:lowres_simplification, lowres_simplification)})
132
124
  SQL
133
125
 
134
126
  invalid('geom_lowres').update_all <<-SQL.squish
@@ -286,10 +278,6 @@ class AbstractFeature < ActiveRecord::Base
286
278
  return error.fetch('invalid_geometry_message') if error
287
279
  end
288
280
 
289
- def sanitize_feature_type
290
- self.feature_type = FEATURE_TYPES.find {|type| self.feature_type.to_s.strip.downcase.include?(type) }
291
- end
292
-
293
281
  def sanitize_input_for_sql(input)
294
282
  self.class.send(:sanitize_sql_for_conditions, input)
295
283
  end
@@ -11,8 +11,6 @@ class Feature < AbstractFeature
11
11
 
12
12
  scope :source_identifier, lambda {|source_identifier| where(:source_identifier => source_identifier) if source_identifier.present? }
13
13
 
14
- validates_inclusion_of :feature_type, :in => FEATURE_TYPES
15
-
16
14
  before_save :truncate_name
17
15
 
18
16
  after_save :refresh_aggregate, if: :automatically_refresh_aggregate?
@@ -88,10 +88,20 @@ module SpatialFeatures
88
88
  private
89
89
 
90
90
  def spatial_feature_imports(import_options, make_valid, tmpdir)
91
- import_options.flat_map do |data_method, importer_name|
91
+ import_options.flat_map do |data_method, configuration|
92
+ case configuration
93
+ when Hash
94
+ importer_name = configuration.fetch(:name)
95
+ options = configuration.except(:name)
96
+ else
97
+ importer_name = configuration
98
+ options = {}
99
+ end
100
+
92
101
  Array.wrap(send(data_method)).flat_map do |data|
93
102
  next unless data.present?
94
- spatial_importer_from_name(importer_name).create_all(data, :make_valid => make_valid, :tmpdir => tmpdir)
103
+
104
+ spatial_importer_from_name(importer_name).create_all(data, **options, :make_valid => make_valid, :tmpdir => tmpdir)
95
105
  end
96
106
  end.compact
97
107
  end
@@ -1,6 +1,7 @@
1
1
  module SpatialFeatures
2
2
  module QueuedSpatialProcessing
3
3
  extend ActiveSupport::Concern
4
+ mattr_accessor :priority_offset, default: 0 # Offsets the queued priority of spatial tasks. Lower numbers run with higher priority
4
5
 
5
6
  def self.update_cached_status(record, method_name, state)
6
7
  return unless record.has_attribute?(:spatial_processing_status_cache)
@@ -11,12 +12,12 @@ module SpatialFeatures
11
12
  record.update_column(:spatial_processing_status_cache, cache) if record.will_save_change_to_spatial_processing_status_cache?
12
13
  end
13
14
 
14
- def queue_update_spatial_cache(*args, **kwargs)
15
- queue_spatial_task('update_spatial_cache', *args, **kwargs)
15
+ def queue_update_spatial_cache(*args, priority: priority_offset + 1, **kwargs)
16
+ queue_spatial_task('update_spatial_cache', *args, priority:, **kwargs)
16
17
  end
17
18
 
18
- def delay_update_features!(*args, **kwargs)
19
- queue_spatial_task('update_features!', *args, **kwargs)
19
+ def delay_update_features!(*args, priority: priority_offset + 0, **kwargs)
20
+ queue_spatial_task('update_features!', *args, priority:, **kwargs)
20
21
  end
21
22
 
22
23
  def updating_features?(**options)
@@ -77,7 +78,7 @@ module SpatialFeatures
77
78
 
78
79
  def queue_spatial_task(method_name, *args, priority: 1, **kwargs)
79
80
  # NOTE: We pass kwargs as an arg because Delayed::Job does not support separation of positional and keyword arguments in Ruby 3.0. Instead we perform manual extraction in `perform`.
80
- Delayed::Job.enqueue SpatialProcessingJob.new(self, method_name, *args, kwargs), :queue => spatial_processing_queue_name + method_name, :priority => priority
81
+ Delayed::Job.enqueue SpatialProcessingJob.new(self, method_name, *args, kwargs), :queue => spatial_processing_queue_name + method_name, priority:
81
82
  end
82
83
 
83
84
  def spatial_processing_queue_name
@@ -6,12 +6,13 @@ module SpatialFeatures
6
6
  attr_reader :errors
7
7
  attr_accessor :source_identifier # An identifier for the source of the features. Used to differentiate groups of features on the spatial model.
8
8
 
9
- def initialize(data, make_valid: false, tmpdir: nil, source_identifier: nil)
9
+ def initialize(data, make_valid: false, tmpdir: nil, source_identifier: nil, feature_name: ->(record) { record.name })
10
10
  @make_valid = make_valid
11
11
  @data = data
12
12
  @errors = []
13
13
  @tmpdir = tmpdir
14
14
  @source_identifier = source_identifier
15
+ @feature_name = feature_name
15
16
  end
16
17
 
17
18
  def features
@@ -51,13 +52,12 @@ module SpatialFeatures
51
52
  def build_feature(record)
52
53
  importable_image_paths = record.importable_image_paths if record.respond_to?(:importable_image_paths)
53
54
  Feature.new do |feature|
54
- feature.name = record.name
55
55
  feature.metadata = record.metadata
56
- feature.feature_type = record.feature_type
57
56
  feature.geog = record.geog
58
57
  feature.importable_image_paths = importable_image_paths
59
58
  feature.make_valid = @make_valid
60
59
  feature.source_identifier = source_identifier
60
+ feature.name = @feature_name.is_a?(Proc) ? @feature_name.call(record) : @feature_name
61
61
  end
62
62
  end
63
63
  end
@@ -22,9 +22,9 @@ module SpatialFeatures
22
22
  def each_record(&block)
23
23
  {'Polygon' => 'POLYGON', 'LineString' => 'LINE', 'Point' => 'POINT'}.each do |kml_type, sql_type|
24
24
  kml_document.css(kml_type).each do |feature|
25
- if placemark = feature.ancestors('Placemark').first
26
- name = placemark.css('name').text
25
+ if (placemark = feature.ancestors('Placemark').first)
27
26
  metadata = extract_metadata(placemark)
27
+ name = placemark.css('name').text
28
28
  else
29
29
  metadata = {}
30
30
  end
@@ -36,7 +36,7 @@ module SpatialFeatures
36
36
 
37
37
  importable_image_paths = images_from_metadata(metadata)
38
38
 
39
- yield OpenStruct.new(:feature_type => sql_type, :geog => geog, :name => name, :metadata => metadata, :importable_image_paths => importable_image_paths)
39
+ yield OpenStruct.new(:geog => geog, :name => name, :metadata => metadata, :importable_image_paths => importable_image_paths)
40
40
  end
41
41
  end
42
42
  end
@@ -6,7 +6,6 @@ module SpatialFeatures
6
6
  class Shapefile < Base
7
7
  class_attribute :default_proj4_projection
8
8
 
9
- FEATURE_TYPE_FOR_DIMENSION = { 0 => 'point', 1 => 'line', 2 => 'polygon' }.freeze
10
9
  PROJ4_4326 = '+proj=longlat +datum=WGS84 +no_defs'.freeze
11
10
 
12
11
  def initialize(data, proj4: nil, **options)
@@ -46,7 +45,7 @@ module SpatialFeatures
46
45
  def data_from_record(record, proj4 = nil)
47
46
  geometry = record.geometry
48
47
  wkt = geometry.as_text
49
- data = { :metadata => record.attributes, feature_type: FEATURE_TYPE_FOR_DIMENSION.fetch(geometry.dimension) }
48
+ data = { :metadata => record.attributes }
50
49
 
51
50
  if proj4 == PROJ4_4326
52
51
  data[:geog] = wkt
@@ -1,3 +1,3 @@
1
1
  module SpatialFeatures
2
- VERSION = "3.4.8"
2
+ VERSION = "3.6.0"
3
3
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spatial_features
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.8
4
+ version: 3.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Wallace
8
8
  - Nicholas Jakobsen
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-01-03 00:00:00.000000000 Z
12
+ date: 2024-02-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -51,14 +51,14 @@ dependencies:
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '3.0'
54
+ version: '3.1'
55
55
  type: :runtime
56
56
  prerelease: false
57
57
  version_requirements: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '3.0'
61
+ version: '3.1'
62
62
  - !ruby/object:Gem::Dependency
63
63
  name: rgeo-geojson
64
64
  requirement: !ruby/object:Gem::Requirement
@@ -101,6 +101,26 @@ dependencies:
101
101
  - - ">="
102
102
  - !ruby/object:Gem::Version
103
103
  version: '0'
104
+ - !ruby/object:Gem::Dependency
105
+ name: rails
106
+ requirement: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '7'
111
+ - - "<"
112
+ - !ruby/object:Gem::Version
113
+ version: '8'
114
+ type: :development
115
+ prerelease: false
116
+ version_requirements: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '7'
121
+ - - "<"
122
+ - !ruby/object:Gem::Version
123
+ version: '8'
104
124
  - !ruby/object:Gem::Dependency
105
125
  name: pg
106
126
  requirement: !ruby/object:Gem::Requirement
@@ -188,7 +208,7 @@ homepage: https://github.com/culturecode/spatial_features
188
208
  licenses:
189
209
  - MIT
190
210
  metadata: {}
191
- post_install_message:
211
+ post_install_message:
192
212
  rdoc_options: []
193
213
  require_paths:
194
214
  - lib
@@ -203,8 +223,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
203
223
  - !ruby/object:Gem::Version
204
224
  version: '0'
205
225
  requirements: []
206
- rubygems_version: 3.3.23
207
- signing_key:
226
+ rubygems_version: 3.5.1
227
+ signing_key:
208
228
  specification_version: 4
209
229
  summary: Adds spatial methods to a model.
210
230
  test_files: []