README.md

# GeoSpatialite

Implements encoding and decoding [geo](https://github.com/felt/geo) geometries to [SpatiaLite format](https://www.gaia-gis.it/gaia-sins/BLOB-Geometry.html).

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

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

### Spatialite

#### macOS

```sh
brew install spatialite-tools
```

#### Debian

```sh
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.

```elixir
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

```elixir
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](https://hexdocs.pm/exqlite/Exqlite.Connection.html#connect/1) option. Assuming a Homebrew installation on macOS, the configuration would be something like:

```elixir
# 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:

```elixir
# 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"
    ]
```