{"id":15064638,"url":"https://github.com/cockroachdb/activerecord-cockroachdb-adapter","last_synced_at":"2025-05-15T12:06:27.115Z","repository":{"id":17442061,"uuid":"81989656","full_name":"cockroachdb/activerecord-cockroachdb-adapter","owner":"cockroachdb","description":"CockroachDB adapter for ActiveRecord.","archived":false,"fork":false,"pushed_at":"2025-04-24T15:30:20.000Z","size":636,"stargazers_count":106,"open_issues_count":29,"forks_count":52,"subscribers_count":45,"default_branch":"master","last_synced_at":"2025-04-24T16:32:52.660Z","etag":null,"topics":["activerecord","cockroachdb","ruby-on-rails"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cockroachdb.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-02-14T21:12:52.000Z","updated_at":"2025-04-24T15:16:05.000Z","dependencies_parsed_at":"2022-07-13T15:59:26.751Z","dependency_job_id":"ca6704c2-78ab-4e44-898f-faf2a8b70a7c","html_url":"https://github.com/cockroachdb/activerecord-cockroachdb-adapter","commit_stats":{"total_commits":313,"total_committers":24,"mean_commits":"13.041666666666666","dds":0.7603833865814696,"last_synced_commit":"356e7b4dd4148dd6e19a33749d93432dd3f51731"},"previous_names":[],"tags_count":44,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cockroachdb%2Factiverecord-cockroachdb-adapter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cockroachdb%2Factiverecord-cockroachdb-adapter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cockroachdb%2Factiverecord-cockroachdb-adapter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cockroachdb%2Factiverecord-cockroachdb-adapter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cockroachdb","download_url":"https://codeload.github.com/cockroachdb/activerecord-cockroachdb-adapter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254337613,"owners_count":22054253,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activerecord","cockroachdb","ruby-on-rails"],"created_at":"2024-09-25T00:23:04.503Z","updated_at":"2025-05-15T12:06:22.087Z","avatar_url":"https://github.com/cockroachdb.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ActiveRecord CockroachDB Adapter\n\nCockroachDB adapter for ActiveRecord. This is a lightweight extension\nof the PostgreSQL adapter that establishes compatibility with [CockroachDB](https://github.com/cockroachdb/cockroach).\n\n## Installation\n\nAdd this line to your project's Gemfile:\n\n```ruby\ngem 'activerecord-cockroachdb-adapter', '~\u003e 8.0.0'\n```\n\nIf you're using Rails 7.1, use the `7.1.x` versions of this gem.\n\nIf you're using Rails 7.2, use the `7.2.x` versions of this gem.\nThe minimal CockroachDB version required is 23.1.12 for this version.\n\nIf you're using Rails 8.0, use the `8.0.x` versions of this gem.\n\nIn `database.yml`, use the following adapter setting:\n\n```\ndevelopment:\n  adapter: cockroachdb\n  port: 26257\n  host: \u003chostname\u003e\n  user: \u003cusername\u003e\n```\n\n## Configuration\n\nIn addition to the standard adapter settings, CockroachDB also supports the following:\n\n- `use_follower_reads_for_type_introspection`: Use follower reads on queries to the `pg_type` catalog when set to `true`. This helps to speed up initialization by reading historical data, but may not find recently created user-defined types.\n- `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.\n\n## Working with Spatial Data\n\nThe 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).\n\n### Installing RGeo\n\nRGeo can be installed with the following command:\n\n```sh\ngem install rgeo\n```\n\nThe 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:\n\n```rb\nrequire 'rgeo'\n\nRGeo::Geos.supported?\n#=\u003e true\n```\n\nIf this is `false`, you may need to specify the GEOS directory while installing. Here's an example linking it to the CockroachDB GEOS binary.\n\n```sh\ngem install rgeo -- --with-geos-dir=/path/to/cockroach/lib/\n```\n\n### Working with RGeo\n\nRGeo 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.\n\nThe 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.\n\nOnce 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.\n\n```rb\nrequire 'rgeo'\nfactory = RGeo::Cartesian.factory(srid: 3857)\n\n# Create a line_string from points\npt1 = factory.point(0,0)\npt2 = factory.point(1,1)\npt3 = factory.point(2,2)\nline_string = factory.line_string([pt1,pt2,pt3])\n\np line_string.length\n#=\u003e 2.8284271247461903\n\n# check line_string equality\nline_string2 = factory.parse_wkt(\"LINESTRING (0 0, 1 1, 2 2)\")\np line_string == line_string2\n#=\u003e true\n\n# create polygon and test intersection with line_string\npt4 = factory.point(0,2)\nouter_ring = factory.linear_ring([pt1,pt2,pt3,pt4,pt1])\npoly = factory.polygon(outer_ring)\n\np line_string.intersects? poly\n#=\u003e true\n```\n### Creating Spatial Tables\n\nTo store spatial data, you must create a column with a spatial type. PostGIS\nprovides a variety of spatial types, including point, linestring, polygon, and\ndifferent kinds of collections. These types are defined in a standard produced\nby the Open Geospatial Consortium. You can specify options indicating the coordinate system and number of coordinates for the values you are storing.\n\nThe adapter extends ActiveRecord's migration syntax to\nsupport these spatial types. The following example creates five spatial\ncolumns in a table:\n\n```rb\ncreate_table :my_spatial_table do |t|\n  t.column :shape1, :geometry\n  t.geometry :shape2\n  t.line_string :path, srid: 3857\n  t.st_point :lonlat, geographic: true\n  t.st_point :lonlatheight, geographic: true, has_z: true\nend\n```\n\nThe first column, \"shape1\", is created with type \"geometry\". This is a general\n\"base class\" for spatial types; the column declares that it can contain values\nof _any_ spatial type.\n\nThe second column, \"shape2\", uses a shorthand syntax for the same type as the shape1 column.\nYou can create a column either by invoking `column` or invoking the name of the type directly.\n\nThe third column, \"path\", has a specific geometric type, `line_string`. It\nalso specifies an SRID (spatial reference ID) that indicates which coordinate\nsystem it expects the data to be in. The column now has a \"constraint\" on it;\nit will accept only LineString data, and only data whose SRID is 3857.\n\nThe fourth column, \"lonlat\", has the `st_point` type, and accepts only Point\ndata. Furthermore, it declares the column as \"geographic\", which means it\naccepts longitude/latitude data, and performs calculations such as distances\nusing a spheroidal domain.\n\nThe fifth column, \"lonlatheight\", is a geographic (longitude/latitude) point\nthat also includes a third \"z\" coordinate that can be used to store height\ninformation.\n\nThe following are the data types understood by PostGIS and exposed by\nthe adapter:\n\n- `:geometry` -- Any geometric type\n- `:st_point` -- Point data\n- `:line_string` -- LineString data\n- `:st_polygon` -- Polygon data\n- `:geometry_collection` -- Any collection type\n- `:multi_point` -- A collection of Points\n- `:multi_line_string` -- A collection of LineStrings\n- `:multi_polygon` -- A collection of Polygons\n\nFollowing are the options understood by the adapter:\n\n- `:geographic` -- If set to true, create a PostGIS geography column for\n  longitude/latitude data over a spheroidal domain; otherwise create a\n  geometry column in a flat coordinate system. Default is false. Also\n  implies :srid set to 4326.\n- `:srid` -- Set a SRID constraint for the column. Default is 4326 for a\n  geography column, or 0 for a geometry column. Note that PostGIS currently\n  (as of version 2.0) requires geography columns to have SRID 4326, so this\n  constraint is of limited use for geography columns.\n- `:has_z` -- Specify that objects in this column include a Z coordinate.\n  Default is false.\n- `:has_m` -- Specify that objects in this column include an M coordinate.\n  Default is false.\n\nTo create a PostGIS spatial index, add `using: :gist` to your index:\n\n```rb\nadd_index :my_table, :lonlat, using: :gist\n\n# or\n\nchange_table :my_table do |t|\n  t.index :lonlat, using: :gist\nend\n```\n### Configuring ActiveRecord\n\nActiveRecord's usefulness stems from the way it automatically configures\nclasses based on the database structure and schema. If a column in the\ndatabase has an integer type, ActiveRecord automatically casts the data to a\nRuby Integer. In the same way, the adapter automatically\ncasts spatial data to a corresponding RGeo data type.\n\nRGeo offers more flexibility in its type system than can be\ninterpreted solely from analyzing the database column. For example, you can\nconfigure RGeo objects to exhibit certain behaviors related to their\nserialization, validation, coordinate system, or computation. These settings\nare embodied in the RGeo factory associated with the object.\n\nYou can configure the adapter to use a particular factory (i.e. a\nparticular combination of settings) for data associated with each type in\nthe database.\n\nHere's an example using a Geos default factory:\n\n```ruby\nRGeo::ActiveRecord::SpatialFactoryStore.instance.tap do |config|\n  # By default, use the GEOS implementation for spatial columns.\n  config.default = RGeo::Geos.factory_generator\n\n  # But use a geographic implementation for point columns.\n  config.register(RGeo::Geographic.spherical_factory(srid: 4326), geo_type: \"point\")\nend\n```\n\nThe default spatial factory for geographic columns is `RGeo::Geographic.spherical_factory`.\nThe default spatial factory for cartesian columns is `RGeo::Cartesian.preferred_factory`.\nYou do not need to configure the `SpatialFactoryStore` if these defaults are ok.\n\nMore 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.\n\n### Reading and Writing Spatial Columns\n\nWhen you access a spatial attribute on your ActiveRecord model, it is given to\nyou as an RGeo geometry object (or nil, for attributes that allow null\nvalues). You can then call the RGeo api on the object. For example, consider\nthe MySpatialTable class we worked with above:\n\n```rb\nrecord = MySpatialTable.find(1)\npoint = record.lonlat                  # Returns an RGeo::Feature::Point\np point.x                              # displays the x coordinate\np point.geometry_type.type_name        # displays \"Point\"\n```\n\nThe RGeo factory for the value is determined by how you configured the\nActiveRecord class, as described above. In this case, we explicitly set a\nspherical factory for the `:lonlat` column:\n\n```rb\nfactory = point.factory                # returns a spherical factory\n```\n\nYou can set a spatial attribute by providing an RGeo geometry object, or by\nproviding the WKT string representation of the geometry. If a string is\nprovided, the adapter will attempt to parse it as WKT and\nset the value accordingly.\n\n```rb\nrecord.lonlat = 'POINT(-122 47)'  # sets the value to the given point\n```\n\nIf the WKT parsing fails, the value currently will be silently set to nil. In\nthe future, however, this will raise an exception.\n\n```rb\nrecord.lonlat = 'POINT(x)'         # sets the value to nil\n```\n\nIf you set the value to an RGeo object, the factory needs to match the factory\nfor the attribute. If the factories do not match, the adapter\nwill attempt to cast the value to the correct factory.\n\n```rb\np2 = factory.point(-122, 47)       # p2 is a point in a spherical factory\nrecord.lonlat = p2                 # sets the value to the given point\nrecord.shape1 = p2                 # shape1 uses a flat geos factory, so it\n                                   # will cast p2 into that coordinate system\n                                   # before setting the value\nrecord.save\n```\n\nIf 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.\n\n```rb\nrecord.path = p2      # This will appear to work, but...\nrecord.save           # This will raise an exception from the database\n```\n\n### Spatial Queries\n\nYou can create simple queries based on representational equality in the same\nway you would on a scalar column:\n\n```ruby\nrecord2 = MySpatialTable.where(:lonlat =\u003e factory.point(-122, 47)).first\n```\n\nYou can also use WKT:\n\n```ruby\nrecord3 = MySpatialTable.where(:lonlat =\u003e 'POINT(-122 47)').first\n```\n\nNote that these queries use representational equality, meaning they return\nrecords where the lonlat value matches the given value exactly. A 0.00001\ndegree difference would not match, nor would a different representation of the\nsame geometry (like a multi_point with a single element). Equality queries\naren't generally all that useful in real world applications. Typically, if you\nwant to perform a spatial query, you'll look for, say, all the points within a\ngiven area. For those queries, you'll need to use the standard spatial SQL\nfunctions provided by PostGIS.\n\nTo perform more advanced spatial queries, you can use the extended Arel interface included in the adapter. The functions accept WKT strings or RGeo features.\n\n```rb\npoint = RGeo::Geos.factory(srid: 0).point(1,1)\n\n# Example Building model where geom is a column of polygons.\nbuildings = Building.arel_table\ncontaining_buiildings = Building.where(buildings[:geom].st_contains(point))\n```\n\nSee the [rgeo-activerecord YARD Docs](https://rubydoc.info/github/rgeo/rgeo-activerecord/RGeo/ActiveRecord/SpatialExpressions) for a list of available PostGIS functions.\n\n### Validation Issues\n\nIf 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.\n\n```rb\nregular_fac = RGeo::Geographic.spherical_factory\nmodified_fac = RGeo::Geographic.spherical_factory(uses_lenient_assertions: true)\n\nwkt = \"POLYGON (0 0, 1 1, 0 1, 1 0, 0 0)\" # closed ring with self intersection\n\nregular_fac.parse_wkt(wkt)\n#=\u003e RGeo::Error::InvalidGeometry (LinearRing failed ring test)\n\np modified_fac.parse_wkt(wkt)\n#=\u003e  #\u003cRGeo::Geographic::SphericalPolygonImpl\u003e\n```\n\nBe 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.\n\nNote 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.\n\n## Modifying the adapter?\n\nSee [CONTRIBUTING.md](/CONTRIBUTING.md) for more details on setting up\nthe environment and making modifications.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcockroachdb%2Factiverecord-cockroachdb-adapter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcockroachdb%2Factiverecord-cockroachdb-adapter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcockroachdb%2Factiverecord-cockroachdb-adapter/lists"}