9749: Move experimental Select API code into a branch

This commit is contained in:
Nick Hall
2016-10-12 21:30:44 +01:00
parent ce4d4ca31d
commit 2993d59c2e
8 changed files with 0 additions and 1296 deletions

View File

@ -2080,63 +2080,6 @@ class DBAPI(DbGeneric):
else:
return repr(value)
def _build_where_clause_recursive(self, table, where):
"""
where - (field, op, value)
- ["NOT", where]
- ["AND", (where, ...)]
- ["OR", (where, ...)]
"""
if where is None:
return ""
elif len(where) == 3:
field, db_op, value = where
return "(%s %s %s)" % (self._hash_name(table, field),
db_op, self._sql_repr(value))
elif where[0] in ["AND", "OR"]:
parts = [self._build_where_clause_recursive(table, part)
for part in where[1]]
return "(%s)" % ((" %s " % where[0]).join(parts))
else:
return "(NOT %s)" % self._build_where_clause_recursive(table,
where[1])
def _build_where_clause(self, table, where):
"""
where - a list in where format
return - "WHERE conditions..."
"""
parts = self._build_where_clause_recursive(table, where)
if parts:
return "WHERE " + parts
else:
return ""
def _build_order_clause(self, table, order_by):
"""
order_by - [(field, "ASC" | "DESC"), ...]
"""
if order_by:
order_clause = ", ".join(["%s %s" % (self._hash_name(table, field),
dir)
for (field, dir) in order_by])
return "ORDER BY " + order_clause
else:
return ""
def _build_select_fields(self, table, select_fields, secondary_fields):
"""
fields - [field, ...]
return: "field, field, field"
"""
all_available = all([(field in secondary_fields)
for field in select_fields])
if all_available: # we can get them without expanding
return select_fields
else:
# nope, we'll have to expand blob to get all fields
return ["blob_data"]
def _check_order_by_fields(self, table, order_by, secondary_fields):
"""
Check to make sure all order_by fields are defined. If not, then
@ -2150,128 +2093,6 @@ class DBAPI(DbGeneric):
return False
return True
def _check_where_fields(self, table, where, secondary_fields):
"""
Check to make sure all where fields are defined. If not, then
we need to do the Python-based select.
secondary_fields are hashed.
"""
if where is None:
return True
elif len(where) == 2: # ["AND" [...]] | ["OR" [...]] | ["NOT" expr]
connector, exprs = where
if connector in ["AND", "OR"]:
for expr in exprs:
value = self._check_where_fields(table, expr,
secondary_fields)
if value == False:
return False
return True
else: # "NOT"
return self._check_where_fields(table, exprs, secondary_fields)
elif len(where) == 3: # (name, db_op, value)
(name, db_op, value) = where
# just the ones we need for where
return self._hash_name(table, name) in secondary_fields
def _select(self, table, fields=None, start=0, limit=-1,
where=None, order_by=None):
"""
Default implementation of a select for those databases
that don't support SQL. Returns a list of dicts, total,
and time.
table - Person, Family, etc.
fields - used by object.get_field()
start - position to start
limit - count to get; -1 for all
where - (field, SQL string_operator, value) |
["AND", [where, where, ...]] |
["OR", [where, where, ...]] |
["NOT", where]
order_by - [[fieldname, "ASC" | "DESC"], ...]
"""
secondary_fields = ([self._hash_name(table, field)
for (field, ptype)
in self.get_table_func(
table, "class_func").get_secondary_fields()]
+ ["handle"])
# handle is a sql field, but not listed in secondaries
# If no fields, then we need objects:
# Check to see if where matches SQL fields:
table_name = table.lower()
if ((not self._check_where_fields(table, where, secondary_fields))
or (not self._check_order_by_fields(table, order_by,
secondary_fields))):
# If not, then need to do select via Python:
generator = super()._select(table, fields, start,
limit, where, order_by)
for item in generator:
yield item
return
# Otherwise, we are SQL
if fields is None:
fields = ["blob_data"]
get_count_only = False
if fields[0] == "count(1)":
hashed_fields = ["count(1)"]
fields = ["count(1)"]
select_fields = ["count(1)"]
get_count_only = True
else:
hashed_fields = [self._hash_name(table, field) for field in fields]
fields = hashed_fields
select_fields = self._build_select_fields(table, fields,
secondary_fields)
where_clause = self._build_where_clause(table, where)
order_clause = self._build_order_clause(table, order_by)
if get_count_only:
select_fields = ["1"]
if start:
query = "SELECT %s FROM %s %s %s LIMIT %s, %s " % (
", ".join(select_fields),
table_name, where_clause, order_clause, start, limit
)
else:
query = "SELECT %s FROM %s %s %s LIMIT %s" % (
", ".join(select_fields),
table_name, where_clause, order_clause, limit
)
if get_count_only:
self.dbapi.execute("SELECT count(1) from (%s) AS temp_select;"
% query)
rows = self.dbapi.fetchall()
yield rows[0][0]
return
self.dbapi.execute(query)
rows = self.dbapi.fetchall()
for row in rows:
if fields[0] != "blob_data":
obj = None # don't build it if you don't need it
data = {}
for field in fields:
if field in select_fields:
data[field.replace("__", ".")
] = row[select_fields.index(field)]
else:
if obj is None: # we need it! create it and cache it:
obj = self.get_table_func(table,
"class_func").create(
pickle.loads(row[0]))
# get the field, even if we need to do a join:
# FIXME: possible optimize:
# do a join in select for this if needed:
field = field.replace("__", ".")
data[field] = obj.get_field(field, self,
ignore_errors=True)
yield data
else:
obj = self.get_table_func(table,
"class_func").create(
pickle.loads(row[0]))
yield obj
def get_summary(self):
"""
Returns dictionary of summary item.