-
Notifications
You must be signed in to change notification settings - Fork 7
feat: Async dialect #35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
3a333e6
WIP
ptiurin a64ef8f
Async Integration tests
ptiurin 59490a7
Get rid of mssql leftover
ptiurin 98878cc
Async unit tests
ptiurin 3aa37b3
Splitting tests into diff files
ptiurin c7cc289
Refactor unit tests
ptiurin a739060
Refactor integration tests
ptiurin 228960f
type hints
ptiurin 16e48c7
Removing commented out code
ptiurin f688958
Mypy checks
ptiurin 9b80da7
Fix final errors
ptiurin f263a0e
Using python 3.8 for testing
ptiurin a22a82d
Try with backport
ptiurin 47900c8
Using backport
ptiurin 8da2b67
Backport in conftest
ptiurin ef6ec3d
Fix name in CI
ptiurin 741e5c7
Setting server side to false
ptiurin e0a0b9e
Adding example to readme
ptiurin dfe14f2
Pinning versions of mock and stubs
ptiurin 506f758
Adding missing typehints
ptiurin 917fc3c
Applying feedback
ptiurin df978a7
Fix rowcount
ptiurin 6d6372b
Reusing cursor in cursor wrapper
ptiurin aeb5330
Fix type issue
ptiurin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,157 @@ | ||
| from __future__ import annotations | ||
ptiurin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| from asyncio import Lock | ||
| from types import ModuleType | ||
| from typing import Any, Iterator, List, Optional, Tuple | ||
|
|
||
| import firebolt.async_db as async_dbapi | ||
| from firebolt.async_db import Connection | ||
|
|
||
| # Ignoring type since sqlalchemy-stubs doesn't cover AdaptedConnection | ||
| from sqlalchemy.engine import AdaptedConnection # type: ignore[attr-defined] | ||
ptiurin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| from sqlalchemy.util.concurrency import await_only | ||
|
|
||
| from firebolt_db.firebolt_dialect import FireboltDialect | ||
|
|
||
|
|
||
| class AsyncCursorWrapper: | ||
| __slots__ = ( | ||
| "_adapt_connection", | ||
| "_connection", | ||
| "await_", | ||
| "_cursor", | ||
| "_rows", | ||
| ) | ||
|
|
||
| server_side = False | ||
|
|
||
| def __init__(self, adapt_connection: AsyncConnectionWrapper): | ||
| self._adapt_connection = adapt_connection | ||
| self._connection = adapt_connection._connection | ||
| self.await_ = adapt_connection.await_ | ||
| self._rows: List[List] = [] | ||
| self._cursor = self._connection.cursor() | ||
|
|
||
| def close(self) -> None: | ||
| self._rows[:] = [] | ||
| self._cursor.close() | ||
|
|
||
| @property | ||
| def description(self) -> str: | ||
| return self._cursor.description | ||
|
|
||
| @property | ||
| def arraysize(self) -> int: | ||
| return self._cursor.arraysize | ||
|
|
||
| @arraysize.setter | ||
| def arraysize(self, value: int) -> None: | ||
| self._cursor.arraysize = value | ||
|
|
||
| @property | ||
| def rowcount(self) -> int: | ||
| return self._cursor.rowcount | ||
|
|
||
| def execute(self, operation: str, parameters: Optional[Tuple] = None) -> None: | ||
| self.await_(self._execute(operation, parameters)) | ||
|
|
||
| async def _execute( | ||
| self, operation: str, parameters: Optional[Tuple] = None | ||
| ) -> None: | ||
| async with self._adapt_connection._execute_mutex: | ||
| await self._cursor.execute(operation, parameters) | ||
| if self._cursor.description: | ||
| self._rows = await self._cursor.fetchall() | ||
| else: | ||
| self._rows = [] | ||
|
|
||
| def executemany(self, operation: str, seq_of_parameters: List[Tuple]) -> None: | ||
| raise NotImplementedError("executemany is not supported yet") | ||
|
|
||
| def __iter__(self) -> Iterator[List]: | ||
| while self._rows: | ||
| yield self._rows.pop(0) | ||
|
|
||
| def fetchone(self) -> Optional[List]: | ||
| if self._rows: | ||
| return self._rows.pop(0) | ||
| else: | ||
| return None | ||
|
|
||
| def fetchmany(self, size: int = None) -> List[List]: | ||
| if size is None: | ||
| size = self._cursor.arraysize | ||
|
|
||
| retval = self._rows[0:size] | ||
| self._rows[:] = self._rows[size:] | ||
| return retval | ||
|
|
||
| def fetchall(self) -> List[List]: | ||
| retval = self._rows[:] | ||
| self._rows[:] = [] | ||
| return retval | ||
|
|
||
|
|
||
| class AsyncConnectionWrapper(AdaptedConnection): | ||
| await_ = staticmethod(await_only) | ||
| __slots__ = ("dbapi", "_connection", "_execute_mutex") | ||
|
|
||
| def __init__(self, dbapi: AsyncAPIWrapper, connection: Connection): | ||
| self.dbapi = dbapi | ||
| self._connection = connection | ||
| self._execute_mutex = Lock() | ||
|
|
||
| def cursor(self) -> AsyncCursorWrapper: | ||
| return AsyncCursorWrapper(self) | ||
|
|
||
| def rollback(self) -> None: | ||
stepansergeevitch marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| pass | ||
|
|
||
| def commit(self) -> None: | ||
| self._connection.commit() | ||
|
|
||
| def close(self) -> None: | ||
| self.await_(self._connection._aclose()) | ||
|
|
||
|
|
||
| class AsyncAPIWrapper(ModuleType): | ||
| """Wrapper around Firebolt async dbapi that returns a similar wrapper for | ||
| Cursor on connect()""" | ||
|
|
||
| def __init__(self, dbapi: ModuleType): | ||
| self.dbapi = dbapi | ||
| self.paramstyle = dbapi.paramstyle # type: ignore[attr-defined] # noqa: F821 | ||
| self._init_dbapi_attributes() | ||
|
|
||
| def _init_dbapi_attributes(self) -> None: | ||
| for name in ( | ||
| "DatabaseError", | ||
| "Error", | ||
| "IntegrityError", | ||
| "NotSupportedError", | ||
| "OperationalError", | ||
| "ProgrammingError", | ||
| ): | ||
| setattr(self, name, getattr(self.dbapi, name)) | ||
|
|
||
| def connect(self, *arg: Any, **kw: Any) -> AsyncConnectionWrapper: | ||
|
|
||
| connection = await_only(self.dbapi.connect(*arg, **kw)) # type: ignore[attr-defined] # noqa: F821,E501 | ||
| return AsyncConnectionWrapper( | ||
| self, | ||
| connection, | ||
| ) | ||
|
|
||
|
|
||
| class AsyncFireboltDialect(FireboltDialect): | ||
| driver = "firebolt_aio" | ||
| supports_statement_cache: bool = False | ||
| supports_server_side_cursors: bool = False | ||
| is_async: bool = True | ||
|
|
||
| @classmethod | ||
| def dbapi(cls) -> AsyncAPIWrapper: | ||
| return AsyncAPIWrapper(async_dbapi) | ||
|
|
||
|
|
||
| dialect = AsyncFireboltDialect | ||
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
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.