global: snapshot

This commit is contained in:
nym21
2026-01-12 16:19:23 +01:00
parent 1484eae53c
commit b675b70067
20 changed files with 11573 additions and 6489 deletions
+15 -5
View File
@@ -162,11 +162,21 @@ pub fn analyze_pattern_level(child_names: &[(String, String)]) -> PatternAnalysi
positions.insert(field_name.clone(), FieldNamePosition::Identity);
}
// Use the first name as base (they're all independent)
let base = child_names
.first()
.map(|(_, n)| n.clone())
.unwrap_or_default();
// Check if all fields are "true Identity" (field_name == effective_name)
// In that case, the base should be empty since metrics are accessed directly by field name
let all_true_identity = child_names
.iter()
.all(|(field_name, effective)| field_name == effective);
let base = if all_true_identity {
String::new()
} else {
// Use the first name as base (they're all independent but have different names)
child_names
.first()
.map(|(_, n)| n.clone())
.unwrap_or_default()
};
PatternAnalysis {
common: CommonDenominator::None,
@@ -67,43 +67,128 @@ class BrkError extends Error {{
/**
* @template T
* @typedef {{Object}} MetricEndpoint
* @property {{(onUpdate?: (value: MetricData<T>) => void) => Promise<MetricData<T>>}} get - Fetch all data points
* @property {{(start?: number, end?: number, onUpdate?: (value: MetricData<T>) => void) => Promise<MetricData<T>>}} range - Fetch data in range
* @typedef {{Object}} MetricEndpointBuilder
* @property {{(n: number) => RangeBuilder<T>}} first - Fetch first n data points
* @property {{(n: number) => RangeBuilder<T>}} last - Fetch last n data points
* @property {{(start: number, end: number) => RangeBuilder<T>}} range - Set explicit range [start, end)
* @property {{(start: number) => FromBuilder<T>}} from - Set start position, chain with take() or to()
* @property {{(end: number) => ToBuilder<T>}} to - Set end position, chain with takeLast() or from()
* @property {{(onUpdate?: (value: MetricData<T>) => void) => Promise<MetricData<T>>}} json - Execute and return JSON (all data)
* @property {{() => Promise<string>}} csv - Execute and return CSV (all data)
* @property {{string}} path - The endpoint path
*/
/** @typedef {{MetricEndpoint<unknown>}} AnyMetricEndpoint */
/** @typedef {{MetricEndpointBuilder<unknown>}} AnyMetricEndpointBuilder */
/**
* @template T
* @typedef {{Object}} FromBuilder
* @property {{(n: number) => RangeBuilder<T>}} take - Take n items from start position
* @property {{(end: number) => RangeBuilder<T>}} to - Set end position
* @property {{(onUpdate?: (value: MetricData<T>) => void) => Promise<MetricData<T>>}} json - Execute and return JSON
* @property {{() => Promise<string>}} csv - Execute and return CSV
*/
/**
* @template T
* @typedef {{Object}} ToBuilder
* @property {{(n: number) => RangeBuilder<T>}} takeLast - Take last n items before end position
* @property {{(start: number) => RangeBuilder<T>}} from - Set start position
* @property {{(onUpdate?: (value: MetricData<T>) => void) => Promise<MetricData<T>>}} json - Execute and return JSON
* @property {{() => Promise<string>}} csv - Execute and return CSV
*/
/**
* @template T
* @typedef {{Object}} RangeBuilder
* @property {{(onUpdate?: (value: MetricData<T>) => void) => Promise<MetricData<T>>}} json - Execute and return JSON
* @property {{() => Promise<string>}} csv - Execute and return CSV
*/
/**
* @template T
* @typedef {{Object}} MetricPattern
* @property {{string}} name - The metric name
* @property {{Partial<Record<Index, MetricEndpoint<T>>>}} by - Index endpoints (lazy getters)
* @property {{Partial<Record<Index, MetricEndpointBuilder<T>>>}} by - Index endpoints (lazy getters)
* @property {{() => Index[]}} indexes - Get the list of available indexes
* @property {{(index: Index) => MetricEndpoint<T>|undefined}} get - Get an endpoint for a specific index
* @property {{(index: Index) => MetricEndpointBuilder<T>|undefined}} get - Get an endpoint for a specific index
*/
/** @typedef {{MetricPattern<unknown>}} AnyMetricPattern */
/**
* Create an endpoint for a metric index.
* Create a metric endpoint builder with typestate pattern.
* @template T
* @param {{BrkClientBase}} client
* @param {{string}} name - The metric vec name
* @param {{Index}} index - The index name
* @returns {{MetricEndpoint<T>}}
* @returns {{MetricEndpointBuilder<T>}}
*/
function _endpoint(client, name, index) {{
const p = `/api/metric/${{name}}/${{index}}`;
return {{
get: (onUpdate) => client.getJson(p, onUpdate),
range: (start, end, onUpdate) => {{
const params = new URLSearchParams();
if (start !== undefined) params.set('start', String(start));
if (end !== undefined) params.set('end', String(end));
const query = params.toString();
return client.getJson(query ? `${{p}}?${{query}}` : p, onUpdate);
/**
* @param {{number}} [start]
* @param {{number}} [end]
* @param {{string}} [format]
* @returns {{string}}
*/
const buildPath = (start, end, format) => {{
const params = new URLSearchParams();
if (start !== undefined) params.set('start', String(start));
if (end !== undefined) params.set('end', String(end));
if (format) params.set('format', format);
const query = params.toString();
return query ? `${{p}}?${{query}}` : p;
}};
/**
* @param {{number}} [start]
* @param {{number}} [end]
* @returns {{RangeBuilder<T>}}
*/
const rangeBuilder = (start, end) => ({{
json(/** @type {{((value: MetricData<T>) => void) | undefined}} */ onUpdate) {{
return client.getJson(buildPath(start, end), onUpdate);
}},
csv() {{ return client.getText(buildPath(start, end, 'csv')); }},
}});
/**
* @param {{number}} start
* @returns {{FromBuilder<T>}}
*/
const fromBuilder = (start) => ({{
take(/** @type {{number}} */ n) {{ return rangeBuilder(start, start + n); }},
to(/** @type {{number}} */ end) {{ return rangeBuilder(start, end); }},
json(/** @type {{((value: MetricData<T>) => void) | undefined}} */ onUpdate) {{
return client.getJson(buildPath(start, undefined), onUpdate);
}},
csv() {{ return client.getText(buildPath(start, undefined, 'csv')); }},
}});
/**
* @param {{number}} end
* @returns {{ToBuilder<T>}}
*/
const toBuilder = (end) => ({{
takeLast(/** @type {{number}} */ n) {{ return rangeBuilder(end - n, end); }},
from(/** @type {{number}} */ start) {{ return rangeBuilder(start, end); }},
json(/** @type {{((value: MetricData<T>) => void) | undefined}} */ onUpdate) {{
return client.getJson(buildPath(undefined, end), onUpdate);
}},
csv() {{ return client.getText(buildPath(undefined, end, 'csv')); }},
}});
return {{
first(/** @type {{number}} */ n) {{ return rangeBuilder(undefined, n); }},
last(/** @type {{number}} */ n) {{ return rangeBuilder(-n, undefined); }},
range(/** @type {{number}} */ start, /** @type {{number}} */ end) {{ return rangeBuilder(start, end); }},
from(/** @type {{number}} */ start) {{ return fromBuilder(start); }},
to(/** @type {{number}} */ end) {{ return toBuilder(end); }},
json(/** @type {{((value: MetricData<T>) => void) | undefined}} */ onUpdate) {{
return client.getJson(buildPath(), onUpdate);
}},
csv() {{ return client.getText(buildPath(undefined, undefined, 'csv')); }},
get path() {{ return p; }},
}};
}}
@@ -272,7 +357,7 @@ pub fn generate_index_accessors(output: &mut String, patterns: &[IndexSetPattern
let by_fields: Vec<String> = pattern
.indexes
.iter()
.map(|idx| format!("{}: MetricEndpoint<T>", idx.serialize_long()))
.map(|idx| format!("{}: MetricEndpointBuilder<T>", idx.serialize_long()))
.collect();
let by_type = format!("{{ {} }}", by_fields.join(", "));
@@ -280,7 +365,7 @@ pub fn generate_index_accessors(output: &mut String, patterns: &[IndexSetPattern
writeln!(output, " * @template T").unwrap();
writeln!(
output,
" * @typedef {{{{ name: string, by: {}, indexes: () => Index[], get: (index: Index) => MetricEndpoint<T>|undefined }}}} {}",
" * @typedef {{{{ name: string, by: {}, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder<T>|undefined }}}} {}",
by_type, pattern.name
)
.unwrap();
@@ -127,6 +127,20 @@ pub fn generate_main_client(
writeln!(output, " }};").unwrap();
writeln!(output, " }}\n").unwrap();
writeln!(output, " /**").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, " *").unwrap();
writeln!(output, " * @param {{string}} metric - The metric name").unwrap();
writeln!(output, " * @param {{Index}} index - The index name").unwrap();
writeln!(output, " * @returns {{MetricEndpointBuilder<unknown>}}").unwrap();
writeln!(output, " */").unwrap();
writeln!(output, " metric(metric, index) {{").unwrap();
writeln!(output, " return _endpoint(this, metric, index);").unwrap();
writeln!(output, " }}\n").unwrap();
generate_api_methods(output, endpoints);
writeln!(output, "}}\n").unwrap();
@@ -29,6 +29,16 @@ pub fn generate_main_client(output: &mut String, endpoints: &[Endpoint]) {
writeln!(output, " self.metrics = MetricsTree(self)").unwrap();
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).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).unwrap();
// Generate API methods
generate_api_methods(output, endpoints);
}
@@ -140,7 +140,7 @@ def _m(acc: str, s: str) -> str:
.unwrap();
}
/// Generate the MetricData and MetricEndpoint classes
/// Generate the MetricData and MetricEndpointBuilder classes
pub fn generate_endpoint_class(output: &mut String) {
writeln!(
output,
@@ -156,36 +156,191 @@ pub fn generate_endpoint_class(output: &mut String) {
AnyMetricData = MetricData[Any]
class MetricEndpoint(Generic[T]):
"""An endpoint for a specific metric + index combination."""
class _EndpointConfig:
"""Shared endpoint configuration."""
client: BrkClientBase
name: str
index: Index
start: Optional[int]
end: Optional[int]
def __init__(self, client: BrkClientBase, name: str, index: str):
self._client = client
self._name = name
self._index = index
def get(self) -> MetricData[T]:
"""Fetch all data points for this metric/index."""
return self._client.get_json(self.path())
def range(self, start: Optional[int] = None, end: Optional[int] = None) -> MetricData[T]:
"""Fetch data points within a range."""
params = []
if start is not None:
params.append(f"start={{start}}")
if end is not None:
params.append(f"end={{end}}")
query = "&".join(params)
p = self.path()
return self._client.get_json(f"{{p}}?{{query}}" if query else p)
def __init__(self, client: BrkClientBase, name: str, index: Index,
start: Optional[int] = None, end: Optional[int] = None):
self.client = client
self.name = name
self.index = index
self.start = start
self.end = end
def path(self) -> str:
"""Get the endpoint path."""
return f"/api/metric/{{self._name}}/{{self._index}}"
return f"/api/metric/{{self.name}}/{{self.index}}"
def _build_path(self, format: Optional[str] = None) -> str:
params = []
if self.start is not None:
params.append(f"start={{self.start}}")
if self.end is not None:
params.append(f"end={{self.end}}")
if format is not None:
params.append(f"format={{format}}")
query = "&".join(params)
p = self.path()
return f"{{p}}?{{query}}" if query else p
def get_json(self) -> Any:
return self.client.get_json(self._build_path())
def get_csv(self) -> str:
return self.client.get_text(self._build_path(format='csv'))
class RangeBuilder(Generic[T]):
"""Final builder with range fully specified. Can only call json() or csv()."""
def __init__(self, config: _EndpointConfig):
self._config = config
def json(self) -> MetricData[T]:
"""Execute the query and return parsed JSON data."""
return self._config.get_json()
def csv(self) -> str:
"""Execute the query and return CSV data as a string."""
return self._config.get_csv()
class FromBuilder(Generic[T]):
"""Builder after calling from(start). Can chain with take() or to()."""
def __init__(self, config: _EndpointConfig):
self._config = config
def take(self, n: int) -> RangeBuilder[T]:
"""Take n items from the start position."""
start = self._config.start or 0
return RangeBuilder(_EndpointConfig(
self._config.client, self._config.name, self._config.index,
start, start + n
))
def to(self, end: int) -> RangeBuilder[T]:
"""Set the end position."""
return RangeBuilder(_EndpointConfig(
self._config.client, self._config.name, self._config.index,
self._config.start, end
))
def json(self) -> MetricData[T]:
"""Execute the query and return parsed JSON data (from start to end of data)."""
return self._config.get_json()
def csv(self) -> str:
"""Execute the query and return CSV data as a string."""
return self._config.get_csv()
class ToBuilder(Generic[T]):
"""Builder after calling to(end). Can chain with take_last() or from()."""
def __init__(self, config: _EndpointConfig):
self._config = config
def take_last(self, n: int) -> RangeBuilder[T]:
"""Take last n items before the end position."""
end = self._config.end or 0
return RangeBuilder(_EndpointConfig(
self._config.client, self._config.name, self._config.index,
end - n, end
))
def from_(self, start: int) -> RangeBuilder[T]:
"""Set the start position."""
return RangeBuilder(_EndpointConfig(
self._config.client, self._config.name, self._config.index,
start, self._config.end
))
def json(self) -> MetricData[T]:
"""Execute the query and return parsed JSON data (from start of data to end)."""
return self._config.get_json()
def csv(self) -> str:
"""Execute the query and return CSV data as a string."""
return self._config.get_csv()
class MetricEndpointBuilder(Generic[T]):
"""Initial builder for metric endpoint queries.
Use method chaining to specify the data range, then call json() or csv() to execute.
Examples:
# Get all data
endpoint.json()
# Get last 10 points
endpoint.last(10).json()
# Get range [100, 200)
endpoint.range(100, 200).json()
# Get 10 points starting from position 100
endpoint.from_(100).take(10).json()
"""
def __init__(self, client: BrkClientBase, name: str, index: Index):
self._config = _EndpointConfig(client, name, index)
def first(self, n: int) -> RangeBuilder[T]:
"""Fetch the first n data points."""
return RangeBuilder(_EndpointConfig(
self._config.client, self._config.name, self._config.index,
None, n
))
def last(self, n: int) -> RangeBuilder[T]:
"""Fetch the last n data points."""
return RangeBuilder(_EndpointConfig(
self._config.client, self._config.name, self._config.index,
-n, None
))
def range(self, start: int, end: int) -> RangeBuilder[T]:
"""Set an explicit range [start, end)."""
return RangeBuilder(_EndpointConfig(
self._config.client, self._config.name, self._config.index,
start, end
))
def from_(self, start: int) -> FromBuilder[T]:
"""Set the start position. Chain with take() or to()."""
return FromBuilder(_EndpointConfig(
self._config.client, self._config.name, self._config.index,
start, None
))
def to(self, end: int) -> ToBuilder[T]:
"""Set the end position. Chain with take_last() or from_()."""
return ToBuilder(_EndpointConfig(
self._config.client, self._config.name, self._config.index,
None, end
))
def json(self) -> MetricData[T]:
"""Execute the query and return parsed JSON data (all data)."""
return self._config.get_json()
def csv(self) -> str:
"""Execute the query and return CSV data as a string (all data)."""
return self._config.get_csv()
def path(self) -> str:
"""Get the base endpoint path."""
return self._config.path()
# Type alias for non-generic usage
AnyMetricEndpoint = MetricEndpoint[Any]
AnyMetricEndpointBuilder = MetricEndpointBuilder[Any]
class MetricPattern(Protocol[T]):
@@ -200,8 +355,8 @@ class MetricPattern(Protocol[T]):
"""Get the list of available indexes for this metric."""
...
def get(self, index: str) -> Optional[MetricEndpoint[T]]:
"""Get an endpoint for a specific index, if supported."""
def get(self, index: Index) -> Optional[MetricEndpointBuilder[T]]:
"""Get an endpoint builder for a specific index, if supported."""
...
"#
@@ -237,10 +392,10 @@ pub fn generate_index_accessors(output: &mut String, patterns: &[IndexSetPattern
for index in &pattern.indexes {
let method_name = index_to_field_name(index);
let index_name = index.serialize_long();
writeln!(output, " def {}(self) -> MetricEndpoint[T]:", method_name).unwrap();
writeln!(output, " def {}(self) -> MetricEndpointBuilder[T]:", method_name).unwrap();
writeln!(
output,
" return MetricEndpoint(self._client, self._name, '{}')",
" return MetricEndpointBuilder(self._client, self._name, '{}')",
index_name
)
.unwrap();
@@ -288,8 +443,8 @@ pub fn generate_index_accessors(output: &mut String, patterns: &[IndexSetPattern
writeln!(output).unwrap();
// Generate get(index) method
writeln!(output, " def get(self, index: str) -> Optional[MetricEndpoint[T]]:").unwrap();
writeln!(output, " \"\"\"Get an endpoint for a specific index, if supported.\"\"\"").unwrap();
writeln!(output, " def get(self, index: Index) -> Optional[MetricEndpointBuilder[T]]:").unwrap();
writeln!(output, " \"\"\"Get an endpoint builder for a specific index, if supported.\"\"\"").unwrap();
for (i, index) in pattern.indexes.iter().enumerate() {
let method_name = index_to_field_name(index);
let index_name = index.serialize_long();
@@ -38,6 +38,25 @@ impl BrkClient {{
pub fn metrics(&self) -> &MetricsTree {{
&self.metrics
}}
/// Create a dynamic metric endpoint builder for any metric/index combination.
///
/// Use this for programmatic access when the metric name is determined at runtime.
/// For type-safe access, use the `metrics()` tree instead.
///
/// # Example
/// ```ignore
/// let data = client.metric("realized_price", Index::Height)
/// .last(10)
/// .json::<f64>()?;
/// ```
pub fn metric(&self, metric: impl Into<Metric>, index: Index) -> MetricEndpointBuilder<serde_json::Value> {{
MetricEndpointBuilder::new(
self.base.clone(),
Arc::from(metric.into().as_str()),
index,
)
}}
"#,
VERSION = VERSION
)
+181 -32
View File
@@ -141,8 +141,8 @@ pub trait AnyMetricPattern {{
/// Generic trait for metric patterns with endpoint access.
pub trait MetricPattern<T>: AnyMetricPattern {{
/// Get an endpoint for a specific index, if supported.
fn get(&self, index: Index) -> Option<Endpoint<T>>;
/// Get an endpoint builder for a specific index, if supported.
fn get(&self, index: Index) -> Option<MetricEndpointBuilder<T>>;
}}
"#
@@ -150,50 +150,199 @@ pub trait MetricPattern<T>: AnyMetricPattern {{
.unwrap();
}
/// Generate the Endpoint struct.
/// Generate the MetricEndpointBuilder structs with typestate pattern.
pub fn generate_endpoint(output: &mut String) {
writeln!(
output,
r#"/// An endpoint for a specific metric + index combination.
pub struct Endpoint<T> {{
r#"/// Shared endpoint configuration.
#[derive(Clone)]
struct EndpointConfig {{
client: Arc<BrkClientBase>,
name: Arc<str>,
index: Index,
start: Option<i64>,
end: Option<i64>,
}}
impl EndpointConfig {{
fn new(client: Arc<BrkClientBase>, name: Arc<str>, index: Index) -> Self {{
Self {{ client, name, index, start: None, end: None }}
}}
fn path(&self) -> String {{
format!("/api/metric/{{}}/{{}}", self.name, self.index.serialize_long())
}}
fn build_path(&self, format: Option<&str>) -> String {{
let mut params = Vec::new();
if let Some(s) = self.start {{ params.push(format!("start={{}}", s)); }}
if let Some(e) = self.end {{ params.push(format!("end={{}}", e)); }}
if let Some(fmt) = format {{ params.push(format!("format={{}}", fmt)); }}
let p = self.path();
if params.is_empty() {{ p }} else {{ format!("{{}}?{{}}", p, params.join("&")) }}
}}
fn get_json<T: DeserializeOwned>(&self, format: Option<&str>) -> Result<T> {{
self.client.get_json(&self.build_path(format))
}}
fn get_text(&self, format: Option<&str>) -> Result<String> {{
self.client.get_text(&self.build_path(format))
}}
}}
/// Initial builder for metric endpoint queries.
///
/// Use method chaining to specify the data range, then call `json()` or `csv()` to execute.
///
/// # Examples
/// ```ignore
/// // Get all data
/// endpoint.json()?;
///
/// // Get last 10 points
/// endpoint.last(10).json()?;
///
/// // Get range [100, 200)
/// endpoint.range(100, 200).json()?;
///
/// // Get 10 points starting from position 100
/// endpoint.from(100).take(10).json()?;
/// ```
pub struct MetricEndpointBuilder<T> {{
config: EndpointConfig,
_marker: std::marker::PhantomData<T>,
}}
impl<T: DeserializeOwned> Endpoint<T> {{
impl<T: DeserializeOwned> MetricEndpointBuilder<T> {{
pub fn new(client: Arc<BrkClientBase>, name: Arc<str>, index: Index) -> Self {{
Self {{
client,
name,
index,
_marker: std::marker::PhantomData,
}}
Self {{ config: EndpointConfig::new(client, name, index), _marker: std::marker::PhantomData }}
}}
/// Fetch all data points for this metric/index.
pub fn get(&self) -> Result<MetricData<T>> {{
self.client.get_json(&self.path())
/// Fetch the first n data points.
pub fn first(mut self, n: u64) -> RangeBuilder<T> {{
self.config.end = Some(n as i64);
RangeBuilder {{ config: self.config, _marker: std::marker::PhantomData }}
}}
/// Fetch data points within a range.
pub fn range(&self, start: Option<i64>, end: Option<i64>) -> Result<MetricData<T>> {{
let mut params = Vec::new();
if let Some(s) = start {{ params.push(format!("start={{}}", s)); }}
if let Some(e) = end {{ params.push(format!("end={{}}", e)); }}
let p = self.path();
let path = if params.is_empty() {{
p
}} else {{
format!("{{}}?{{}}", p, params.join("&"))
}};
self.client.get_json(&path)
/// Fetch the last n data points.
pub fn last(mut self, n: u64) -> RangeBuilder<T> {{
self.config.start = Some(-(n as i64));
RangeBuilder {{ config: self.config, _marker: std::marker::PhantomData }}
}}
/// Get the endpoint path.
/// Set an explicit range [start, end).
pub fn range(mut self, start: i64, end: i64) -> RangeBuilder<T> {{
self.config.start = Some(start);
self.config.end = Some(end);
RangeBuilder {{ config: self.config, _marker: std::marker::PhantomData }}
}}
/// Set the start position. Chain with `take(n)` or `to(end)`.
pub fn from(mut self, start: i64) -> FromBuilder<T> {{
self.config.start = Some(start);
FromBuilder {{ config: self.config, _marker: std::marker::PhantomData }}
}}
/// Set the end position. Chain with `takeLast(n)` or `from(start)`.
pub fn to(mut self, end: i64) -> ToBuilder<T> {{
self.config.end = Some(end);
ToBuilder {{ config: self.config, _marker: std::marker::PhantomData }}
}}
/// Execute the query and return parsed JSON data (all data).
pub fn json(self) -> Result<MetricData<T>> {{
self.config.get_json(None)
}}
/// Execute the query and return CSV data as a string (all data).
pub fn csv(self) -> Result<String> {{
self.config.get_text(Some("csv"))
}}
/// Get the base endpoint path.
pub fn path(&self) -> String {{
format!("/api/metric/{{}}/{{}}", self.name, self.index.serialize_long())
self.config.path()
}}
}}
/// Builder after calling `from(start)`. Can chain with `take(n)` or `to(end)`.
pub struct FromBuilder<T> {{
config: EndpointConfig,
_marker: std::marker::PhantomData<T>,
}}
impl<T: DeserializeOwned> FromBuilder<T> {{
/// Take n items from the start position.
pub fn take(mut self, n: u64) -> RangeBuilder<T> {{
let start = self.config.start.unwrap_or(0);
self.config.end = Some(start + n as i64);
RangeBuilder {{ config: self.config, _marker: std::marker::PhantomData }}
}}
/// Set the end position.
pub fn to(mut self, end: i64) -> RangeBuilder<T> {{
self.config.end = Some(end);
RangeBuilder {{ config: self.config, _marker: std::marker::PhantomData }}
}}
/// Execute the query and return parsed JSON data (from start to end of data).
pub fn json(self) -> Result<MetricData<T>> {{
self.config.get_json(None)
}}
/// Execute the query and return CSV data as a string.
pub fn csv(self) -> Result<String> {{
self.config.get_text(Some("csv"))
}}
}}
/// Builder after calling `to(end)`. Can chain with `takeLast(n)` or `from(start)`.
pub struct ToBuilder<T> {{
config: EndpointConfig,
_marker: std::marker::PhantomData<T>,
}}
impl<T: DeserializeOwned> ToBuilder<T> {{
/// Take last n items before the end position.
pub fn take_last(mut self, n: u64) -> RangeBuilder<T> {{
let end = self.config.end.unwrap_or(0);
self.config.start = Some(end - n as i64);
RangeBuilder {{ config: self.config, _marker: std::marker::PhantomData }}
}}
/// Set the start position.
pub fn from(mut self, start: i64) -> RangeBuilder<T> {{
self.config.start = Some(start);
RangeBuilder {{ config: self.config, _marker: std::marker::PhantomData }}
}}
/// Execute the query and return parsed JSON data (from start of data to end).
pub fn json(self) -> Result<MetricData<T>> {{
self.config.get_json(None)
}}
/// Execute the query and return CSV data as a string.
pub fn csv(self) -> Result<String> {{
self.config.get_text(Some("csv"))
}}
}}
/// Final builder with range fully specified. Can only call `json()` or `csv()`.
pub struct RangeBuilder<T> {{
config: EndpointConfig,
_marker: std::marker::PhantomData<T>,
}}
impl<T: DeserializeOwned> RangeBuilder<T> {{
/// Execute the query and return parsed JSON data.
pub fn json(self) -> Result<MetricData<T>> {{
self.config.get_json(None)
}}
/// Execute the query and return CSV data as a string.
pub fn csv(self) -> Result<String> {{
self.config.get_text(Some("csv"))
}}
}}
@@ -225,10 +374,10 @@ pub fn generate_index_accessors(output: &mut String, patterns: &[IndexSetPattern
writeln!(output, "impl<T: DeserializeOwned> {}<T> {{", by_name).unwrap();
for index in &pattern.indexes {
let method_name = index_to_field_name(index);
writeln!(output, " pub fn {}(&self) -> Endpoint<T> {{", method_name).unwrap();
writeln!(output, " pub fn {}(&self) -> MetricEndpointBuilder<T> {{", method_name).unwrap();
writeln!(
output,
" Endpoint::new(self.client.clone(), self.name.clone(), Index::{})",
" MetricEndpointBuilder::new(self.client.clone(), self.name.clone(), Index::{})",
index
)
.unwrap();
@@ -291,7 +440,7 @@ pub fn generate_index_accessors(output: &mut String, patterns: &[IndexSetPattern
// Implement MetricPattern<T> trait
writeln!(output, "impl<T: DeserializeOwned> MetricPattern<T> for {}<T> {{", pattern.name).unwrap();
writeln!(output, " fn get(&self, index: Index) -> Option<Endpoint<T>> {{").unwrap();
writeln!(output, " fn get(&self, index: Index) -> Option<MetricEndpointBuilder<T>> {{").unwrap();
writeln!(output, " match index {{").unwrap();
for index in &pattern.indexes {
let method_name = index_to_field_name(index);