diff --git a/bitshift/query/__init__.py b/bitshift/query/__init__.py index 5498b62..d183bde 100644 --- a/bitshift/query/__init__.py +++ b/bitshift/query/__init__.py @@ -1,5 +1,4 @@ -from .associations import BinaryOp, UnaryOp -from .node import Node +from .nodes import * ## TODO from .tree import Tree __all__ = ["parse_query"] @@ -8,20 +7,18 @@ def parse_query(query): """ Parse a search query. + The result is normalized with a sorting function so that ``"foo OR bar"`` + and ``"bar OR foo"`` result in the same tree. This is important for caching + purposes. + :param query: The query be converted. :type query: str :return: A tree storing the data in the query. :rtype: :py:class:`~.query.tree.Tree` """ - - - - - "bubble sort lang:python" - - - # gets a string, returns a Tree - # TODO: note: resultant Trees should be normalized so that "foo OR bar" - # and "bar OR foo" result in equivalent trees pass + + # "foo" -> Tree() + # "foo bar" -> "foo bar" OR ("foo" or "bar") + # "foo bar baz" -> ""foo bar baz" OR ("foo" OR "bar baz") OR ("foo" OR "bar baz") OR ('foo' OR 'bar' OR 'baz')" diff --git a/bitshift/query/associations.py b/bitshift/query/associations.py deleted file mode 100644 index 17e7a1e..0000000 --- a/bitshift/query/associations.py +++ /dev/null @@ -1,29 +0,0 @@ -__all__ = ["BinaryOp", "UnaryOp"] - -class _Association(object): - pass - - -class BinaryOp(_Association): - AND = 1 - OR = 2 - - def __init__(self, left, right, op): - self.left = left - self.right = right - self.op = op - - def __str__(self): - ops = {AND: "And", OR: "Or"} - return "{0}({1}, {2})".format(ops[self.op], self.left, self.right) - - -class UnaryOp(_Association): - NOT = 1 - - def __init__(self, node, op): - self.node = node - self.op = op - - def __str__(self): - pass diff --git a/bitshift/query/node.py b/bitshift/query/node.py deleted file mode 100644 index 3317dac..0000000 --- a/bitshift/query/node.py +++ /dev/null @@ -1,4 +0,0 @@ -__all__ = ["Node"] - -class Node(object): - pass diff --git a/bitshift/query/nodes.py b/bitshift/query/nodes.py new file mode 100644 index 0000000..c1f2dfe --- /dev/null +++ b/bitshift/query/nodes.py @@ -0,0 +1,81 @@ +__all__ = ["Node", "Text", "BinaryOp", "UnaryOp"] + +class _Literal(object): + """Represents a literal component of a search query, present at the leaves. + + A literal might be a string or a regular expression. + """ + pass + + +class _String(_Literal) + """Represents a string literal.""" + + def __init__(self, string): + self.string = string + + def __repr__(self): + return "String({0!r})".format(self.string) + + +class _Regex(_Literal): + """Represents a regular expression literal.""" + + def __init__(self, regex): + self.regex = regex + + def __repr__(self): + return "Regex({0!r})".format(self.regex) + + +class Node(object): + """Represents a single node in a query tree.""" + pass + + +class Text(Node): + """Represents a text node. + + Searches in codelet names (full-text search), symbols (equality), and + source code (full-text search). + """ + + def __init__(self, text): + self.text = text + + def __repr__(self): + return "Text({0})".format(self.text) + + +# Language -> code_lang (direct) +# DateRange -> codelet_date_created (cmp), codelet_date_modified (cmp) +# Author -> author_name (FTS) +# Symbol -> func, class, var -> symbol_type, symbol_name (direct) + + +class BinaryOp(Node): + """Represents a relationship between two nodes: ``and``, ``or``.""" + AND = 1 + OR = 2 + + def __init__(self, left, right, op): + self.left = left + self.right = right + self.op = op + + def __repr__(self): + ops = {self.AND: "And", self.OR: "Or"} + return "{0}({1}, {2})".format(ops[self.op], self.left, self.right) + + +class UnaryOp(Node): + """Represents a transformation applied to one node: ``not``.""" + NOT = 1 + + def __init__(self, node, op): + self.node = node + self.op = op + + def __repr__(self): + ops = {self.NOT: "Not"} + return "{0}({1})".format(ops[self.op], self.node) diff --git a/bitshift/query/tree.py b/bitshift/query/tree.py index 90702dc..fe65744 100644 --- a/bitshift/query/tree.py +++ b/bitshift/query/tree.py @@ -1,4 +1,13 @@ __all__ = ["Tree"] class Tree(object): - pass + """Represents a query tree.""" + + def __init__(self, root): + self._root = root + + def serialize(self): + pass + + def build_query(self): + pass