On 21/05/24 09:34, Stefano Zacchiroli wrote:
On Mon, May 20, 2024 at 11:22:33PM +0200, Daniele Nicolodi wrote:
 From the perspective of the maintainer of bean-query, I wonder whether a
tool like this could have been implemented as a front-end  that interprets
the command line options and translates them into a query for bean-query in
the form 'PRINT FROM ...'

If you thought about this approach, I would like to know which shortcomings
of bean-query didn't allow to implement bean-grep this way.

Probably a disappointment to you (sorry!), but I didn't consider that
approach. I'm familiar with the Python API of Beancount, so that was my
go-to design choice. Hence I don't think I've useful feedback to give
you on the applicability of the approach you propose.

Just a gut feeling, though: if the translation you suggest requires
generating queries as textual strings, that would make me feel itchy,
due to the usual SQL-style problems of generating invalid syntax,
possibly involuntary SQL-injections, etc. If OTOH there is an abstract
(AST-based?) API to do the same, it would be less of a problem.

beanquery parses a query into an AST representation which is then "compiled" into an tree of evaluator nodes (for lack of a better name, if someone has a better idea of how these should be called, please let me know) that are then executed. An example of both can be obtained running the '.explain' command in the shell:

beanquery> .explain select date + 1 from #postings
parsed statement
----------------
  (select
    targets: (
      (target
        expression: (add
          left: (column
            name: 'date')
          right: (constant
            value: 1))))
    from-clause: (table
      name: 'postings'))

compiled query
--------------
EvalQuery(table=<beanquery.query_env.PostingsTable object at 0x1064cdb50>, c_targets=[EvalTarget(c_expr=Add[date,int](date(<class 'datetime.date'>), EvalConstant(1)), name='date + 1', is_aggregate=False)], c_where=None, group_indexes=None, having_index=None, order_spec=None, limit=None, distinct=None)

The parser AST is displayed in s-expression-like format, inspired to the one produced by tree-sitter, but it is just Python classes:

>>> beanquery.parser.parse('SELECT 1+1 FROM #')
Select(
  targets=[
    Target(
      expression=Add(
        left=Constant(value=1),
        right=Constant(value=1)),
      name=None)
  ],
  from_clause=Table(name=''),
  where_clause=None,
  group_by=None,
  order_by=None,
  pivot_by=None,
  limit=None,
  distinct=None
)

(reformatted for readability)

The public API exposes the possibility to directly pass the parser AST. The evaluator nodes are not public API, and writing the evaluation nodes by hand becomes tedious for anything non-trivial.

On the other hand, beanquery exposed an DB-API 2.0 compatible API with parameters placeholders and parameters substitutions:

>>> from datetime import date
>>> import beanquery
>>> conn = beanquery.connect('beancount:tests/test01.beancount')
>>> curs = conn.execute(
...   'SELECT date WHERE date > %s',
...    (date.today(),)
... )
>>> curs.fetchall()
[]
>>> curs = conn.execute(
...   'SELECT date WHERE date > %(today)s',
...   {'today': date.today()})
>>> curs.fetchall()
[]

Query parameters are not interpolated in the query, but the AST has direct support for them:

>>> beanquery.parser.parse(
...   'SELECT date FROM #postings WHERE date > %(today)s')
Select(
  targets=[
    Target(
      expression=Column(name='date'), name=None)
  ],
  from_clause=Table(name='postings'),
  where_clause=Greater(
    left=Column(name='date'),
    right=Placeholder(name='today')
          ^^^^^^^^^^^^^^^^^^^^^^^^^
  ),
  group_by=None,
  order_by=None,
  pivot_by=None,
  limit=None,
  distinct=None
)


Some day I need to document all this...

Cheers,
Dan

--
You received this message because you are subscribed to the Google Groups 
"Beancount" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/beancount/a8c82044-1b99-4e83-b458-c7af6583c6ba%40grinta.net.

Reply via email to