postgrest-py
postgrest-py copied to clipboard
feat: new query api
I have a proposal for a new query API for postgrest-py. The objective is to be more strict with respect to the order in that the different methods can be chained like the SQL statements keeping the full type annotation.
In select:
singleandmaybe_singlecan't be chainedlimitandrangeonly can be chained with asingle, or amaybe_singleorderonly can be chained with alimit, a range, asingle, amaybe_single, or otherorderwhereonly can be chained with alimit, a range, asingle, amaybe_single,order, or otherwherefrom_only can be chained with awhere, alimit, a range, asingle, amaybe_single, or anorderselectonly can be chained with afrom_
In update:
valuescan't be chainedwhereonly can be chained with otherwhere, or avaluesupdateonly can be chained with awhere, or avalues
In delete:
whereonly can be chained with otherwheredeleteonly can be chained with awhere
The statements are independents of the client execution way following the idea of other ORM like the new API of SQLALchemy
I think that is a good option to implement this proposal as an addition, not a substitution of the actual implementation.
The code below like a proof of concept only shows the typing annotations:
from typing import Generic, Iterable, Type, TypeVar
class Filter:
def ne(self, key, value) -> "Filter":
...
def eq(self, key, value) -> "Filter":
...
ne = Filter().ne
eq = Filter().eq
T = TypeVar("T")
class WhereStatement(Generic[T]):
def __init__(self, type: Type[T]) -> None:
self.__type = type
def where(self, filter: Filter) -> T:
return self.__type()
class Statement:
...
class ValuesStatement:
def values(self, data: dict) -> Statement:
...
class SingleStatement:
def single(self) -> Statement:
...
class MaybeSingleStatement:
def maybe_single(self) -> Statement:
...
class UnionSingleStatement(SingleStatement, MaybeSingleStatement):
...
class LimitOrRangeStatement(UnionSingleStatement):
def limit(self) -> UnionSingleStatement:
...
def range(self) -> UnionSingleStatement:
...
class OrderStatement(LimitOrRangeStatement):
def order(self) -> "OrderStatement":
...
class FromStatement(WhereStatement["FromStatement"], OrderStatement):
def __init__(self) -> None:
WhereStatement.__init__(self, type(self))
class SelectStatement:
def __init__(self, *colums: Iterable[str]) -> None:
pass
def from_(self, table: str) -> FromStatement:
...
class UpdateStatement(WhereStatement["UpdateStatement"], ValuesStatement):
def __init__(self, table: str) -> None:
WhereStatement.__init__(self, type(self))
class DeleteStatement(WhereStatement["DeleteStatement"], Statement):
def __init__(self, table: str) -> None:
WhereStatement.__init__(self, type(self))
select = SelectStatement
update = UpdateStatement
delete = DeleteStatement
class PostgrestClient:
def exec(self, statement: Statement):
...
client = PostgrestClient()
filter = ne("key1", "value1").eq("key2", "value2")
select_query = select("column1", "column2").from_("table").where(filter).single()
result_select_query = client.exec(select_query)
update_query = update("table").where(filter).values({"key1": "new_value"})
result_update_query = client.exec(update_query)
delete_query = delete("table").where(filter)
result_delete_query = client.exec(delete_query)
Sourcery Code Quality Report
Merging this PR leaves code quality unchanged.
| Quality metrics | Before | After | Change |
|---|---|---|---|
| Complexity | 2.19 ⭐ | 2.19 ⭐ | 0.00 |
| Method Length | 30.00 ⭐ | 30.00 ⭐ | 0.00 |
| Working memory | 5.50 ⭐ | 5.50 ⭐ | 0.00 |
| Quality | 84.75% ⭐ | 84.75% ⭐ | 0.00% |
| Other metrics | Before | After | Change |
|---|---|---|---|
| Lines | 17 | 17 | 0 |
| Changed files | Quality Before | Quality After | Quality Change |
|---|---|---|---|
| postgrest_py/exceptions.py | 84.75% ⭐ | 84.75% ⭐ | 0.00% |
Here are some functions in these files that still need a tune-up:
| File | Function | Complexity | Length | Working Memory | Quality | Recommendation |
|---|
Legend and Explanation
The emojis denote the absolute quality of the code:
- ⭐ excellent
- 🙂 good
- 😞 poor
- ⛔ very poor
The 👍 and 👎 indicate whether the quality has improved or gotten worse with this pull request.
Please see our documentation here for details on how these metrics are calculated.
We are actively working on this report - lots more documentation and extra metrics to come!
Help us improve this quality report!
Codecov Report
Merging #102 (e653ccf) into master (796687d) will not change coverage. The diff coverage is
100.00%.
@@ Coverage Diff @@
## master #102 +/- ##
=======================================
Coverage 90.10% 90.10%
=======================================
Files 22 22
Lines 869 869
=======================================
Hits 783 783
Misses 86 86
| Impacted Files | Coverage Δ | |
|---|---|---|
| postgrest_py/exceptions.py | 43.47% <100.00%> (ø) |
Continue to review full report at Codecov.
Legend - Click here to learn more
Δ = absolute <relative> (impact),ø = not affected,? = missing dataPowered by Codecov. Last update 796687d...e653ccf. Read the comment docs.
Closing this one out as it has been in draft for over a year now. I'm also not sure about changing the API design as we are following the JavaScript library closely and some of these changes would shift us away from that.