Skip to content

Commit 927237c

Browse files
ref
1 parent 92dfd12 commit 927237c

File tree

2 files changed

+29
-16
lines changed

2 files changed

+29
-16
lines changed

src/sentry/billing/platform/services/usage/_outcomes_query.py

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def query_orgs_with_usage(request: GetOrgsWithUsageRequest) -> GetOrgsWithUsageR
6161

6262
offset = request.page_token.offset if request.HasField("page_token") else 0
6363

64-
snuba_request = _build_orgs_query(
64+
snuba_request = _build_distinct_orgs_query(
6565
start=start,
6666
end=end,
6767
categories=categories,
@@ -96,7 +96,9 @@ def query_outcomes_usage(request: GetUsageRequest) -> GetUsageResponse:
9696
# (e.g., proto ATTACHMENT=3 vs Relay ATTACHMENT=4). Convert before querying.
9797
categories = [proto_to_sentry_category(c) for c in request.categories]
9898

99-
snuba_request = _build_query(org_id, start, end, categories, total_outcomes=_BILLABLE_OUTCOMES)
99+
snuba_request = _build_usage_query(
100+
org_id, start, end, categories, total_outcomes=_BILLABLE_OUTCOMES
101+
)
100102
result = raw_snql_query(snuba_request, referrer=_REFERRER)
101103
rows = result["data"]
102104

@@ -114,7 +116,7 @@ def query_outcomes_usage(request: GetUsageRequest) -> GetUsageResponse:
114116
return _build_response(rows)
115117

116118

117-
def _build_orgs_query(
119+
def _build_distinct_orgs_query(
118120
start: datetime,
119121
end: datetime,
120122
categories: Sequence[int],
@@ -150,8 +152,8 @@ def _build_orgs_query(
150152
)
151153

152154

153-
def _build_query(
154-
org_id: int,
155+
def _build_usage_query(
156+
org_id: int | None,
155157
start: datetime,
156158
end: datetime,
157159
categories: Sequence[int],
@@ -160,14 +162,16 @@ def _build_query(
160162
limit: int = _QUERY_LIMIT,
161163
offset: int = 0,
162164
) -> Request:
165+
"""Build a per-category, per-day usage breakdown query."""
163166
# Half-open interval [start, end) — standard sentry.snuba.outcomes convention.
164167
# `end` has already been shifted +1 day in query_outcomes_usage() to convert
165168
# the proto's inclusive end into the exclusive boundary Snuba expects.
166169
where = [
167170
Condition(Column("timestamp"), Op.GTE, start),
168171
Condition(Column("timestamp"), Op.LT, end),
169-
Condition(Column("org_id"), Op.EQ, org_id),
170172
]
173+
if org_id is not None:
174+
where.append(Condition(Column("org_id"), Op.EQ, org_id))
171175
if categories:
172176
where.append(Condition(Column("category"), Op.IN, categories))
173177

@@ -224,22 +228,31 @@ def _build_query(
224228
),
225229
]
226230

231+
groupby = [Column("category"), Column("time")]
232+
if org_id is None:
233+
select.insert(0, Column("org_id"))
234+
groupby.insert(0, Column("org_id"))
235+
227236
query = Query(
228237
match=Entity("outcomes"),
229238
select=select,
230-
groupby=[Column("category"), Column("time")],
239+
groupby=groupby,
231240
where=where,
232241
orderby=[OrderBy(Column("time"), Direction.ASC)],
233242
granularity=Granularity(_DAILY_GRANULARITY),
234243
limit=Limit(limit),
235244
offset=Offset(offset),
236245
)
237246

247+
tenant_ids: dict[str, int] = {}
248+
if org_id is not None:
249+
tenant_ids["organization_id"] = org_id
250+
238251
return Request(
239252
dataset=_DATASET,
240253
app_id=_APP_ID,
241254
query=query,
242-
tenant_ids={"organization_id": org_id},
255+
tenant_ids=tenant_ids,
243256
)
244257

245258

tests/sentry/billing/platform/services/usage/test_outcomes_query.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818

1919
from sentry.billing.platform.services.usage._outcomes_query import (
2020
_BILLABLE_OUTCOMES,
21-
_build_query,
2221
_build_response,
22+
_build_usage_query,
2323
_over_quota_condition,
2424
_total_function,
2525
query_orgs_with_usage,
@@ -182,7 +182,7 @@ def test_build_query_with_categories(self):
182182
start = datetime(2025, 3, 1, tzinfo=timezone.utc)
183183
end = datetime(2025, 3, 31, tzinfo=timezone.utc)
184184

185-
snuba_request = _build_query(org_id=1, start=start, end=end, categories=[1, 2])
185+
snuba_request = _build_usage_query(org_id=1, start=start, end=end, categories=[1, 2])
186186

187187
query = snuba_request.query
188188
category_conditions = [
@@ -196,7 +196,7 @@ def test_build_query_no_categories(self):
196196
start = datetime(2025, 3, 1, tzinfo=timezone.utc)
197197
end = datetime(2025, 3, 31, tzinfo=timezone.utc)
198198

199-
snuba_request = _build_query(org_id=1, start=start, end=end, categories=[])
199+
snuba_request = _build_usage_query(org_id=1, start=start, end=end, categories=[])
200200

201201
query = snuba_request.query
202202
category_conditions = [
@@ -208,7 +208,7 @@ def test_build_query_basic_structure(self):
208208
start = datetime(2025, 3, 1, tzinfo=timezone.utc)
209209
end = datetime(2025, 3, 31, tzinfo=timezone.utc)
210210

211-
snuba_request = _build_query(org_id=42, start=start, end=end, categories=[])
211+
snuba_request = _build_usage_query(org_id=42, start=start, end=end, categories=[])
212212

213213
assert snuba_request.dataset == "outcomes"
214214
assert snuba_request.app_id == "billing"
@@ -223,7 +223,7 @@ def test_build_query_groups_by_category_and_time_only(self):
223223
start = datetime(2025, 3, 1, tzinfo=timezone.utc)
224224
end = datetime(2025, 3, 31, tzinfo=timezone.utc)
225225

226-
snuba_request = _build_query(org_id=1, start=start, end=end, categories=[])
226+
snuba_request = _build_usage_query(org_id=1, start=start, end=end, categories=[])
227227

228228
groupby_names = [col.name for col in snuba_request.query.groupby]
229229
assert groupby_names == ["category", "time"]
@@ -232,7 +232,7 @@ def test_build_query_total_filters_billable_outcomes(self):
232232
start = datetime(2025, 3, 1, tzinfo=timezone.utc)
233233
end = datetime(2025, 3, 31, tzinfo=timezone.utc)
234234

235-
snuba_request = _build_query(
235+
snuba_request = _build_usage_query(
236236
org_id=1, start=start, end=end, categories=[], total_outcomes=_BILLABLE_OUTCOMES
237237
)
238238

@@ -258,7 +258,7 @@ def test_build_query_total_all_outcomes_when_none(self):
258258
start = datetime(2025, 3, 1, tzinfo=timezone.utc)
259259
end = datetime(2025, 3, 31, tzinfo=timezone.utc)
260260

261-
snuba_request = _build_query(
261+
snuba_request = _build_usage_query(
262262
org_id=1, start=start, end=end, categories=[], total_outcomes=None
263263
)
264264

@@ -281,7 +281,7 @@ def test_build_query_select_has_sumif_columns(self):
281281
start = datetime(2025, 3, 1, tzinfo=timezone.utc)
282282
end = datetime(2025, 3, 31, tzinfo=timezone.utc)
283283

284-
snuba_request = _build_query(org_id=1, start=start, end=end, categories=[])
284+
snuba_request = _build_usage_query(org_id=1, start=start, end=end, categories=[])
285285

286286
select = snuba_request.query.select
287287
aliases = []

0 commit comments

Comments
 (0)