From 860260d0ad5d09fa4fabf07b1f8dfec2410ef9f1 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sat, 24 May 2014 16:12:49 -0400 Subject: [PATCH] Finish Database.search() (closes #19) --- bitshift/database/__init__.py | 49 ++++++++++++++++++++++++++++++++++--------- bitshift/query/__init__.py | 2 +- bitshift/query/nodes.py | 9 ++++---- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/bitshift/database/__init__.py b/bitshift/database/__init__.py index 68af79c..e4fa430 100644 --- a/bitshift/database/__init__.py +++ b/bitshift/database/__init__.py @@ -9,6 +9,7 @@ import mmh3 import oursql from .migration import VERSION, MIGRATIONS +from ..codelet import Codelet from ..query.nodes import (String, Regex, Text, Language, Author, Date, Symbol, BinaryOp, UnaryOp) @@ -65,7 +66,35 @@ class Database(object): num_results = 0 # TODO: NotImplemented return ids, num_results - def _get_codelets_from_ids(self, ids): + def _get_authors_for_codelet(self, cursor, codelet_id): + """Return a list of authors for a given codelet.""" + query = """SELECT author_name, author_url + FROM authors + WHERE author_codelet = ?""" + + cursor.execute(query, (codelet_id,)) + return cursor.fetchall() + + def _get_symbols_for_code(self, cursor, code_id): + """Return a list of symbols for a given codelet.""" + query = """SELECT symbol_type, symbol_name, sloc_type, sloc_row, + sloc_col, sloc_end_row, sloc_end_col + FROM symbols + INNER JOIN symbol_locations ON sloc_symbol = symbol_id + WHERE symbol_code = ?""" + + symbols = {type_: {} for type_ in Symbol.TYPES_INV} + cursor.execute(query, (code_id,)) + for type_, name, loc_type, row, col, erow, ecol in cursor.fetchall(): + sdict = symbols[Symbol.TYPES_INV[type_]] + if name not in sdict: + sdict[name] = ((), ()) + sdict[name][loc_type].append((row, col, erow, ecol)) + for type_, sdict in symbols.items(): + symbols[type_] = [(n, d, u) for n, (d, u) in sdict.iteritems()] + return symbols + + def _get_codelets_from_ids(self, cursor, ids): """Return a list of Codelet objects given a list of codelet IDs.""" query = """SELECT * FROM codelets @@ -73,17 +102,18 @@ class Database(object): INNER JOIN origins ON codelet_origin = origin_id WHERE codelet_id = ?""" - with self._conn.cursor(oursql.DictCursor) as cursor: - cursor.executemany(query, [(id,) for id in ids]) - for row in cursor.fetchone(): + with self._conn.cursor(oursql.DictCursor) as dict_cursor: + dict_cursor.executemany(query, [(id,) for id in ids]) + for row in dict_cursor.fetchone(): + codelet_id = row["codelet_id"] if row["origin_url_base"]: url = row["codelet_url"] else: url = row["origin_url_base"] + row["codelet_url"] origin = (row["origin_name"], row["origin_url"], row["origin_image"]) - authors = NotImplemented # TODO: list of 3-tuples (author_name, author_url or None) - symbols = NotImplemented # TODO: dict of {sym_type: (name, decls, uses)} + authors = self._get_authors_for_codelet(cursor, codelet_id) + symbols = self._get_symbols_for_code(cursor, row["code_id"]) yield Codelet( row["codelet_name"], row["code_code"], None, row["code_lang"], authors, url, @@ -103,13 +133,12 @@ class Database(object): def _insert_symbols(self, cursor, code_id, sym_type, symbols): """Insert a list of symbols of a given type into the database.""" - sym_types = ["functions", "classes", "variables"] query1 = "INSERT INTO symbols VALUES (DEFAULT, ?, ?, ?)" query2 = """INSERT INTO symbol_locations VALUES (DEFAULT, ?, ?, ?, ?, ?, ?)""" for (name, decls, uses) in symbols: - cursor.execute(query1, (code_id, sym_types.index(sym_type), name)) + cursor.execute(query1, (code_id, Symbol.TYPES_INV[sym_type], name)) sym_id = cursor.lastrowid params = ([tuple([sym_id, 0] + list(loc)) for loc in decls] + [tuple([sym_id, 1] + list(loc)) for loc in uses]) @@ -153,8 +182,8 @@ class Database(object): num_mnt = num_results / (10 ** num_exp) cursor.execute(query2, (cache_id, num_mnt, num_exp)) cursor.executemany(query3, [(cache_id, c_id) for c_id in ids]) - codelet_gen = self._get_codelets_from_ids(ids) - return (num_results, list(codelet_gen)) + codelet_gen = self._get_codelets_from_ids(cursor, ids) + return (num_results, list(codelet_gen)) def insert(self, codelet): """ diff --git a/bitshift/query/__init__.py b/bitshift/query/__init__.py index dab6fe0..41d01cf 100644 --- a/bitshift/query/__init__.py +++ b/bitshift/query/__init__.py @@ -231,7 +231,7 @@ class _QueryParser(object): index = nest.index(UnaryOp.NOT) if index == len(nest) - 1: err = "Invalid query: '%s' given without argument." - raise QueryParseException(err % UnaryOp.OPS[op]) + raise QueryParseException(err % UnaryOp.OPS[UnaryOp.NOT]) right = UnaryOp(UnaryOp.NOT, self._parse_nest(nest[index + 1:])) if index > 0: left = self._parse_nest(nest[:index]) diff --git a/bitshift/query/nodes.py b/bitshift/query/nodes.py index 5a6f62c..5d157b5 100644 --- a/bitshift/query/nodes.py +++ b/bitshift/query/nodes.py @@ -190,11 +190,12 @@ class Symbol(_Node): Searches in symbol_type and symbol_name. """ - ALL = 0 - FUNCTION = 1 - CLASS = 2 - VARIABLE = 3 + ALL = -1 + FUNCTION = 0 + CLASS = 1 + VARIABLE = 2 TYPES = {FUNCTION: "FUNCTION", CLASS: "CLASS", VARIABLE: "VARIABLE"} + TYPES_INV = ["functions", "classes", "variables"] def __init__(self, type_, name): """