Add BQL query method to FavaClient
Implemented query_bql() method to enable efficient Beancount Query Language (BQL) queries against Fava API. This is the foundation for replacing manual balance aggregation (115 lines) with optimized BQL queries. Benefits: - Efficient server-side filtering and aggregation - 5-10x expected performance improvement - Cleaner, more maintainable code Next: Implement get_user_balance_bql() using this method. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
6d6ac190c7
commit
e1ad3bc5a5
1 changed files with 55 additions and 0 deletions
|
|
@ -491,6 +491,61 @@ class FavaClient:
|
|||
logger.error(f"Fava connection error: {e}")
|
||||
raise
|
||||
|
||||
async def query_bql(self, query_string: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Execute arbitrary Beancount Query Language (BQL) query.
|
||||
|
||||
This is a general-purpose method for executing BQL queries against Fava/Beancount.
|
||||
Use this for efficient aggregations, filtering, and data retrieval.
|
||||
|
||||
Args:
|
||||
query_string: BQL query (e.g., "SELECT account, sum(position) WHERE account ~ 'User-abc'")
|
||||
|
||||
Returns:
|
||||
{
|
||||
"rows": [[col1, col2, ...], ...],
|
||||
"types": [{"name": "col1", "type": "str"}, ...],
|
||||
"column_names": ["col1", "col2", ...]
|
||||
}
|
||||
|
||||
Example:
|
||||
result = await fava.query_bql("SELECT account, sum(position) WHERE account ~ 'User-abc'")
|
||||
for row in result["rows"]:
|
||||
account, balance = row
|
||||
print(f"{account}: {balance}")
|
||||
|
||||
See:
|
||||
https://beancount.github.io/docs/beancount_query_language.html
|
||||
"""
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
||||
response = await client.get(
|
||||
f"{self.base_url}/query",
|
||||
params={"query_string": query_string}
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
|
||||
# Fava returns: {"data": {"rows": [...], "types": [...]}}
|
||||
data = result.get("data", {})
|
||||
rows = data.get("rows", [])
|
||||
types = data.get("types", [])
|
||||
column_names = [t.get("name") for t in types]
|
||||
|
||||
return {
|
||||
"rows": rows,
|
||||
"types": types,
|
||||
"column_names": column_names
|
||||
}
|
||||
|
||||
except httpx.HTTPStatusError as e:
|
||||
logger.error(f"BQL query error: {e.response.status_code} - {e.response.text}")
|
||||
logger.error(f"Query was: {query_string}")
|
||||
raise
|
||||
except httpx.RequestError as e:
|
||||
logger.error(f"Fava connection error: {e}")
|
||||
raise
|
||||
|
||||
async def get_account_transactions(
|
||||
self,
|
||||
account_name: str,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue