# `Localize.Translate.QueryBuilder`
[🔗](https://github.com/elixir-localize/localize_translate/blob/v0.1.0/lib/localize/translate/query_builder.ex#L2)

Provides helpers for filtering translations in `Ecto.Queries`.

This module requires `Ecto.SQL` to be available during the compilation.

# `translated`
*macro* 

Generates a SQL fragment for accessing a translated field in an `Ecto.Query`.

The generated SQL fragment can be coupled with the rest of the functions and operators
provided by `Ecto.Query` and `Ecto.Query.API`.

### Arguments

* `module` is the `Ecto.Schema` module that uses `Localize.Translate`. Validated at
  compile time.

* `translatable` is either a query binding (such as `a`) for whole-record access, or a
  field access expression (such as `a.title`) for a specific translatable field.

* `locale` is either a single locale (atom or string) or a list of locales acting as a
  fallback chain. May be a literal, a variable, or a runtime expression.

### Returns

A `fragment/1` AST suitable for use in `Ecto.Query` clauses. The fragment evaluates to
the translated value with fallback to the base column, or `NULL` when no translation
exists for the requested locales.

### Safety

This macro emits errors when used with untranslatable schema modules or fields. Errors
are emitted during compilation so invalid queries fail before they can run.

### Examples

Assuming the Article schema defined in
[Structured translations](Localize.Translate.html#module-structured-translations):

    # Return all articles that have a Spanish translation
    from a in Article, where: not is_nil(translated(Article, a, :es))
    #=> SELECT a0."id", a0."title", a0."body", a0."translations"
    #=> FROM "articles" AS a0
    #=> WHERE (NOT (NULLIF((a0."translations"->'es'),'null') IS NULL))

    # Query items with a certain translated value
    from a in Article, where: translated(Article, a.title, :fr) == "Elixir"
    #=> SELECT a0."id", a0."title", a0."body", a0."translations"
    #=> FROM "articles" AS a0
    #=> WHERE (COALESCE(a0."translations"->$1->>$2, a0."title") = 'Elixir')

    # Query items using a case insensitive comparison
    from a in Article, where: ilike(translated(Article, a.body, :es), "%elixir%")
    #=> SELECT a0."id", a0."title", a0."body", a0."translations"
    #=> FROM "articles" AS a0
    #=> WHERE (COALESCE(a0."translations"->$1->>$2, a0."body") ILIKE '%elixir%')

### Structured translations vs free-form translations

`Localize.Translate.QueryBuilder` works with both structured translations and free-form
translations.

When using structured translations, the translations are saved as an embedded schema.
This means that **the locale keys will be always present even if there is no
translation for that locale.** In the database we have a `NULL` value (`nil` in
Elixir).

    # If MyApp.Article uses structured translations
    from a in Article, where: not is_nil(translated(Article, a, :es))
    #=> SELECT a0."id", a0."title", a0."body", a0."translations"
    #=> FROM "articles" AS a0
    #=> WHERE (NOT (NULLIF((a0."translations"->'es'),'null') IS NULL))

### More complex queries

The `translated/3` macro can also be used with relations and joined schemas. For more
complex examples take a look at the QueryBuilder tests (the file is located in
`test/localize/translate/query_builder_test.exs`).

# `translated_as`
*macro* 

Generates a SQL fragment for use in an `Ecto.Query` `select` clause, aliased to the
original field name.

Wraps `translated/3` so the returned column carries the base column's name. Ecto can
therefore load the translated value directly into the schema struct without further
processing or conversion.

### Arguments

* `module` is the `Ecto.Schema` module that uses `Localize.Translate`.

* `translatable` is a field access expression such as `a.title`. The base field name is
  used as the column alias.

* `locale` is either a single locale or a list of locales acting as a fallback chain.

### Returns

A `fragment/1` AST that selects the translated value aliased to the original field
name. See `translated/3` for the underlying SQL produced.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
