Database persistence for audience definitions and memberships.
Implements IAudienceRepository using next.jdbc + HoneySQL.
Column layout for audience_segments: audience_id VARCHAR — keyword name (e.g. "premium-users") filters TEXT/JSONB — serialised as JSON tags TEXT/JSONB — serialised as JSON composition TEXT/JSONB — optional, serialised as JSON cache_config TEXT/JSONB — optional, serialised as JSON
JSON columns use cheshire for serialisation. On PostgreSQL the
columns are JSONB; on H2 (tests) they are stored as TEXT — both
are handled by ->json below.
Database persistence for audience definitions and memberships. Implements IAudienceRepository using next.jdbc + HoneySQL. Column layout for audience_segments: audience_id VARCHAR — keyword name (e.g. "premium-users") filters TEXT/JSONB — serialised as JSON tags TEXT/JSONB — serialised as JSON composition TEXT/JSONB — optional, serialised as JSON cache_config TEXT/JSONB — optional, serialised as JSON JSON columns use cheshire for serialisation. On PostgreSQL the columns are JSONB; on H2 (tests) they are stored as TEXT — both are handled by `->json` below.
(<-json value)Deserialise a DB JSON value back to Clojure data.
Public because it is the only decoder that knows about all three shapes a
JSON column arrives in, and cache.clj had a fourth, narrower copy that
handled maps and strings and returned nil for a PGobject — so on PostgreSQL
every cached audience read its TTL as nil, missed the cache and recomputed
its membership on every resolve (BOU-419 review).
Handles:
Deserialise a DB JSON value back to Clojure data. Public because it is the only decoder that knows about all three shapes a JSON column arrives in, and `cache.clj` had a fourth, narrower copy that handled maps and strings and returned nil for a PGobject — so on PostgreSQL every cached audience read its TTL as nil, missed the cache and recomputed its membership on every resolve (BOU-419 review). Handles: - nil → nil - already-parsed map / vector → as-is - String → parsed with keyword keys - org.postgresql.util.PGobject → .getValue then parsed
(audience-ddl dialect)DDL for the audience tables, for one adapter.
Written once here rather than as a PostgreSQL migration plus a hand-copied H2 variant in a test fixture, which is how those two drifted.
DDL for the audience tables, for one adapter. Written once here rather than as a PostgreSQL migration plus a hand-copied H2 variant in a test fixture, which is how those two drifted.
(clear-memberships! datasource audience-id)Delete all membership records for the given audience.
Args: datasource - javax.sql.DataSource audience-id - keyword
Returns: nil
Delete all membership records for the given audience. Args: datasource - javax.sql.DataSource audience-id - keyword Returns: nil
(create-audience-store datasource)Create an AudienceStore backed by a JDBC datasource.
Args: datasource - javax.sql.DataSource (HikariCP pool or plain)
Returns: AudienceStore implementing IAudienceRepository
Create an AudienceStore backed by a JDBC datasource. Args: datasource - javax.sql.DataSource (HikariCP pool or plain) Returns: AudienceStore implementing IAudienceRepository
(dialect datasource)The adapter behind datasource, from its product name.
The adapter behind `datasource`, from its product name.
(get-memberships datasource audience-id)Return all user UUIDs that are members of the given audience.
Args: datasource - javax.sql.DataSource audience-id - keyword
Returns: Vector of java.util.UUID, or [] if the segment does not exist
Return all user UUIDs that are members of the given audience. Args: datasource - javax.sql.DataSource audience-id - keyword Returns: Vector of java.util.UUID, or [] if the segment does not exist
(initialize-audience-schema! datasource)Create the audience tables if absent. Idempotent.
Create the audience tables if absent. Idempotent.
(json-param dialect v)A JSON string as dialect accepts it in an INSERT or UPDATE.
PostgreSQL declares these columns JSONB and refuses a string parameter —
"column is of type jsonb but expression is of type character varying". The
other three adapters store TEXT and take it as is. A cast rather than a
PGobject so this needs no PostgreSQL class on the classpath, the way
<-json above already avoids one on the read side.
Audience had never run against PostgreSQL: its only fixture was H2, whose columns were TEXT, and the JSONB migration ran nowhere (BOU-419 review).
A JSON string as `dialect` accepts it in an INSERT or UPDATE. PostgreSQL declares these columns `JSONB` and refuses a string parameter — "column is of type jsonb but expression is of type character varying". The other three adapters store TEXT and take it as is. A cast rather than a `PGobject` so this needs no PostgreSQL class on the classpath, the way `<-json` above already avoids one on the read side. Audience had never run against PostgreSQL: its only fixture was H2, whose columns were TEXT, and the JSONB migration ran nowhere (BOU-419 review).
(save-memberships! datasource audience-id user-ids)Batch-insert user UUIDs into audience_memberships for an audience.
Idempotent: one SELECT fetches the audience's existing user-ids, the already-present ids are removed in memory, and only the missing ones are inserted via chunked multi-row INSERTs — all inside a single transaction. This keeps the SQL portable across H2 and PostgreSQL (no ON CONFLICT) and avoids per-user round-trips.
Args: datasource - javax.sql.DataSource audience-id - keyword (e.g. :premium-users) user-ids - collection of java.util.UUID
Returns: nil
Batch-insert user UUIDs into audience_memberships for an audience. Idempotent: one SELECT fetches the audience's existing user-ids, the already-present ids are removed in memory, and only the missing ones are inserted via chunked multi-row INSERTs — all inside a single transaction. This keeps the SQL portable across H2 and PostgreSQL (no ON CONFLICT) and avoids per-user round-trips. Args: datasource - javax.sql.DataSource audience-id - keyword (e.g. :premium-users) user-ids - collection of java.util.UUID Returns: nil
(uuid-value dialect u)A UUID as dialect stores it.
H2 and PostgreSQL have a real UUID column and reject a string parameter — "column is of type uuid but expression is of type character varying". SQLite (TEXT) and MySQL (CHAR(36)) have no UUID type to convert to.
A UUID as `dialect` stores it. H2 and PostgreSQL have a real UUID column and reject a string parameter — "column is of type uuid but expression is of type character varying". SQLite (TEXT) and MySQL (CHAR(36)) have no UUID type to convert to.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |