felt / geo

A collection of GIS functions for Elixir

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Unable to add support for ST_ClosestPoint

adityasanka opened this issue · comments

Hi @bryanjos, thanks for the awesome library. I am trying to add a macro to lib/geo/postgis.ex to support ST_ClosestPoint

defmacro st_closestpoint(geometryA, geometryB) do
      quote do: fragment("ST_ClosestPoint(?,?)", unquote(geometryA), unquote(geometryB))
end

I receive the following error while trying to use it with my queries

iex > alias StoreRoom.{Repo, BusStop, Route}
iex > import Ecto.Query
iex > import Geo.PostGIS
iex > home = %Geo.Point{coordinates: {****, ****}, srid: 4326}
iex > query = from r in Route, order_by: st_distance(r.line, ^home), distinct: r.code, limit: 5, select: r
iex > (from r in subquery(query), select: %{pickup: st_closestpoint(r.line, ^home)}) |> Repo.all()
** (Postgrex.Error) ERROR 42883 (undefined_function): function st_closestpoint(geography, unknown) does not exist
[debug] QUERY ERROR db=1.9ms
SELECT ST_ClosestPoint(s0."line",$1) FROM (SELECT DISTINCT ON (r0."code") r0."id" AS "id", r0."org" AS "org", r0."code" AS "code", r0."name" AS "name", r0."line" AS "line", r0."inserted_at" AS "inserted_at", r0."updated_at" AS "updated_at" FROM "routes" AS r0 ORDER BY r0."code", ST_Distance(r0."line",$2) LIMIT 5) AS s0 [%Geo.Point{coordinates: {78.3762, 17.4474}, srid: 4326}, %Geo.Point{coordinates: {78.3762, 17.4474}, srid: 4326}]
    (ecto) lib/ecto/adapters/sql.ex:436: Ecto.Adapters.SQL.execute_and_cache/7
    (ecto) lib/ecto/repo/queryable.ex:130: Ecto.Repo.Queryable.execute/5
    (ecto) lib/ecto/repo/queryable.ex:35: Ecto.Repo.Queryable.all/4

I am fairly new to elixir and postgis. Forgive me if this is a trivial mistake. Any guidance would of great help

Everything looks right there as far as I can tell. Only thing I can think of is make sure the Postgrex types are set up. Do you get a similar error with st_distance in your query? Also maybe check that you have the postgis extension installed in postgres.

Hi @bryanjos, thank you for the quick reply. The postgis extension is installed and has been enabled for this database.

I verified this by using st_distance

iex(6)> (from r in subquery(query), select: %{distance: st_distance(r.line, ^home)}) |> Repo.all()
[debug] QUERY OK db=249.8ms
SELECT ST_Distance(s0."line",$1) FROM (SELECT DISTINCT ON (r0."code") r0."id" AS "id", r0."org" AS "org", r0."code" AS "code", r0."name" AS "name", r0."line" AS "line", r0."inserted_at" AS "inserted_at", r0."updated_at" AS "updated_at" FROM "routes" AS r0 ORDER BY r0."code", ST_Distance(r0."line",$2) LIMIT 5) AS s0 [%Geo.Point{coordinates: {78.3762, 17.4474}, srid: 4326}, %Geo.Point{coordinates: {78.3762, 17.4474}, srid: 4326}]
[%{distance: 1097.178381035}, %{distance: 182.273171646},
 %{distance: 2809.06654445}, %{distance: 171.211571728},
 %{distance: 4322.601294866}]

I have also have the Postgrex types setup using

# define custom postgres types
Postgrex.Types.define(StoreRoom.PostgresTypes,
              [Geo.PostGIS.Extension] ++ Ecto.Adapters.Postgres.extensions(),
              json: Poison)

I went ahead changed the above macro to the following, to check if issue is with "ST_ClosestPoint"

# custom macros
    defmacro st_closestpoint(geometryA, geometryB) do
      quote do: fragment("ST_Distance(?,?)", unquote(geometryA), unquote(geometryB))
    end

Everything worked fine with the following query

iex(9)> (from r in subquery(query), select: %{distance1: st_distance(r.line, ^home), distance2: st_closestpoint(r.line, ^home)}) |> Repo.all()
[debug] QUERY OK db=59.6ms
SELECT ST_Distance(s0."line",$1), ST_Distance(s0."line",$2) FROM (SELECT DISTINCT ON (r0."code") r0."id" AS "id", r0."org" AS "org", r0."code" AS "code", r0."name" AS "name", r0."line" AS "line", r0."inserted_at" AS "inserted_at", r0."updated_at" AS "updated_at" FROM "routes" AS r0 ORDER BY r0."code", ST_Distance(r0."line",$3) LIMIT 5) AS s0 [%Geo.Point{coordinates: {78.3762, 17.4474}, srid: 4326}, %Geo.Point{coordinates: {78.3762, 17.4474}, srid: 4326}, %Geo.Point{coordinates: {78.3762, 17.4474}, srid: 4326}]
[%{distance1: 1097.178381035, distance2: 1097.178381035},
 %{distance1: 182.273171646, distance2: 182.273171646},
 %{distance1: 2809.06654445, distance2: 2809.06654445},
 %{distance1: 171.211571728, distance2: 171.211571728},
 %{distance1: 4322.601294866, distance2: 4322.601294866}]

I am unable to figure out the issue with "ST_ClosestPoint". I need to add a few other helper macros as well. Please point me in the right direction. Thanks in advance

Sounds like maybe it could be that the function isn't defined in postgis. Try doing a normal sql query with that function and see if you get a similar error

Hi @bryanjos,

I was using the type geography while declaring schema for my tables. ST_ClosestPoint only works with geometry

create table(:routes, primary_key: false) do
      add :id, :binary_id, primary_key: true
      add :org, :string
      add :code, :string
      add :name, :string
      add :line, :geometry

      timestamps()
end

Thanks Bryan.