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.