Skip to content

Instantly share code, notes, and snippets.

@dkgndianko
Created October 28, 2019 11:46
Show Gist options
  • Save dkgndianko/1387538d8286dc85d7fe0ca83fcec4ac to your computer and use it in GitHub Desktop.
Save dkgndianko/1387538d8286dc85d7fe0ca83fcec4ac to your computer and use it in GitHub Desktop.
Dynamically generate getter methods for a repository based on the name of fields
from typing import List, Callable, Iterator, Tuple
LOGICAL_SEPARATORS = ["and", "or"]
OPERATORS = ["lt", "gt", "not", "in", "none"]
OPERATORS_MAPPING = {"=": "=", "lt": "<", "gt": ">", "lte": "<=", "gte": ">=", "not": "!=", "none": "is None",
"is": "is"}
def _generate_method(method_name: str) -> Callable:
zip_iterator = _process_getter(method_name.split("_"))
def the_method(*args):
res = []
l = len(args)
it = iter(args)
for param, operation, logical in zip_iterator:
try:
value = next(it)
if isinstance(value, bool): # we must base on type of param
operation = "is"
res.append(f"{param} {OPERATORS_MAPPING[operation]} {value}")
except StopIteration:
raise TypeError(f"{method_name} is missing 1 required positional argument: '{param}'")
return ", ".join(res)
return the_method
def _process_getter(parts: List[str]) -> Iterator[Tuple[str, str, str]]:
current_name = None
operators = []
logicals = []
names = []
last_logical = None
operation = None
for name in parts:
if not current_name:
current_name = name
continue
if name in OPERATORS:
operation = name
elif name in LOGICAL_SEPARATORS:
operators.append(operation or "=")
logicals.append(last_logical or "and")
names.append(current_name)
last_logical = name
current_name = None
else:
current_name = f"{current_name}_{name}"
operators.append(operation or "=")
logicals.append(last_logical or "and")
names.append(current_name)
return zip(names, operators, logicals)
def test():
methods = {"username_and_password": ("mouhamad", "CTSM@@Ngui"), "value_gt_and_name_not_and_age_lt": (2, "Beep", 63), "last_change_or_password_expired": ("2019-05-21", False), "age_gt_and_is_enabled_and_locked": (18, False, False)}
# for m in methods:
# r = _process_getter(m.split("_"))
# r = [str(e) for e in r]
# print(f"{m} -> {r}")
for m, values in methods.items():
f = _generate_method(m)
res = f(*values)
print(f"{m} -> {res}")
if __name__ == "__main__":
test()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment