Ecto Custom Types and PostGIS

722 views
Skip to first unread message

Bryan Joseph

unread,
Jan 25, 2015, 4:00:01 PM1/25/15
to elixi...@googlegroups.com
Hi,

I created a library called Geo and one thing it does is add custom encoders and decoders to use the geospatial types with Postgrex. I have wanted to do was add the ability to use the Geometry type in Ecto whenever it was possible to add custom types. Now that custom types are available, I gave it some time yesterday, but I think I need some help understanding how to do it.

So when using Postgres with PostGIS, creating a geometry column is usually done like so:

geom geometry(Point, 4326)

Where you define the type as Geometry, the type of Geometry and optionally the projection. You could also do something like this:

geom geometry

In which case all geometry types are allowed in that field.

I think I can understand how to implement load and dump. For instance, usually when you insert a geometry, you use the WKT (Well Known Text) string and when querying for a geometry, it comes out as a WKB (Well Known Binary) string. I use those methods when encoding and decoding in Postgrex now.

I guess I'm not sure how the translation from the Geometry struct using Ecto.Type to the Geometry column in Postgres would work. Also do custom types work with the new mirgrations?

José Valim

unread,
Jan 25, 2015, 4:22:19 PM1/25/15
to elixi...@googlegroups.com
Bryan,

You are already tacking both Postgrex and Ecto sides of things. I will describe the complete process though to ensure there are no gaps. There are two parts.

The first one is that you actually need to teach Postgrex, the Postgres adapter, about geo types. It seems you started this but note that Eric is refactoring the extensions mechanism. Once that is merged, you will be able to teach Postgrex how to encode from Postgres text/binary format to an Elixir data structure very cleanly.

To integrate the above with Ecto, you will need two things. The first one is tell the Repo configuration that you are using those extensions:

    config :my_app, Repo, extensions: [Geo]

Now, after that is done, you need to tell Ecto how to handle your types. Here is the thing, you probably don't need to do anything here because the type you return from the adapter will likely be fine. For example, Ecto does not do anything for integer, binaries and so on. It just passes the type returned by the adapter straight-through. Your implementation will likely end-up something like:

    defmodule Ecto.Geo do
      @behaviour Ecto.Type
      
      # Return the underlying Postgrex type. Is that :geo?
      def type, do: :geo

      # Never blank
      def blank?, do: false

      # Here I am assuming you have a Geo struct in Ecto land
      def load(%Geo{} = geo), do: {:ok, geo}
      def load(_), do: :error

      def dump(%Geo{} = geo), do: {:ok, geo}
      def dump(_), do: :error

      # You can implement casting logic here. For example, if you allow
      # those geometries to somehow be given as strings.
      def cast(%Geo{} = geo), do: {:ok, geo}
      def cast(_), do: :error
    end

Today you probably have custom encoder and decoder functions for the Postgrex adapter and they may work in this setup too as long as you pass them in the adapter configuration.

José Valim
Skype: jv.ptec
Founder and Lead Developer

--
You received this message because you are subscribed to the Google Groups "elixir-ecto" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-ecto...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Bryan Joseph

unread,
Jan 26, 2015, 9:02:59 AM1/26/15
to elixi...@googlegroups.com, jose....@plataformatec.com.br
Thanks José! I will give that a shot with the encoder and decoder functions I created and will be on the look out for the extensions update. I never thought about giving the Repo configuration the encoder and decoder attributes. That clears things up a lot for me.

Bryan Joseph

unread,
Jan 27, 2015, 11:01:07 AM1/27/15
to elixi...@googlegroups.com, jose....@plataformatec.com.br
Just wanted to follow up and say I got it working!

I added a section in the readme on Github (https://github.com/bryanjos/geo) and I updated the library in Hex. I'll be on the lookout for the Postgrex extensions update and implement that when it's available. Thanks again for your help.

José Valim

unread,
Jan 27, 2015, 11:13:16 AM1/27/15
to elixi...@googlegroups.com
This is awesome! I am really looking forward to see how this will play once we merge the extensions system to postgrex. Your feedback would be very important once it happens.



José Valim
Skype: jv.ptec
Founder and Lead Developer

Bryan Joseph

unread,
Jan 27, 2015, 1:45:10 PM1/27/15
to elixi...@googlegroups.com, jose....@plataformatec.com.br
Thanks! I'll be happy to give any feedback I have.

Jason S

unread,
Jan 27, 2015, 1:46:23 PM1/27/15
to elixi...@googlegroups.com, elixi...@googlegroups.com, jose....@plataformatec.com.br
This is probably a Postgrex question. If I want to have multiple Encoders and Formatters do I just pass them in as an array? 

José Valim

unread,
Jan 27, 2015, 2:10:28 PM1/27/15
to elixi...@googlegroups.com

This is probably a Postgrex question. If I want to have multiple Encoders and Formatters do I just pass them in as an array? 

No, you would have to provide one final function. That's one of the issues with the current mechanism and why we are moving to extensions.

Jason S

unread,
Jan 27, 2015, 2:17:40 PM1/27/15
to elixi...@googlegroups.com, elixi...@googlegroups.com
Nice!



On Tue, Jan 27, 2015 at 1:10 PM, José Valim <jose....@plataformatec.com.br> wrote:


This is probably a Postgrex question. If I want to have multiple Encoders and Formatters do I just pass them in as an array? 

No, you would have to provide one final function. That's one of the issues with the current mechanism and why we are moving to extensions.

Eric Meadows-Jönsson

unread,
Jan 28, 2015, 12:23:38 PM1/28/15
to elixi...@googlegroups.com
Postgrex extensions have been merged into master. I would love for you to try it out before release 0.8.0. There are code examples in the README, the test suite and the main code base because we use extensions internally to encode and decode the types Postgrex types.
--
Eric Meadows-Jönsson
Reply all
Reply to author
Forward
0 new messages