AshGeo

All your Ash resources, in space!

HexHex DocsDownloadsBuild StatusCoverage StatusLicenseGitHub Stars

AshGeo contains tools for using geospatial data in Ash resources and expressions, backed by PostGIS, Geo, Geo.PostGIS and [Topo].

It provides:

Installation

def deps do
  [
    {:ash_geo, "~> 0.3.0"},
  ]
end

This package provides a collection of non-overlapping functionality based on several dependencies, not all of which may be necessary your application. Therefore, the dependencies for the functionality you wish to use must be added alongside :ash_geo.

Configuration

config/config.exs:

# Geo.PostGIS: Use Jason coder
config :geo_postgis, json_library: Jason

# Ash: Type shorthands
config :ash, :custom_types, [
  geometry: AshGeo.Geometry,
  geo_json: AshGeo.GeoJson,
  geo_wkt: AshGeo.GeoWkt,
  geo_wkb: AshGeo.GeoWkb,
  geo_any: AshGeo.GeoAny,
  # You may add shorthands for any narrowed types here
  #point26918: CoolApp.Type.GeometryPoint26918,
]

config/runtime.exs:

# Postgrex: Geo.PostGIS types
Postgrex.Types.define(CoolApp.PostgresTypes,
  [Geo.PostGIS.Extension | Ecto.Adapters.Postgres.extensions()],
  json: Jason)

# Ecto: Geo.PostGIS types
config :cool_app, CoolApp.Repo, types: CoolApp.PostgresTypes

Usage

defmodule Area do
  use Ash.Resource, data_layer: AshPostgres.DataLayer

  import AshGeo.Postgis

  attributes do
    uuid_primary_key :id,
    attribute :geom, :geometry, allow_nil?: false
  end

  actions do
    create :create do
      argument :geom, :geo_any

      change set_attribute(:geom, arg(:geom))
    end

    read :containing do
      argument :geom, :geo_any do
        allow_nil? false
        constraints geo_types: :point
      end

      filter expr(^st_within(^arg(:geom), geom))
    end
  end

  code_interface do
    define_for Area
    define :create, args: [:geom]
    define :containing, args: [:geom]
  end
end

Try it out:

Area.create! "POLYGON ((30 0, 20 30, 0 10, 30 0))"
Area.create! "POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))"
Area.containing! "POINT(30 30)"
Area.containing! "POINT(20 20)"
Area.containing! "POINT(10 40)"
Area.containing! "POLYGON((0 0, 30 20, 40 30, 0 0))"

The full documentation can be found on HexDocs.

Roadmap

Developing

To get set up with the development environment, you will need a Postgres instance with support for the PostGIS extensions listed in test/support/repo.ex (the postgis/postgis image works nicely) and a superuser account ash_geo_test credentialed according to config/config.exs.

You may now generate and apply the test migrations:

mix ash_postgres.generate_migrations

AshGeo uses ex_check to bundle the test configuration, and simply running mix check should closely follow the configuration used in CI.

Contributing

If you have ideas or come across any bugs, feel free to open a pull request or an issue. You can also find me on the Ash Discord as @\.

License

MIT License

Copyright (c) 2023 bcksl

See LICENSE.md for details.