+ def _format_filter(q_filter):
+ db_filter = {}
+ # split keys with ANYINDEX in this way:
+ # {"A.B.ANYINDEX.C.D.ANYINDEX.E": v } -> {"A.B.ANYINDEX": {"C.D.ANYINDEX": {"E": v}}}
+ if q_filter:
+ for k, v in q_filter.items():
+ db_v = v
+ kleft, _, kright = k.rpartition(".ANYINDEX.")
+ while kleft:
+ k = kleft + ".ANYINDEX"
+ db_v = {kright: db_v}
+ kleft, _, kright = k.rpartition(".ANYINDEX.")
+ deep_update(db_filter, {k: db_v})
+
+ return db_filter
+
+ def _find(self, table, q_filter):
+
+ def recursive_find(key_list, key_next_index, content, operator, target):
+ if key_next_index == len(key_list) or content is None:
+ try:
+ if operator == "eq":
+ if isinstance(target, list) and not isinstance(content, list):
+ return True if content in target else False
+ return True if content == target else False
+ elif operator in ("neq", "ne"):
+ if isinstance(target, list) and not isinstance(content, list):
+ return True if content not in target else False
+ return True if content != target else False
+ if operator == "gt":
+ return content > target
+ elif operator == "gte":
+ return content >= target
+ elif operator == "lt":
+ return content < target
+ elif operator == "lte":
+ return content <= target
+ elif operator == "cont":
+ return content in target
+ elif operator == "ncont":
+ return content not in target
+ else:
+ raise DbException("Unknown filter operator '{}' in key '{}'".
+ format(operator, ".".join(key_list)), http_code=HTTPStatus.BAD_REQUEST)
+ except TypeError:
+ return False
+
+ elif isinstance(content, dict):
+ return recursive_find(key_list, key_next_index+1, content.get(key_list[key_next_index]), operator,
+ target)
+ elif isinstance(content, list):
+ look_for_match = True # when there is a match return immediately
+ if (target is None and operator not in ("neq", "ne")) or \
+ (target is not None and operator in ("neq", "ne")):
+ look_for_match = False # when there is a match return immediately
+
+ for content_item in content:
+ if key_list[key_next_index] == "ANYINDEX" and isinstance(v, dict):
+ for k2, v2 in target.items():
+ k_new_list = k2.split(".")
+ new_operator = "eq"
+ if k_new_list[-1] in ("eq", "ne", "gt", "gte", "lt", "lte", "cont", "ncont", "neq"):
+ new_operator = k_new_list.pop()
+ if not recursive_find(k_new_list, 0, content_item, new_operator, v2):
+ match = False
+ break
+ else:
+ match = True
+
+ else:
+ match = recursive_find(key_list, key_next_index, content_item, operator, target)
+ if match == look_for_match:
+ return match
+ if key_list[key_next_index].isdecimal() and int(key_list[key_next_index]) < len(content):
+ match = recursive_find(key_list, key_next_index+1, content[int(key_list[key_next_index])],
+ operator, target)
+ if match == look_for_match:
+ return match
+ return not look_for_match
+ else: # content is not dict, nor list neither None, so not found
+ if operator in ("neq", "ne"):
+ return True if target is None else False
+ else:
+ return True if target is None else False