Dx.Ecto.Query.Batches (dx v0.3.5)

View Source

Determines which field to batch queries by.

Problem

We have data requirements that need to be fulfilled by executing queries.

Each data requirement consists of a group, for example a set of fixed options for running a query, and a list of filters, each filter being a field + value to match on.

Each query can only have one field to be batched on, i.e. one field takes a list of values to fulfill multiple data requirements.

The goal is to minimize the number of queries. This is trivial when filtering by 0 or 1 fields. When filtering by 2 or more fields, some work must be done to determine the ideal field to batch by.

Approach

We basically count the filter combinations for each potential field to batch on. Each combination consists of the field to batch on + all other filters as a fixed set.

Examples

iex> add_filters(:query1, [color: "red", char: "A"])
...> |> get_batches()
[
  query1: [
    {:char, ["A"], color: "red"}
  ]
]

iex> add_filters(:query1, [color: "red", char: "A"])
...> |> add_filters(:query1, [color: "blue", char: "A"])
...> |> get_batches()
[
  query1: [
    {:color, ["blue", "red"], char: "A"}
  ]
]

iex> add_filters(:query1, [color: "red", char: "A", size: "L"])
...> |> add_filters(:query1, [color: "blue", size: "S", char: "A"])
...> |> add_filters(:query1, [color: "pink", size: "S", char: "B"])
...> |> add_filters(:query1, [color: "pink", size: "S", char: "A"])
...> |> get_batches()
[
  query1: [
    {:char, ["A"], color: "blue", size: "S"},
    {:char, ["A", "B"], color: "pink", size: "S"},
    {:char, ["A"], color: "red", size: "L"}
  ]
]

iex> add_filters(:query1, [color: "red"])
...> |> add_filters(:query1, [color: "blue"])
...> |> get_batches()
[
  query1: [
    {:color, ["blue", "red"], []}
  ]
]

iex> add_filters(:query1, [])
...> |> get_batches()
[
  query1: [
    {}
  ]
]

Summary

Functions

Adds one data requirement, consisting of a group + list of filters, to a given (or newly initialized) state

Returns an optimal set of batches for the given state returned by the other functions.

Initializes a new state to call other functions on

Functions

add_filters(state \\ %{}, group, filters)

Adds one data requirement, consisting of a group + list of filters, to a given (or newly initialized) state

get_batches(state)

Returns an optimal set of batches for the given state returned by the other functions.

Format

[
  group1: [
    {:batch_key, list_of_values, other_filters_keyword},
    # ...
  ],
  # ...
]

map_put_in(map, list, value)

new()

Initializes a new state to call other functions on