X-Git-Url: https://git.jsancho.org/?p=datasette-pytables.git;a=blobdiff_plain;f=datasette_pytables%2F__init__.py;h=86f879c0a1b423019ccb88de9616e8ecfee0ce1f;hp=5d9fb22f78a88601900a08396b40541267f967c1;hb=d62ba74e92c673f170c444899e14cae4b065e79a;hpb=a0ba326e2827753049cf411967bea0503c30154a diff --git a/datasette_pytables/__init__.py b/datasette_pytables/__init__.py index 5d9fb22..86f879c 100644 --- a/datasette_pytables/__init__.py +++ b/datasette_pytables/__init__.py @@ -1,4 +1,3 @@ -from collections import OrderedDict from moz_sql_parser import parse import re import tables @@ -71,7 +70,7 @@ class Connection: self.path = path self.h5file = tables.open_file(path) - def execute(self, sql, params=None, truncate=False, page_size=None): + def execute(self, sql, params=None, truncate=False, page_size=None, max_returned_rows=None): if params is None: params = {} rows = [] @@ -81,7 +80,9 @@ class Connection: parsed_sql = _parse_sql(sql, params) if parsed_sql['from'] == 'sqlite_master': - return self._execute_datasette_query(sql, params) + rows = self._execute_datasette_query(sql, params) + description = (('value',)) + return rows, truncated, description table = self.h5file.get_node(parsed_sql['from']) table_rows = [] @@ -94,7 +95,10 @@ class Connection: # Use 'where' statement or get all the rows def _cast_param(field, pname): # Cast value to the column type - coltype = table.coltypes[field] + if type(table) is tables.table.Table: + coltype = table.coltypes[field] + else: + coltype = table.dtype.name fcast = None if coltype == 'string': fcast = str @@ -107,6 +111,7 @@ class Connection: def _translate_where(where): # Translate SQL to PyTables expression + nonlocal start, end expr = '' operator = list(where)[0] @@ -118,9 +123,10 @@ class Connection: elif operator == 'exists': pass elif where == {'eq': ['rowid', 'p0']}: - nonlocal start, end start = int(params['p0']) end = start + 1 + elif where == {'gt': ['rowid', 'p0']}: + start = int(params['p0']) + 1 else: left, right = where[operator] if left in params: @@ -139,16 +145,14 @@ class Connection: query = parsed_sql['where'] # Limit number of rows + limit = None if 'limit' in parsed_sql: - max_rows = int(parsed_sql['limit']) - if end - start > max_rows: - end = start + max_rows + limit = int(parsed_sql['limit']) # Truncate if needed - if page_size and truncate: - if end - start > page_size: - end = start + page_size - truncated = True + if page_size and max_returned_rows and truncate: + if max_returned_rows == page_size: + max_returned_rows += 1 # Execute query if query: @@ -162,7 +166,14 @@ class Connection: rows.append(Row({'count(*)': int(table.nrows)})) else: if type(table) is tables.table.Table: + count = 0 for table_row in table_rows: + count += 1 + if limit and count > limit: + break + if truncate and max_returned_rows and count > max_returned_rows: + truncated = True + break row = Row() for field in fields: field_name = field['value'] @@ -182,7 +193,14 @@ class Connection: else: # Any kind of array rowid = start - 1 + count = 0 for table_row in table_rows: + count += 1 + if limit and count > limit: + break + if truncate and max_returned_rows and count > max_returned_rows: + truncated = True + break row = Row() rowid += 1 for field in fields: @@ -210,10 +228,7 @@ class Connection: description.append((field,)) # Return the rows - if truncate: - return rows, truncated, tuple(description) - else: - return rows + return rows, truncated, tuple(description) def _execute_datasette_query(self, sql, params): "Datasette special queries for getting tables info" @@ -232,12 +247,29 @@ class Connection: else: raise Exception("SQLite queries cannot be executed with this connector") -class Row(OrderedDict): - def __getitem__(self, label): - if type(label) is int: - return super(OrderedDict, self).__getitem__(list(self.keys())[label]) +class Row(list): + def __init__(self, values=None): + self.labels = [] + self.values = [] + if values: + for idx in values: + self.__setitem__(idx, values[idx]) + + def __setitem__(self, idx, value): + if type(idx) is str: + if idx in self.labels: + self.values[self.labels.index(idx)] = value + else: + self.labels.append(idx) + self.values.append(value) + else: + self.values[idx] = value + + def __getitem__(self, idx): + if type(idx) is str: + return self.values[self.labels.index(idx)] else: - return super(OrderedDict, self).__getitem__(label) + return self.values[idx] def __iter__(self): - return self.values().__iter__() + return self.values.__iter__()