zf

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

types.ex (8177B)


      1 if Code.ensure_loaded?(Tds) do
      2   defmodule Tds.Ecto.UUID do
      3     @moduledoc """
      4     An TDS adapter type for UUIDs strings.
      5 
      6     If you are using Tds adapter and UUIDs in your project, instead of `Ecto.UUID`
      7     you should use Tds.Ecto.UUID to generate correct bytes that should be stored
      8     in database.
      9     """
     10 
     11     use Ecto.Type
     12 
     13     @typedoc """
     14     A hex-encoded UUID string.
     15     """
     16     @type t :: <<_::288>>
     17 
     18     @typedoc """
     19     A raw binary representation of a UUID.
     20     """
     21     @type raw :: <<_::128>>
     22 
     23     @doc false
     24     @impl true
     25     def type(), do: :uuid
     26 
     27     @doc """
     28     Casts to UUID.
     29     """
     30     @impl true
     31     @spec cast(t | raw | any) :: {:ok, t} | :error
     32     def cast(<< a1, a2, a3, a4, a5, a6, a7, a8, ?-,
     33                 b1, b2, b3, b4, ?-,
     34                 c1, c2, c3, c4, ?-,
     35                 d1, d2, d3, d4, ?-,
     36                 e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12 >>) do
     37       << c(a1), c(a2), c(a3), c(a4), c(a5), c(a6), c(a7), c(a8), ?-,
     38         c(b1), c(b2), c(b3), c(b4), ?-,
     39         c(c1), c(c2), c(c3), c(c4), ?-,
     40         c(d1), c(d2), c(d3), c(d4), ?-,
     41         c(e1), c(e2), c(e3), c(e4), c(e5), c(e6), c(e7), c(e8), c(e9), c(e10), c(e11), c(e12) >>
     42     catch
     43       :error -> :error
     44     else
     45       casted -> {:ok, casted}
     46     end
     47 
     48     def cast(<<bin::binary-size(16)>>), do: encode(bin)
     49     def cast(_), do: :error
     50 
     51     @doc """
     52     Same as `cast/1` but raises `Ecto.CastError` on invalid arguments.
     53     """
     54     def cast!(value) do
     55       case cast(value) do
     56         {:ok, uuid} -> uuid
     57         :error -> raise Ecto.CastError, type: __MODULE__, value: value
     58       end
     59     end
     60 
     61     @compile {:inline, c: 1}
     62 
     63     defp c(?0), do: ?0
     64     defp c(?1), do: ?1
     65     defp c(?2), do: ?2
     66     defp c(?3), do: ?3
     67     defp c(?4), do: ?4
     68     defp c(?5), do: ?5
     69     defp c(?6), do: ?6
     70     defp c(?7), do: ?7
     71     defp c(?8), do: ?8
     72     defp c(?9), do: ?9
     73     defp c(?A), do: ?a
     74     defp c(?B), do: ?b
     75     defp c(?C), do: ?c
     76     defp c(?D), do: ?d
     77     defp c(?E), do: ?e
     78     defp c(?F), do: ?f
     79     defp c(?a), do: ?a
     80     defp c(?b), do: ?b
     81     defp c(?c), do: ?c
     82     defp c(?d), do: ?d
     83     defp c(?e), do: ?e
     84     defp c(?f), do: ?f
     85     defp c(_),  do: throw(:error)
     86 
     87     @doc """
     88     Converts a string representing a UUID into a binary.
     89     """
     90     @impl true
     91     @spec dump(t | any) :: {:ok, raw} | :error
     92     def dump(<<a1, a2, a3, a4, a5, a6, a7, a8, ?-,
     93                b1, b2, b3, b4, ?-,
     94                c1, c2, c3, c4, ?-,
     95                d1, d2, d3, d4, ?-,
     96                e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12>>) do
     97       try do
     98         << d(a7)::4, d(a8)::4, d(a5)::4, d(a6)::4,
     99           d(a3)::4, d(a4)::4, d(a1)::4, d(a2)::4,
    100           d(b3)::4, d(b4)::4, d(b1)::4, d(b2)::4,
    101           d(c3)::4, d(c4)::4, d(c1)::4, d(c2)::4,
    102           d(d1)::4, d(d2)::4, d(d3)::4, d(d4)::4,
    103           d(e1)::4, d(e2)::4, d(e3)::4, d(e4)::4,
    104           d(e5)::4, d(e6)::4, d(e7)::4, d(e8)::4,
    105           d(e9)::4, d(e10)::4, d(e11)::4, d(e12)::4 >>
    106       catch
    107         :error -> :error
    108       else
    109         binary ->
    110           {:ok, binary}
    111       end
    112     end
    113 
    114     def dump(_), do: :error
    115 
    116     def dump!(value) do
    117       case dump(value) do
    118         {:ok, binary} -> binary
    119         :error -> raise ArgumentError, "Invalid uuid value #{inspect(value)}"
    120       end
    121     end
    122 
    123     @compile {:inline, d: 1}
    124 
    125     defp d(?0), do: 0
    126     defp d(?1), do: 1
    127     defp d(?2), do: 2
    128     defp d(?3), do: 3
    129     defp d(?4), do: 4
    130     defp d(?5), do: 5
    131     defp d(?6), do: 6
    132     defp d(?7), do: 7
    133     defp d(?8), do: 8
    134     defp d(?9), do: 9
    135     defp d(?A), do: 10
    136     defp d(?B), do: 11
    137     defp d(?C), do: 12
    138     defp d(?D), do: 13
    139     defp d(?E), do: 14
    140     defp d(?F), do: 15
    141     defp d(?a), do: 10
    142     defp d(?b), do: 11
    143     defp d(?c), do: 12
    144     defp d(?d), do: 13
    145     defp d(?e), do: 14
    146     defp d(?f), do: 15
    147     defp d(_),  do: throw(:error)
    148 
    149     @doc """
    150     Converts a binary UUID into a string.
    151     """
    152     @impl true
    153     @spec load(raw | any) :: {:ok, t} | :error
    154     def load(<<_::128>> = uuid) do
    155       encode(uuid)
    156     end
    157 
    158     def load(<<_::64, ?-, _::32, ?-, _::32, ?-, _::32, ?-, _::96>> = string) do
    159       raise ArgumentError, "trying to load string UUID as Tds.Ecto.UUID: #{inspect string}. " <>
    160                           "Maybe you wanted to declare :uuid as your database field?"
    161     end
    162 
    163     def load(_), do: :error
    164 
    165     @doc """
    166     Generates a version 4 (random) UUID.
    167     """
    168     @spec generate() :: t
    169     def generate do
    170       {:ok, uuid} = encode(bingenerate())
    171       uuid
    172     end
    173 
    174     @doc """
    175     Generates a version 4 (random) UUID in the binary format.
    176     """
    177     @spec bingenerate() :: raw
    178     def bingenerate do
    179       <<u0::56, u1::36, u2::28>> = :crypto.strong_rand_bytes(15)
    180       <<u0::56, 4::4, u1::36, 2::4, u2::28>>
    181     end
    182 
    183     # Callback invoked by autogenerate fields.
    184     @impl true
    185     def autogenerate, do: generate()
    186 
    187     defp encode(<<a1::4, a2::4, a3::4, a4::4,
    188                   a5::4, a6::4, a7::4, a8::4,
    189                   b1::4, b2::4, b3::4, b4::4,
    190                   c1::4, c2::4, c3::4, c4::4,
    191                   d1::4, d2::4, d3::4, d4::4,
    192                   e1::4, e2::4, e3::4, e4::4,
    193                   e5::4, e6::4, e7::4, e8::4,
    194                   e9::4, e10::4, e11::4, e12::4 >>) do
    195       << e(a7), e(a8), e(a5), e(a6), e(a3), e(a4), e(a1), e(a2), ?-,
    196         e(b3), e(b4), e(b1), e(b2), ?-,
    197         e(c3), e(c4), e(c1), e(c2), ?-,
    198         e(d1), e(d2), e(d3), e(d4), ?-,
    199         e(e1), e(e2), e(e3), e(e4), e(e5), e(e6), e(e7), e(e8), e(e9), e(e10), e(e11), e(e12) >>
    200     catch
    201       :error -> :error
    202     else
    203       encoded -> {:ok, encoded}
    204     end
    205 
    206     @compile {:inline, e: 1}
    207 
    208     defp e(0),  do: ?0
    209     defp e(1),  do: ?1
    210     defp e(2),  do: ?2
    211     defp e(3),  do: ?3
    212     defp e(4),  do: ?4
    213     defp e(5),  do: ?5
    214     defp e(6),  do: ?6
    215     defp e(7),  do: ?7
    216     defp e(8),  do: ?8
    217     defp e(9),  do: ?9
    218     defp e(10), do: ?a
    219     defp e(11), do: ?b
    220     defp e(12), do: ?c
    221     defp e(13), do: ?d
    222     defp e(14), do: ?e
    223     defp e(15), do: ?f
    224   end
    225 
    226   defmodule Tds.Ecto.VarChar do
    227     @moduledoc """
    228     An Tds adapter Ecto Type that wraps erlang string into tuple so TDS driver
    229     can understand if erlang string should be encoded as NVarChar or Varchar.
    230 
    231     Due some limitations in Ecto and Tds driver, it is not possible to
    232     support collations other than the one that is set on connection during login.
    233     Please be aware of this limitation if you plan to store varchar values in
    234     your database using Ecto since you will probably lose some codepoints in
    235     the value during encoding. Instead use `tds_encoding` library and first
    236     encode value and then annotate it as `:binary` by calling `Ecto.Query.API.type/2`
    237     in your query. This way all codepoints will be properly preserved during
    238     insert to database.
    239     """
    240     use Ecto.Type
    241 
    242     @typedoc """
    243     A erlang string
    244     """
    245     @type t :: String.t
    246 
    247     @typedoc """
    248     A value annotated as varchar.
    249     """
    250     @type varchar :: {String.t, :varchar}
    251 
    252     @doc false
    253     @impl true
    254     def type(), do: :varchar
    255 
    256     @doc """
    257     Casts to string.
    258     """
    259     @spec cast(t | varchar | any) :: {:ok, t} | :error
    260     @impl true
    261     def cast({value, :varchar}) do
    262       # In case we get already dumped value
    263       {:ok, value}
    264     end
    265 
    266     def cast(value) when is_binary(value) do
    267       {:ok, value}
    268     end
    269 
    270     def cast(_), do: :error
    271 
    272     @doc """
    273     Same as `cast/1` but raises `Ecto.CastError` on invalid arguments.
    274     """
    275     @spec cast!(t | varchar | any) :: t
    276     def cast!(value) do
    277       case cast(value) do
    278         {:ok, uuid} -> uuid
    279         :error -> raise Ecto.CastError, type: __MODULE__, value: value
    280       end
    281     end
    282 
    283     @doc """
    284     Loads the DB type as is.
    285     """
    286     @impl true
    287     @spec load(t | any) :: {:ok, t} | :error
    288     def load(value) do
    289       {:ok, value}
    290     end
    291 
    292     @doc """
    293     Converts a string representing a VarChar into a tuple `{value, :varchar}`.
    294 
    295     Returns `:error` if value is not binary.
    296     """
    297     @impl true
    298     @spec dump(t | any) :: {:ok, varchar} | :error
    299     def dump(value) when is_binary(value) do
    300       {:ok, {value, :varchar}}
    301     end
    302 
    303     def dump(_), do: :error
    304   end
    305 end