activerecord-cockroachdb-adapter 5.2.3 → 6.0.0beta1

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: a28ccd96cddcfaf334a3a854f8312a754e11b3a610ce338e53465abc567dcd71
4
- data.tar.gz: 37ea9e0cb5d202128a46fbeb97fce75a9ef6aa8ae8043fc2c1f11fc38ae01ff1
3
+ metadata.gz: a580dde40d074b1982c6642310513d79bbcb710032a476a64bb9fcb99bec72bb
4
+ data.tar.gz: 91b11b334235484e298704ae514d435a61451a02f3f759881141fd6354549ee4
5
5
  SHA512:
6
- metadata.gz: 2a3a26fe9bbd9043bbbcd50b1c262cdc88bfded513b8f4d1fb2488d0a76cc9943c8201c082f6a6a5c65123801ad3fa10851ff708e771f3be9b07b53464ed4ae5
7
- data.tar.gz: f5e123cce6d782b4427b4e97066cd874b9539a4a7de78d122ed46672326864bf4640aa3a9810b506f3bd307e6a1ff2fdf9447f2e215a391022350e023c41278d
6
+ metadata.gz: 77b98dff7d2069ba0cdcd78bccf5aedf9ac31192c0813d7893a5a6f1084537d9d0b03039be58fe83a5a0e0cd58d5d42ba567e43beee62507d8212242722fdb13
7
+ data.tar.gz: f1bf6e2fa1925d94133a98dcd03690a24da2631134cc6a5eb6dd860253392f398db88572942f409f13dec4d3d7aeb34f18317a5b8cd4b30c70e4d75d13599b47
data/README.md CHANGED
@@ -7,7 +7,7 @@ CockroachDB adapter for ActiveRecord 4 and 5. This is a lightweight extension of
7
7
  Add this line to your project's Gemfile:
8
8
 
9
9
  ```ruby
10
- gem 'activerecord-cockroachdb-adapter', '~> 5.2'
10
+ gem 'activerecord-cockroachdb-adapter', '~> 5.2.0'
11
11
  ```
12
12
 
13
13
  If you're using Rails 4.x, use the `0.1.x` versions of this gem.
@@ -21,303 +21,7 @@ development:
21
21
  host: <hostname>
22
22
  user: <username>
