zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

extension.ex (4440B)


      1 defmodule Postgrex.Extension do
      2   @moduledoc """
      3   An extension knows how to encode and decode PostgreSQL types to and
      4   from Elixir values.
      5 
      6   Custom extensions can be enabled via `Postgrex.Types.define/3`.
      7   `Postgrex.Types.define/3` must be called on its own file, outside of
      8   any module and function, as it only needs to be defined once during
      9   compilation.
     10 
     11   For example to support label trees using the text encoding format:
     12 
     13       defmodule MyApp.LTree do
     14         @behaviour Postgrex.Extension
     15 
     16         # It can be memory efficient to copy the decoded binary because a
     17         # reference counted binary that points to a larger binary will be passed
     18         # to the decode/4 callback. Copying the binary can allow the larger
     19         # binary to be garbage collected sooner if the copy is going to be kept
     20         # for a longer period of time. See `:binary.copy/1` for more
     21         # information.
     22         def init(opts) do
     23           Keyword.get(opts, :decode_copy, :copy)
     24         end
     25 
     26         # Use this extension when `type` from %Postgrex.TypeInfo{} is "ltree"
     27         def matching(_state), do: [type: "ltree"]
     28 
     29         # Use the text format, "ltree" does not have a binary format.
     30         def format(_state), do: :text
     31 
     32         # Use quoted expression to encode a string that is the same as
     33         # postgresql's ltree text format. The quoted expression should contain
     34         # clauses that match those of a `case` or `fn`. Encoding matches on the
     35         # value and returns encoded `iodata()`. The first 4 bytes in the
     36         # `iodata()` must be the byte size of the rest of the encoded data, as a
     37         # signed 32bit big endian integer.
     38         def encode(_state) do
     39           quote do
     40             bin when is_binary(bin) ->
     41               [<<byte_size(bin) :: signed-size(32)>> | bin]
     42           end
     43         end
     44 
     45         # Use quoted expression to decode the data to a string. Decoding matches
     46         # on an encoded binary with the same signed 32bit big endian integer
     47         # length header.
     48         def decode(:reference) do
     49           quote do
     50             <<len::signed-size(32), bin::binary-size(len)>> ->
     51               bin
     52           end
     53         end
     54         def decode(:copy) do
     55           quote do
     56             <<len::signed-size(32), bin::binary-size(len)>> ->
     57               :binary.copy(bin)
     58           end
     59         end
     60       end
     61 
     62   This example could be used in a custom types module:
     63 
     64       Postgrex.Types.define(MyApp.Types, [MyApp.LTree])
     65 
     66   Or pass in opts for the extension that will be passed to the `init/1` callback:
     67 
     68       Postgrex.Types.define(MyApp.Types, [{MyApp.LTree, [decode_copy: :copy]}])
     69 
     70   """
     71 
     72   @type t :: module
     73   @type state :: term
     74 
     75   @doc """
     76   Should perform any initialization of the extension. The function receives the
     77   user options. The state returned from this function will be passed to other
     78   callbacks.
     79   """
     80   @callback init(Keyword.t()) :: state
     81 
     82   @doc """
     83   Prelude defines properties and values that are attached to the body of
     84   the types module.
     85   """
     86   @callback prelude(state) :: Macro.t()
     87 
     88   @doc """
     89   Specifies the types the extension matches, see `Postgrex.TypeInfo` for
     90   specification of the fields.
     91   """
     92   @callback matching(state) :: [
     93               type: String.t(),
     94               send: String.t(),
     95               receive: String.t(),
     96               input: String.t(),
     97               output: String.t()
     98             ]
     99 
    100   @doc """
    101   Returns the format the type should be encoded as. See
    102   http://www.postgresql.org/docs/9.4/static/protocol-overview.html#PROTOCOL-FORMAT-CODES.
    103   """
    104   @callback format(state) :: :binary | :text
    105 
    106   @doc """
    107   Returns a quoted list of clauses that encode an Elixir value to iodata.
    108 
    109   It must use a signed 32 bit big endian integer byte length header.
    110 
    111       def encode(_) do
    112         quote do
    113           integer ->
    114             <<8 :: signed-32, integer :: signed-64>>
    115         end
    116       end
    117 
    118   """
    119   @callback encode(state) :: Macro.t()
    120 
    121   @doc """
    122   Returns a quoted list of clauses that decode a binary to an Elixir value.
    123 
    124   The pattern must use binary syntax and decode a fixed length using the signed
    125   32 bit big endian integer byte length header.
    126 
    127       def decode(_) do
    128         quote do
    129           # length header is in bytes
    130           <<len :: signed-32, integer :: signed-size(len)-unit(8)>> ->
    131             integer
    132         end
    133       end
    134   """
    135   @callback decode(state) :: Macro.t()
    136 
    137   @optional_callbacks [prelude: 1]
    138 end