|
1 | 1 | from __future__ import annotations |
2 | 2 |
|
| 3 | +import asyncio |
3 | 4 | import fnmatch |
4 | 5 | import hashlib |
5 | 6 | import json |
|
25 | 26 | import param # type: ignore |
26 | 27 | import requests |
27 | 28 |
|
| 29 | +try: |
| 30 | + import aiohttp |
| 31 | +except ImportError: |
| 32 | + aiohttp = None |
| 33 | + |
28 | 34 | from panel.io.cache import _generate_hash |
29 | 35 |
|
30 | 36 | from ..base import MultiTypeComponent |
31 | 37 | from ..filters.base import Filter |
32 | 38 | from ..state import state |
33 | 39 | from ..transforms.base import Filter as FilterTransform, Transform |
34 | 40 | from ..transforms.sql import ( |
35 | | - SQLCount, SQLDistinct, SQLLimit, SQLMinMax, SQLSample, SQLSelectFrom, |
36 | | - SQLTransform, |
| 41 | + SQLCount, SQLDistinct, SQLFilter, SQLLimit, SQLMinMax, SQLSample, |
| 42 | + SQLSelectFrom, SQLTransform, |
37 | 43 | ) |
38 | 44 | from ..util import get_dataframe_schema, is_ref, merge_schemas |
39 | 45 | from ..validation import ValidationError, match_suggestion_message |
@@ -635,6 +641,24 @@ def get(self, table: str, **query) -> DataFrame: |
635 | 641 | A DataFrame containing the queried table. |
636 | 642 | """ |
637 | 643 |
|
| 644 | + async def get_async(self, table: str, **query) -> DataFrame: |
| 645 | + """ |
| 646 | + Return a table asynchronously; optionally filtered by the given query. |
| 647 | +
|
| 648 | + Parameters |
| 649 | + ---------- |
| 650 | + table : str |
| 651 | + The name of the table to query |
| 652 | + query : dict |
| 653 | + A dictionary containing all the query parameters |
| 654 | +
|
| 655 | + Returns |
| 656 | + ------- |
| 657 | + DataFrame |
| 658 | + A DataFrame containing the queried table. |
| 659 | + """ |
| 660 | + return await asyncio.to_thread(self.get, table, **query) |
| 661 | + |
638 | 662 | def __str__(self) -> str: |
639 | 663 | return self.name |
640 | 664 |
|
@@ -668,6 +692,32 @@ def get(self, table: str, **query) -> pd.DataFrame: |
668 | 692 | df = pd.DataFrame(r.json()) |
669 | 693 | return df |
670 | 694 |
|
| 695 | + async def get_async(self, table: str, **query) -> pd.DataFrame: |
| 696 | + """ |
| 697 | + Return a table asynchronously; optionally filtered by the given query. |
| 698 | +
|
| 699 | + Parameters |
| 700 | + ---------- |
| 701 | + table : str |
| 702 | + The name of the table to query |
| 703 | + query : dict |
| 704 | + A dictionary containing all the query parameters |
| 705 | +
|
| 706 | + Returns |
| 707 | + ------- |
| 708 | + DataFrame |
| 709 | + A pandas DataFrame containing the queried table. |
| 710 | + """ |
| 711 | + if aiohttp is None: |
| 712 | + return super().get_async(table, **query) |
| 713 | + |
| 714 | + query = dict(table=table, **query) |
| 715 | + async with aiohttp.ClientSession() as session: |
| 716 | + async with session.get(self.url+'/data', params=query) as response: |
| 717 | + data = await response.json() |
| 718 | + df = pd.DataFrame(data) |
| 719 | + return df |
| 720 | + |
671 | 721 |
|
672 | 722 | class InMemorySource(Source): |
673 | 723 | """ |
@@ -978,6 +1028,55 @@ def execute(self, sql_query: str, *args, **kwargs) -> pd.DataFrame: |
978 | 1028 | """ |
979 | 1029 | raise NotImplementedError |
980 | 1030 |
|
| 1031 | + async def execute_async(self, sql_query: str, *args, **kwargs) -> pd.DataFrame: |
| 1032 | + """ |
| 1033 | + Executes a SQL query asynchronously and returns the result as a DataFrame. |
| 1034 | +
|
| 1035 | + This default implementation runs the synchronous execute() method in a thread |
| 1036 | + to avoid blocking the event loop. Subclasses can override this method |
| 1037 | + to provide truly asynchronous implementations. |
| 1038 | +
|
| 1039 | + Arguments |
| 1040 | + --------- |
| 1041 | + sql_query : str |
| 1042 | + The SQL Query to execute |
| 1043 | + *args : list |
| 1044 | + Positional arguments to pass to the SQL query |
| 1045 | + **kwargs : dict |
| 1046 | + Keyword arguments to pass to the SQL query |
| 1047 | +
|
| 1048 | + Returns |
| 1049 | + ------- |
| 1050 | + pd.DataFrame |
| 1051 | + The result as a pandas DataFrame |
| 1052 | + """ |
| 1053 | + return await asyncio.to_thread(self.execute, sql_query, *args, **kwargs) |
| 1054 | + |
| 1055 | + async def get_async(self, table: str, **query) -> DataFrame: |
| 1056 | + """ |
| 1057 | + Return a table asynchronously; optionally filtered by the given query. |
| 1058 | +
|
| 1059 | + Parameters |
| 1060 | + ---------- |
| 1061 | + table : str |
| 1062 | + The name of the table to query |
| 1063 | + query : dict |
| 1064 | + A dictionary containing all the query parameters |
| 1065 | +
|
| 1066 | + Returns |
| 1067 | + ------- |
| 1068 | + DataFrame |
| 1069 | + A DataFrame containing the queried table. |
| 1070 | + """ |
| 1071 | + sql_expr = self.get_sql_expr(table) |
| 1072 | + |
| 1073 | + conditions = list(query.items()) |
| 1074 | + if conditions: |
| 1075 | + sql_filter = SQLFilter(conditions=conditions) |
| 1076 | + sql_expr = sql_filter.apply(sql_expr) |
| 1077 | + |
| 1078 | + return await self.execute_async(sql_expr) |
| 1079 | + |
981 | 1080 | @cached_schema |
982 | 1081 | def get_schema( |
983 | 1082 | self, table: str | None = None, limit: int | None = None, shuffle: bool = False |
|
0 commit comments