Ejemplo n.º 1
0
    def test_expr_function_arity(self):
        # Compile with the correct number of arguments.
        qc.compile_expression(qp.Function('sum', [qp.Column('number')]),
                              qe.TargetsEnvironment())

        # Compile with an incorrect number of arguments.
        with self.assertRaises(qc.CompilationError):
            qc.compile_expression(qp.Function('sum', [qp.Column('date'),
                                                      qp.Column('account')]),
                                  qe.TargetsEnvironment())
Ejemplo n.º 2
0
 def test_expr_binaryop(self):
     self.assertEqual(qc.EvalEqual(qe.DateColumn(),
                                   qc.EvalConstant(datetime.date(2014, 1, 1))),
                      qc.compile_expression(
                          qp.Equal(qp.Column('date'),
                                   qp.Constant(datetime.date(2014, 1, 1))),
                          qe.TargetsEnvironment()))
Ejemplo n.º 3
0
    def __init__(self, is_interactive, loadfun, outfile):
        super().__init__(is_interactive, query_parser.Parser(), outfile)

        self.loadfun = loadfun
        self.entries = None
        self.errors = None
        self.options_map = None

        self.env_targets = query_env.TargetsEnvironment()
        self.env_entries = query_env.FilterEntriesEnvironment()
        self.env_postings = query_env.FilterPostingsEnvironment()
Ejemplo n.º 4
0
    def __init__(self, is_interactive, loadfun, outfile,
                 default_format='text', do_numberify=False):
        super().__init__(is_interactive, query_parser.Parser(), outfile,
                         default_format, do_numberify)

        self.loadfun = loadfun
        self.entries = None
        self.errors = None
        self.options_map = None

        self.env_targets = query_env.TargetsEnvironment()
        self.env_entries = query_env.FilterEntriesEnvironment()
        self.env_postings = query_env.FilterPostingsEnvironment()
Ejemplo n.º 5
0
def generate_bql_grammar_json() -> None:
    """Generate a JSON file with BQL grammar attributes.

    The online code editor needs to have the list of available columns,
    functions, and keywords for syntax highlighting and completion.

    Should be run whenever the BQL changes."""

    target_env = query_env.TargetsEnvironment()
    data = {
        "columns": sorted(set(_env_to_list(target_env.columns))),
        "functions": sorted(set(_env_to_list(target_env.functions))),
        "keywords": sorted({kw.lower() for kw in query_parser.Lexer.keywords}),
    }
    path = BASE_PATH / "frontend" / "src" / "codemirror" / "bql-grammar.ts"
    path.write_text("export default " + json.dumps(data))
Ejemplo n.º 6
0
def generate_bql_grammar_json():
    """Generate a JSON file with BQL grammar attributes.

    The online code editor needs to have the list of available columns,
    functions, and keywords for syntax highlighting and completion.

    Should be run whenever the BQL changes."""

    target_env = query_env.TargetsEnvironment()
    data = {
        'columns': sorted(_env_to_list(target_env.columns)),
        'functions': sorted(_env_to_list(target_env.functions)),
        'keywords': sorted([kw.lower() for kw in query_parser.Lexer.keywords]),
    }
    path = os.path.join(
        os.path.dirname(__file__),
        '../fava/static/javascript/codemirror/bql-grammar.json')
    with open(path, 'w') as json_file:
        json.dump(data, json_file)
Ejemplo n.º 7
0
def run_query(entries, options_map, query, *format_args, numberify=False):
    """Compile and execute a query, return the result types and rows.

    Args:
      entries: A list of entries, as produced by the loader.
      options_map: A dict of options, as produced by the loader.
      query: A string, a single BQL query, optionally containing some new-style
        (e.g., {}) formatting specifications.
      format_args: A tuple of arguments to be formatted in the query. This is
        just provided as a convenience.
      numberify: If true, numberify the results before returning them.
    Returns:
      A pair of result types and result rows.
    Raises:
      ParseError: If the statement cannot be parsed.
      CompilationError: If the statement cannot be compiled.
    """
    env_targets = query_env.TargetsEnvironment()
    env_entries = query_env.FilterEntriesEnvironment()
    env_postings = query_env.FilterPostingsEnvironment()

    # Apply formatting to the query.
    formatted_query = query.format(*format_args)

    # Parse the statement.
    parser = query_parser.Parser()
    statement = parser.parse(formatted_query)

    # Compile the SELECT statement.
    c_query = query_compile.compile(statement, env_targets, env_postings,
                                    env_entries)

    # Execute it to obtain the result rows.
    rtypes, rrows = query_execute.execute_query(c_query, entries, options_map)

    # Numberify the results, if requested.
    if numberify:
        dformat = options_map['dcontext'].build()
        rtypes, rrows = numberify_lib.numberify_results(rtypes, rrows, dformat)

    return rtypes, rrows
