# `Localize.Ecto`
[🔗](https://github.com/elixir-localize/localize_sql/blob/v1.0.1/lib/localize/ecto.ex#L1)

Locale-aware query expressions for Ecto.

Text sorts differently in different languages, and neither PostgreSQL
nor SQLite sorts linguistically unless a query asks it to. This
library resolves a [Localize](https://hexdocs.pm/localize) language
tag to an ICU collation and applies it to a query expression, so that
ordering, comparison and case mapping follow the user's locale.

There is one module per database, because Ecto requires the SQL of a
fragment to be a compile-time literal and the two databases do not
spell everything the same way:

* `Localize.Ecto.Postgres` — PostgreSQL. `collate/1,2`, `lower/1,2`,
  `upper/1,2`, `initcap/1,2`, plus `at_time_zone/2` and `ts_match/2,3`.

* `Localize.Ecto.SQLite3` — SQLite, via the `localize_icu` extension
  this library ships. `collate/1,2`, `lower/1,2`, `upper/1,2` and
  `initcap/1,2`.

Both resolve collation names through the same
`Localize.Ecto.Collation`, so a locale produces the same name —
`"de-x-icu"`, `"sv-x-icu"`, `"de-u-co-phonebk-x-icu"` — on either
database and a query written for one sorts identically on the other.

This module exposes the PostgreSQL macros directly, so existing code
that imports it keeps working and PostgreSQL users need not think
about the split:

    import Ecto.Query
    import Localize.Ecto

    # Collate using the current locale (Localize.get_locale/0)
    from p in Product, order_by: collate(p.name)

    # Collate using an explicit locale
    from p in Product, order_by: collate(p.name, "sv")

    # Locale determined at runtime
    def sorted_products(locale) do
      from p in Product, order_by: collate(p.name, ^locale)
    end

    # Collate a comparison: name < 'münchen' under German collation
    from p in Product, where: collate(p.name < "münchen", "de"), select: p.name

    # Use a collation created in a migration, by name
    from p in Product, order_by: collate(p.name, collation: "german_phonebook")

For SQLite, import `Localize.Ecto.SQLite3` instead. An application
talking to both databases imports each where it needs it.

Collations for locales carrying a BCP 47 collation type, such as
`de-u-co-phonebk`, are not preloaded by PostgreSQL. Create them once
in a migration with `Localize.Ecto.Migration.create_collation/2` and
they resolve automatically thereafter. SQLite needs no such migration.

# `at_time_zone`
*macro* 

Applies PostgreSQL's `AT TIME ZONE` with a validated time zone.

See `Localize.Ecto.Postgres.at_time_zone/2`.

### Examples

    iex> import Ecto.Query
    iex> query = from e in "events", select: at_time_zone(e.starts_at, "Australia/Sydney")
    iex> match?(%Ecto.Query{}, query)
    true

# `collate`
*macro* 

Applies a `COLLATE` clause for the current locale.

See `Localize.Ecto.Postgres.collate/1`.

### Examples

    iex> import Ecto.Query
    iex> query = from p in "products", order_by: collate(p.name), select: p.name
    iex> match?(%Ecto.Query{}, query)
    true

# `collate`
*macro* 

Applies a `COLLATE` clause for the given locale or collation.

See `Localize.Ecto.Postgres.collate/2`.

### Examples

    iex> import Ecto.Query
    iex> query = from p in "products", order_by: collate(p.name, "sv"), select: p.name
    iex> match?(%Ecto.Query{}, query)
    true

    iex> import Ecto.Query
    iex> query = from p in "products", select: collate(p.name < p.description, "de")
    iex> match?(%Ecto.Query{}, query)
    true

# `initcap`
*macro* 

Locale-aware `initcap()` using the collation of the current locale.

See `Localize.Ecto.Postgres.initcap/1`.

# `initcap`
*macro* 

Locale-aware `initcap()`.

See `Localize.Ecto.Postgres.initcap/2`.

# `lower`
*macro* 

Locale-aware `lower()` using the collation of the current locale.

See `Localize.Ecto.Postgres.lower/1`.

# `lower`
*macro* 

Locale-aware `lower()`.

See `Localize.Ecto.Postgres.lower/2`.

### Examples

    iex> import Ecto.Query
    iex> query = from p in "products", select: lower(p.name, "tr")
    iex> match?(%Ecto.Query{}, query)
    true

# `ts_match`
*macro* 

Locale-aware full-text search match using the current locale.

See `Localize.Ecto.Postgres.ts_match/2`.

# `ts_match`
*macro* 

Locale-aware full-text search match.

See `Localize.Ecto.Postgres.ts_match/3`.

### Examples

    iex> import Ecto.Query
    iex> query = from p in "products", where: ts_match(p.description, "wooden chair", "de"), select: p.id
    iex> match?(%Ecto.Query{}, query)
    true

# `upper`
*macro* 

Locale-aware `upper()` using the collation of the current locale.

See `Localize.Ecto.Postgres.upper/1`.

# `upper`
*macro* 

Locale-aware `upper()`.

See `Localize.Ecto.Postgres.upper/2`.

---

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