Browse Source

Start exploding query trees.

tags/v1.0^2
Ben Kurtovic 10 years ago
parent
commit
cd27777f83
1 changed files with 52 additions and 9 deletions
  1. +52
    -9
      bitshift/database/__init__.py

+ 52
- 9
bitshift/database/__init__.py View File

@@ -9,6 +9,8 @@ import mmh3
import oursql

from .migration import VERSION, MIGRATIONS
from ..query.nodes import (String, Regex, Text, Language, Author, Date, Symbol,
BinaryOp, UnaryOp)

__all__ = ["Database"]

@@ -51,23 +53,64 @@ class Database(object):
"Run `python -m bitshift.database.migration`."
raise RuntimeError(err)

def _search_with_query(self, cursor, query):
"""Convert a query tree into SQL SELECTs, execute, and return results.
def _explode_query_tree(self, tree):
"""Convert a query tree into components of an SQL SELECT statement."""
def _parse_node(node):
if isinstance(node, Text):
tables |= {"code", "symbols"}
# (FTS: codelet_name, =: symbol_name, FTS: code_code) vs. node.text (_Literal)
pass
elif isinstance(node, Language):
tables |= {"code"}
return "(code_lang = ?)", [node.lang]
elif isinstance(node, Author):
tables |= {"authors"}
# (FTS: author_name) vs. node.name (_Literal)
pass
elif isinstance(node, Date):
# read node.type, node.relation
# (>=/<=: codelet_date_created / codelet_date_modified) vs. node.date (datetime.datetime)
pass
elif isinstance(node, Symbol):
tables |= {"symbols"}
# (symbol_type, symbol_name) vs. (node.type, node.name)
pass
elif isinstance(node, BinaryOp):
left_cond, left_args = _parse_node(node.left)
right_cond, right_args = _parse_node(node.right)
op = node.OPS[node.op]
cond = "(" + left_cond + " " + op + " " + right_cond + ")"
return cond, left_args + right_args
elif isinstance(node, UnaryOp):
cond, args = _parse_node(node.node)
return "(" + node.OPS[node.op] + " " + cond + ")", args

tables = set()
conditional, arglist = _parse_node(tree.root)
# joins = " ".join(tables)

return conditional, joins, tuple(arglist)

def _search_with_query(self, cursor, query, page):
"""Execute an SQL query based on a query tree, and return results.

The returned data is a 2-tuple of (list of codelet IDs, estimated
number of total results).
"""
raise NotImplementedError() ## TODO

results = cursor.fetchall()
ids = NotImplemented ## TODO: extract ids from results
num_results = NotImplemented ## TODO: num if results else 0

conditional, joins, args = self._explode_query_tree(query)
base = "SELECT codelet_id FROM codelets %s WHERE %s LIMIT 10"
qstring = base % (joins, conditional)
if page > 1:
qstring += " OFFSET %d" % ((page - 1) * 10)

cursor.execute(qstring, args)
ids = [id for id, in cursor.fetchall()]
num_results = 0 # TODO: NotImplemented
return ids, num_results

def _get_codelets_from_ids(self, cursor, ids):
"""Return a list of Codelet objects given a list of codelet IDs."""
raise NotImplementedError() ## TODO
raise NotImplementedError() # TODO

def _decompose_url(self, cursor, url):
"""Break up a URL into an origin (with a URL base) and a suffix."""


Loading…
Cancel
Save