+ 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, oper, target):
+ if key_next_index == len(key_list) or content is None:
+ try:
+ if oper in ("eq", "cont"):
+ if isinstance(target, list):
+ if isinstance(content, list):
+ return any(content_item in target for content_item in content)
+ return content in target
+ elif isinstance(content, list):
+ return target in content
+ else:
+ return content == target
+ elif oper in ("neq", "ne", "ncont"):
+ if isinstance(target, list):
+ if isinstance(content, list):
+ return all(content_item not in target for content_item in content)
+ return content not in target
+ elif isinstance(content, list):
+ return target not in content
+ else:
+ return content != target
+ if oper == "gt":
+ return content > target
+ elif oper == "gte":
+ return content >= target
+ elif oper == "lt":
+ return content < target
+ elif oper == "lte":
+ return content <= target
+ else:
+ raise DbException("Unknown filter operator '{}' in key '{}'".
+ format(oper, ".".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]), oper,
+ target)
+ elif isinstance(content, list):
+ look_for_match = True # when there is a match return immediately
+ if (target is None) != (oper in ("neq", "ne", "ncont")): # one True and other False (Xor)
+ look_for_match = False # when there is not a match return immediately
+
+ for content_item in content:
+ if key_list[key_next_index] == "ANYINDEX" and isinstance(v, dict):
+ matches = True
+ 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):
+ matches = False
+ break
+
+ else:
+ matches = recursive_find(key_list, key_next_index, content_item, oper, target)
+ if matches == look_for_match:
+ return matches
+ if key_list[key_next_index].isdecimal() and int(key_list[key_next_index]) < len(content):
+ matches = recursive_find(key_list, key_next_index + 1, content[int(key_list[key_next_index])],
+ oper, target)
+ if matches == look_for_match:
+ return matches
+ return not look_for_match
+ else: # content is not dict, nor list neither None, so not found
+ if oper in ("neq", "ne", "ncont"):
+ return target is not None
+ else:
+ return target is None