GeoSpatialite

View Source

Implements encoding and decoding geo geometries to SpatiaLite format.

Geometries currently supported:

  • Point
  • LineString
  • Polygon
  • MultiPolygon

Geometries not yet supported:

  • PointZ
  • PointM
  • PointZM
  • LineStringZ
  • LineStringZM
  • PolygonZ
  • MultiPointZ
  • MultiLineString
  • MultiLineStringZ
  • MultiPoint
  • MultiPolygonZ
  • GeometryCollection

The TinyPoint encoding is also not yet supported.

Installation

def deps do
  [
    {:geo_spatialite, "~> 0.1.0"}
  ]
end

Spatialite

macOS

brew install spatialite-tools

Debian

apt-get install libsqlite3-mod-spatialite

Ecto

Setup

Databases must initialize SpatiaLite via a migration and call extension-specific functions for managing columns and indexing.

defmodule App.Repo.Migrations.InitializeSpatialite do
  use Ecto.Migration

  def change do
    execute(
      """
      SELECT InitSpatialMetaData();
      """
    )
  end
end

defmodule App.Repo.Migrations.CreateCats do
  use Ecto.Migration

  def change do
    create table(:cats) do
      add :name, :string
    end

    execute(
      """
      SELECT AddGeometryColumn('cats', 'geom_point', 4326, 'POINT');
      """,
      """
      SELECT DiscardGeometryColumn('cats', 'geom_point');
      ALTER TABLE cats DROP COLUMN geom_point;
      """
    )

    # Indexing (optional)
    execute(
      """
      SELECT CreateSpatialIndex('cats', 'geom_point');
      """,
      """
      SELECT DisableSpatialIndex('cats', 'geom_point');
      DROP INDEX idx_cats_geom_point;
      """
    )
  end
end

Schema

defmodule Cat do
  use Ecto.Schema

  schema "cats" do
    field :name, :string
    field :geom, GeoSpatialite.Geometry
  end
end

Extension

The SpatiaLite extension must be loaded via the load_extensions option. Assuming a Homebrew installation on macOS, the configuration would be something like:

# config/dev.exs

config :app, App.Repo,
  database: Path.expand("../app_dev.db", Path.dirname(__ENV__.file)),
  pool_size: 5,
  stacktrace: true,
  load_extensions: [
    "/opt/homebrew/lib/mod_spatialite.dylib"
  ],
  show_sensitive_data_on_connection_error: true

Another example could be using runtime configuration to deploy to a Debian-based Docker container:

# config/runtime.exs

  config :app, App.Repo,
    database: database_path,
    pool_size: String.to_integer(System.get_env("POOL_SIZE") || "5"),
    custom_pragmas: [{"trusted_schema", true}],
    load_extensions: [
      "/usr/lib/x86_64-linux-gnu/mod_spatialite.so"
    ]