server: api doc part 3

This commit is contained in:
nym21
2025-10-08 17:48:15 +02:00
parent a53f89c849
commit 114228e8eb
29 changed files with 645 additions and 319 deletions
+13
View File
@@ -0,0 +1,13 @@
use schemars::JsonSchema;
use serde::Serialize;
#[derive(Debug, Serialize, JsonSchema)]
/// Metric count statistics - distinct metrics and total metric-index combinations
pub struct MetricCount {
#[schemars(example = 3141)]
/// Number of unique metrics available (e.g., realized_price, market_cap)
pub distinct_metrics: usize,
#[schemars(example = 21000)]
/// Total number of metric-index combinations across all timeframes
pub total_endpoints: usize,
}
-241
View File
@@ -1,241 +0,0 @@
use std::{
collections::BTreeMap,
fmt::{self, Debug},
};
use brk_error::Error;
use brk_structs::{
DateIndex, DecadeIndex, DifficultyEpoch, EmptyAddressIndex, EmptyOutputIndex, HalvingEpoch,
Height, InputIndex, LoadedAddressIndex, MonthIndex, OpReturnIndex, OutputIndex,
P2AAddressIndex, P2MSOutputIndex, P2PK33AddressIndex, P2PK65AddressIndex, P2PKHAddressIndex,
P2SHAddressIndex, P2TRAddressIndex, P2WPKHAddressIndex, P2WSHAddressIndex, PrintableIndex,
QuarterIndex, SemesterIndex, TxIndex, UnknownOutputIndex, WeekIndex, YearIndex,
};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Default, Serialize, JsonSchema)]
/// Indexes and their accepted variants
pub struct Indexes(BTreeMap<Index, &'static [&'static str]>);
impl Indexes {
pub fn new(tree: BTreeMap<Index, &'static [&'static str]>) -> Self {
Self(tree)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum Index {
#[schemars(description = "Date/day index")]
DateIndex,
#[schemars(description = "Decade index")]
DecadeIndex,
#[schemars(description = "Difficulty epoch index (equivalent to ~2 weeks)")]
DifficultyEpoch,
#[schemars(description = "Empty output index")]
EmptyOutputIndex,
#[schemars(description = "Halving epoch index (equivalent to ~4 years)")]
HalvingEpoch,
#[schemars(description = "Height/block index")]
Height,
#[schemars(description = "Transaction input index (based on total)")]
InputIndex,
#[schemars(description = "Month index")]
MonthIndex,
#[schemars(description = "Op return index")]
OpReturnIndex,
#[schemars(description = "Transaction output index (based on total)")]
OutputIndex,
#[schemars(description = "Index of P2A address")]
P2AAddressIndex,
#[schemars(description = "Index of P2MS output")]
P2MSOutputIndex,
#[schemars(description = "Index of P2PK (33 bytes) address")]
P2PK33AddressIndex,
#[schemars(description = "Index of P2PK (65 bytes) address")]
P2PK65AddressIndex,
#[schemars(description = "Index of P2PKH address")]
P2PKHAddressIndex,
#[schemars(description = "Index of P2SH address")]
P2SHAddressIndex,
#[schemars(description = "Index of P2TR address")]
P2TRAddressIndex,
#[schemars(description = "Index of P2WPKH address")]
P2WPKHAddressIndex,
#[schemars(description = "Index of P2WSH address")]
P2WSHAddressIndex,
#[schemars(description = "Quarter index")]
QuarterIndex,
#[schemars(description = "Semester index")]
SemesterIndex,
#[schemars(description = "Transaction index")]
TxIndex,
#[schemars(description = "Unknown output index")]
UnknownOutputIndex,
#[schemars(description = "Week index")]
WeekIndex,
#[schemars(description = "Year index")]
YearIndex,
#[schemars(description = "Loaded Address Index")]
LoadedAddressIndex,
#[schemars(description = "Empty Address Index")]
EmptyAddressIndex,
}
impl Index {
pub fn all() -> [Self; 27] {
[
Self::DateIndex,
Self::DecadeIndex,
Self::DifficultyEpoch,
Self::EmptyOutputIndex,
Self::HalvingEpoch,
Self::Height,
Self::InputIndex,
Self::MonthIndex,
Self::OpReturnIndex,
Self::OutputIndex,
Self::P2AAddressIndex,
Self::P2MSOutputIndex,
Self::P2PK33AddressIndex,
Self::P2PK65AddressIndex,
Self::P2PKHAddressIndex,
Self::P2SHAddressIndex,
Self::P2TRAddressIndex,
Self::P2WPKHAddressIndex,
Self::P2WSHAddressIndex,
Self::QuarterIndex,
Self::SemesterIndex,
Self::TxIndex,
Self::UnknownOutputIndex,
Self::WeekIndex,
Self::YearIndex,
Self::LoadedAddressIndex,
Self::EmptyAddressIndex,
]
}
pub fn possible_values(&self) -> &'static [&'static str] {
match self {
Self::DateIndex => DateIndex::to_possible_strings(),
Self::DecadeIndex => DecadeIndex::to_possible_strings(),
Self::DifficultyEpoch => DifficultyEpoch::to_possible_strings(),
Self::EmptyOutputIndex => EmptyOutputIndex::to_possible_strings(),
Self::HalvingEpoch => HalvingEpoch::to_possible_strings(),
Self::Height => Height::to_possible_strings(),
Self::InputIndex => InputIndex::to_possible_strings(),
Self::MonthIndex => MonthIndex::to_possible_strings(),
Self::OpReturnIndex => OpReturnIndex::to_possible_strings(),
Self::OutputIndex => OutputIndex::to_possible_strings(),
Self::P2AAddressIndex => P2AAddressIndex::to_possible_strings(),
Self::P2MSOutputIndex => P2MSOutputIndex::to_possible_strings(),
Self::P2PK33AddressIndex => P2PK33AddressIndex::to_possible_strings(),
Self::P2PK65AddressIndex => P2PK65AddressIndex::to_possible_strings(),
Self::P2PKHAddressIndex => P2PKHAddressIndex::to_possible_strings(),
Self::P2SHAddressIndex => P2SHAddressIndex::to_possible_strings(),
Self::P2TRAddressIndex => P2TRAddressIndex::to_possible_strings(),
Self::P2WPKHAddressIndex => P2WPKHAddressIndex::to_possible_strings(),
Self::P2WSHAddressIndex => P2WSHAddressIndex::to_possible_strings(),
Self::QuarterIndex => QuarterIndex::to_possible_strings(),
Self::SemesterIndex => SemesterIndex::to_possible_strings(),
Self::TxIndex => TxIndex::to_possible_strings(),
Self::UnknownOutputIndex => UnknownOutputIndex::to_possible_strings(),
Self::WeekIndex => WeekIndex::to_possible_strings(),
Self::YearIndex => YearIndex::to_possible_strings(),
Self::LoadedAddressIndex => LoadedAddressIndex::to_possible_strings(),
Self::EmptyAddressIndex => EmptyAddressIndex::to_possible_strings(),
}
}
pub fn all_possible_values() -> Vec<&'static str> {
Self::all()
.into_iter()
.flat_map(|i| i.possible_values().iter().cloned())
.collect::<Vec<_>>()
}
pub fn serialize_short(&self) -> &'static str {
self.possible_values()
.iter()
.find(|str| str.len() > 1)
.unwrap()
}
pub fn serialize_long(&self) -> &'static str {
self.possible_values().last().unwrap()
}
}
impl TryFrom<&str> for Index {
type Error = Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
Ok(match value.to_lowercase().as_str() {
v if (Self::DateIndex).possible_values().contains(&v) => Self::DateIndex,
v if (Self::DecadeIndex).possible_values().contains(&v) => Self::DecadeIndex,
v if (Self::DifficultyEpoch).possible_values().contains(&v) => Self::DifficultyEpoch,
v if (Self::EmptyOutputIndex).possible_values().contains(&v) => Self::EmptyOutputIndex,
v if (Self::HalvingEpoch).possible_values().contains(&v) => Self::HalvingEpoch,
v if (Self::Height).possible_values().contains(&v) => Self::Height,
v if (Self::InputIndex).possible_values().contains(&v) => Self::InputIndex,
v if (Self::MonthIndex).possible_values().contains(&v) => Self::MonthIndex,
v if (Self::OpReturnIndex).possible_values().contains(&v) => Self::OpReturnIndex,
v if (Self::OutputIndex).possible_values().contains(&v) => Self::OutputIndex,
v if (Self::P2AAddressIndex).possible_values().contains(&v) => Self::P2AAddressIndex,
v if (Self::P2MSOutputIndex).possible_values().contains(&v) => Self::P2MSOutputIndex,
v if (Self::P2PK33AddressIndex).possible_values().contains(&v) => {
Self::P2PK33AddressIndex
}
v if (Self::P2PK65AddressIndex).possible_values().contains(&v) => {
Self::P2PK65AddressIndex
}
v if (Self::P2PKHAddressIndex).possible_values().contains(&v) => {
Self::P2PKHAddressIndex
}
v if (Self::P2SHAddressIndex).possible_values().contains(&v) => Self::P2SHAddressIndex,
v if (Self::P2TRAddressIndex).possible_values().contains(&v) => Self::P2TRAddressIndex,
v if (Self::P2WPKHAddressIndex).possible_values().contains(&v) => {
Self::P2WPKHAddressIndex
}
v if (Self::P2WSHAddressIndex).possible_values().contains(&v) => {
Self::P2WSHAddressIndex
}
v if (Self::QuarterIndex).possible_values().contains(&v) => Self::QuarterIndex,
v if (Self::SemesterIndex).possible_values().contains(&v) => Self::SemesterIndex,
v if (Self::TxIndex).possible_values().contains(&v) => Self::TxIndex,
v if (Self::WeekIndex).possible_values().contains(&v) => Self::WeekIndex,
v if (Self::YearIndex).possible_values().contains(&v) => Self::YearIndex,
v if (Self::UnknownOutputIndex).possible_values().contains(&v) => {
Self::UnknownOutputIndex
}
v if (Self::LoadedAddressIndex).possible_values().contains(&v) => {
Self::LoadedAddressIndex
}
v if (Self::EmptyAddressIndex).possible_values().contains(&v) => {
Self::EmptyAddressIndex
}
_ => return Err(Error::Str("Bad index")),
})
}
}
impl fmt::Display for Index {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{self:?}")
}
}
impl<'de> Deserialize<'de> for Index {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let str = String::deserialize(deserializer)?;
if let Ok(index) = Index::try_from(str.as_str()) {
// dbg!(index);
Ok(index)
} else {
Err(serde::de::Error::custom("Bad index"))
}
}
}
+13 -7
View File
@@ -6,7 +6,7 @@ use brk_computer::Computer;
use brk_error::{Error, Result};
use brk_indexer::Indexer;
use brk_parser::Parser;
use brk_structs::Height;
use brk_structs::{Height, Index, IndexInfo};
use brk_traversable::TreeNode;
use nucleo_matcher::{
Config, Matcher,
@@ -15,21 +15,20 @@ use nucleo_matcher::{
use quick_cache::sync::Cache;
use vecdb::{AnyCollectableVec, AnyStoredVec};
mod count;
mod deser;
mod format;
mod index;
mod metrics;
mod output;
mod pagination;
mod params;
mod vecs;
pub use count::*;
pub use format::Format;
pub use index::*;
pub use output::{Output, Value};
pub use pagination::{PaginatedIndexParam, PaginationParam};
pub use pagination::{PaginatedIndexParam, PaginatedMetrics, PaginationParam};
pub use params::{Params, ParamsDeprec, ParamsOpt};
pub use vecs::PaginatedMetrics;
use vecs::Vecs;
use crate::vecs::{IndexToVec, MetricToVec};
@@ -229,6 +228,13 @@ impl<'a> Interface<'a> {
&self.vecs.index_to_metric_to_vec
}
pub fn metric_count(&self) -> MetricCount {
MetricCount {
distinct_metrics: self.distinct_metric_count(),
total_endpoints: self.total_metric_count(),
}
}
pub fn distinct_metric_count(&self) -> usize {
self.vecs.distinct_metric_count
}
@@ -237,7 +243,7 @@ impl<'a> Interface<'a> {
self.vecs.total_metric_count
}
pub fn get_indexes(&self) -> &Indexes {
pub fn get_indexes(&self) -> &[IndexInfo] {
&self.vecs.indexes
}
@@ -253,7 +259,7 @@ impl<'a> Interface<'a> {
self.vecs.index_to_ids(paginated_index)
}
pub fn metric_to_indexes(&self, metric: String) -> Option<&Vec<&'static str>> {
pub fn metric_to_indexes(&self, metric: String) -> Option<&Vec<Index>> {
self.vecs.metric_to_indexes(metric)
}
+16 -1
View File
@@ -1,7 +1,8 @@
use brk_structs::Index;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::{Index, deser::de_unquote_usize};
use crate::deser::de_unquote_usize;
#[derive(Debug, Default, Serialize, Deserialize, JsonSchema)]
pub struct PaginationParam {
@@ -28,3 +29,17 @@ pub struct PaginatedIndexParam {
#[serde(flatten)]
pub pagination: PaginationParam,
}
/// A paginated list of available metric names (1000 per page)
#[derive(Debug, Serialize, JsonSchema)]
pub struct PaginatedMetrics {
/// Current page number (0-indexed)
#[schemars(example = 0)]
pub current_page: usize,
/// Maximum valid page index (0-indexed)
#[schemars(example = 21000)]
pub max_page: usize,
/// List of metric names (max 1000 per page)
#[schemars(example = ["price_open", "price_close", "realized_price", "..."])]
pub metrics: &'static [&'static str],
}
+8 -13
View File
@@ -1,22 +1,23 @@
use std::ops::Deref;
use brk_structs::Index;
use schemars::JsonSchema;
use serde::Deserialize;
use crate::{
Format, Index,
Format,
deser::{de_unquote_i64, de_unquote_usize},
metrics::MaybeMetrics,
};
#[derive(Debug, Deserialize, JsonSchema)]
pub struct Params {
/// Requested metrics
#[serde(alias = "m")]
#[schemars(description = "Requested metrics")]
pub metrics: MaybeMetrics,
/// Requested index
#[serde(alias = "i")]
#[schemars(description = "Requested index")]
pub index: Index,
#[serde(flatten)]
@@ -42,26 +43,20 @@ impl From<((Index, String), ParamsOpt)> for Params {
#[derive(Default, Debug, Deserialize, JsonSchema)]
pub struct ParamsOpt {
#[serde(default, alias = "f", deserialize_with = "de_unquote_i64")]
/// Inclusive starting index, if negative will be from the end
#[schemars(description = "Inclusive starting index, if negative will be from the end")]
#[serde(default, alias = "f", deserialize_with = "de_unquote_i64")]
from: Option<i64>,
#[serde(default, alias = "t", deserialize_with = "de_unquote_i64")]
/// Exclusive ending index, if negative will be from the end, overrides 'count'
#[schemars(
description = "Exclusive ending index, if negative will be from the end, overrides 'count'"
)]
#[serde(default, alias = "t", deserialize_with = "de_unquote_i64")]
to: Option<i64>,
#[serde(default, alias = "c", deserialize_with = "de_unquote_usize")]
/// Number of values requested
#[schemars(description = "Number of values requested")]
#[serde(default, alias = "c", deserialize_with = "de_unquote_usize")]
count: Option<usize>,
#[serde(default)]
/// Format of the output
#[schemars(description = "Format of the output")]
#[serde(default)]
format: Format,
}
+16 -41
View File
@@ -2,29 +2,23 @@ use std::collections::BTreeMap;
use brk_computer::Computer;
use brk_indexer::Indexer;
use brk_structs::{Index, IndexInfo};
use brk_traversable::{Traversable, TreeNode};
use derive_deref::{Deref, DerefMut};
use schemars::JsonSchema;
use serde::Serialize;
use vecdb::AnyCollectableVec;
use crate::{
index::Indexes,
pagination::{PaginatedIndexParam, PaginationParam},
};
use super::index::Index;
use crate::pagination::{PaginatedIndexParam, PaginatedMetrics, PaginationParam};
#[derive(Default)]
pub struct Vecs<'a> {
pub metric_to_index_to_vec: BTreeMap<&'a str, IndexToVec<'a>>,
pub index_to_metric_to_vec: BTreeMap<Index, MetricToVec<'a>>,
pub metrics: Vec<&'a str>,
pub indexes: Indexes,
pub indexes: Vec<IndexInfo>,
pub distinct_metric_count: usize,
pub total_metric_count: usize,
pub catalog: Option<TreeNode>,
metric_to_indexes: BTreeMap<&'a str, Vec<&'static str>>,
metric_to_indexes: BTreeMap<&'a str, Vec<Index>>,
index_to_metrics: BTreeMap<Index, Vec<&'a str>>,
}
@@ -67,24 +61,19 @@ impl<'a> Vecs<'a> {
.values()
.map(|tree| tree.len())
.sum::<usize>();
this.indexes = Indexes::new(
this.index_to_metric_to_vec
.keys()
.map(|i| (*i, i.possible_values()))
.collect::<BTreeMap<_, _>>(),
);
this.indexes = this
.index_to_metric_to_vec
.keys()
.map(|i| IndexInfo {
index: *i,
aliases: i.possible_values(),
})
.collect();
this.metric_to_indexes = this
.metric_to_index_to_vec
.iter()
.map(|(id, index_to_vec)| {
(
*id,
index_to_vec
.keys()
.map(|i| i.serialize_long())
.collect::<Vec<_>>(),
)
})
.map(|(id, index_to_vec)| (*id, index_to_vec.keys().copied().collect::<Vec<_>>()))
.collect();
this.index_to_metrics = this
.index_to_metric_to_vec
@@ -142,12 +131,12 @@ impl<'a> Vecs<'a> {
PaginatedMetrics {
current_page: pagination.page.unwrap_or_default(),
total_pages: len / PaginationParam::PER_PAGE,
max_page: len.div_ceil(PaginationParam::PER_PAGE).saturating_sub(1),
metrics: &self.metrics[start..end],
}
}
pub fn metric_to_indexes(&self, metric: String) -> Option<&Vec<&'static str>> {
pub fn metric_to_indexes(&self, metric: String) -> Option<&Vec<Index>> {
self.metric_to_indexes
.get(metric.replace("-", "_").as_str())
}
@@ -171,17 +160,3 @@ pub struct IndexToVec<'a>(BTreeMap<Index, &'a dyn AnyCollectableVec>);
#[derive(Default, Deref, DerefMut)]
pub struct MetricToVec<'a>(BTreeMap<&'a str, &'a dyn AnyCollectableVec>);
/// A paginated list of available metric names (1000 per page)
#[derive(Debug, Serialize, JsonSchema)]
pub struct PaginatedMetrics {
/// Current page number (0-indexed)
#[schemars(example = 0)]
current_page: usize,
/// Total number of pages available
#[schemars(example = 21000)]
total_pages: usize,
/// List of metric names (max 1000 per page)
#[schemars(example = ["price_open", "price_close", "realized_price", "..."])]
metrics: &'static [&'static str],
}