Adds the service layer for activation metrics

What does this MR do and why?

Adds the service layer for activation metrics

Database Queries

Note: This is a new table (activation_metrics) with no production data yet. Query plans should be generated against Database Lab (postgres.ai) with seeded data. See preparation when adding or modifying queries.

1. .for_user(user) scope

SELECT "activation_metrics".*
FROM "activation_metrics"
WHERE "activation_metrics"."user_id" = ?

Query plan:

2. .for_namespace(namespace) scope

SELECT "activation_metrics".*
FROM "activation_metrics"
WHERE "activation_metrics"."namespace_id" = ?

Query plan:

3. .by_metric(:merged_mr) scope

SELECT "activation_metrics".*
FROM "activation_metrics"
WHERE "activation_metrics"."metric" = 0

Query plan:

4. .completed?(user_id:, metric:, namespace_id:)

SELECT 1 AS one
FROM "activation_metrics"
WHERE "activation_metrics"."user_id" = ?
  AND "activation_metrics"."metric" = 0
  AND "activation_metrics"."namespace_id" = ?
LIMIT 1

Query plan:

5. .record_for — find_by path

SELECT "activation_metrics".*
FROM "activation_metrics"
WHERE "activation_metrics"."user_id" = ?
  AND "activation_metrics"."namespace_id" = ?
  AND "activation_metrics"."metric" = 0
LIMIT 1

Query plan:

6. .record_for — insert path

INSERT INTO "activation_metrics" ("user_id", "namespace_id", "metric", "created_at", "updated_at")
VALUES (?, ?, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
RETURNING "id"

Query plan:

7. Finder — default query

SELECT "activation_metrics".*
FROM "activation_metrics"
WHERE "activation_metrics"."user_id" = ?

Query plan:

Index usage summary

Query Index Used
.for_user unique_activation_metric_user_id_namespace_id_and_metric
.for_namespace index_activation_metrics_on_namespace_id
.by_metric unique_activation_metric_user_id_namespace_id_and_metric
.completed? unique_activation_metric_user_id_namespace_id_and_metric (index-only scan)
.record_for (find) unique_activation_metric_user_id_namespace_id_and_metric
.record_for (insert) unique_activation_metric_user_id_namespace_id_and_metric (unique constraint, NULLS NOT DISTINCT)
Finder unique_activation_metric_user_id_namespace_id_and_metric

Migration

Replaces the existing unique index with one that uses NULLS NOT DISTINCT (PostgreSQL 15+) to enforce uniqueness even when namespace_id is NULL:

  • Updated: unique_activation_metric_user_id_namespace_id_and_metric on (user_id, namespace_id, metric) — added NULLS NOT DISTINCT to treat NULL namespace_id as equal for uniqueness. Same index name retained, also provides FK index coverage for user_id

References

Screenshots or screen recordings

Before After

How to set up and validate locally

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Related to #584191

Edited by Jay Montal

Merge request reports

Loading