Skip to content
Postrex Extension for PostGIS
Branch: master
Clone or download
Latest commit e1be354 May 21, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
config Update for Ecto 3.0 Dec 1, 2018
lib Add PointZ handling Feb 7, 2019
test Add PointZ handling Feb 7, 2019
.gitignore added st_point macro May 8, 2018
.tool-versions Update for Ecto 3.0 Dec 1, 2018
.travis.yml Update to 3.1.0 Feb 11, 2019
CHANGELOG.md Update to 3.1.0 Feb 11, 2019
LICENSE Initial Commit Jul 15, 2017
README.md Update ecto link to ecto_sql May 2, 2019
mix.exs
mix.lock Bump ecto_sql from 3.1.2 to 3.1.3 May 20, 2019

README.md

GeoPostGIS

Build Status Hex.pm

Postgrex extension for the PostGIS data types. Uses the geo library

Documentation

Installation

If available in Hex, the package can be installed by adding geo_postgis to your list of dependencies in mix.exs:

def deps do
  [{:geo_postgis, "~> 3.1"}]
end

Optional Configuration

When a binary is passed to `Geo.PostGIS.Geometry.cast/1` implementation of `Ecto.Type.cast/1`, it is assumed to be a GeoJSON string. When this happens, geo_postgis will use Poison, by default, to convert the binary to a map and then convert that map to one of the Geo structs. If in these cases you would like to use a different JSON parser, you can set the config below.

# config.exs
config :geo_postgis,
  json_library: Poison # If you want to set your JSON module

Examples

Postgrex Extension for the PostGIS data types, Geometry and Geography

Postgrex.Types.define(MyApp.PostgresTypes, [Geo.PostGIS.Extension], [])

opts = [hostname: "localhost", username: "postgres", database: "geo_postgrex_test", types: MyApp.PostgresTypes ]
[hostname: "localhost", username: "postgres", database: "geo_postgrex_test", types: MyApp.PostgresTypes]

{:ok, pid} = Postgrex.Connection.start_link(opts)
{:ok, #PID<0.115.0>}

geo = %Geo.Point{coordinates: {30, -90}, srid: 4326}
%Geo.Point{coordinates: {30, -90}, srid: 4326}

{:ok, _} = Postgrex.Connection.query(pid, "CREATE TABLE point_test (id int, geom geometry(Point, 4326))")
{:ok, %Postgrex.Result{columns: nil, command: :create_table, num_rows: 0, rows: nil}}

{:ok, _} = Postgrex.Connection.query(pid, "INSERT INTO point_test VALUES ($1, $2)", [42, geo])
{:ok, %Postgrex.Result{columns: nil, command: :insert, num_rows: 1, rows: nil}}

Postgrex.Connection.query(pid, "SELECT * FROM point_test")
{:ok, %Postgrex.Result{columns: ["id", "geom"], command: :select, num_rows: 1,
rows: [{42, %Geo.Point{coordinates: {30.0, -90.0}, srid: 4326 }}]}}

Use with Ecto Referencing the documentation:

#If using with Ecto, you may want something like thing instead
Postgrex.Types.define(MyApp.PostgresTypes,
              [Geo.PostGIS.Extension] ++ Ecto.Adapters.Postgres.extensions(),
              json: Poison)

#Add extensions to your repo config
config :thanks, Repo,
  database: "geo_postgrex_test",
  username: "postgres",
  password: "postgres",
  hostname: "localhost",
  adapter: Ecto.Adapters.Postgres,
  types: MyApp.PostgresTypes


#Create a model
defmodule Test do
  use Ecto.Model

  schema "test" do
    field :name,           :string
    field :geom,           Geo.PostGIS.Geometry
  end
end

#Geometry or Geography columns can be created in migrations too
defmodule Repo.Migrations.Init do
  use Ecto.Migration

  def up do
    create table(:test) do
      add :name,     :string
      add :geom,     :geometry
    end
  end

  def down do
    drop table(:test)
  end
end

Ecto migrations can also use more elaborate Postgis GIS Objects. These types are useful for enforcing constraints on {Lng,Lat} (order matters), or ensuring that a particular projection/coordinate system/format is used.

defmodule Repo.Migrations.AdvancedInit do
  use Ecto.Migration

  def up do
    create table(:test) do
      add :name,     :string
    end
    # Add a field `lng_lat_point` with type `geometry(Point,4326)`.
    # This can store a "standard GPS" (epsg4326) coordinate pair {longitude,latitude}.
    execute("SELECT AddGeometryColumn ('test','lng_lat_point',4326,'POINT',2);")
  end

  def down do
    drop table(:test)
  end
end

Be sure to enable the Postgis extension if you haven't already done so:

defmodule MyApp.Repo.Migrations.EnablePostgis do
  use Ecto.Migration

  def up do
    execute "CREATE EXTENSION IF NOT EXISTS postgis"
  end

  def down do
    execute "DROP EXTENSION IF EXISTS postgis"
  end
end

Postgis functions can also be used in ecto queries. Currently only the OpenGIS functions are implemented. Have a look at lib/geo_postgis.ex for the implemented functions. You can use them like:

defmodule Example do
  import Ecto.Query
  import Geo.PostGIS

  def example_query(geom) do
    from location in Location, limit: 5, select: st_distance(location.geom, ^geom)
  end

end

Development

After you got the dependencies via mix deps.get make sure that:

  • postgis is installed
  • your postgres user has the database "geo_postgrex_test"
  • your postgres db user can login without a password or you set the PGPASSWORD environment variable appropriately

Then you can run the tests as you are used to with mix test.

You can’t perform that action at this time.