db.select() can now use filter; returns total count, and selection

This commit is contained in:
Doug Blank 2016-01-08 14:07:43 -05:00
parent cc00442e0b
commit 1654757c22

View File

@ -1880,7 +1880,7 @@ class DbWriteBase(DbReadBase):
filter=None): filter=None):
""" """
Default implementation of a select for those databases Default implementation of a select for those databases
that don't support SQL. Yields data row by row. that don't support SQL. Returns a list of dicts, and total.
table - Person, Family, etc. table - Person, Family, etc.
fields - used by object.get_field() fields - used by object.get_field()
@ -1890,6 +1890,11 @@ class DbWriteBase(DbReadBase):
filter - {field: (SQL string_operator, value), } filter - {field: (SQL string_operator, value), }
handles all SQL except for NOT expression, eg NOT x = y handles all SQL except for NOT expression, eg NOT x = y
""" """
class Result(list):
"""
A list rows of just matching for this page, with total = all.
"""
total = 0
def hash_name(name): def hash_name(name):
""" """
Used in filter to eval expressions involving selected Used in filter to eval expressions involving selected
@ -1914,61 +1919,73 @@ class DbWriteBase(DbReadBase):
data = self._tables[table]["handles_func"]() data = self._tables[table]["handles_func"]()
position = 0 position = 0
selected = 0 selected = 0
for handle in data: result = Result()
if position < start: if filter:
pass # skip it for handle in data:
else: # have to evaluate all, because there is a filter
item = self._tables[table]["handle_func"](handle) item = self._tables[table]["handle_func"](handle)
row = {} row = {}
env = {} env = {}
for field in fields: for field in filter.keys():
# just the ones we need for filter
value = item.get_field(field) value = item.get_field(field)
row[field] = value env[hash_name(field)] = value
if filter: matched = True
env[hash_name(field)] = value for name, (op, value) in filter.items():
if filter: v = eval(hash_name(name), env)
matched = True if op == "=":
for name, (op, value) in filter.items(): matched = v == value
v = eval(hash_name(name), env) elif op == ">":
if op == "=": matched = v > value
matched = v == value elif op == ">=":
elif op == ">": matched = v >= value
matched = v > value elif op == "<":
elif op == ">=": matched = v < value
matched = v >= value elif op == "<=":
elif op == "<": matched = v <= value
matched = v < value elif op == "IN":
elif op == "<=": matched = v in value
matched = v <= value elif op == "IS":
elif op == "IN": matched = v is value
matched = v in value elif op == "IS NOT":
elif op == "IS": matched = v is not value
matched = v is value elif op == "IS NULL":
elif op == "IS NOT": matched = v is None
matched = v is not value elif op == "IS NOT NULL":
elif op == "IS NULL": matched = v is not None
matched = v is None elif op == "BETWEEN":
elif op == "IS NOT NULL": matched = value[0] <= v <= value[1]
matched = v is not None elif op in ["<>", "!="]:
elif op == "BETWEEN": matched = v != value
matched = value[0] <= v <= value[1] elif op == "LIKE":
elif op in ["<>", "!="]: value = value.replace("%", "(.*)").replace("_", ".")
matched = v != value matched = re.match(value, v)
elif op == "LIKE":
value = value.replace("%", "(.*)").replace("_", ".")
matched = re.match(value, v)
else:
raise Exception("invalid select operator: '%s'" % op)
if not matched:
break
if matched:
selected += 1
yield row
else: else:
continue raise Exception("invalid select operator: '%s'" % op)
else: if not matched:
break
if matched:
if selected < limit and start <= position:
# now, we get all of the fields
for field in fields:
value = item.get_field(field)
row[field] = value
selected += 1
result.append(row)
position += 1
result.total = position
else: # no filter
for handle in data:
if position >= start:
if selected >= limit:
break
item = self._tables[table]["handle_func"](handle)
row = {}
for field in fields:
value = item.get_field(field)
row[field] = value
result.append(row)
selected += 1 selected += 1
yield row position += 1
position += 1 result.total = self._tables[table]["count_func"]()
if selected == limit: return result
break