X-Git-Url: https://git.jsancho.org/?p=datasette-pytables.git;a=blobdiff_plain;f=datasette_pytables%2F__init__.py;h=217214f6f4d7ece9b9566e8018f85ee85c5ee47f;hp=d44c9f93485e4e187c4ec06f3565da0df6723684;hb=1d4a2abc6556f51a94b28f1e06cd682be961a7ea;hpb=8608557baec40b36d79ab47379fe735b69e0f2fa diff --git a/datasette_pytables/__init__.py b/datasette_pytables/__init__.py index d44c9f9..217214f 100644 --- a/datasette_pytables/__init__.py +++ b/datasette_pytables/__init__.py @@ -1,6 +1,6 @@ -import tables -import sqlparse from collections import OrderedDict +import sqlparse +import tables _connector_type = 'pytables' @@ -43,17 +43,51 @@ def _parse_sql(sql): else: current_keyword = str(token) parsed_sql[current_keyword] = "" + elif type(token) is sqlparse.sql.Where: + parsed_sql['where'] = token else: if not token.is_whitespace: parsed_sql[current_keyword] += str(token) return parsed_sql +_operators = { + '=': '==', +} + +def _translate_condition(table, condition, params): + field = condition.left.get_real_name() + + operator = list(filter(lambda t: t.ttype == sqlparse.tokens.Comparison, condition.tokens))[0] + if operator.value in _operators: + operator = _operators[operator.value] + else: + operator = operator.value + + value = condition.right.value + if value.startswith(':'): + # Value is a parameters + value = value[1:] + if value in params: + # Cast value to the column type + coltype = table.coltypes[field] + if coltype == 'string': + params[value] = str(params[value]) + elif coltype.startswith('int'): + params[value] = int(params[value]) + elif coltype.startswith('float'): + params[value] = float(params[value]) + + translated = "{left} {operator} {right}".format(left=field, operator=operator, right=value) + return translated, params + class Connection: def __init__(self, path): self.path = path self.h5file = tables.open_file(path) def execute(self, sql, params=None, truncate=False): + if params is None: + params = {} rows = [] truncated = False description = [] @@ -65,7 +99,22 @@ class Connection: # Use 'where' statement or get all the rows if 'where' in parsed_sql: - pass + query = [] + start = 0 + end = table.nrows + for condition in parsed_sql['where'].get_sublists(): + if str(condition) == '"rowid"=:p0': + start = int(params['p0']) + end = start + 1 + else: + translated, params = _translate_condition(table, condition, params) + query.append(translated) + if query: + query = ') & ('.join(query) + query = '(' + query + ')' + table_rows = table.where(query, params, start, end) + else: + table_rows = table.iterrows(start, end) else: table_rows = table.iterrows() @@ -80,7 +129,10 @@ class Connection: row[field] = table_row.nrow elif field == '*': for col in table.colnames: - row[col] = table_row[col] + value = table_row[col] + if type(value) is bytes: + value = value.decode('utf-8') + row[col] = value else: row[field] = table_row[field] rows.append(row) @@ -93,6 +145,7 @@ class Connection: else: description.append((field,)) + # Return the rows if truncate: return rows, truncated, tuple(description) else: @@ -102,6 +155,8 @@ class Row(OrderedDict): def __getitem__(self, label): if type(label) is int: return super(OrderedDict, self).__getitem__(list(self.keys())[label]) + else: + return super(OrderedDict, self).__getitem__(label) def __iter__(self): return self.values().__iter__()