Last active
October 28, 2019 12:01
-
-
Save dkgndianko/7bd2e4a7047cf826da3728ea63e2631b to your computer and use it in GitHub Desktop.
Dynamically generate getter methods for a repository based on the name of fields
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"} | |
# TODO: Add docstrings | |
# After first generation, add method to the repository class for further calling. | |
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