Ejemplo n.º 8
0
def generate_bql_grammar_json():
    """Generate a JSON file with BQL grammar attributes.

    The online code editor needs to have the list of available columns,
    functions, and keywords for syntax highlighting and completion.

    Should be run whenever the BQL changes."""

    target_env = query_env.TargetsEnvironment()
    data = {
        "columns": sorted(set(_env_to_list(target_env.columns))),
        "functions": sorted(set(_env_to_list(target_env.functions))),
        "keywords": sorted({kw.lower()
                            for kw in query_parser.Lexer.keywords}),
    }
    path = os.path.join(
        os.path.dirname(__file__),
        "../fava/static/javascript/codemirror/bql-grammar.ts",
    )
    with open(path, "w", encoding="utf-8") as json_file:
        json_file.write("export default " + json.dumps(data))
Ejemplo n.º 9
0
class QueryBase(cmptest.TestCase):

    maxDiff = 8192

    # Default execution contexts.
    xcontext_entries = qe.FilterEntriesEnvironment()
    xcontext_targets = qe.TargetsEnvironment()
    xcontext_postings = qe.FilterPostingsEnvironment()

    def setUp(self):
        super().setUp()
        self.parser = query_parser.Parser()

    def parse(self, bql_string):
        """Parse a query.

        Args:
          bql_string: An SQL query to be parsed.
        Returns:
          A parsed statement (Select() node).
        """
        return self.parser.parse(bql_string.strip())

    def compile(self, bql_string):
        """Parse a query and compile it.

        Args:
          bql_string: An SQL query to be parsed.
        Returns:
          A compiled EvalQuery node.
        """
        return qc.compile_select(self.parse(bql_string), self.xcontext_targets,
                                 self.xcontext_postings, self.xcontext_entries)

    def check_query(self,
                    input_string,
                    bql_string,
                    expected_types,
                    expected_rows,
                    sort_rows=False,
                    debug=False):

        entries, _, options_map = loader.load_string(input_string)
        query = self.compile(bql_string)
        result_types, result_rows = qx.execute_query(query, entries,
                                                     options_map)

        if debug:
            with misc_utils.box('result_types'):
                print(result_types)
            with misc_utils.box('result_rows'):
                print(result_rows)
        self.assertEqual(expected_types, result_types)
        if sort_rows:
            result_rows.sort()
        self.assertEqual(expected_rows, result_rows)

    def check_sorted_query(self, input_string, bql_string, expected_types,
                           expected_rows):
        return self.check_query(input_string, bql_string, expected_types,
                                expected_rows, True)
Ejemplo n.º 10
0
 def test_expr_constant(self):
     self.assertEqual(
         qc.EvalConstant(D(17)),
         qc.compile_expression(qp.Constant(D(17)), qe.TargetsEnvironment()))
Ejemplo n.º 11
0
 def test_expr_unaryop(self):
     self.assertEqual(
         qc.EvalNot(qe.AccountColumn()),
         qc.compile_expression(qp.Not(qp.Column('account')),
                               qe.TargetsEnvironment()))
Ejemplo n.º 12
0
 def test_expr_function(self):
     self.assertEqual(
         qe.SumPosition([qe.PositionColumn()]),
         qc.compile_expression(qp.Function('sum', [qp.Column('position')]),
                               qe.TargetsEnvironment()))
