activerecord-trilogis-adapter 7.0.2 → 8.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 +4 -4
- data/LICENSE +21 -0
- data/lib/active_record/connection_adapters/trilogis/arel_tosql.rb +120 -45
- data/lib/active_record/connection_adapters/trilogis/railtie.rb +21 -14
- data/lib/active_record/connection_adapters/trilogis/schema_creation.rb +7 -7
- data/lib/active_record/connection_adapters/trilogis/schema_statements.rb +169 -40
- data/lib/active_record/connection_adapters/trilogis/spatial_column.rb +56 -42
- data/lib/active_record/connection_adapters/trilogis/spatial_column_info.rb +39 -20
- data/lib/active_record/connection_adapters/trilogis/spatial_expressions.rb +78 -4
- data/lib/active_record/connection_adapters/trilogis/spatial_table_definition.rb +79 -22
- data/lib/active_record/connection_adapters/trilogis/version.rb +1 -1
- data/lib/active_record/connection_adapters/trilogis_adapter.rb +219 -111
- data/lib/active_record/dependency_loader.rb +38 -0
- data/lib/active_record/tasks/trilogis_database_tasks.rb +2 -1
- data/lib/active_record/type/spatial.rb +217 -63
- data/lib/activerecord-trilogis-adapter.rb +15 -2
- metadata +110 -35
- data/LICENSE.txt +0 -29
- data/lib/active_record/connection_adapters/trilogis/column_methods.rb +0 -54
- data/lib/active_record/connection_adapters/trilogis/connection.rb +0 -17
- data/lib/active_record/connection_adapters/trilogis/rails/dbconsole.rb +0 -48
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
module ActiveRecord
|
|
4
|
-
module ConnectionAdapters
|
|
5
|
-
module Trilogis
|
|
6
|
-
#
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module ConnectionAdapters
|
|
5
|
+
module Trilogis
|
|
6
|
+
# Queries MySQL INFORMATION_SCHEMA for spatial column metadata
|
|
7
|
+
# and caches the results for performance
|
|
7
8
|
class SpatialColumnInfo
|
|
8
9
|
def initialize(adapter, table_name)
|
|
9
10
|
@adapter = adapter
|
|
@@ -11,30 +12,48 @@ module ActiveRecord # :nodoc:
|
|
|
11
12
|
end
|
|
12
13
|
|
|
13
14
|
def all
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
# Query MySQL's ST_GEOMETRY_COLUMNS view for SRID info
|
|
16
|
+
# This view properly returns SRS_ID for spatial columns
|
|
17
|
+
sql = <<~SQL.squish
|
|
18
|
+
SELECT
|
|
19
|
+
gc.COLUMN_NAME as column_name,
|
|
20
|
+
gc.SRS_ID as srs_id,
|
|
21
|
+
gc.GEOMETRY_TYPE_NAME as geometry_type,
|
|
22
|
+
c.COLUMN_TYPE as column_type
|
|
23
|
+
FROM INFORMATION_SCHEMA.ST_GEOMETRY_COLUMNS gc
|
|
24
|
+
JOIN INFORMATION_SCHEMA.COLUMNS c
|
|
25
|
+
ON gc.TABLE_SCHEMA = c.TABLE_SCHEMA
|
|
26
|
+
AND gc.TABLE_NAME = c.TABLE_NAME
|
|
27
|
+
AND gc.COLUMN_NAME = c.COLUMN_NAME
|
|
28
|
+
WHERE gc.TABLE_SCHEMA = DATABASE()
|
|
29
|
+
AND gc.TABLE_NAME = #{@adapter.quote(@table_name)}
|
|
30
|
+
SQL
|
|
17
31
|
|
|
18
32
|
result = {}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
33
|
+
@adapter.exec_query(sql, "SCHEMA").each do |row|
|
|
34
|
+
column_name = row["column_name"] || row["COLUMN_NAME"]
|
|
35
|
+
srs_id = row["srs_id"] || row["SRS_ID"]
|
|
36
|
+
row["geometry_type"] || row["GEOMETRY_TYPE"]
|
|
37
|
+
column_type = (row["column_type"] || row["COLUMN_TYPE"]).to_s.sub(/m$/, "")
|
|
38
|
+
|
|
39
|
+
result[column_name] = {
|
|
40
|
+
name: column_name,
|
|
41
|
+
srid: srs_id.to_i,
|
|
42
|
+
type: column_type
|
|
27
43
|
}
|
|
28
44
|
end
|
|
29
45
|
result
|
|
30
46
|
end
|
|
31
47
|
|
|
32
|
-
#
|
|
33
|
-
|
|
34
|
-
|
|
48
|
+
# Get spatial info for a specific column if it's spatial
|
|
49
|
+
# Returns nil for non-spatial columns to avoid unnecessary queries
|
|
50
|
+
def get(column_name, sql_type)
|
|
51
|
+
# Only query for known spatial types
|
|
52
|
+
return unless TrilogisAdapter::SPATIAL_COLUMN_TYPES.include?(sql_type.to_s.downcase)
|
|
35
53
|
|
|
36
|
-
|
|
37
|
-
|
|
54
|
+
# Don't memoize - always query fresh data to avoid stale cache issues
|
|
55
|
+
# when columns are added during tests
|
|
56
|
+
all[column_name]
|
|
38
57
|
end
|
|
39
58
|
end
|
|
40
59
|
end
|
|
@@ -3,18 +3,92 @@
|
|
|
3
3
|
module RGeo
|
|
4
4
|
module ActiveRecord
|
|
5
5
|
module Trilogis
|
|
6
|
+
# MySQL-specific spatial expressions
|
|
6
7
|
module SpatialExpressions
|
|
8
|
+
# MySQL ST_Distance_Sphere for geographic distance calculations
|
|
7
9
|
def st_distance_sphere(rhs, units = nil)
|
|
8
10
|
args = [self, rhs]
|
|
9
11
|
args << units.to_s if units
|
|
10
12
|
SpatialNamedFunction.new("ST_Distance_Sphere", args, [false, true, true, false])
|
|
11
13
|
end
|
|
14
|
+
|
|
15
|
+
# Additional MySQL spatial functions
|
|
16
|
+
def st_buffer(distance)
|
|
17
|
+
SpatialNamedFunction.new("ST_Buffer", [self, distance], [false, true, false])
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def st_contains(rhs)
|
|
21
|
+
SpatialNamedFunction.new("ST_Contains", [self, rhs], [false, true, true])
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def st_within(rhs)
|
|
25
|
+
SpatialNamedFunction.new("ST_Within", [self, rhs], [false, true, true])
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def st_intersects(rhs)
|
|
29
|
+
SpatialNamedFunction.new("ST_Intersects", [self, rhs], [false, true, true])
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def st_crosses(rhs)
|
|
33
|
+
SpatialNamedFunction.new("ST_Crosses", [self, rhs], [false, true, true])
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def st_touches(rhs)
|
|
37
|
+
SpatialNamedFunction.new("ST_Touches", [self, rhs], [false, true, true])
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def st_overlaps(rhs)
|
|
41
|
+
SpatialNamedFunction.new("ST_Overlaps", [self, rhs], [false, true, true])
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def st_equals(rhs)
|
|
45
|
+
SpatialNamedFunction.new("ST_Equals", [self, rhs], [false, true, true])
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def st_disjoint(rhs)
|
|
49
|
+
SpatialNamedFunction.new("ST_Disjoint", [self, rhs], [false, true, true])
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def st_area
|
|
53
|
+
SpatialNamedFunction.new("ST_Area", [self], [false, true])
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def st_length
|
|
57
|
+
SpatialNamedFunction.new("ST_Length", [self], [false, true])
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def st_centroid
|
|
61
|
+
SpatialNamedFunction.new("ST_Centroid", [self], [false, true])
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def st_envelope
|
|
65
|
+
SpatialNamedFunction.new("ST_Envelope", [self], [false, true])
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def st_astext
|
|
69
|
+
SpatialNamedFunction.new("ST_AsText", [self], [false, true])
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def st_asbinary
|
|
73
|
+
SpatialNamedFunction.new("ST_AsBinary", [self], [false, true])
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def st_srid
|
|
77
|
+
SpatialNamedFunction.new("ST_SRID", [self], [false, true])
|
|
78
|
+
end
|
|
12
79
|
end
|
|
13
80
|
end
|
|
14
81
|
end
|
|
15
82
|
end
|
|
16
83
|
|
|
17
|
-
# Allow chaining of spatial expressions from attributes
|
|
18
|
-
Arel::Attribute.include RGeo::ActiveRecord::Trilogis::SpatialExpressions
|
|
19
|
-
|
|
20
|
-
RGeo
|
|
84
|
+
# Allow chaining of spatial expressions from Arel attributes
|
|
85
|
+
Arel::Attribute.include RGeo::ActiveRecord::Trilogis::SpatialExpressions if defined?(Arel::Attribute)
|
|
86
|
+
|
|
87
|
+
# Include in RGeo spatial nodes if they exist
|
|
88
|
+
if defined?(RGeo::ActiveRecord::SpatialConstantNode)
|
|
89
|
+
RGeo::ActiveRecord::SpatialConstantNode.include RGeo::ActiveRecord::Trilogis::SpatialExpressions
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
if defined?(RGeo::ActiveRecord::SpatialNamedFunction)
|
|
93
|
+
RGeo::ActiveRecord::SpatialNamedFunction.include RGeo::ActiveRecord::Trilogis::SpatialExpressions
|
|
94
|
+
end
|
|
@@ -1,36 +1,93 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
module ActiveRecord
|
|
4
|
-
module ConnectionAdapters
|
|
5
|
-
module Trilogis
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (info = TrilogisAdapter.spatial_column_options(type.to_sym))
|
|
11
|
-
if (limit = options.delete(:limit)) && limit.is_a?(::Hash)
|
|
12
|
-
options.merge!(limit)
|
|
13
|
-
end
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module ConnectionAdapters
|
|
5
|
+
module Trilogis
|
|
6
|
+
module ColumnMethods
|
|
7
|
+
# Generic spatial column method
|
|
8
|
+
def spatial(name, options = {})
|
|
9
|
+
raise "You must set a type. For example: 't.spatial :location, type: :point'" unless options[:type]
|
|
14
10
|
|
|
15
|
-
|
|
11
|
+
column(name, options[:type], **options)
|
|
12
|
+
end
|
|
16
13
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
# Define spatial column types with both underscore and non-underscore versions
|
|
15
|
+
def geometry(name, options = {})
|
|
16
|
+
column(name, :geometry, **options)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def geometrycollection(name, options = {})
|
|
20
|
+
column(name, :geometrycollection, **options)
|
|
21
|
+
end
|
|
22
|
+
alias geometry_collection geometrycollection
|
|
23
|
+
|
|
24
|
+
def linestring(name, options = {})
|
|
25
|
+
column(name, :linestring, **options)
|
|
26
|
+
end
|
|
27
|
+
alias line_string linestring
|
|
28
|
+
|
|
29
|
+
def multilinestring(name, options = {})
|
|
30
|
+
column(name, :multilinestring, **options)
|
|
31
|
+
end
|
|
32
|
+
alias multi_line_string multilinestring
|
|
33
|
+
|
|
34
|
+
def multipoint(name, options = {})
|
|
35
|
+
column(name, :multipoint, **options)
|
|
36
|
+
end
|
|
37
|
+
alias multi_point multipoint
|
|
38
|
+
|
|
39
|
+
def multipolygon(name, options = {})
|
|
40
|
+
column(name, :multipolygon, **options)
|
|
41
|
+
end
|
|
42
|
+
alias multi_polygon multipolygon
|
|
43
|
+
|
|
44
|
+
def point(name, options = {})
|
|
45
|
+
column(name, :point, **options)
|
|
46
|
+
end
|
|
22
47
|
|
|
23
|
-
|
|
48
|
+
def polygon(name, options = {})
|
|
49
|
+
column(name, :polygon, **options)
|
|
24
50
|
end
|
|
25
51
|
end
|
|
26
52
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
53
|
+
class TableDefinition < ActiveRecord::ConnectionAdapters::MySQL::TableDefinition
|
|
54
|
+
include ColumnMethods
|
|
55
|
+
|
|
56
|
+
# Override column to handle spatial types
|
|
57
|
+
def column(name, type, index: nil, **options)
|
|
58
|
+
# Store spatial-specific options before processing
|
|
59
|
+
spatial_options = {
|
|
60
|
+
srid: options.delete(:srid),
|
|
61
|
+
has_m: options.delete(:has_m),
|
|
62
|
+
has_z: options.delete(:has_z),
|
|
63
|
+
geographic: options.delete(:geographic)
|
|
64
|
+
}.compact
|
|
65
|
+
|
|
66
|
+
# Call super to create column definition
|
|
67
|
+
result = super
|
|
68
|
+
|
|
69
|
+
# Add spatial options back to the column definition if it's a spatial type
|
|
70
|
+
if spatial_type?(type) && (col = @columns_hash[name.to_s])
|
|
71
|
+
spatial_options.each do |key, value|
|
|
72
|
+
col.options[key] = value
|
|
73
|
+
end
|
|
31
74
|
end
|
|
75
|
+
|
|
76
|
+
# Add spatial index if requested
|
|
77
|
+
@indexes << [name, { type: :spatial }] if index && spatial_type?(type) && [true, :spatial].include?(index)
|
|
78
|
+
|
|
79
|
+
result
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
def spatial_type?(type)
|
|
85
|
+
TrilogisAdapter::SPATIAL_COLUMN_TYPES.include?(type.to_s)
|
|
32
86
|
end
|
|
33
87
|
end
|
|
34
88
|
end
|
|
89
|
+
|
|
90
|
+
# Include column methods in MySQL::Table for migrations
|
|
91
|
+
MySQL::Table.include Trilogis::ColumnMethods if defined?(MySQL::Table)
|
|
35
92
|
end
|
|
36
93
|
end
|