asyncclient.py 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. import asyncio
  2. import io
  3. from datetime import tzinfo
  4. from typing import Optional, Union, Dict, Any, Sequence, Iterable, Generator, BinaryIO
  5. from clickhouse_connect.driver.client import Client
  6. from clickhouse_connect.driver.common import StreamContext
  7. from clickhouse_connect.driver.httpclient import HttpClient
  8. from clickhouse_connect.driver.external import ExternalData
  9. from clickhouse_connect.driver.query import QueryContext, QueryResult
  10. from clickhouse_connect.driver.summary import QuerySummary
  11. from clickhouse_connect.datatypes.base import ClickHouseType
  12. from clickhouse_connect.driver.insert import InsertContext
  13. # pylint: disable=too-many-public-methods, too-many-instance-attributes, too-many-arguments, too-many-locals
  14. class AsyncClient:
  15. """
  16. AsyncClient is a wrapper around the ClickHouse Client object that allows for async calls to the ClickHouse server.
  17. Internally, each of the methods that uses IO is wrapped in a call to EventLoop.run_in_executor.
  18. """
  19. def __init__(self, *, client: Client):
  20. if isinstance(client, HttpClient):
  21. client.headers['User-Agent'] = client.headers['User-Agent'].replace('mode:sync;', 'mode:async;')
  22. self.client = client
  23. def set_client_setting(self, key, value):
  24. """
  25. Set a clickhouse setting for the client after initialization. If a setting is not recognized by ClickHouse,
  26. or the setting is identified as "read_only", this call will either throw a Programming exception or attempt
  27. to send the setting anyway based on the common setting 'invalid_setting_action'.
  28. :param key: ClickHouse setting name
  29. :param value: ClickHouse setting value
  30. """
  31. self.client.set_client_setting(key=key, value=value)
  32. def get_client_setting(self, key) -> Optional[str]:
  33. """
  34. :param key: The setting key
  35. :return: The string value of the setting, if it exists, or None
  36. """
  37. return self.client.get_client_setting(key=key)
  38. def min_version(self, version_str: str) -> bool:
  39. """
  40. Determine whether the connected server is at least the submitted version
  41. For Altinity Stable versions like 22.8.15.25.altinitystable
  42. the last condition in the first list comprehension expression is added
  43. :param version_str: A version string consisting of up to 4 integers delimited by dots
  44. :return: True if version_str is greater than the server_version, False if less than
  45. """
  46. return self.client.min_version(version_str)
  47. def close(self):
  48. """
  49. Subclass implementation to close the connection to the server/deallocate the client
  50. """
  51. self.client.close()
  52. async def query(self,
  53. query: Optional[str] = None,
  54. parameters: Optional[Union[Sequence, Dict[str, Any]]] = None,
  55. settings: Optional[Dict[str, Any]] = None,
  56. query_formats: Optional[Dict[str, str]] = None,
  57. column_formats: Optional[Dict[str, Union[str, Dict[str, str]]]] = None,
  58. encoding: Optional[str] = None,
  59. use_none: Optional[bool] = None,
  60. column_oriented: Optional[bool] = None,
  61. use_numpy: Optional[bool] = None,
  62. max_str_len: Optional[int] = None,
  63. context: QueryContext = None,
  64. query_tz: Optional[Union[str, tzinfo]] = None,
  65. column_tzs: Optional[Dict[str, Union[str, tzinfo]]] = None,
  66. external_data: Optional[ExternalData] = None) -> QueryResult:
  67. """
  68. Main query method for SELECT, DESCRIBE and other SQL statements that return a result matrix.
  69. For parameters, see the create_query_context method.
  70. :return: QueryResult -- data and metadata from response
  71. """
  72. def _query():
  73. return self.client.query(query=query, parameters=parameters, settings=settings, query_formats=query_formats,
  74. column_formats=column_formats, encoding=encoding, use_none=use_none,
  75. column_oriented=column_oriented, use_numpy=use_numpy, max_str_len=max_str_len,
  76. context=context, query_tz=query_tz, column_tzs=column_tzs,
  77. external_data=external_data)
  78. loop = asyncio.get_running_loop()
  79. result = await loop.run_in_executor(None, _query)
  80. return result
  81. async def query_column_block_stream(self,
  82. query: Optional[str] = None,
  83. parameters: Optional[Union[Sequence, Dict[str, Any]]] = None,
  84. settings: Optional[Dict[str, Any]] = None,
  85. query_formats: Optional[Dict[str, str]] = None,
  86. column_formats: Optional[Dict[str, Union[str, Dict[str, str]]]] = None,
  87. encoding: Optional[str] = None,
  88. use_none: Optional[bool] = None,
  89. context: QueryContext = None,
  90. query_tz: Optional[Union[str, tzinfo]] = None,
  91. column_tzs: Optional[Dict[str, Union[str, tzinfo]]] = None,
  92. external_data: Optional[ExternalData] = None) -> StreamContext:
  93. """
  94. Variation of main query method that returns a stream of column oriented blocks.
  95. For parameters, see the create_query_context method.
  96. :return: StreamContext -- Iterable stream context that returns column oriented blocks
  97. """
  98. def _query_column_block_stream():
  99. return self.client.query_column_block_stream(query=query, parameters=parameters, settings=settings,
  100. query_formats=query_formats, column_formats=column_formats,
  101. encoding=encoding, use_none=use_none, context=context,
  102. query_tz=query_tz, column_tzs=column_tzs,
  103. external_data=external_data)
  104. loop = asyncio.get_running_loop()
  105. result = await loop.run_in_executor(None, _query_column_block_stream)
  106. return result
  107. async def query_row_block_stream(self,
  108. query: Optional[str] = None,
  109. parameters: Optional[Union[Sequence, Dict[str, Any]]] = None,
  110. settings: Optional[Dict[str, Any]] = None,
  111. query_formats: Optional[Dict[str, str]] = None,
  112. column_formats: Optional[Dict[str, Union[str, Dict[str, str]]]] = None,
  113. encoding: Optional[str] = None,
  114. use_none: Optional[bool] = None,
  115. context: QueryContext = None,
  116. query_tz: Optional[Union[str, tzinfo]] = None,
  117. column_tzs: Optional[Dict[str, Union[str, tzinfo]]] = None,
  118. external_data: Optional[ExternalData] = None) -> StreamContext:
  119. """
  120. Variation of main query method that returns a stream of row oriented blocks.
  121. For parameters, see the create_query_context method.
  122. :return: StreamContext -- Iterable stream context that returns blocks of rows
  123. """
  124. def _query_row_block_stream():
  125. return self.client.query_row_block_stream(query=query, parameters=parameters, settings=settings,
  126. query_formats=query_formats, column_formats=column_formats,
  127. encoding=encoding, use_none=use_none, context=context,
  128. query_tz=query_tz, column_tzs=column_tzs,
  129. external_data=external_data)
  130. loop = asyncio.get_running_loop()
  131. result = await loop.run_in_executor(None, _query_row_block_stream)
  132. return result
  133. async def query_rows_stream(self,
  134. query: Optional[str] = None,
  135. parameters: Optional[Union[Sequence, Dict[str, Any]]] = None,
  136. settings: Optional[Dict[str, Any]] = None,
  137. query_formats: Optional[Dict[str, str]] = None,
  138. column_formats: Optional[Dict[str, Union[str, Dict[str, str]]]] = None,
  139. encoding: Optional[str] = None,
  140. use_none: Optional[bool] = None,
  141. context: QueryContext = None,
  142. query_tz: Optional[Union[str, tzinfo]] = None,
  143. column_tzs: Optional[Dict[str, Union[str, tzinfo]]] = None,
  144. external_data: Optional[ExternalData] = None) -> StreamContext:
  145. """
  146. Variation of main query method that returns a stream of row oriented blocks.
  147. For parameters, see the create_query_context method.
  148. :return: StreamContext -- Iterable stream context that returns blocks of rows
  149. """
  150. def _query_rows_stream():
  151. return self.client.query_rows_stream(query=query, parameters=parameters, settings=settings,
  152. query_formats=query_formats, column_formats=column_formats,
  153. encoding=encoding, use_none=use_none, context=context,
  154. query_tz=query_tz, column_tzs=column_tzs,
  155. external_data=external_data)
  156. loop = asyncio.get_running_loop()
  157. result = await loop.run_in_executor(None, _query_rows_stream)
  158. return result
  159. async def raw_query(self,
  160. query: str,
  161. parameters: Optional[Union[Sequence, Dict[str, Any]]] = None,
  162. settings: Optional[Dict[str, Any]] = None,
  163. fmt: str = None,
  164. use_database: bool = True,
  165. external_data: Optional[ExternalData] = None) -> bytes:
  166. """
  167. Query method that simply returns the raw ClickHouse format bytes.
  168. :param query: Query statement/format string
  169. :param parameters: Optional dictionary used to format the query
  170. :param settings: Optional dictionary of ClickHouse settings (key/string values)
  171. :param fmt: ClickHouse output format
  172. :param use_database Send the database parameter to ClickHouse so the command will be executed in the client
  173. database context
  174. :param external_data External data to send with the query
  175. :return: bytes representing raw ClickHouse return value based on format
  176. """
  177. def _raw_query():
  178. return self.client.raw_query(query=query, parameters=parameters, settings=settings, fmt=fmt,
  179. use_database=use_database, external_data=external_data)
  180. loop = asyncio.get_running_loop()
  181. result = await loop.run_in_executor(None, _raw_query)
  182. return result
  183. async def raw_stream(self, query: str,
  184. parameters: Optional[Union[Sequence, Dict[str, Any]]] = None,
  185. settings: Optional[Dict[str, Any]] = None,
  186. fmt: str = None,
  187. use_database: bool = True,
  188. external_data: Optional[ExternalData] = None) -> io.IOBase:
  189. """
  190. Query method that returns the result as an io.IOBase iterator.
  191. :param query: Query statement/format string
  192. :param parameters: Optional dictionary used to format the query
  193. :param settings: Optional dictionary of ClickHouse settings (key/string values)
  194. :param fmt: ClickHouse output format
  195. :param use_database Send the database parameter to ClickHouse so the command will be executed in the client
  196. database context
  197. :param external_data External data to send with the query
  198. :return: io.IOBase stream/iterator for the result
  199. """
  200. def _raw_stream():
  201. return self.client.raw_stream(query=query, parameters=parameters, settings=settings, fmt=fmt,
  202. use_database=use_database, external_data=external_data)
  203. loop = asyncio.get_running_loop()
  204. result = await loop.run_in_executor(None, _raw_stream)
  205. return result
  206. async def query_np(self,
  207. query: Optional[str] = None,
  208. parameters: Optional[Union[Sequence, Dict[str, Any]]] = None,
  209. settings: Optional[Dict[str, Any]] = None,
  210. query_formats: Optional[Dict[str, str]] = None,
  211. column_formats: Optional[Dict[str, str]] = None,
  212. encoding: Optional[str] = None,
  213. use_none: Optional[bool] = None,
  214. max_str_len: Optional[int] = None,
  215. context: QueryContext = None,
  216. external_data: Optional[ExternalData] = None):
  217. """
  218. Query method that returns the results as a numpy array.
  219. For parameter values, see the create_query_context method.
  220. :return: Numpy array representing the result set
  221. """
  222. def _query_np():
  223. return self.client.query_np(query=query, parameters=parameters, settings=settings,
  224. query_formats=query_formats, column_formats=column_formats, encoding=encoding,
  225. use_none=use_none, max_str_len=max_str_len, context=context,
  226. external_data=external_data)
  227. loop = asyncio.get_running_loop()
  228. result = await loop.run_in_executor(None, _query_np)
  229. return result
  230. async def query_np_stream(self,
  231. query: Optional[str] = None,
  232. parameters: Optional[Union[Sequence, Dict[str, Any]]] = None,
  233. settings: Optional[Dict[str, Any]] = None,
  234. query_formats: Optional[Dict[str, str]] = None,
  235. column_formats: Optional[Dict[str, str]] = None,
  236. encoding: Optional[str] = None,
  237. use_none: Optional[bool] = None,
  238. max_str_len: Optional[int] = None,
  239. context: QueryContext = None,
  240. external_data: Optional[ExternalData] = None) -> StreamContext:
  241. """
  242. Query method that returns the results as a stream of numpy arrays.
  243. For parameter values, see the create_query_context method.
  244. :return: Generator that yield a numpy array per block representing the result set
  245. """
  246. def _query_np_stream():
  247. return self.client.query_np_stream(query=query, parameters=parameters, settings=settings,
  248. query_formats=query_formats, column_formats=column_formats,
  249. encoding=encoding, use_none=use_none, max_str_len=max_str_len,
  250. context=context, external_data=external_data)
  251. loop = asyncio.get_running_loop()
  252. result = await loop.run_in_executor(None, _query_np_stream)
  253. return result
  254. async def query_df(self,
  255. query: Optional[str] = None,
  256. parameters: Optional[Union[Sequence, Dict[str, Any]]] = None,
  257. settings: Optional[Dict[str, Any]] = None,
  258. query_formats: Optional[Dict[str, str]] = None,
  259. column_formats: Optional[Dict[str, str]] = None,
  260. encoding: Optional[str] = None,
  261. use_none: Optional[bool] = None,
  262. max_str_len: Optional[int] = None,
  263. use_na_values: Optional[bool] = None,
  264. query_tz: Optional[str] = None,
  265. column_tzs: Optional[Dict[str, Union[str, tzinfo]]] = None,
  266. context: QueryContext = None,
  267. external_data: Optional[ExternalData] = None,
  268. use_extended_dtypes: Optional[bool] = None):
  269. """
  270. Query method that results the results as a pandas dataframe.
  271. For parameter values, see the create_query_context method.
  272. :return: Pandas dataframe representing the result set
  273. """
  274. def _query_df():
  275. return self.client.query_df(query=query, parameters=parameters, settings=settings,
  276. query_formats=query_formats, column_formats=column_formats, encoding=encoding,
  277. use_none=use_none, max_str_len=max_str_len, use_na_values=use_na_values,
  278. query_tz=query_tz, column_tzs=column_tzs, context=context,
  279. external_data=external_data, use_extended_dtypes=use_extended_dtypes)
  280. loop = asyncio.get_running_loop()
  281. result = await loop.run_in_executor(None, _query_df)
  282. return result
  283. async def query_df_stream(self,
  284. query: Optional[str] = None,
  285. parameters: Optional[Union[Sequence, Dict[str, Any]]] = None,
  286. settings: Optional[Dict[str, Any]] = None,
  287. query_formats: Optional[Dict[str, str]] = None,
  288. column_formats: Optional[Dict[str, str]] = None,
  289. encoding: Optional[str] = None,
  290. use_none: Optional[bool] = None,
  291. max_str_len: Optional[int] = None,
  292. use_na_values: Optional[bool] = None,
  293. query_tz: Optional[str] = None,
  294. column_tzs: Optional[Dict[str, Union[str, tzinfo]]] = None,
  295. context: QueryContext = None,
  296. external_data: Optional[ExternalData] = None,
  297. use_extended_dtypes: Optional[bool] = None) -> StreamContext:
  298. """
  299. Query method that returns the results as a StreamContext.
  300. For parameter values, see the create_query_context method.
  301. :return: Generator that yields a Pandas dataframe per block representing the result set
  302. """
  303. def _query_df_stream():
  304. return self.client.query_df_stream(query=query, parameters=parameters, settings=settings,
  305. query_formats=query_formats, column_formats=column_formats,
  306. encoding=encoding,
  307. use_none=use_none, max_str_len=max_str_len, use_na_values=use_na_values,
  308. query_tz=query_tz, column_tzs=column_tzs, context=context,
  309. external_data=external_data, use_extended_dtypes=use_extended_dtypes)
  310. loop = asyncio.get_running_loop()
  311. result = await loop.run_in_executor(None, _query_df_stream)
  312. return result
  313. def create_query_context(self,
  314. query: Optional[Union[str, bytes]] = None,
  315. parameters: Optional[Union[Sequence, Dict[str, Any]]] = None,
  316. settings: Optional[Dict[str, Any]] = None,
  317. query_formats: Optional[Dict[str, str]] = None,
  318. column_formats: Optional[Dict[str, Union[str, Dict[str, str]]]] = None,
  319. encoding: Optional[str] = None,
  320. use_none: Optional[bool] = None,
  321. column_oriented: Optional[bool] = None,
  322. use_numpy: Optional[bool] = False,
  323. max_str_len: Optional[int] = 0,
  324. context: Optional[QueryContext] = None,
  325. query_tz: Optional[Union[str, tzinfo]] = None,
  326. column_tzs: Optional[Dict[str, Union[str, tzinfo]]] = None,
  327. use_na_values: Optional[bool] = None,
  328. streaming: bool = False,
  329. as_pandas: bool = False,
  330. external_data: Optional[ExternalData] = None,
  331. use_extended_dtypes: Optional[bool] = None) -> QueryContext:
  332. """
  333. Creates or updates a reusable QueryContext object
  334. :param query: Query statement/format string
  335. :param parameters: Optional dictionary used to format the query
  336. :param settings: Optional dictionary of ClickHouse settings (key/string values)
  337. :param query_formats: See QueryContext __init__ docstring
  338. :param column_formats: See QueryContext __init__ docstring
  339. :param encoding: See QueryContext __init__ docstring
  340. :param use_none: Use None for ClickHouse NULL instead of default values. Note that using None in Numpy
  341. arrays will force the numpy array dtype to 'object', which is often inefficient. This effect also
  342. will impact the performance of Pandas dataframes.
  343. :param column_oriented: Deprecated. Controls orientation of the QueryResult result_set property
  344. :param use_numpy: Return QueryResult columns as one-dimensional numpy arrays
  345. :param max_str_len: Limit returned ClickHouse String values to this length, which allows a Numpy
  346. structured array even with ClickHouse variable length String columns. If 0, Numpy arrays for
  347. String columns will always be object arrays
  348. :param context: An existing QueryContext to be updated with any provided parameter values
  349. :param query_tz Either a string or a pytz tzinfo object. (Strings will be converted to tzinfo objects).
  350. Values for any DateTime or DateTime64 column in the query will be converted to Python datetime.datetime
  351. objects with the selected timezone
  352. :param column_tzs A dictionary of column names to tzinfo objects (or strings that will be converted to
  353. tzinfo objects). The timezone will be applied to datetime objects returned in the query
  354. :param use_na_values: Deprecated alias for use_advanced_dtypes
  355. :param as_pandas Return the result columns as pandas.Series objects
  356. :param streaming Marker used to correctly configure streaming queries
  357. :param external_data ClickHouse "external data" to send with query
  358. :param use_extended_dtypes: Only relevant to Pandas Dataframe queries. Use Pandas "missing types", such as
  359. pandas.NA and pandas.NaT for ClickHouse NULL values, as well as extended Pandas dtypes such as IntegerArray
  360. and StringArray. Defaulted to True for query_df methods
  361. :return: Reusable QueryContext
  362. """
  363. return self.client.create_query_context(query=query, parameters=parameters, settings=settings,
  364. query_formats=query_formats, column_formats=column_formats,
  365. encoding=encoding, use_none=use_none,
  366. column_oriented=column_oriented,
  367. use_numpy=use_numpy, max_str_len=max_str_len, context=context,
  368. query_tz=query_tz, column_tzs=column_tzs,
  369. use_na_values=use_na_values,
  370. streaming=streaming, as_pandas=as_pandas,
  371. external_data=external_data,
  372. use_extended_dtypes=use_extended_dtypes)
  373. async def query_arrow(self,
  374. query: str,
  375. parameters: Optional[Union[Sequence, Dict[str, Any]]] = None,
  376. settings: Optional[Dict[str, Any]] = None,
  377. use_strings: Optional[bool] = None,
  378. external_data: Optional[ExternalData] = None):
  379. """
  380. Query method using the ClickHouse Arrow format to return a PyArrow table
  381. :param query: Query statement/format string
  382. :param parameters: Optional dictionary used to format the query
  383. :param settings: Optional dictionary of ClickHouse settings (key/string values)
  384. :param use_strings: Convert ClickHouse String type to Arrow string type (instead of binary)
  385. :param external_data ClickHouse "external data" to send with query
  386. :return: PyArrow.Table
  387. """
  388. def _query_arrow():
  389. return self.client.query_arrow(query=query, parameters=parameters, settings=settings,
  390. use_strings=use_strings, external_data=external_data)
  391. loop = asyncio.get_running_loop()
  392. result = await loop.run_in_executor(None, _query_arrow)
  393. return result
  394. async def query_arrow_stream(self,
  395. query: str,
  396. parameters: Optional[Union[Sequence, Dict[str, Any]]] = None,
  397. settings: Optional[Dict[str, Any]] = None,
  398. use_strings: Optional[bool] = None,
  399. external_data: Optional[ExternalData] = None) -> StreamContext:
  400. """
  401. Query method that returns the results as a stream of Arrow tables
  402. :param query: Query statement/format string
  403. :param parameters: Optional dictionary used to format the query
  404. :param settings: Optional dictionary of ClickHouse settings (key/string values)
  405. :param use_strings: Convert ClickHouse String type to Arrow string type (instead of binary)
  406. :param external_data ClickHouse "external data" to send with query
  407. :return: Generator that yields a PyArrow.Table for per block representing the result set
  408. """
  409. def _query_arrow_stream():
  410. return self.client.query_arrow_stream(query=query, parameters=parameters, settings=settings,
  411. use_strings=use_strings, external_data=external_data)
  412. loop = asyncio.get_running_loop()
  413. result = await loop.run_in_executor(None, _query_arrow_stream)
  414. return result
  415. async def command(self,
  416. cmd: str,
  417. parameters: Optional[Union[Sequence, Dict[str, Any]]] = None,
  418. data: Union[str, bytes] = None,
  419. settings: Dict[str, Any] = None,
  420. use_database: bool = True,
  421. external_data: Optional[ExternalData] = None) -> Union[str, int, Sequence[str], QuerySummary]:
  422. """
  423. Client method that returns a single value instead of a result set
  424. :param cmd: ClickHouse query/command as a python format string
  425. :param parameters: Optional dictionary of key/values pairs to be formatted
  426. :param data: Optional 'data' for the command (for INSERT INTO in particular)
  427. :param settings: Optional dictionary of ClickHouse settings (key/string values)
  428. :param use_database: Send the database parameter to ClickHouse so the command will be executed in the client
  429. database context. Otherwise, no database will be specified with the command. This is useful for determining
  430. the default user database
  431. :param external_data ClickHouse "external data" to send with command/query
  432. :return: Decoded response from ClickHouse as either a string, int, or sequence of strings, or QuerySummary
  433. if no data returned
  434. """
  435. def _command():
  436. return self.client.command(cmd=cmd, parameters=parameters, data=data, settings=settings,
  437. use_database=use_database, external_data=external_data)
  438. loop = asyncio.get_running_loop()
  439. result = await loop.run_in_executor(None, _command)
  440. return result
  441. async def ping(self) -> bool:
  442. """
  443. Validate the connection, does not throw an Exception (see debug logs)
  444. :return: ClickHouse server is up and reachable
  445. """
  446. def _ping():
  447. return self.client.ping()
  448. loop = asyncio.get_running_loop()
  449. result = await loop.run_in_executor(None, _ping)
  450. return result
  451. async def insert(self,
  452. table: Optional[str] = None,
  453. data: Sequence[Sequence[Any]] = None,
  454. column_names: Union[str, Iterable[str]] = '*',
  455. database: Optional[str] = None,
  456. column_types: Sequence[ClickHouseType] = None,
  457. column_type_names: Sequence[str] = None,
  458. column_oriented: bool = False,
  459. settings: Optional[Dict[str, Any]] = None,
  460. context: InsertContext = None) -> QuerySummary:
  461. """
  462. Method to insert multiple rows/data matrix of native Python objects. If context is specified arguments
  463. other than data are ignored
  464. :param table: Target table
  465. :param data: Sequence of sequences of Python data
  466. :param column_names: Ordered list of column names or '*' if column types should be retrieved from the
  467. ClickHouse table definition
  468. :param database: Target database -- will use client default database if not specified.
  469. :param column_types: ClickHouse column types. If set then column data does not need to be retrieved from
  470. the server
  471. :param column_type_names: ClickHouse column type names. If set then column data does not need to be
  472. retrieved from the server
  473. :param column_oriented: If true the data is already "pivoted" in column form
  474. :param settings: Optional dictionary of ClickHouse settings (key/string values)
  475. :param context: Optional reusable insert context to allow repeated inserts into the same table with
  476. different data batches
  477. :return: QuerySummary with summary information, throws exception if insert fails
  478. """
  479. def _insert():
  480. return self.client.insert(table=table, data=data, column_names=column_names, database=database,
  481. column_types=column_types, column_type_names=column_type_names,
  482. column_oriented=column_oriented, settings=settings, context=context)
  483. loop = asyncio.get_running_loop()
  484. result = await loop.run_in_executor(None, _insert)
  485. return result
  486. async def insert_df(self, table: str = None,
  487. df=None,
  488. database: Optional[str] = None,
  489. settings: Optional[Dict] = None,
  490. column_names: Optional[Sequence[str]] = None,
  491. column_types: Sequence[ClickHouseType] = None,
  492. column_type_names: Sequence[str] = None,
  493. context: InsertContext = None) -> QuerySummary:
  494. """
  495. Insert a pandas DataFrame into ClickHouse. If context is specified arguments other than df are ignored
  496. :param table: ClickHouse table
  497. :param df: two-dimensional pandas dataframe
  498. :param database: Optional ClickHouse database
  499. :param settings: Optional dictionary of ClickHouse settings (key/string values)
  500. :param column_names: An optional list of ClickHouse column names. If not set, the DataFrame column names
  501. will be used
  502. :param column_types: ClickHouse column types. If set then column data does not need to be retrieved from
  503. the server
  504. :param column_type_names: ClickHouse column type names. If set then column data does not need to be
  505. retrieved from the server
  506. :param context: Optional reusable insert context to allow repeated inserts into the same table with
  507. different data batches
  508. :return: QuerySummary with summary information, throws exception if insert fails
  509. """
  510. def _insert_df():
  511. return self.client.insert_df(table=table, df=df, database=database, settings=settings,
  512. column_names=column_names,
  513. column_types=column_types, column_type_names=column_type_names,
  514. context=context)
  515. loop = asyncio.get_running_loop()
  516. result = await loop.run_in_executor(None, _insert_df)
  517. return result
  518. async def insert_arrow(self, table: str,
  519. arrow_table, database: str = None,
  520. settings: Optional[Dict] = None) -> QuerySummary:
  521. """
  522. Insert a PyArrow table DataFrame into ClickHouse using raw Arrow format
  523. :param table: ClickHouse table
  524. :param arrow_table: PyArrow Table object
  525. :param database: Optional ClickHouse database
  526. :param settings: Optional dictionary of ClickHouse settings (key/string values)
  527. :return: QuerySummary with summary information, throws exception if insert fails
  528. """
  529. def _insert_arrow():
  530. return self.client.insert_arrow(table=table, arrow_table=arrow_table, database=database, settings=settings)
  531. loop = asyncio.get_running_loop()
  532. result = await loop.run_in_executor(None, _insert_arrow)
  533. return result
  534. async def create_insert_context(self,
  535. table: str,
  536. column_names: Optional[Union[str, Sequence[str]]] = None,
  537. database: Optional[str] = None,
  538. column_types: Sequence[ClickHouseType] = None,
  539. column_type_names: Sequence[str] = None,
  540. column_oriented: bool = False,
  541. settings: Optional[Dict[str, Any]] = None,
  542. data: Optional[Sequence[Sequence[Any]]] = None) -> InsertContext:
  543. """
  544. Builds a reusable insert context to hold state for a duration of an insert
  545. :param table: Target table
  546. :param database: Target database. If not set, uses the client default database
  547. :param column_names: Optional ordered list of column names. If not set, all columns ('*') will be assumed
  548. in the order specified by the table definition
  549. :param database: Target database -- will use client default database if not specified
  550. :param column_types: ClickHouse column types. Optional Sequence of ClickHouseType objects. If neither column
  551. types nor column type names are set, actual column types will be retrieved from the server.
  552. :param column_type_names: ClickHouse column type names. Specified column types by name string
  553. :param column_oriented: If true the data is already "pivoted" in column form
  554. :param settings: Optional dictionary of ClickHouse settings (key/string values)
  555. :param data: Initial dataset for insert
  556. :return Reusable insert context
  557. """
  558. def _create_insert_context():
  559. return self.client.create_insert_context(table=table, column_names=column_names, database=database,
  560. column_types=column_types, column_type_names=column_type_names,
  561. column_oriented=column_oriented, settings=settings, data=data)
  562. loop = asyncio.get_running_loop()
  563. result = await loop.run_in_executor(None, _create_insert_context)
  564. return result
  565. async def data_insert(self, context: InsertContext) -> QuerySummary:
  566. """
  567. Subclass implementation of the data insert
  568. :context: InsertContext parameter object
  569. :return: No return, throws an exception if the insert fails
  570. """
  571. def _data_insert():
  572. return self.client.data_insert(context=context)
  573. loop = asyncio.get_running_loop()
  574. result = await loop.run_in_executor(None, _data_insert)
  575. return result
  576. async def raw_insert(self, table: str,
  577. column_names: Optional[Sequence[str]] = None,
  578. insert_block: Union[str, bytes, Generator[bytes, None, None], BinaryIO] = None,
  579. settings: Optional[Dict] = None,
  580. fmt: Optional[str] = None,
  581. compression: Optional[str] = None) -> QuerySummary:
  582. """
  583. Insert data already formatted in a bytes object
  584. :param table: Table name (whether qualified with the database name or not)
  585. :param column_names: Sequence of column names
  586. :param insert_block: Binary or string data already in a recognized ClickHouse format
  587. :param settings: Optional dictionary of ClickHouse settings (key/string values)
  588. :param compression: Recognized ClickHouse `Accept-Encoding` header compression value
  589. :param fmt: Valid clickhouse format
  590. """
  591. def _raw_insert():
  592. return self.client.raw_insert(table=table, column_names=column_names, insert_block=insert_block,
  593. settings=settings, fmt=fmt, compression=compression)
  594. loop = asyncio.get_running_loop()
  595. result = await loop.run_in_executor(None, _raw_insert)
  596. return result