Ejemplo n.º 13
0
class CompileSelectBase(unittest.TestCase):

    maxDiff = 8192

    # Default execution contexts.
    xcontext_entries = qe.FilterEntriesEnvironment()
    xcontext_targets = qe.TargetsEnvironment()
    xcontext_postings = qe.FilterPostingsEnvironment()

    def setUp(self):
        self.parser = qp.Parser()

    def parse(self, query):
        return self.parser.parse(query.strip())

    def compile(self, query):
        """Parse one query and compile it.

        Args:
          query: An SQL query to be parsed.
        Returns:
          The AST.
        """
        statement = self.parse(query)
        c_query = qc.compile(statement, self.xcontext_targets,
                             self.xcontext_postings, self.xcontext_entries)
        if isinstance(c_query, qp.Select):
            self.assertSelectInvariants(c_query)
        return c_query

    def assertSelectInvariants(self, query):
        """Assert the invariants on the query.

        Args:
          query: An instance of EvalQuery, a compiled query statement.
        Raises:
          AssertionError: if the check fails.
        """
        # Check that the group references cover all the simple indexes.
        if query.group_indexes is not None:
            non_aggregate_indexes = [
                index for index, c_target in enumerate(query.c_targets)
                if not qc.is_aggregate(c_target.c_expr)
            ]

            self.assertEqual(set(non_aggregate_indexes),
                             set(query.group_indexes),
                             "Invalid indexes: {}".format(query))

    def assertIndexes(self, query, expected_simple_indexes,
                      expected_aggregate_indexes, expected_group_indexes,
                      expected_order_indexes):
        """Check the four lists of indexes for comparison.

        Args:
          query: An instance of EvalQuery, a compiled query statement.
          expected_simple_indexes: The expected visible non-aggregate indexes.
          expected_aggregate_indexes: The expected visible aggregate indexes.
          expected_group_indexes: The expected group_indexes.
          expected_order_indexes: The expected order_indexes.
        Raises:
          AssertionError: if the check fails.
        """
        # Compute the list of _visible_ aggregates and non-aggregates.
        simple_indexes = [
            index for index, c_target in enumerate(query.c_targets)
            if c_target.name and not qc.is_aggregate(c_target.expression)
        ]
        aggregate_indexes = [
            index for index, c_target in enumerate(query.c_targets)
            if c_target.name and qc.is_aggregate(c_target.expression)
        ]

        self.assertEqual(set(expected_simple_indexes), set(simple_indexes))

        self.assertEqual(set(expected_aggregate_indexes),
                         set(aggregate_indexes))

        self.assertEqual(
            set(expected_group_indexes)
            if expected_group_indexes is not None else None,
            set(query.group_indexes)
            if query.group_indexes is not None else None)

        self.assertEqual(
            set(expected_order_indexes)
            if expected_order_indexes is not None else None,
            set(query.order_indexes)
            if query.order_indexes is not None else None)

    def assertCompile(self, expected, query, debug=False):
        """Assert parsed and compiled contents from 'query' is 'expected'.

        Args:
          expected: An expected AST to compare against the parsed value.
          query: An SQL query to be parsed.
          debug: A boolean, if true, print extra debugging information on the console.
        Raises:
          AssertionError: If the actual AST does not match the expected one.
        """
        actual = self.compile(query)
        if debug:
            print()
            print()
            print(actual)
            print()
        try:
            self.assertEqual(expected, actual)
            return actual
        except AssertionError:
            print()
            print("Expected: {}".format(expected))
            print("Actual  : {}".format(actual))
            raise
Ejemplo n.º 14
0
 def test_expr_column(self):
     self.assertEqual(
         qe.FilenameColumn(),
         qc.compile_expression(qp.Column('filename'),
                               qe.TargetsEnvironment()))
Ejemplo n.º 15
0
 def test_expr_invalid(self):
     with self.assertRaises(qc.CompilationError):
         qc.compile_expression(qp.Column('invalid'),
                               qe.TargetsEnvironment())
Ejemplo n.º 16
0
import json
import os

from beancount.query import query_env
from beancount.query import query_parser


def _env_to_list(attributes):
    result = []
    for name in attributes.keys():
        if isinstance(name, tuple):
            name = name[0]
        result.append(name)
    return result


TARGET_ENV = query_env.TargetsEnvironment()

DATA = {
    'columns': _env_to_list(TARGET_ENV.columns),
    'functions': _env_to_list(TARGET_ENV.functions),
    'keywords': [kw.lower() for kw in query_parser.Lexer.keywords],
}

PATH = os.path.join(os.path.dirname(__file__),
                    '../fava/static/javascript/codemirror/bql-grammar.json')

with open(PATH, 'w') as fd:
    json.dump(DATA, fd)