23
23
  ```
24
- ## Configuration
25
24
 
26
- In addition to the standard adapter settings, CockroachDB also supports the following:
27
-
28
- - `disable_cockroachdb_telemetry`: Determines if a telemetry call is made to the database when the connection pool is initialized. Setting this to `true` will prevent the call from being made.
29
-
30
- ## Working with Spatial Data
31
-
32
- The adapter uses [RGeo](https://github.com/rgeo/rgeo) and [RGeo-ActiveRecord](https://github.com/rgeo/rgeo-activerecord) to represent geometric and geographic data as Ruby objects and easily interface them with the adapter. The following is a brief introduction to RGeo and tips to help setup your spatial application. More documentation about RGeo can be found in the [YARD Docs](https://rubydoc.info/github/rgeo/rgeo) and [wiki](https://github.com/rgeo/rgeo/wiki).
33
-
34
- ### Installing RGeo
35
-
36
- RGeo can be installed with the following command:
37
-
38
- ```sh
39
- gem install rgeo
40
- ```
41
-
42
- The best way to use RGeo is with GEOS support. If you have a version of libgeos installed, you can check that it was properly linked with RGeo by running the following commands:
43
-
44
- ```rb
45
- require 'rgeo'
46
-
47
- RGeo::Geos.supported?
48
- #=> true
49
- ```
50
-
51
- If this is `false`, you may need to specify the GEOS directory while installing. Here's an example linking it to the CockroachDB GEOS binary.
52
-
53
- ```sh
54
- gem install rgeo -- --with-geos-dir=/path/to/cockroach/lib/
55
- ```
56
-
57
- ### Working with RGeo
58
-
59
- RGeo uses [factories](https://en.wikipedia.org/wiki/Factory_(object-oriented_programming)) to create geometry objects and define their properties. Different factories define their own implementations for standard methods. For instance, the `RGeo::Geographic.spherical_factory` accepts latitudes and longitues as its coordinates and does computations on a spherical surface, while `RGeo::Cartesian.factory` implements geometry objects on a plane.
60
-
61
- The factory (or factories) you choose to use will depend on the requirements of your application and what you need to do with the geometries they produce. For example, if you are working with points or other simple geometries across long distances and need precise results, the spherical factory is a good choice. If you're working with polygons or multipolygons and analyzing complex relationships between them (`intersects?`, `difference`, etc.), then using a cartesian factory backed by GEOS is a much better option.
62
-
63
- Once you've selected a factory, you need to create objects. RGeo supports geometry creation through standard constructors (`point`, `line_string`, `polygon`, etc.) or by WKT and WKB.
64
-
65
- ```rb
66
- require 'rgeo'
67
- factory = RGeo::Cartesian.factory(srid: 3857)
68
-
69
- # Create a line_string from points
70
- pt1 = factory.point(0,0)
71
- pt2 = factory.point(1,1)
72
- pt3 = factory.point(2,2)
73
- line_string = factory.line_string([pt1,pt2,pt3])
74
-
75
- p line_string.length
76
- #=> 2.8284271247461903
77
-
78
- # check line_string equality
79
- line_string2 = factory.parse_wkt("LINESTRING (0 0, 1 1, 2 2)")
80
- p line_string == line_string2
81
- #=> true
82
-
83
- # create polygon and test intersection with line_string
84
- pt4 = factory.point(0,2)
85
- outer_ring = factory.linear_ring([pt1,pt2,pt3,pt4,pt1])
86
- poly = factory.polygon(outer_ring)
87
-
88
- p line_string.intersects? poly
89
- #=> true
90
- ```
91
- ### Creating Spatial Tables
92
-
93
- To store spatial data, you must create a column with a spatial type. PostGIS
94
- provides a variety of spatial types, including point, linestring, polygon, and
95
- different kinds of collections. These types are defined in a standard produced
96
- by the Open Geospatial Consortium. You can specify options indicating the coordinate system and number of coordinates for the values you are storing.
97
-
98
- The adapter extends ActiveRecord's migration syntax to
99
- support these spatial types. The following example creates five spatial
100
- columns in a table:
101
-
102
- ```rb
103
- create_table :my_spatial_table do |t|
104
- t.column :shape1, :geometry
105
- t.geometry :shape2
106
- t.line_string :path, srid: 3857
107
- t.st_point :lonlat, geographic: true
108
- t.st_point :lonlatheight, geographic: true, has_z: true
109
- end
110
- ```
111
-
112
- The first column, "shape1", is created with type "geometry". This is a general
113
- "base class" for spatial types; the column declares that it can contain values
114
- of _any_ spatial type.
115
-
116
- The second column, "shape2", uses a shorthand syntax for the same type as the shape1 column.
117
- You can create a column either by invoking `column` or invoking the name of the type directly.
118
-
119
- The third column, "path", has a specific geometric type, `line_string`. It
120
- also specifies an SRID (spatial reference ID) that indicates which coordinate
121
- system it expects the data to be in. The column now has a "constraint" on it;
122
- it will accept only LineString data, and only data whose SRID is 3857.
123
-
124
- The fourth column, "lonlat", has the `st_point` type, and accepts only Point
125
- data. Furthermore, it declares the column as "geographic", which means it
126
- accepts longitude/latitude data, and performs calculations such as distances
127
- using a spheroidal domain.
128
-
129
- The fifth column, "lonlatheight", is a geographic (longitude/latitude) point
130
- that also includes a third "z" coordinate that can be used to store height
131
- information.
132
-
133
- The following are the data types understood by PostGIS and exposed by
134
- the adapter:
135
-
136
- - `:geometry` -- Any geometric type
137
- - `:st_point` -- Point data
138
- - `:line_string` -- LineString data
139
- - `:st_polygon` -- Polygon data
140
- - `:geometry_collection` -- Any collection type
141
- - `:multi_point` -- A collection of Points
142
- - `:multi_line_string` -- A collection of LineStrings
143
- - `:multi_polygon` -- A collection of Polygons
144
-
145
- Following are the options understood by the adapter:
146
-
147
- - `:geographic` -- If set to true, create a PostGIS geography column for
148
- longitude/latitude data over a spheroidal domain; otherwise create a
149
- geometry column in a flat coordinate system. Default is false. Also
150
- implies :srid set to 4326.
151
- - `:srid` -- Set a SRID constraint for the column. Default is 4326 for a
152
- geography column, or 0 for a geometry column. Note that PostGIS currently
153
- (as of version 2.0) requires geography columns to have SRID 4326, so this
154
- constraint is of limited use for geography columns.
155
- - `:has_z` -- Specify that objects in this column include a Z coordinate.
156
- Default is false.
157
- - `:has_m` -- Specify that objects in this column include an M coordinate.
158
- Default is false.
159
-
160
- To create a PostGIS spatial index, add `using: :gist` to your index:
161
-
162
- ```rb
163
- add_index :my_table, :lonlat, using: :gist
164
-
165
- # or
166
-
167
- change_table :my_table do |t|
168
- t.index :lonlat, using: :gist
169
- end
170
- ```
171
- ### Configuring ActiveRecord
172
-
173
- ActiveRecord's usefulness stems from the way it automatically configures
174
- classes based on the database structure and schema. If a column in the
175
- database has an integer type, ActiveRecord automatically casts the data to a
176
- Ruby Integer. In the same way, the adapter automatically
177
- casts spatial data to a corresponding RGeo data type.
178
-
179
- RGeo offers more flexibility in its type system than can be
180
- interpreted solely from analyzing the database column. For example, you can
181
- configure RGeo objects to exhibit certain behaviors related to their
182
- serialization, validation, coordinate system, or computation. These settings
183
- are embodied in the RGeo factory associated with the object.
184
-
185
- You can configure the adapter to use a particular factory (i.e. a
186
- particular combination of settings) for data associated with each type in
187
- the database.
188
-
189
- Here's an example using a Geos default factory:
190
-
191
- ```ruby
192
- RGeo::ActiveRecord::SpatialFactoryStore.instance.tap do |config|
193
- # By default, use the GEOS implementation for spatial columns.
194
- config.default = RGeo::Geos.factory_generator
195
-
196
- # But use a geographic implementation for point columns.
197
- config.register(RGeo::Geographic.spherical_factory(srid: 4326), geo_type: "point")
198
- end
199
- ```
200
-
201
- The default spatial factory for geographic columns is `RGeo::Geographic.spherical_factory`.
202
- The default spatial factory for cartesian columns is `RGeo::Cartesian.preferred_factory`.
203
- You do not need to configure the `SpatialFactoryStore` if these defaults are ok.
204
-
205
- More information about configuration options for the `SpatialFactoryStore` can be found in the [rgeo-activerecord](https://github.com/rgeo/rgeo-activerecord#spatial-factories-for-columns) docs.
206
-
207
- ### Reading and Writing Spatial Columns
208
-
209
- When you access a spatial attribute on your ActiveRecord model, it is given to
210
- you as an RGeo geometry object (or nil, for attributes that allow null
211
- values). You can then call the RGeo api on the object. For example, consider
212
- the MySpatialTable class we worked with above:
213
-
214
- ```rb
215
- record = MySpatialTable.find(1)
216
- point = record.lonlat # Returns an RGeo::Feature::Point
217
- p point.x # displays the x coordinate
218
- p point.geometry_type.type_name # displays "Point"
219
- ```
220
-
221
- The RGeo factory for the value is determined by how you configured the
222
- ActiveRecord class, as described above. In this case, we explicitly set a
223
- spherical factory for the `:lonlat` column:
224
-
225
- ```rb
226
- factory = point.factory # returns a spherical factory
227
- ```
228
-
229
- You can set a spatial attribute by providing an RGeo geometry object, or by
230
- providing the WKT string representation of the geometry. If a string is
231
- provided, the adapter will attempt to parse it as WKT and
232
- set the value accordingly.
233
-
234
- ```rb
235
- record.lonlat = 'POINT(-122 47)' # sets the value to the given point
236
- ```
237
-
238
- If the WKT parsing fails, the value currently will be silently set to nil. In
239
- the future, however, this will raise an exception.
240
-
241
- ```rb
242
- record.lonlat = 'POINT(x)' # sets the value to nil
243
- ```
244
-
245
- If you set the value to an RGeo object, the factory needs to match the factory
246
- for the attribute. If the factories do not match, the adapter
247
- will attempt to cast the value to the correct factory.
248
-
249
- ```rb
250
- p2 = factory.point(-122, 47) # p2 is a point in a spherical factory
251
- record.lonlat = p2 # sets the value to the given point
252
- record.shape1 = p2 # shape1 uses a flat geos factory, so it
253
- # will cast p2 into that coordinate system
254
- # before setting the value
255
- record.save
256
- ```
257
-
258
- If you attempt to set the value to the wrong type, such as setting a linestring attribute to a point value, you will get an exception from the database when you attempt to save the record.
259
-
260
- ```rb
261
- record.path = p2 # This will appear to work, but...
262
- record.save # This will raise an exception from the database
263
- ```
264
-
265
- ### Spatial Queries
266
-
267
- You can create simple queries based on representational equality in the same
268
- way you would on a scalar column:
269
-
270
- ```ruby
271
- record2 = MySpatialTable.where(:lonlat => factory.point(-122, 47)).first
272
- ```
273
-
274
- You can also use WKT:
275
-
276
- ```ruby
277
- record3 = MySpatialTable.where(:lonlat => 'POINT(-122 47)').first
278
- ```
279
-
280
- Note that these queries use representational equality, meaning they return
281
- records where the lonlat value matches the given value exactly. A 0.00001
282
- degree difference would not match, nor would a different representation of the
283
- same geometry (like a multi_point with a single element). Equality queries
284
- aren't generally all that useful in real world applications. Typically, if you
285
- want to perform a spatial query, you'll look for, say, all the points within a
286
- given area. For those queries, you'll need to use the standard spatial SQL
287
- functions provided by PostGIS.
288
-
289
- To perform more advanced spatial queries, you can use the extended Arel interface included in the adapter. The functions accept WKT strings or RGeo features.
290
-
291
- ```rb
292
- point = RGeo::Geos.factory(srid: 0).point(1,1)
293
-
294
- # Example Building model where geom is a column of polygons.
295
- buildings = Building.arel_table
296
- containing_buiildings = Building.where(buildings[:geom].st_contains(point))
297
- ```
298
-
299
- See the [rgeo-activerecord YARD Docs](https://rubydoc.info/github/rgeo/rgeo-activerecord/RGeo/ActiveRecord/SpatialExpressions) for a list of available PostGIS functions.
300
-
301
- ### Validation Issues
302
-
303
- If you see an `RGeo::Error::InvalidGeometry (LinearRing failed ring test)` message while loading data or creating geometries, this means that the geometry you are trying to instantiate is not topologically valid. This is usually due to self-intersections in the geometry. The default behavior of RGeo factories is to raise this error when an invalid geometry is being instansiated, but this can be ignored by setting the `uses_lenient_assertions` flag to `true` when creating your factory.
304
-
305
- ```rb
306
- regular_fac = RGeo::Geographic.spherical_factory
307
- modified_fac = RGeo::Geographic.spherical_factory(uses_lenient_assertions: true)
308
-
309
- wkt = "POLYGON (0 0, 1 1, 0 1, 1 0, 0 0)" # closed ring with self intersection
310
-
311
- regular_fac.parse_wkt(wkt)
312
- #=> RGeo::Error::InvalidGeometry (LinearRing failed ring test)
313
-
314
- p modified_fac.parse_wkt(wkt)
315
- #=> #<RGeo::Geographic::SphericalPolygonImpl>
316
- ```
317
-
318
- Be careful when performing calculations on potentially invalid geometries, as the results might be nonsensical. For example, the area returned of an hourglass made of 2 equivalent triangles with a self-intersection in the middle is 0.
319
-
320
- Note that when using the `spherical_factory`, there is a chance that valid geometries will be interpreted as invalid due to floating point issues with small geometries.
321
25
 
322
26
  ## Modifying the adapter?
323
27
 
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "activerecord-cockroachdb-adapter"
7
- spec.version = "5.2.3"
7
+ spec.version = "6.0.0beta1"
8
8
  spec.licenses = ["Apache-2.0"]
9
9
  spec.authors = ["Cockroach Labs"]
10
10
  spec.email = ["cockroach-db@googlegroups.com"]
@@ -13,9 +13,8 @@ Gem::Specification.new do |spec|
13
13
  spec.description = "Allows the use of CockroachDB as a backend for ActiveRecord and Rails apps."
14
14
  spec.homepage = "https://github.com/cockroachdb/activerecord-cockroachdb-adapter"
15
15
 
16
- spec.add_dependency "activerecord", "~> 5.2"
16
+ spec.add_dependency "activerecord", "~> 6.0.3"
17
17
  spec.add_dependency "pg", ">= 0.20"
18
- spec.add_dependency "rgeo-activerecord", "~> 7.0.0"
19
18
 
20
19
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
21
20
  # to allow pushing to a single host or delete this section to allow pushing to any host.
@@ -11,7 +11,6 @@ connections:
11
11
  user: root
12
12
  requiressl: disable
13
13
  min_messages: warning
14
- disable_cockroachdb_telemetry: true
15
14
  arunit_without_prepared_statements:
16
15
  database: activerecord_unittest
17
16
  host: localhost
@@ -20,7 +19,6 @@ connections:
20
19
  requiressl: disable
21
20
  min_messages: warning
22
21
  prepared_statements: false
23
- disable_cockroachdb_telemetry: true
24
22
  arunit2:
25
23
  database: activerecord_unittest2
26
24
  host: localhost
@@ -28,4 +26,3 @@ connections:
28
26
  user: root
29
27
  requiressl: disable
30
28
  min_messages: warning
31
- disable_cockroachdb_telemetry: true
@@ -3,7 +3,7 @@
3
3
  set -euox pipefail
4
4
 
5
5
  # Download CockroachDB
6
- VERSION=v20.2.3
6
+ VERSION=v20.2.1
7
7
  wget -qO- https://binaries.cockroachdb.com/cockroach-$VERSION.linux-amd64.tgz | tar xvz
8
8
  readonly COCKROACH=./cockroach-$VERSION.linux-amd64/cockroach
9
9
 
@@ -21,7 +21,7 @@ run_cockroach() {
21
21
  cockroach quit --insecure || true
22
22
  rm -rf cockroach-data
23
23
  # Start CockroachDB.
24
- cockroach start-single-node --max-sql-memory=25% --cache=25% --insecure --host=localhost --spatial-libs=./cockroach-$VERSION.linux-amd64/lib --listening-url-file="$urlfile" >/dev/null 2>&1 &
24
+ cockroach start-single-node --max-sql-memory=25% --cache=25% --insecure --host=localhost --listening-url-file="$urlfile" >/dev/null 2>&1 &
25
25
  # Ensure CockroachDB is stopped on script exit.
26
26
  trap "echo 'Exit routine: Killing CockroachDB.' && kill -9 $! &> /dev/null" EXIT
27
27
  # Wait until CockroachDB has started.
@@ -2,87 +2,8 @@ module ActiveRecord
2
2
  module ConnectionAdapters
3
3
  module CockroachDB
4
4
  module PostgreSQLColumnMonkeyPatch
5
- # most functions taken from activerecord-postgis-adapter spatial_column
6
- # https://github.com/rgeo/activerecord-postgis-adapter/blob/master/lib/active_record/connection_adapters/postgis/spatial_column.rb
7
- def initialize(name, default, sql_type_metadata = nil, null = true, table_name = nil,
8
- default_function = nil, collation = nil, comment = nil, cast_type = nil, opts = nil)
9
- @sql_type_metadata = sql_type_metadata
10
- @geographic = !!(sql_type_metadata.sql_type =~ /geography\(/i)
11
-
12
- @cast_type = cast_type
13
- @geographic = !!(sql_type_metadata.sql_type =~ /geography\(/i)
14
- if opts
15
- # This case comes from an entry in the geometry_columns table
16
- set_geometric_type_from_name(opts[:type])
17
- @srid = opts[:srid].to_i
18
- @has_z = !!opts[:has_z]
19
- @has_m = !!opts[:has_m]
20
- elsif @geographic
21
- # Geographic type information is embedded in the SQL type
22
- @srid = 4326
23
- @has_z = @has_m = false
24
- build_from_sql_type(sql_type_metadata.sql_type)
25
- elsif sql_type =~ /geography|geometry|point|linestring|polygon/i
26
- build_from_sql_type(sql_type_metadata.sql_type)
27
- elsif sql_type_metadata.sql_type =~ /geography|geometry|point|linestring|polygon/i
28
- # A geometry column with no geometry_columns entry.
29
- # @geometric_type = geo_type_from_sql_type(sql_type)
30
- build_from_sql_type(sql_type_metadata.sql_type)
31
- end
32
- super(name, default, sql_type_metadata, null, table_name, default_function, collation, comment: comment)
33
- if spatial?
34
- if @srid
35
- @limit = { srid: @srid, type: to_type_name(geometric_type) }
36
- @limit[:has_z] = true if @has_z
37
- @limit[:has_m] = true if @has_m
38
- @limit[:geographic] = true if @geographic
39
- end
40
- end
41
- end
42
-
43
- attr_reader :geographic,
44
- :geometric_type,
45
- :has_m,
46
- :has_z,
47
- :srid
48
-
49
- alias geographic? geographic
50
- alias has_z? has_z
51
- alias has_m? has_m
52
-
53
- def limit
54
- spatial? ? @limit : super
55
- end
56
-
57
- def spatial?
58
- %i[geometry geography].include?(@sql_type_metadata.type)
59
- end
60
-
61
5
  def serial?
62
- default_function == 'unique_rowid()'
63
- end
64
-
65
- private
66
-
67
- def set_geometric_type_from_name(name)
68
- @geometric_type = RGeo::ActiveRecord.geometric_type_from_name(name) || RGeo::Feature::Geometry
69
- end
70
-
71
- def build_from_sql_type(sql_type)
72
- geo_type, @srid, @has_z, @has_m = OID::Spatial.parse_sql_type(sql_type)
73
- set_geometric_type_from_name(geo_type)
74
- end
75
-
76
- def to_type_name(geometric_type)
77
- name = geometric_type.type_name.underscore
78
- case name
79
- when 'point'
80
- 'st_point'
81
- when 'polygon'
82
- 'st_polygon'
83
- else
84
- name
85
- end
6
+ default_function == "unique_rowid()"
86
7
  end
87
8
  end
88
9
  end
@@ -14,19 +14,10 @@ module ActiveRecord
14
14
  # always be strings. Then, we won't have to make any additional changes
15
15
  # to ActiveRecord to support inserting integer values into string
16
16
  # columns.
17
- #
18
- # For spatial types, data is stored as Well-known Binary (WKB) strings
19
- # (https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry#Well-known_binary)
20
- # but when creating objects, using RGeo features is more convenient than
21
- # converting to WKB, so this does it automatically.
22
17
  def _quote(value)
23
18
  case value
24
19
  when Numeric
25
20
  "'#{quote_string(value.to_s)}'"
26
- when RGeo::Feature::Geometry
27
- "'#{RGeo::WKRep::WKBGenerator.new(hex_format: true, type_format: :ewkb, emit_ewkb_srid: true).generate(value)}'"
28
- when RGeo::Cartesian::BoundingBox
29
- "'#{value.min_x},#{value.min_y},#{value.max_x},#{value.max_y}'::box"
30
21
  else
31
22
  super
32
23
  end
@@ -39,52 +39,8 @@ module ActiveRecord
39
39
  nil
40
40
  end
41
41
 
42
- def columns(table_name)
43
- # Limit, precision, and scale are all handled by the superclass.
44
- column_definitions(table_name).map do |column_name, type, default, notnull, oid, fmod, collation, comment|
45
- oid = oid.to_i
46
- fmod = fmod.to_i
47
- type_metadata = fetch_type_metadata(column_name, type, oid, fmod)
48
- cast_type = get_oid_type(oid.to_i, fmod.to_i, column_name, type)
49
- default_value = extract_value_from_default(default)
50
-
51
- default_function = extract_default_function(default_value, default)
52
- new_column(table_name, column_name, default_value, cast_type, type_metadata, !notnull,
53
- default_function, collation, comment)
54
- end
55
- end
56
-
57
- def new_column(table_name, column_name, default, cast_type, sql_type_metadata = nil,
58
- null = true, default_function = nil, collation = nil, comment = nil)
59
- # JDBC gets true/false in Rails 4, where other platforms get 't'/'f' strings.
60
- if null.is_a?(String)
61
- null = (null == "t")
62
- end
63
-
64
- column_info = spatial_column_info(table_name).get(column_name, sql_type_metadata.sql_type)
65
-
66
- PostgreSQLColumn.new(
67
- column_name,
68
- default,
69
- sql_type_metadata,
70
- null,
71
- table_name,
72
- default_function,
73
- collation,
74
- comment,
75
- cast_type,
76
- column_info
77
- )
78
- end
79
-
80
42
  # CockroachDB will use INT8 if the SQL type is INTEGER, so we make it use
81
43
  # INT4 explicitly when needed.
82
- #
83
- # For spatial columns, include the limit to properly format the column name
84
- # since type alone is not enough to format the column.
85
- # Ex. type_to_sql(:geography, limit: "Point,4326")
86
- # => "geography(Point,4326)"
87
- #
88
44
  def type_to_sql(type, limit: nil, precision: nil, scale: nil, array: nil, **) # :nodoc:
89
45
  sql = \
90
46
  case type.to_s
@@ -96,44 +52,39 @@ module ActiveRecord
96
52
  when 5..8; "int8"
97
53
  else super
98
54
  end
99
- when "geometry", "geography"
100
- "#{type}(#{limit})"
101
55
  else
102
56
  super
103
57
  end
104
58
  # The call to super might have appeneded [] already.
105
59
  if array && type != :primary_key && !sql.end_with?("[]")
106
- sql = "#{sql}[]"
60
+ sql = "#{sql}[]"
107
61
  end
108
62
  sql
109
63
  end
110
64
 
111
- # override
112
- def native_database_types
113
- # Add spatial types
114
- super.merge(
115
- geography: { name: "geography" },
116
- geometry: { name: "geometry" },
117
- geometry_collection: { name: "geometry_collection" },
118
- line_string: { name: "line_string" },
119
- multi_line_string: { name: "multi_line_string" },
120
- multi_point: { name: "multi_point" },
121
- multi_polygon: { name: "multi_polygon" },
122
- spatial: { name: "geometry" },
123
- st_point: { name: "st_point" },
124
- st_polygon: { name: "st_polygon" }
125
- )
126
- end
65
+ # This overrides the method from PostegreSQL adapter
66
+ # Resets the sequence of a table's primary key to the maximum value.
67
+ def reset_pk_sequence!(table, pk = nil, sequence = nil)
68
+ unless pk && sequence
69
+ default_pk, default_sequence = pk_and_sequence_for(table)
127
70
 
128
- # override
129
- def create_table_definition(*args, **kwargs)
130
- CockroachDB::TableDefinition.new(*args, **kwargs)
131
- end
71
+ pk ||= default_pk
72
+ sequence ||= default_sequence
73
+ end
74
+
75
+ if @logger && pk && !sequence
76
+ @logger.warn "#{table} has primary key #{pk} with no default sequence."
77
+ end
78
+
79
+ if pk && sequence
80
+ quoted_sequence = quote_table_name(sequence)
81
+ max_pk = query_value("SELECT MAX(#{quote_column_name pk}) FROM #{quote_table_name(table)}", "SCHEMA")
82
+ if max_pk.nil?
83
+ minvalue = query_value("SELECT seqmin FROM pg_sequence WHERE seqrelid = #{quote(quoted_sequence)}::regclass", "SCHEMA")
84
+ end
132
85
 
133
- # memoize hash of column infos for tables
134
- def spatial_column_info(table_name)
135
- @spatial_column_info ||= {}
136
- @spatial_column_info[table_name.to_sym] ||= SpatialColumnInfo.new(self, table_name.to_s)
86
+ query_value("SELECT setval(#{quote(quoted_sequence)}, #{max_pk ? max_pk : minvalue}, #{max_pk ? true : false})", "SCHEMA")
87
+ end
137
88
  end
138
89
  end
139
90
  end
@@ -1,24 +1,12 @@
1
- require "rgeo/active_record"
2
-
3
1
  require 'active_record/connection_adapters/postgresql_adapter'
4
- require "active_record/connection_adapters/cockroachdb/column_methods"
5
2
  require "active_record/connection_adapters/cockroachdb/schema_statements"
6
3
  require "active_record/connection_adapters/cockroachdb/referential_integrity"
7
4
  require "active_record/connection_adapters/cockroachdb/transaction_manager"
5
+ require "active_record/connection_adapters/cockroachdb/column"
8
6
  require "active_record/connection_adapters/cockroachdb/database_statements"
9
- require "active_record/connection_adapters/cockroachdb/table_definition"
10
7
  require "active_record/connection_adapters/cockroachdb/quoting"
11
8
  require "active_record/connection_adapters/cockroachdb/type"
12
9
  require "active_record/connection_adapters/cockroachdb/attribute_methods"
13
- require "active_record/connection_adapters/cockroachdb/column"
14
- require "active_record/connection_adapters/cockroachdb/spatial_column_info"
15
- require "active_record/connection_adapters/cockroachdb/setup"
16
- require "active_record/connection_adapters/cockroachdb/oid/spatial"
17
- require "active_record/connection_adapters/cockroachdb/arel_tosql"
18
-
19
- # Run to ignore spatial tables that will break schemna dumper.
20
- # Defined in ./setup.rb
21
- ActiveRecord::ConnectionAdapters::CockroachDB.initial_setup
22
10
 
23
11
  module ActiveRecord
24
12
  module ConnectionHandling
@@ -39,14 +27,13 @@ module ActiveRecord
39
27
  # The postgres drivers don't allow the creation of an unconnected
40
28
  # PG::Connection object, so just pass a nil connection object for the
41
29
  # time being.
42
- ConnectionAdapters::CockroachDBAdapter.new(nil, logger, conn_params, config)
43
- # This rescue flow appears in new_client, but it is needed here as well
44
- # since Cockroach will sometimes not raise until a query is made.
45
- rescue ActiveRecord::StatementInvalid => error
46
- if conn_params && conn_params[:dbname] && error.cause.message.include?(conn_params[:dbname])
47
- raise ActiveRecord::NoDatabaseError, error.cause.message
30
+ conn = PG.connect(conn_params)
31
+ ConnectionAdapters::CockroachDBAdapter.new(conn, logger, conn_params, config)
32
+ rescue ::PG::Error => error
33
+ if error.message.include?("does not exist")
34
+ raise ActiveRecord::NoDatabaseError
48
35
  else
49
- raise ActiveRecord::ConnectionNotEstablished, error.message
36
+ raise
50
37
  end
51
38
  end
52
39
  end
@@ -54,130 +41,15 @@ end
54
41
 
55
42
  module ActiveRecord
56
43
  module ConnectionAdapters
57
- module CockroachDBConnectionPool
58
- def initialize(pool_config)
59
- super(pool_config)
60
- disable_telemetry = pool_config.config[:disable_cockroachdb_telemetry]
61
- adapter = pool_config.config[:adapter]
62
- return if disable_telemetry || adapter != "cockroachdb"
63
-
64
-
65
- begin
66
- with_connection do |conn|
67
- if conn.active?
68
- begin
69
- query = "SELECT crdb_internal.increment_feature_counter('ActiveRecord %d.%d')"
70
- conn.execute(query % [ActiveRecord::VERSION::MAJOR, ActiveRecord::VERSION::MINOR])
71
- rescue ActiveRecord::StatementInvalid
72
- # The increment_feature_counter built-in is not supported on this
73
- # CockroachDB version. Ignore.
74
- rescue StandardError => e
75
- conn.logger.warn "Unexpected error when incrementing feature counter: #{e}"
76
- end
77
- end
78
- end
79
- rescue StandardError
80
- # Prevent failures on db creation and parallel testing.
81
- end
82
- end
83
- end
84
- ConnectionPool.prepend(CockroachDBConnectionPool)
85
-
86
44
  class CockroachDBAdapter < PostgreSQLAdapter
87
45
  ADAPTER_NAME = "CockroachDB".freeze
88
46
  DEFAULT_PRIMARY_KEY = "rowid"
89
47
 
90
- SPATIAL_COLUMN_OPTIONS =
91
- {
92
- geography: { geographic: true },
93
- geometry: {},
94
- geometry_collection: {},
95
- line_string: {},
96
- multi_line_string: {},
97
- multi_point: {},
98
- multi_polygon: {},
99
- spatial: {},
100
- st_point: {},
101
- st_polygon: {},
102
- }
103
-
104
- # http://postgis.17.x6.nabble.com/Default-SRID-td5001115.html
105
- DEFAULT_SRID = 0
106
-
107
48
  include CockroachDB::SchemaStatements
108
49
  include CockroachDB::ReferentialIntegrity
109
50
  include CockroachDB::DatabaseStatements
110
51
  include CockroachDB::Quoting
111
52
 
112
- # override
113
- # This method makes a sql query to gather information about columns
114
- # in a table. It returns an array of arrays (one for each col) and
115
- # is mapped to columns in the SchemaStatements#columns method.
116
- #
117
- # The issue with the default method is that the sql_type field is
118
- # retrieved with the `format_type` function, but this is implemented
119
- # differently in CockroachDB than PostGIS, so geometry/geography
120
- # types are missing information which makes parsing them impossible.
121
- # Below is an example of what `format_type` returns for a geometry
122
- # column.
123
- #
124
- # column_type: geometry(POINT, 4326)
125
- # Expected: geometry(POINT, 4326)
126
- # Actual: geometry
127
- #
128
- # The solution is to make the default query with super, then
129
- # iterate through the columns and if it is a spatial type,
130
- # access the proper column_type with the information_schema.columns
131
- # table.
132
- #
133
- # @see: https://github.com/rails/rails/blob/8695b028261bdd244e254993255c6641bdbc17a5/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L829
134
- def column_definitions(table_name)
135
- fields = super
136
- # iterate through and identify all spatial fields based on format_type
137
- # being geometry or geography, then query for the information_schema.column
138
- # column_type because that contains the necessary information.
139
- fields.map do |field|
140
- dtype = field[1]
141
- if dtype == 'geometry' || dtype == 'geography'
142
- col_name = field[0]
143
- data_type = \
144
- query(<<~SQL, "SCHEMA")
145
- SELECT c.data_type
146
- FROM information_schema.columns c
147
- WHERE c.table_name = #{quote(table_name)}
148
- AND c.column_name = #{quote(col_name)}
149
- SQL
150
- field[1] = data_type[0][0]
151
- end
152
- field
153
- end
154
- end
155
-
156
- def arel_visitor
157
- Arel::Visitors::CockroachDB.new(self)
158
- end
159
-
160
- def self.spatial_column_options(key)
161
- SPATIAL_COLUMN_OPTIONS[key]
162
- end
163
-
164
- def postgis_lib_version
165
- @postgis_lib_version ||= select_value("SELECT PostGIS_Lib_Version()")
166
- end
167
-
168
- def default_srid
169
- DEFAULT_SRID
170
- end
171
-
172
- def srs_database_columns
173
- {
174
- auth_name_column: "auth_name",
175
- auth_srid_column: "auth_srid",
176
- proj4text_column: "proj4text",
177
- srtext_column: "srtext",
178
- }
179
- end
180
-
181
53
  def debugging?
182
54
  !!ENV["DEBUG_COCKROACHDB_ADAPTER"]
183
55
  end
@@ -208,11 +80,6 @@ module ActiveRecord
208
80
  false
209
81
  end
210
82
 
211
- def supports_ranges?
212
- # See cockroachdb/cockroach#17022
213
- false
214
- end
215
-
216
83
  def supports_materialized_views?
217
84
  false
218
85
  end
@@ -253,10 +120,6 @@ module ActiveRecord
253
120
  @crdb_version >= 202
254
121
  end
255
122
 
256
- def supports_partitioned_indexes?
257
- false
258
- end
259
-
260
123
  # This is hardcoded to 63 (as previously was in ActiveRecord 5.0) to aid in
261
124
  # migration from PostgreSQL to CockroachDB. In practice, this limitation
262
125
  # is arbitrary since CockroachDB supports index name lengths and table alias
@@ -274,7 +137,6 @@ module ActiveRecord
274
137
 
275
138
  def initialize(connection, logger, conn_params, config)
276
139
  super(connection, logger, conn_params, config)
277
-
278
140
  crdb_version_string = query_value("SHOW crdb_version")
279
141
  if crdb_version_string.include? "v1."
280
142
  version_num = 1
@@ -291,26 +153,11 @@ module ActiveRecord
291
153
  end
292
154
  @crdb_version = version_num
293
155
  end
294
-
156
+
295
157
  private
296
158
 
297
159
  def initialize_type_map(m = type_map)
298
- %w(
299
- geography
300
- geometry
301
- geometry_collection
302
- line_string
303
- multi_line_string
304
- multi_point
305
- multi_polygon
306
- st_point
307
- st_polygon
308
- ).each do |geo_type|
309
- m.register_type(geo_type) do |oid, _, sql_type|
310
- CockroachDB::OID::Spatial.new(oid, sql_type)
311
- end
312
- end
313
-
160
+ super(m)
314
161
  # NOTE(joey): PostgreSQL intervals have a precision.
315
162
  # CockroachDB intervals do not, so overide the type
316
163
  # definition. Returning a ArgumentError may not be correct.
@@ -322,8 +169,6 @@ module ActiveRecord
322
169
  end
323
170
  OID::SpecializedString.new(:interval, precision: precision)
324
171
  end
325
-
326
- super(m)
327
172
  end
328
173
 
329
174
  # Configures the encoding, verbosity, schema search path, and time zone of the connection.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-cockroachdb-adapter
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.2.3
4
+ version: 6.0.0beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cockroach Labs
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-06-27 00:00:00.000000000 Z
11
+ date: 2020-12-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '5.2'
19
+ version: 6.0.3
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '5.2'
26
+ version: 6.0.3
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: pg
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,20 +38,6 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0.20'
41
- - !ruby/object:Gem::Dependency
42
- name: rgeo-activerecord
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: 7.0.0
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: 7.0.0
55
41
  description: Allows the use of CockroachDB as a backend for ActiveRecord and Rails
56
42
  apps.
57
43
  email:
@@ -75,19 +61,13 @@ files:
75
61
  - build/local-test.sh
76
62
  - build/teamcity-test.sh
77
63
  - docker.sh
78
- - lib/active_record/connection_adapters/cockroachdb/arel_tosql.rb
79
64
  - lib/active_record/connection_adapters/cockroachdb/attribute_methods.rb
80
65
  - lib/active_record/connection_adapters/cockroachdb/column.rb
81
- - lib/active_record/connection_adapters/cockroachdb/column_methods.rb
82
66
  - lib/active_record/connection_adapters/cockroachdb/database_statements.rb
83
67
  - lib/active_record/connection_adapters/cockroachdb/database_tasks.rb
84
- - lib/active_record/connection_adapters/cockroachdb/oid/spatial.rb
85
68
  - lib/active_record/connection_adapters/cockroachdb/quoting.rb
86
69
  - lib/active_record/connection_adapters/cockroachdb/referential_integrity.rb
87
70
  - lib/active_record/connection_adapters/cockroachdb/schema_statements.rb
88
- - lib/active_record/connection_adapters/cockroachdb/setup.rb
89
- - lib/active_record/connection_adapters/cockroachdb/spatial_column_info.rb
90
- - lib/active_record/connection_adapters/cockroachdb/table_definition.rb
91
71
  - lib/active_record/connection_adapters/cockroachdb/transaction_manager.rb
92
72
  - lib/active_record/connection_adapters/cockroachdb/type.rb
93
73
  - lib/active_record/connection_adapters/cockroachdb_adapter.rb
@@ -108,11 +88,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
108
88
  version: '0'
109
89
  required_rubygems_version: !ruby/object:Gem::Requirement
110
90
  requirements:
111
- - - ">="
91
+ - - ">"
112
92
  - !ruby/object:Gem::Version
113
- version: '0'
93
+ version: 1.3.1
114
94
  requirements: []
115
- rubygems_version: 3.2.15
95
+ rubygems_version: 3.1.4
116
96
  signing_key:
117
97
  specification_version: 4
118
98
  summary: CockroachDB adapter for ActiveRecord.
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RGeo
4
- module ActiveRecord
5
- ##
6
- # Extend rgeo-activerecord visitors to use PostGIS specific functionality
7
- module SpatialToPostGISSql
8
- def visit_in_spatial_context(node, collector)
9
- # Use ST_GeomFromEWKT for EWKT geometries
10
- if node.is_a?(String) && node =~ /SRID=[\d+]{0,};/
11
- collector << "#{st_func('ST_GeomFromEWKT')}(#{quote(node)})"
12
- else
13
- super(node, collector)
14
- end
15
- end
16
- end
17
- end
18
- end
19
- RGeo::ActiveRecord::SpatialToSql.prepend RGeo::ActiveRecord::SpatialToPostGISSql
20
-
21
- module Arel # :nodoc:
22
- module Visitors # :nodoc:
23
- class CockroachDB < PostgreSQL # :nodoc:
24
- include RGeo::ActiveRecord::SpatialToSql
25
- end
26
- end
27
- end
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ActiveRecord
4
- module ConnectionAdapters
5
- module CockroachDB
6
- module ColumnMethods
7
- def spatial(name, options = {})
8
- raise "You must set a type. For example: 't.spatial type: :st_point'" unless options[:type]
9
-
10
- column(name, options[:type], **options)
11
- end
12
-
13
- def geography(name, options = {})
14
- column(name, :geography, **options)
15
- end
16
-
17
- def geometry(name, options = {})
18
- column(name, :geometry, **options)
19
- end
20
-
21
- def geometry_collection(name, options = {})
22
- column(name, :geometry_collection, **options)
23
- end
24
-
25
- def line_string(name, options = {})
26
- column(name, :line_string, **options)
27
- end
28
-
29
- def multi_line_string(name, options = {})
30
- column(name, :multi_line_string, **options)
31
- end
32
-
33
- def multi_point(name, options = {})
34
- column(name, :multi_point, **options)
35
- end
36
-
37
- def multi_polygon(name, options = {})
38
- column(name, :multi_polygon, **options)
39
- end
40
-
41
- def st_point(name, options = {})
42
- column(name, :st_point, **options)
43
- end
44
-
45
- def st_polygon(name, options = {})
46
- column(name, :st_polygon, **options)
47
- end
48
- end
49
- end
50
-
51
- PostgreSQL::Table.include CockroachDB::ColumnMethods
52
- end
53
- end
@@ -1,121 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ActiveRecord
4
- module ConnectionAdapters
5
- module CockroachDB
6
- module OID
7
- class Spatial < Type::Value
8
- # sql_type is a string that comes from the database definition
9
- # examples:
10
- # "geometry(Point,4326)"
11
- # "geography(Point,4326)"
12
- # "geometry(Polygon,4326) NOT NULL"
13
- # "geometry(Geography,4326)"
14
- def initialize(oid, sql_type)
15
- @sql_type = sql_type
16
- @geo_type, @srid, @has_z, @has_m = self.class.parse_sql_type(sql_type)
17
- end
18
-
19
- # sql_type: geometry, geometry(Point), geometry(Point,4326), ...
20
- #
21
- # returns [geo_type, srid, has_z, has_m]
22
- # geo_type: geography, geometry, point, line_string, polygon, ...
23
- # srid: 1234
24
- # has_z: false
25
- # has_m: false
26
- def self.parse_sql_type(sql_type)
27
- geo_type = nil
28
- srid = 0
29
- has_z = false
30
- has_m = false
31
-
32
- if sql_type =~ /(geography|geometry)\((.*)\)$/i
33
- # geometry(Point)
34
- # geometry(Point,4326)
35
- params = Regexp.last_match(2).split(',')
36
- if params.first =~ /([a-z]+[^zm])(z?)(m?)/i
37
- has_z = Regexp.last_match(2).length > 0
38
- has_m = Regexp.last_match(3).length > 0
39
- geo_type = Regexp.last_match(1)
40
- end
41
- srid = Regexp.last_match(1).to_i if params.last =~ /(\d+)/
42
- else
43
- geo_type = sql_type
44
- end
45
- [geo_type, srid, has_z, has_m]
46
- end
47
-
48
- def spatial_factory
49
- @spatial_factory ||=
50
- RGeo::ActiveRecord::SpatialFactoryStore.instance.factory(
51
- factory_attrs
52
- )
53
- end
54
-
55
- def geographic?
56
- @sql_type =~ /geography/
57
- end
58
-
59
- def spatial?
60
- true
61
- end
62
-
63
- def type
64
- geographic? ? :geography : :geometry
65
- end
66
-
67
- # support setting an RGeo object or a WKT string
68
- def serialize(value)
69
- return if value.nil?
70
-
71
- geo_value = cast_value(value)
72
-
73
- # TODO: - only valid types should be allowed
74
- # e.g. linestring is not valid for point column
75
- # raise "maybe should raise" unless RGeo::Feature::Geometry.check_type(geo_value)
76
-
77
- RGeo::WKRep::WKBGenerator.new(hex_format: true, type_format: :ewkb, emit_ewkb_srid: true)
78
- .generate(geo_value)
79
- end
80
-
81
- private
82
-
83
- def cast_value(value)
84
- return if value.nil?
85
-
86
- value.is_a?(String) ? parse_wkt(value) : value
87
- end
88
-
89
- # convert WKT string into RGeo object
90
- def parse_wkt(string)
91
- wkt_parser(string).parse(string)
92
- rescue RGeo::Error::ParseError
93
- nil
94
- end
95
-
96
- def binary_string?(string)
97
- string[0] == "\x00" || string[0] == "\x01" || string[0, 4] =~ /[0-9a-fA-F]{4}/
98
- end
99
-
100
- def wkt_parser(string)
101
- if binary_string?(string)
102
- RGeo::WKRep::WKBParser.new(spatial_factory, support_ewkb: true, default_srid: @srid)
103
- else
104
- RGeo::WKRep::WKTParser.new(spatial_factory, support_ewkt: true, default_srid: @srid)
105
- end
106
- end
107
-
108
- def factory_attrs
109
- {
110
- geo_type: @geo_type.underscore,
111
- has_m: @has_m,
112
- has_z: @has_z,
113
- srid: @srid,
114
- sql_type: type.to_s
115
- }
116
- end
117
- end
118
- end
119
- end
120
- end
121
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ActiveRecord # :nodoc:
4
- module ConnectionAdapters # :nodoc:
5
- module CockroachDB # :nodoc:
6
- def self.initial_setup
7
- ::ActiveRecord::SchemaDumper.ignore_tables |= %w[
8
- geography_columns
9
- geometry_columns
10
- layer
11
- raster_columns
12
- raster_overviews
13
- spatial_ref_sys
14
- topology
15
- ]
16
- end
17
- end
18
- end
19
- end
@@ -1,44 +0,0 @@
1
- module ActiveRecord
2
- module ConnectionAdapters
3
- module CockroachDB
4
- class SpatialColumnInfo
5
- def initialize(adapter, table_name)
6
- @adapter = adapter
7
- @table_name = table_name
8
- end
9
-
10
- def all
11
- info = @adapter.query(
12
- "SELECT f_geometry_column,coord_dimension,srid,type FROM geometry_columns WHERE f_table_name='#{@table_name}'"
13
- )
14
- result = {}
15
- info.each do |row|
16
- name = row[0]
17
- type = row[3]
18
- dimension = row[1].to_i
19
- has_m = !!(type =~ /m$/i)
20
- type.sub!(/m$/, '')
21
- has_z = dimension > 3 || dimension == 3 && !has_m
22
- result[name] = {
23
- dimension: dimension,
24
- has_m: has_m,
25
- has_z: has_z,
26
- name: name,
27
- srid: row[2].to_i,
28
- type: type
29
- }
30
- end
31
- result
32
- end
33
-
34
- # do not query the database for non-spatial columns/tables
35
- def get(column_name, type)
36
- return unless CockroachDBAdapter.spatial_column_options(type.to_sym)
37
-
38
- @spatial_column_info ||= all
39
- @spatial_column_info[column_name]
40
- end
41
- end
42
- end
43
- end
44
- end
@@ -1,56 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ActiveRecord # :nodoc:
4
- module ConnectionAdapters # :nodoc:
5
- module CockroachDB # :nodoc:
6
- class TableDefinition < PostgreSQL::TableDefinition # :nodoc:
7
- include ColumnMethods
8
-
9
- # Support for spatial columns in tables
10
- # super: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
11
- def new_column_definition(name, type, **options)
12
- if (info = CockroachDBAdapter.spatial_column_options(type.to_sym))
13
- if (limit = options.delete(:limit)) && limit.is_a?(::Hash)
14
- options.merge!(limit)
15
- end
16
-
17
- geo_type = ColumnDefinitionUtils.geo_type(options[:type] || type || info[:type])
18
- base_type = info[:type] || (options[:geographic] ? :geography : :geometry)
19
-
20
- options[:limit] = ColumnDefinitionUtils.limit_from_options(geo_type, options)
21
- options[:spatial_type] = geo_type
22
- column = super(name, base_type, **options)
23
- else
24
- column = super(name, type, **options)
25
- end
26
-
27
- column
28
- end
29
- end
30
-
31
- module ColumnDefinitionUtils
32
- class << self
33
- def geo_type(type = 'GEOMETRY')
34
- g_type = type.to_s.delete('_').upcase
35
- return 'POINT' if g_type == 'STPOINT'
36
- return 'POLYGON' if g_type == 'STPOLYGON'
37
-
38
- g_type
39
- end
40
-
41
- def limit_from_options(type, options = {})
42
- spatial_type = geo_type(type)
43
- spatial_type << 'Z' if options[:has_z]
44
- spatial_type << 'M' if options[:has_m]
45
- spatial_type << ",#{options[:srid] || default_srid(options)}"
46
- spatial_type
47
- end
48
-
49
- def default_srid(options)
50
- options[:geographic] ? 4326 : CockroachDBAdapter::DEFAULT_SRID
51
- end
52
- end
53
- end
54
- end
55
- end
56
- end