项目作者: hauleth

项目描述 :
Simple macro for generating SQL's functions macro wrappers
高级语言: Elixir
项目地址: git://github.com/hauleth/ecto_function.git
创建时间: 2017-10-17T08:53:08Z
项目社区:https://github.com/hauleth/ecto_function

开源协议:MIT License

下载


Ecto.Function

Hex.pm
Travis

Helper macro for defining macros that simplifies calling DB functions.

Installation

The package can be installed by adding ecto_function to your list of dependencies in mix.exs:

  1. def deps do
  2. [
  3. {:ecto_function, "~> 1.0.1"}
  4. ]
  5. end

The docs can be found at https://hexdocs.pm/ecto_function.

Usage

When you use a lot of DB functions inside your queries then this probably looks
like this:

  1. from item in "items",
  2. where: fragment("date_trunc(?, ?)", "hour", item.inserted_at) < fragment("date_trunc(?, ?)", "hour", fragment("now()")),
  3. select: %{regr: fragment("regr_sxy(?, ?)", item.y, item.x)}

There are a lot of fragment calls which makes code quite challenging to read.
However there is way out for such code, you can write macros:

  1. defmodule Foo do
  2. defmacro date_trunc(part, field) do
  3. quote do: fragment("date_trunc(?, ?)", ^part, ^field)
  4. end
  5. defmacro now do
  6. quote do: fragment("now()")
  7. end
  8. defmacro regr_sxy(y, x) do
  9. quote do: fragment("regr_sxy(y, x)", ^y, ^x)
  10. end
  11. end

And then cleanup your query to:

  1. import Foo
  2. import Ecto.Query
  3. from item in "items",
  4. where: date_trunc("hour", item.inserted_at) < date_trunc("hour", now()),
  5. select: %{regr: regr_sxy(item.y, item.x)}

However there is still a lot of repetition in your new fancy helper module. You
need to repeat function name twice, name each argument, insert all that carets
and stuff.

What about little help?

  1. defmodule Foo do
  2. import Ecto.Function
  3. defqueryfunc date_trunc(part, field)
  4. defqueryfunc now
  5. defqueryfunc regr_sxy/2
  6. end

Much cleaner…

Reasoning

Your DB is powerful. Really. A lot of
computations can be done there. There is whole chapter dedicated to
describing all PostgreSQL functions and Ecto supports only few of them:

  • sum
  • avg
  • min
  • max

To be exact. Saying that we have “limited choice” would be disrespectful to DB
systems like PostgreSQL or Oracle. Of course Ecto core team have walid reasoning
to support only that much functions: these are available in probably any DB
system ever, so supporting them directly in library is no brainer. However you
as end-user shouldn’t be limited to so small set. Let’s be honest, you probably
will never change your DB engine, and if you do so, then you probably rewrite
while system from the ground. So this is why this module was created. To provide
you access to all functions in your SQL DB (could work with NoSQL DB also, but I
test only against PostgreSQL).

For completeness you can also check Ecto.OLAP which provide helpers for
some more complex functionalities like GROUPING (and in near future also
window functions).

But why not introduce that directly to Ecto?

Because there is no need. Personally I would like to see Ecto splitted a little,
like changesets should be in separate library in my humble opinion. Also I
believe that such PR would never be merged as “non scope” for the reasons I gave
earlier.