dropbox / sqlalchemy-stubs

Mypy plugin and stubs for SQLAlchemy
Apache License 2.0
572 stars 102 forks source link

Implement SQLResult #9

Open ilevkivskyi opened 6 years ago

ilevkivskyi commented 6 years ago

A user should be able to annotate an argument/variable that is expected to take rows of a specific table/join/etc. For example:

class BasicData(SQLResult):
    id: int
    name: str

We can also support a Python 2 compatible syntax like for named tuples. This type should be added to an actual tiny runtime package that will be shipped with stubs/plugins. This should be accompanied by at least two plugin hooks:

Note that SQLResult, Iterable[SQLResult] can be used as a more precise result for some functions in https://github.com/dropbox/sqlalchemy-stubs/issues/4.

ilevkivskyi commented 6 years ago

Alternative idea may be to make RowProxy generic in a single argument that may be only a TypedDict or a NamedTuple. This way we can write:

class BasicData(NamedTuple):
    id: int
    name: str

row: RowProxy[BasicData]

I think we should also support SQLResult[<Table instance>]/RowProxy[<Table instance>] as a shortcut for very common case where a query returns just all columns from a given table.

ilevkivskyi commented 6 years ago

Just to clarify, this is how it is supposed to be used by an end user:


class BasicData(SQLResult):
    name: str
    id: int

def row_to_some_class(row: BasicData) -> SomeClass:
    name, id = row  # This is OK
    return SomeClass(row.id, row.name)  # Also OK

row = session.query(User.id, User.name).first()
row_to_some_class(row)  # OK

another_row = session.query(User).first()
row_to_some_class(another_row)  # Error, incompatible tuple type because of
                                # fullname and e-mail