AshGeo
all-your-ash-resources-in-space
All your Ash resources, in space!
AshGeo contains tools for using PostGIS with your Ash resources and expressions, backed by Geo and Geo.PostGIS.
It provides:
- All the
st_*
functions that you would get withGeo.PostGIS
for use with Ashexpr
, and more to come. - An
Ash.Type
backed by each ofGeo.JSON
,Geo.WKB
andGeo.WKT
which may be used asargument
types in your Ash actions, and will automatically cast input from GeoJSON, WKT and WKB encodings. - An
Ash.Type
forGeo.PostGIS.Geometry
, for use with resource attributes. - All types may be overridden and narrowed with
use
, allowing you to add stricter constraints and storage types (e.g.geometry(Point,26918)
). - Validations for
Geo
types (such asis_point_zm(:arg)
for checking that argument:arg
is a instance ofGeo.PointZM
) - Validations backed by
Topo
, allowing checks of simple constraints such ascontains?
without needing to hit the database.
installation
Installation
def deps do
[
{:ash_geo, "~> 0.1"},
]
end
configuration
Configuration
config-config-exs
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
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
Usage
defmodule Area do
use Ash.Resource, data_layer: AshPostgres.DataLayer
import AshGeo.Expr
attributes do
uuid_primary_key :id,
attribute :geom, :geometry, allow_nil?: false
end
actions do
action :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
Roadmap
- Add more PostGIS function wrappers (check out the PostGIS reference to see all that are available).
- Continue to improve the test suite.
- Replace validation macros with Spark DSL patches or similar.
- Replace PostGIS
fragment
macros with custom predicates (ash#374
) - Add more informative error messages
(
ash#365
).
developing
Developing
To get set up with the development environment, you will need a Postgres
instance with support for the PostGIS extensions listed in
AshGeo.Test.Repo.installed_extensions()
(the postgis/postgis
image works nicely) and a superuser account ash_geo_test
credentialed
according to config/config.exs
.
AshGeo uses ex_check
to bundle the test configuration, and simply running
mix check
should closely follow the configuration used in CI.
contributing
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
License
MIT License
Copyright (c) 2023 bcksl
See LICENSE.md for details.