Generic SQL helpers shared across the library (and host apps that build their own queries against the GoodAnalytics tables).
Summary
Functions
Dumps a UUID string into the binary form a raw SQL parameter expects.
Escapes the LIKE/ILIKE metacharacters (\, %, _) in term so a
user-supplied search string matches literally instead of as a wildcard.
Coerces a numeric aggregate result to an integer.
Ecto query fragment that normalizes a URL column for page-level grouping:
strips the query string, collapses duplicate slashes (keeping ://), and
drops a trailing slash, defaulting empty/null to "/".
The label for the null/empty bucket in a dimension breakdown.
Functions
@spec dump_uuid!(Ecto.UUID.t()) :: binary()
Dumps a UUID string into the binary form a raw SQL parameter expects.
Raises ArgumentError when uuid is not a valid UUID.
Escapes the LIKE/ILIKE metacharacters (\, %, _) in term so a
user-supplied search string matches literally instead of as a wildcard.
Every metacharacter is escaped in a single pass, so the result is the same
regardless of which character appears first. The caller wraps the result in
%...% (or similar) and, for raw SQL, appends ESCAPE '\\' to the condition.
Examples
iex> GoodAnalytics.SQL.escape_like("50%off")
"50\\%off"
iex> GoodAnalytics.SQL.escape_like("a_b")
"a\\_b"
Coerces a numeric aggregate result to an integer.
Postgres sum/count can come back as a Decimal, a plain integer, or
nil (empty set). Returns the integer value, treating nil as 0.
Ecto query fragment that normalizes a URL column for page-level grouping:
strips the query string, collapses duplicate slashes (keeping ://), and
drops a trailing slash, defaulting empty/null to "/".
Single source of truth so the analytics "Top Pages" breakdown grouping and any drill-down filter on the same dimension stay in lockstep. Import the module and use it inside a query:
import GoodAnalytics.SQL
from(e in Event, group_by: normalized_url(e.url), select: normalized_url(e.url))
@spec not_set() :: String.t()
The label for the null/empty bucket in a dimension breakdown.
Rows whose dimension value is NULL or absent are grouped under this label
via coalesce(column, not_set()). Query builders and any consumer that
renders or joins on the bucket value must reference this single source so the
label stays consistent across grouping, joins, and display.