mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-30 12:18:11 -07:00
global: snapshot
This commit is contained in:
@@ -151,7 +151,10 @@ mod tests {
|
||||
#[test]
|
||||
fn test_common_prefix_lth() {
|
||||
let names = vec!["lth_cost_basis_max", "lth_cost_basis_min", "lth_cost_basis"];
|
||||
assert_eq!(find_common_prefix(&names), Some("lth_cost_basis_".to_string()));
|
||||
assert_eq!(
|
||||
find_common_prefix(&names),
|
||||
Some("lth_cost_basis_".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -9,11 +9,11 @@ use brk_cohort::{
|
||||
AGE_RANGE_NAMES, AMOUNT_RANGE_NAMES, EPOCH_NAMES, GE_AMOUNT_NAMES, LT_AMOUNT_NAMES,
|
||||
MAX_AGE_NAMES, MIN_AGE_NAMES, SPENDABLE_TYPE_NAMES, TERM_NAMES, YEAR_NAMES,
|
||||
};
|
||||
use brk_types::{pools, Index, PoolSlug};
|
||||
use brk_types::{Index, PoolSlug, pools};
|
||||
use serde::Serialize;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{to_camel_case, VERSION};
|
||||
use crate::{VERSION, to_camel_case};
|
||||
|
||||
/// Collected constant data for client generation.
|
||||
pub struct ClientConstants {
|
||||
|
||||
@@ -73,11 +73,17 @@ pub fn generate_parameterized_field<S: LanguageSyntax>(
|
||||
indent: &str,
|
||||
) {
|
||||
let field_name = syntax.field_name(&field.name);
|
||||
let type_ann = metadata.field_type_annotation(field, pattern.is_generic, None, syntax.generic_syntax());
|
||||
let type_ann =
|
||||
metadata.field_type_annotation(field, pattern.is_generic, None, syntax.generic_syntax());
|
||||
let path_expr = compute_path_expr(syntax, pattern, field, "acc");
|
||||
let value = compute_field_value(syntax, field, metadata, &path_expr);
|
||||
|
||||
writeln!(output, "{}", syntax.field_init(indent, &field_name, &type_ann, &value)).unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
"{}",
|
||||
syntax.field_init(indent, &field_name, &type_ann, &value)
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// Generate a tree node field with a specific child node for pattern instance base detection.
|
||||
@@ -127,7 +133,12 @@ pub fn generate_tree_node_field<S: LanguageSyntax>(
|
||||
)
|
||||
};
|
||||
|
||||
writeln!(output, "{}", syntax.field_init(indent, &field_name, &type_ann, &value)).unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
"{}",
|
||||
syntax.field_init(indent, &field_name, &type_ann, &value)
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// Generate a leaf field using the actual metric name from the TreeNode::Leaf.
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
|
||||
use std::fmt::Write;
|
||||
|
||||
use crate::{Endpoint, Parameter, generators::{normalize_return_type, write_description}, to_camel_case};
|
||||
use crate::{
|
||||
Endpoint, Parameter,
|
||||
generators::{normalize_return_type, write_description},
|
||||
to_camel_case,
|
||||
};
|
||||
|
||||
/// Generate API methods for the BrkClient class.
|
||||
pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) {
|
||||
@@ -33,7 +37,13 @@ pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) {
|
||||
|
||||
// Add endpoint path
|
||||
writeln!(output, " *").unwrap();
|
||||
writeln!(output, " * Endpoint: `{} {}`", endpoint.method.to_uppercase(), endpoint.path).unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
" * Endpoint: `{} {}`",
|
||||
endpoint.method.to_uppercase(),
|
||||
endpoint.path
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
if !endpoint.path_params.is_empty() || !endpoint.query_params.is_empty() {
|
||||
writeln!(output, " *").unwrap();
|
||||
@@ -89,7 +99,12 @@ pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) {
|
||||
}
|
||||
}
|
||||
writeln!(output, " const query = params.toString();").unwrap();
|
||||
writeln!(output, " const path = `{}${{query ? '?' + query : ''}}`;", path).unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
" const path = `{}${{query ? '?' + query : ''}}`;",
|
||||
path
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
if endpoint.supports_csv {
|
||||
writeln!(output, " if (format === 'csv') {{").unwrap();
|
||||
|
||||
@@ -506,7 +506,11 @@ pub fn generate_static_constants(output: &mut String) {
|
||||
// VERSION, INDEXES, POOL_ID_TO_POOL_NAME
|
||||
writeln!(output, " VERSION = \"{}\";\n", constants.version).unwrap();
|
||||
write_static_const(output, "INDEXES", &format_json(&constants.indexes));
|
||||
write_static_const(output, "POOL_ID_TO_POOL_NAME", &format_json(&constants.pool_map));
|
||||
write_static_const(
|
||||
output,
|
||||
"POOL_ID_TO_POOL_NAME",
|
||||
&format_json(&constants.pool_map),
|
||||
);
|
||||
|
||||
// Cohort constants with camelCase keys
|
||||
for (name, value) in CohortConstants::all() {
|
||||
|
||||
@@ -4,7 +4,11 @@ use std::fmt::Write;
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{TypeSchemas, generators::{MANUAL_GENERIC_TYPES, write_description}, get_union_variants, ref_to_type_name, to_camel_case};
|
||||
use crate::{
|
||||
TypeSchemas,
|
||||
generators::{MANUAL_GENERIC_TYPES, write_description},
|
||||
get_union_variants, ref_to_type_name, to_camel_case,
|
||||
};
|
||||
|
||||
/// Generate JSDoc type definitions from OpenAPI schemas.
|
||||
pub fn generate_type_definitions(output: &mut String, schemas: &TypeSchemas) {
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
|
||||
use std::fmt::Write;
|
||||
|
||||
use crate::{Endpoint, Parameter, escape_python_keyword, generators::{normalize_return_type, write_description}, to_snake_case};
|
||||
use crate::{
|
||||
Endpoint, Parameter, escape_python_keyword,
|
||||
generators::{normalize_return_type, write_description},
|
||||
to_snake_case,
|
||||
};
|
||||
|
||||
use super::client::generate_class_constants;
|
||||
use super::types::js_type_to_python;
|
||||
@@ -30,22 +34,58 @@ pub fn generate_main_client(output: &mut String, endpoints: &[Endpoint]) {
|
||||
writeln!(output).unwrap();
|
||||
|
||||
// Generate metric() method for dynamic metric access
|
||||
writeln!(output, " def metric(self, metric: str, index: Index) -> MetricEndpointBuilder[Any]:").unwrap();
|
||||
writeln!(output, " \"\"\"Create a dynamic metric endpoint builder for any metric/index combination.").unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
" def metric(self, metric: str, index: Index) -> MetricEndpointBuilder[Any]:"
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
" \"\"\"Create a dynamic metric endpoint builder for any metric/index combination."
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(output).unwrap();
|
||||
writeln!(output, " Use this for programmatic access when the metric name is determined at runtime.").unwrap();
|
||||
writeln!(output, " For type-safe access, use the `metrics` tree instead.").unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
" Use this for programmatic access when the metric name is determined at runtime."
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
" For type-safe access, use the `metrics` tree instead."
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(output, " \"\"\"").unwrap();
|
||||
writeln!(output, " return MetricEndpointBuilder(self, metric, index)").unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
" return MetricEndpointBuilder(self, metric, index)"
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(output).unwrap();
|
||||
|
||||
// Generate helper methods
|
||||
writeln!(output, " def index_to_date(self, index: Index, i: int) -> Union[date, datetime]:").unwrap();
|
||||
writeln!(output, " \"\"\"Convert an index value to a date/datetime for date-based indexes.\"\"\"").unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
" def index_to_date(self, index: Index, i: int) -> Union[date, datetime]:"
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
" \"\"\"Convert an index value to a date/datetime for date-based indexes.\"\"\""
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(output, " return _index_to_date(index, i)").unwrap();
|
||||
writeln!(output).unwrap();
|
||||
writeln!(output, " def date_to_index(self, index: Index, d: Union[date, datetime]) -> int:").unwrap();
|
||||
writeln!(output, " \"\"\"Convert a date/datetime to an index value for date-based indexes.\"\"\"").unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
" def date_to_index(self, index: Index, d: Union[date, datetime]) -> int:"
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
" \"\"\"Convert a date/datetime to an index value for date-based indexes.\"\"\""
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(output, " return _date_to_index(index, d)").unwrap();
|
||||
writeln!(output).unwrap();
|
||||
// Generate API methods
|
||||
@@ -112,7 +152,13 @@ pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) {
|
||||
}
|
||||
}
|
||||
writeln!(output).unwrap();
|
||||
writeln!(output, " Endpoint: `{} {}`\"\"\"", endpoint.method.to_uppercase(), endpoint.path).unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
" Endpoint: `{} {}`\"\"\"",
|
||||
endpoint.method.to_uppercase(),
|
||||
endpoint.path
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Build path
|
||||
let path = build_path_template(&endpoint.path, &endpoint.path_params);
|
||||
|
||||
@@ -654,7 +654,12 @@ def _dep(c: BrkClientBase, n: str, i: Index) -> DateMetricEndpointBuilder[Any]:
|
||||
.unwrap();
|
||||
writeln!(output, " @property").unwrap();
|
||||
writeln!(output, " def name(self) -> str: return self._n").unwrap();
|
||||
writeln!(output, " def indexes(self) -> List[str]: return list({})", idx_var).unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
" def indexes(self) -> List[str]: return list({})",
|
||||
idx_var
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
" def get(self, index: Index) -> Optional[MetricEndpointBuilder[T]]: return _ep(self.by._c, self._n, index) if index in {} else None",
|
||||
|
||||
@@ -38,11 +38,23 @@ pub fn generate_python_client(
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(output, "from urllib.parse import urlparse").unwrap();
|
||||
writeln!(output, "from datetime import date, datetime, timedelta, timezone").unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
"from datetime import date, datetime, timedelta, timezone"
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(output, "import json\n").unwrap();
|
||||
writeln!(output, "if TYPE_CHECKING:").unwrap();
|
||||
writeln!(output, " import pandas as pd # type: ignore[import-not-found]").unwrap();
|
||||
writeln!(output, " import polars as pl # type: ignore[import-not-found]\n").unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
" import pandas as pd # type: ignore[import-not-found]"
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
" import polars as pl # type: ignore[import-not-found]\n"
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(output, "T = TypeVar('T')\n").unwrap();
|
||||
|
||||
types::generate_type_definitions(&mut output, schemas);
|
||||
|
||||
@@ -115,7 +115,13 @@ pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) {
|
||||
}
|
||||
// Add endpoint path
|
||||
writeln!(output, " ///").unwrap();
|
||||
writeln!(output, " /// Endpoint: `{} {}`", endpoint.method.to_uppercase(), endpoint.path).unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
" /// Endpoint: `{} {}`",
|
||||
endpoint.method.to_uppercase(),
|
||||
endpoint.path
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let params = build_method_params(endpoint);
|
||||
writeln!(
|
||||
@@ -128,7 +134,12 @@ pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) {
|
||||
let (path, index_arg) = build_path_template(endpoint);
|
||||
|
||||
if endpoint.query_params.is_empty() {
|
||||
writeln!(output, " self.base.get_json(&format!(\"{}\"{}))", path, index_arg).unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
" self.base.get_json(&format!(\"{}\"{}))",
|
||||
path, index_arg
|
||||
)
|
||||
.unwrap();
|
||||
} else {
|
||||
writeln!(output, " let mut query = Vec::new();").unwrap();
|
||||
for param in &endpoint.query_params {
|
||||
@@ -149,13 +160,26 @@ pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) {
|
||||
}
|
||||
}
|
||||
writeln!(output, " let query_str = if query.is_empty() {{ String::new() }} else {{ format!(\"?{{}}\", query.join(\"&\")) }};").unwrap();
|
||||
writeln!(output, " let path = format!(\"{}{{}}\"{}, query_str);", path, index_arg).unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
" let path = format!(\"{}{{}}\"{}, query_str);",
|
||||
path, index_arg
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
if endpoint.supports_csv {
|
||||
writeln!(output, " if format == Some(Format::CSV) {{").unwrap();
|
||||
writeln!(output, " self.base.get_text(&path).map(FormatResponse::Csv)").unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
" self.base.get_text(&path).map(FormatResponse::Csv)"
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(output, " }} else {{").unwrap();
|
||||
writeln!(output, " self.base.get_json(&path).map(FormatResponse::Json)").unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
" self.base.get_json(&path).map(FormatResponse::Json)"
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(output, " }}").unwrap();
|
||||
} else {
|
||||
writeln!(output, " self.base.get_json(&path)").unwrap();
|
||||
@@ -199,7 +223,10 @@ fn param_type_to_rust(param_type: &str) -> String {
|
||||
|
||||
/// Build path template and extra format args for Index params.
|
||||
fn build_path_template(endpoint: &Endpoint) -> (String, &'static str) {
|
||||
let has_index_param = endpoint.path_params.iter().any(|p| p.name == "index" && p.param_type == "Index");
|
||||
let has_index_param = endpoint
|
||||
.path_params
|
||||
.iter()
|
||||
.any(|p| p.name == "index" && p.param_type == "Index");
|
||||
if has_index_param {
|
||||
(endpoint.path.replace("{index}", "{}"), ", index.name()")
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user