mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-25 15:19:58 -07:00
query: init
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
use axum::{routing::get, Router};
|
||||
use axum::{Router, routing::get};
|
||||
|
||||
use super::AppState;
|
||||
|
||||
mod explorer;
|
||||
mod vecs;
|
||||
|
||||
pub use vecs::VecIdToIndexToVec;
|
||||
pub use vecs::DTS;
|
||||
|
||||
pub trait ApiRoutes {
|
||||
fn add_api_routes(self) -> Self;
|
||||
|
||||
50
crates/brk_server/src/api/vecs/dts.rs
Normal file
50
crates/brk_server/src/api/vecs/dts.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
use std::{fs, io};
|
||||
|
||||
use brk_query::{Index, Query};
|
||||
|
||||
use crate::WEBSITE_DEV_PATH;
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub trait DTS {
|
||||
fn generate_dts_file(&self) -> io::Result<()>;
|
||||
}
|
||||
|
||||
impl DTS for Query<'static> {
|
||||
fn generate_dts_file(&self) -> io::Result<()> {
|
||||
if !fs::exists(WEBSITE_DEV_PATH)? {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let path = format!("{WEBSITE_DEV_PATH}/scripts/types/vecid-to-indexes.d.ts");
|
||||
|
||||
let mut contents = Index::all()
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i_of_i, i)| format!("type {} = {};", i, i_of_i))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
|
||||
contents += "\n\ninterface VecIdToIndexes {\n";
|
||||
|
||||
self.vecid_to_index_to_vec.iter().for_each(|(id, index_to_vec)| {
|
||||
let indexes = index_to_vec
|
||||
.keys()
|
||||
.map(|i| i.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
|
||||
contents += &format!(
|
||||
" {}: [{indexes}]\n",
|
||||
if id.contains("-") {
|
||||
format!("\"{id}\"")
|
||||
} else {
|
||||
id.to_owned()
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
contents.push('}');
|
||||
|
||||
fs::write(path, contents)
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
use color_eyre::eyre::eyre;
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Format {
|
||||
CSV,
|
||||
TSV,
|
||||
JSON,
|
||||
}
|
||||
|
||||
impl TryFrom<Option<String>> for Format {
|
||||
type Error = color_eyre::Report;
|
||||
fn try_from(value: Option<String>) -> Result<Self, Self::Error> {
|
||||
if let Some(value) = value {
|
||||
let value = value.to_lowercase();
|
||||
let value = value.as_str();
|
||||
if value == "csv" {
|
||||
Ok(Self::CSV)
|
||||
} else if value == "tsv" {
|
||||
Ok(Self::TSV)
|
||||
} else if value == "json" {
|
||||
Ok(Self::JSON)
|
||||
} else {
|
||||
Err(eyre!("Fail"))
|
||||
}
|
||||
} else {
|
||||
Err(eyre!("Fail"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
use std::fmt::{self, Debug};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum Index {
|
||||
Addressindex,
|
||||
Dateindex,
|
||||
Height,
|
||||
P2PK33index,
|
||||
P2PK65index,
|
||||
P2PKHindex,
|
||||
P2SHindex,
|
||||
P2TRindex,
|
||||
P2WPKHindex,
|
||||
P2WSHindex,
|
||||
Txindex,
|
||||
Txinindex,
|
||||
Txoutindex,
|
||||
}
|
||||
|
||||
impl Index {
|
||||
pub fn all() -> [Self; 13] {
|
||||
[
|
||||
Self::Addressindex,
|
||||
Self::Dateindex,
|
||||
Self::Height,
|
||||
Self::P2PK33index,
|
||||
Self::P2PK65index,
|
||||
Self::P2PKHindex,
|
||||
Self::P2SHindex,
|
||||
Self::P2TRindex,
|
||||
Self::P2WPKHindex,
|
||||
Self::P2WSHindex,
|
||||
Self::Txindex,
|
||||
Self::Txinindex,
|
||||
Self::Txoutindex,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for Index {
|
||||
type Error = ();
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
Ok(match value {
|
||||
"d" | "date" | "dateindex" => Self::Dateindex,
|
||||
"h" | "height" => Self::Height,
|
||||
"txi" | "txindex" => Self::Txindex,
|
||||
"txini" | "txinindex" => Self::Txinindex,
|
||||
"txouti" | "txoutindex" => Self::Txoutindex,
|
||||
"addri" | "addressindex" => Self::Addressindex,
|
||||
"p2pk33i" | "p2pk33index" => Self::P2PK33index,
|
||||
"p2pk65i" | "p2pk65index" => Self::P2PK65index,
|
||||
"p2pkhi" | "p2pkhindex" => Self::P2PKHindex,
|
||||
"p2shi" | "p2shindex" => Self::P2SHindex,
|
||||
"p2tri" | "p2trindex" => Self::P2TRindex,
|
||||
"p2wpkhi" | "p2wpkhindex" => Self::P2WPKHindex,
|
||||
"p2wshi" | "p2wshindex" => Self::P2WSHindex,
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Index {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
Debug::fmt(self, f)
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,11 @@ use std::time::Instant;
|
||||
|
||||
use axum::{
|
||||
Json,
|
||||
extract::{Query, State},
|
||||
extract::{Query as AxumQuery, State},
|
||||
http::{HeaderMap, StatusCode, Uri},
|
||||
response::{IntoResponse, Response},
|
||||
};
|
||||
use brk_query::{Format, Index, Params};
|
||||
use color_eyre::eyre::eyre;
|
||||
use serde_json::Value;
|
||||
|
||||
@@ -13,20 +14,14 @@ use crate::{log_result, traits::HeaderMapExtended};
|
||||
|
||||
use super::AppState;
|
||||
|
||||
mod format;
|
||||
mod index;
|
||||
mod query;
|
||||
mod tree;
|
||||
mod dts;
|
||||
|
||||
use format::Format;
|
||||
use index::Index;
|
||||
use query::QueryS;
|
||||
pub use tree::*;
|
||||
pub use dts::*;
|
||||
|
||||
pub async fn handler(
|
||||
headers: HeaderMap,
|
||||
uri: Uri,
|
||||
query: Query<QueryS>,
|
||||
query: AxumQuery<Params>,
|
||||
State(app_state): State<AppState>,
|
||||
) -> Response {
|
||||
let instant = Instant::now();
|
||||
@@ -49,12 +44,16 @@ pub async fn handler(
|
||||
|
||||
fn req_to_response_res(
|
||||
headers: HeaderMap,
|
||||
Query(QueryS { format, from, i, to, v }): Query<QueryS>,
|
||||
AppState { vecs, .. }: AppState,
|
||||
AxumQuery(Params {
|
||||
format,
|
||||
from,
|
||||
index,
|
||||
to,
|
||||
values,
|
||||
}): AxumQuery<Params>,
|
||||
AppState { query, .. }: AppState,
|
||||
) -> color_eyre::Result<Response> {
|
||||
let format = Format::try_from(format).ok();
|
||||
|
||||
let indexes = i
|
||||
let indexes = index
|
||||
.to_lowercase()
|
||||
.split(",")
|
||||
.flat_map(|s| Index::try_from(s).ok())
|
||||
@@ -66,10 +65,14 @@ fn req_to_response_res(
|
||||
return Err(eyre!("Unknown index"));
|
||||
}
|
||||
|
||||
let ids = v
|
||||
.to_lowercase()
|
||||
.split(",")
|
||||
.map(|s| (s.to_owned(), vecs.get(&s.replace("_", "-"))))
|
||||
let ids = values
|
||||
.into_iter()
|
||||
.map(|v| v.to_lowercase())
|
||||
.flat_map(|v| v.split(",").map(|v| v.to_owned()).collect::<Vec<_>>())
|
||||
.map(|s| {
|
||||
let opt = query.vecid_to_index_to_vec.get(&s.replace("_", "-"));
|
||||
(s, opt)
|
||||
})
|
||||
.filter(|(_, opt)| opt.is_some())
|
||||
.map(|(id, vec)| (id, vec.unwrap()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct QueryS {
|
||||
pub i: String,
|
||||
pub v: String,
|
||||
pub from: Option<i64>,
|
||||
pub to: Option<i64>,
|
||||
pub format: Option<String>,
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
use std::{collections::BTreeMap, fs, io};
|
||||
|
||||
use brk_vec::AnyStorableVec;
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
|
||||
use crate::WEBSITE_DEV_PATH;
|
||||
|
||||
use super::index::Index;
|
||||
|
||||
#[derive(Default, Deref, DerefMut)]
|
||||
pub struct VecIdToIndexToVec(BTreeMap<String, IndexToVec>);
|
||||
|
||||
impl VecIdToIndexToVec {
|
||||
// Not the most performant or type safe but only built once so that's okay
|
||||
pub fn insert(&mut self, vec: &'static dyn AnyStorableVec) {
|
||||
let file_name = vec.file_name();
|
||||
let split = file_name.split("_to_").collect::<Vec<_>>();
|
||||
if split.len() != 2 {
|
||||
panic!();
|
||||
}
|
||||
let str = vec.index_type_to_string().split("::").last().unwrap().to_lowercase();
|
||||
let index = Index::try_from(str.as_str())
|
||||
.inspect_err(|_| {
|
||||
dbg!(str);
|
||||
})
|
||||
.unwrap();
|
||||
if split[0] != index.to_string().to_lowercase() {
|
||||
dbg!(split[0], index.to_string());
|
||||
panic!();
|
||||
}
|
||||
let key = split[1].to_string().replace("_", "-");
|
||||
let prev = self.entry(key).or_default().insert(index, vec);
|
||||
if prev.is_some() {
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_dts_file(&self) -> io::Result<()> {
|
||||
if !fs::exists(WEBSITE_DEV_PATH)? {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let path = format!("{WEBSITE_DEV_PATH}/scripts/types/vecid-to-indexes.d.ts");
|
||||
|
||||
let mut contents = Index::all()
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i_of_i, i)| format!("type {} = {};", i, i_of_i))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
|
||||
contents += "\n\ninterface VecIdToIndexes {\n";
|
||||
|
||||
self.iter().for_each(|(id, index_to_vec)| {
|
||||
let indexes = index_to_vec
|
||||
.keys()
|
||||
.map(|i| i.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
|
||||
contents += &format!(
|
||||
" {}: [{indexes}]\n",
|
||||
if id.contains("-") {
|
||||
format!("\"{id}\"")
|
||||
} else {
|
||||
id.to_owned()
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
contents.push('}');
|
||||
|
||||
fs::write(path, contents)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Deref, DerefMut)]
|
||||
pub struct IndexToVec(BTreeMap<Index, &'static dyn AnyStorableVec>);
|
||||
Reference in New Issue
Block a user