ericmj/postgrex — pull request #27 by awright415 (2014-11-14 18:19:28+00:00)
Title: Add support for Postgres range types

This PR adds basic support for Postgres' built-in range type (binary format). Currently it handles 5 of the 6 range types: int4range, int8range, daterange, tsrange, and tstzrange. The one that's missing is numrange for Numerics.

Each range type expects and returns a tuple with elements that follow the existing data representation for int, date, and timestamp (e.g., `{1,3}` and `{{2014,1,1},{2014,12,31}}`). More structured representations would best be handled downstream with custom encoder/decoders, like Ecto does with Ecto.Date and Ecto.DateTime.

For open-ended ranges, I went with the existing `:"-inf"` and `:inf` style over `nil` values. Using `nil` would be closer to the Postgres query syntax, but `inf` makes the actual behavior more explicit.

One last thing to note is that the values are all treated as lower/upper inclusive ranges, smoothing out a quirk of how Postgres serializes/returns range values.

Postgres will return range values as lower-inclusive/upper-exclusive, regardless of how the initial query is structured. So, e.g., Postgres would return 1 and 6 as the bounds of `SELECT '[1,5]'::int4range`, but the upper-inclusive bit flag would indicate 6 is not included in the range.

To more closely match input/output, as well as the behavior of Elixir's Range type, the decoder functions convert to inclusive upper bounds on the fly. So the same query above returns `{1, 5}` after decoding.