from __future__ import annotations
import json
from dataclasses import dataclass
from typing import Literal, Optional, Union
TaxonomyAxis = Literal["hardware", "software", "devices", "dataforts"]
@dataclass(frozen=True)
class _MatcherExact:
value: str
kind: Literal["exact"] = "exact"
@dataclass(frozen=True)
class _MatcherPrefix:
value: str
kind: Literal["prefix"] = "prefix"
@dataclass(frozen=True)
class _MatcherAxis:
axis: TaxonomyAxis
kind: Literal["axis"] = "axis"
@dataclass(frozen=True)
class _MatcherAxisKey:
axis: TaxonomyAxis
key: str
kind: Literal["axis_key"] = "axis_key"
@dataclass(frozen=True)
class _MatcherRegex:
pattern: str
kind: Literal["regex"] = "regex"
@dataclass(frozen=True)
class _MatcherVersionRange:
axis_key: str
min: Optional[str] = None
max: Optional[str] = None
kind: Literal["version_range"] = "version_range"
TagMatcher = Union[
_MatcherExact,
_MatcherPrefix,
_MatcherAxis,
_MatcherAxisKey,
_MatcherRegex,
_MatcherVersionRange,
]
class TagMatcherCls:
@staticmethod
def exact(value: str) -> TagMatcher:
return _MatcherExact(value=value)
@staticmethod
def prefix(value: str) -> TagMatcher:
return _MatcherPrefix(value=value)
@staticmethod
def axis(axis: TaxonomyAxis) -> TagMatcher:
return _MatcherAxis(axis=axis)
@staticmethod
def axis_key(axis: TaxonomyAxis, key: str) -> TagMatcher:
return _MatcherAxisKey(axis=axis, key=key)
@staticmethod
def regex(pattern: str) -> TagMatcher:
return _MatcherRegex(pattern=pattern)
@staticmethod
def version_range(
axis_key: str,
*,
min: Optional[str] = None,
max: Optional[str] = None,
) -> TagMatcher:
return _MatcherVersionRange(axis_key=axis_key, min=min, max=max)
@dataclass(frozen=True)
class _GroupClass:
kind: Literal["class"] = "class"
@dataclass(frozen=True)
class _GroupState:
kind: Literal["state"] = "state"
@dataclass(frozen=True)
class _GroupRegion:
kind: Literal["region"] = "region"
@dataclass(frozen=True)
class _GroupPublisher:
kind: Literal["publisher"] = "publisher"
@dataclass(frozen=True)
class _GroupTagStem:
prefix: str
kind: Literal["tag_stem"] = "tag_stem"
@dataclass(frozen=True)
class _GroupTagValue:
axis: TaxonomyAxis
key: str
kind: Literal["tag_value"] = "tag_value"
GroupBy = Union[
_GroupClass,
_GroupState,
_GroupRegion,
_GroupPublisher,
_GroupTagStem,
_GroupTagValue,
]
class GroupByCls:
@staticmethod
def class_() -> GroupBy:
return _GroupClass()
@staticmethod
def state() -> GroupBy:
return _GroupState()
@staticmethod
def region() -> GroupBy:
return _GroupRegion()
@staticmethod
def publisher() -> GroupBy:
return _GroupPublisher()
@staticmethod
def tag_stem(prefix: str) -> GroupBy:
return _GroupTagStem(prefix=prefix)
@staticmethod
def tag_value(axis: TaxonomyAxis, key: str) -> GroupBy:
return _GroupTagValue(axis=axis, key=key)
@dataclass(frozen=True)
class _AggCount:
kind: Literal["count"] = "count"
@dataclass(frozen=True)
class _AggDistinctPublishers:
kind: Literal["distinct_publishers"] = "distinct_publishers"
@dataclass(frozen=True)
class _AggDistinctValues:
axis: TaxonomyAxis
key: str
kind: Literal["distinct_values"] = "distinct_values"
@dataclass(frozen=True)
class _AggSumNumericTag:
axis_key: str
kind: Literal["sum_numeric_tag"] = "sum_numeric_tag"
@dataclass(frozen=True)
class _AggMinNumericTag:
axis_key: str
kind: Literal["min_numeric_tag"] = "min_numeric_tag"
@dataclass(frozen=True)
class _AggMaxNumericTag:
axis_key: str
kind: Literal["max_numeric_tag"] = "max_numeric_tag"
Aggregation = Union[
_AggCount,
_AggDistinctPublishers,
_AggDistinctValues,
_AggSumNumericTag,
_AggMinNumericTag,
_AggMaxNumericTag,
]
class AggregationCls:
@staticmethod
def count() -> Aggregation:
return _AggCount()
@staticmethod
def distinct_publishers() -> Aggregation:
return _AggDistinctPublishers()
@staticmethod
def distinct_values(axis: TaxonomyAxis, key: str) -> Aggregation:
return _AggDistinctValues(axis=axis, key=key)
@staticmethod
def sum_numeric_tag(axis_key: str) -> Aggregation:
return _AggSumNumericTag(axis_key=axis_key)
@staticmethod
def min_numeric_tag(axis_key: str) -> Aggregation:
return _AggMinNumericTag(axis_key=axis_key)
@staticmethod
def max_numeric_tag(axis_key: str) -> Aggregation:
return _AggMaxNumericTag(axis_key=axis_key)
@dataclass
class CapacityQuery:
group_by: GroupBy
matcher: Optional[TagMatcher] = None
max_rtt_ms: Optional[int] = None
sum_axis_key: Optional[str] = None
limit: int = 0
@dataclass
class CapacityRow:
bucket: str
idle: int
busy: int
reserved: int
available: int
summed_capacity: Optional[int] = None
@dataclass
class AggregateRow:
bucket: str
value: int
def _to_dict(obj: object) -> dict:
from dataclasses import asdict
return asdict(obj)
def tag_matcher_to_json(matcher: TagMatcher) -> str:
return json.dumps(_to_dict(matcher))
def group_by_to_json(group_by: GroupBy) -> str:
return json.dumps(_to_dict(group_by))
def aggregation_to_json(aggregation: Aggregation) -> str:
return json.dumps(_to_dict(aggregation))
def capacity_query_to_json(query: CapacityQuery) -> str:
matcher_dict = _to_dict(query.matcher) if query.matcher is not None else None
payload = {
"matcher": matcher_dict,
"group_by": _to_dict(query.group_by),
"max_rtt_ms": query.max_rtt_ms,
"sum_axis_key": query.sum_axis_key,
"limit": query.limit,
}
return json.dumps(payload)
__all__ = [
"Aggregation",
"AggregationCls",
"AggregateRow",
"CapacityQuery",
"CapacityRow",
"GroupBy",
"GroupByCls",
"TagMatcher",
"TagMatcherCls",
"TaxonomyAxis",
"tag_matcher_to_json",
"group_by_to_json",
"aggregation_to_json",
"capacity_query_to_json",
]