Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions bbconf/bbagent.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import datetime
import logging
import statistics
import threading
Expand Down Expand Up @@ -32,7 +33,9 @@
FileStats,
GEOStatistics,
StatsReturn,
UsageItem,
UsageModel,
UsageResponse,
UsageStats,
)
from bbconf.modules.analysis_files import BedAgentAnalysisFile
Expand Down Expand Up @@ -401,6 +404,97 @@ def get_detailed_usage(self) -> UsageStats:
bed_downloads=bed_downloads,
)

def get_usage(
Comment thread
nsheff marked this conversation as resolved.
self,
event_type: str,
date_from: datetime.datetime | None = None,
date_to: datetime.datetime | None = None,
limit: int | None = None,
offset: int = 0,
) -> UsageResponse:
"""
Get per-key usage counts for a single event type, optionally restricted
to a date range.

Unlike get_detailed_usage (which sums across all time and is hardcoded to
the top 20 keys), this method groups by key and sums the counts of the
time-bucketed rows whose window overlaps the requested date range, and
supports pagination. It is read-only and does not modify any usage data.

Args:
event_type: One of "files", "bed_meta", "bedset_meta", "bed_search",
"bedset_search".
date_from: Include only rows whose window ends on or after this date
(date_to >= date_from). None means no lower bound.
date_to: Include only rows whose window starts on or before this date
(date_from <= date_to). None means no upper bound.
limit: Maximum number of keys to return. None means no limit.
offset: Number of keys to skip (for pagination).

Returns:
UsageResponse with per-key counts ordered by count descending.
"""
# model, key column, and (for UsageSearch) the `type` filter value.
usage_map = {
"files": (UsageFiles, UsageFiles.file_path, None),
"bed_meta": (UsageBedMeta, UsageBedMeta.bed_id, None),
"bedset_meta": (UsageBedSetMeta, UsageBedSetMeta.bedset_id, None),
"bed_search": (UsageSearch, UsageSearch.query, "bed"),
"bedset_search": (UsageSearch, UsageSearch.query, "bedset"),
}

if event_type not in usage_map:
raise ValueError(
f"Invalid event_type '{event_type}'. Must be one of: "
f"{', '.join(usage_map)}."
)

model, key_column, search_type = usage_map[event_type]

_LOGGER.info(f"Getting usage statistics for event type '{event_type}'.")

statement = (
select(key_column, func.sum(model.count))
.group_by(key_column)
.order_by(func.sum(model.count).desc())
)

statement = statement.where(key_column.isnot(None), key_column != "")
if search_type is not None:
statement = statement.where(model.type == search_type)
if date_from is not None:
statement = statement.where(model.date_to >= date_from)
if date_to is not None:
statement = statement.where(model.date_from <= date_to)

if limit is not None:
statement = statement.limit(limit).offset(offset)
elif offset:
statement = statement.offset(offset)

# bed downloads are keyed by file path; shorten to the bed id, matching
# get_detailed_usage.
shorten_key = event_type == "files"

with Session(self.config.db_engine.engine) as session:
results = [
UsageItem(
key=(f[0].split("/")[-1].split(".")[0] if shorten_key else f[0]),
count=f[1],
)
for f in session.execute(statement).all()
]

return UsageResponse(
event_type=event_type,
date_from=date_from,
date_to=date_to,
limit=limit,
offset=offset,
count=len(results),
results=results,
)

def get_list_genomes(self) -> list[str]:
"""
Get list of genomes from the database.
Expand Down
24 changes: 24 additions & 0 deletions bbconf/models/base_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,30 @@ class UsageModel(BaseModel):
date_to: datetime.datetime | None = None


class UsageItem(BaseModel):
"""
A single per-key usage count.
"""

key: str
count: int


class UsageResponse(BaseModel):
"""
Per-key usage counts for a single event type, optionally restricted to a
date range. Returned by BedBaseAgent.get_usage.
"""

event_type: str
date_from: datetime.datetime | None = None
date_to: datetime.datetime | None = None
limit: int | None = None
offset: int = 0
count: int
results: list[UsageItem]


class FileInfo(BaseModel):
"""
Main information about a file used for BEDbase verse statistics.
Expand Down