Function Decorator API
Hi, I have an idea for an alternate API which I think might be cleaner and less error-prone.
Here's a quick mockup:
class Binder:
def __init__(self, params: list, value) -> None:
self.params = params
self.value = value
def __str__(self):
self.params.append(self.value)
return "?"
def bound(fn):
def wrapper(*args, **kwargs):
params = []
res = fn(
*[Binder(params, arg) for arg in args],
**{k: Binder(params, v) for k, v in kwargs.items()}
)
return res, params
return wrapper
@bound
def make_me_a_query(foo: str, bar: int):
return f"SELECT * FROM table WHERE field1 = {foo} AND field2 = {bar} OR field3 < {bar}"
print(make_me_a_query("abc", bar=123))
# ('SELECT * FROM table WHERE field1 = ? AND field2 = ? OR field3 < ?', ['abc', 123, 123])
The idea is to use a function decorator that replaces the args with magic "Binder" class instances, which record their values into the params list when the fstring tries to convert them into a string (which means the order is correct, etc.)
I haven't got my head around sqlbind's more advanced features yet, but I'll have a think about how they could be adapted to this sort of API.
To elaborate on "less error-prone" part, I believe it makes it harder to, for example forget the q/ prefix on a parameter and end up with sql injection.
You are so right about injection. The other thing it could easily pass tests. It bothers me a lot. I think about simple linter to check no parameters go into strings without some sort of binding. May be it could be an extension for bandit. Your idea is also viable approach. I need some time to toy with it and try to apply to existing code.
Closing for now. A general solution requires https://peps.python.org/pep-0675/ to be widely adopted by type checkers. Or writing a typing plugin.
By the way, I just came across this PEP, that might also be useful in the future: https://peps.python.org/pep-0750/
@DavidBuchanan314 yes, its a great PEP along side with a LiteralString. I'm waiting it's support for mypy and at least typing_extensions. It would allow to restrict accidental injections.