timeplus.query
query
This module defines query class
:copyright: (c) 2022 by Timeplus
:license: Apache2, see LICENSE for more details.
View Source
0""" 1query 2 3This module defines query class 4:copyright: (c) 2022 by Timeplus 5:license: Apache2, see LICENSE for more details. 6""" 7 8import requests 9import json 10from websocket import create_connection 11import rx 12import dateutil.parser 13 14from timeplus.resource import ResourceBase 15from timeplus.env import Env 16from timeplus.type import Type 17from timeplus.error import TimeplusAPIError 18 19 20class Query(ResourceBase): 21 """ 22 Query class defines query object. 23 """ 24 25 _resource_name = "queries" 26 27 def __init__(self, env=None): 28 ResourceBase.__init__(self, env) 29 self.stopped = False 30 31 @classmethod 32 def build(cls, query, env=None): 33 obj = cls(env=env) 34 obj._data = query 35 return obj 36 37 @classmethod 38 def execSQL(cls, sql, timeout=1000, env=None): 39 if env is None: 40 env = Env.current() 41 42 headers = env.headers() 43 base_url = env.base_url() 44 45 url = f"{base_url}/sql" 46 env.logger().debug(f"post {url}") 47 sqlRequest = {"sql": sql, "timeout": timeout} 48 49 try: 50 r = requests.post(f"{url}", json=sqlRequest, headers=headers) 51 if r.status_code < 200 or r.status_code > 299: 52 err_msg = f"failed to run sql due to {r.text}" 53 raise TimeplusAPIError("post", r.status_code, err_msg) 54 else: 55 return r.json() 56 except Exception as e: 57 env.logger.error(f"failed to run sql {e}") 58 raise e 59 60 @classmethod 61 def exec(cls, sql, env=None): 62 if env is None: 63 env = Env.current() 64 headers = env.headers() 65 base_url = env.base_url() 66 67 url = f"{base_url}/exec" 68 env.logger.debug(f"post {url}") 69 sqlRequest = { 70 "sql": sql, 71 } 72 73 try: 74 r = requests.post(f"{url}", json=sqlRequest, headers=headers) 75 if r.status_code < 200 or r.status_code > 299: 76 err_msg = f"failed to run exec due to {r.text}" 77 raise TimeplusAPIError("post", r.status_code, err_msg) 78 else: 79 return r.json() 80 except Exception as e: 81 env.logger.error(f"failed to run exec {e}") 82 raise e 83 84 def name(self, *args): 85 return self.prop("name", *args) 86 87 def description(self, *args): 88 return self.prop("description", *args) 89 90 def sql(self, *args): 91 return self.prop("sql", *args) 92 93 def tags(self, *args): 94 return self.prop("tags", *args) 95 96 def id(self): 97 return self.prop("id") 98 99 def stat(self): 100 self.get() 101 return self.prop("stat") 102 103 def status(self): 104 self.get() 105 return self.prop("status") 106 107 def header(self): 108 self.get() 109 return self.prop("result")["header"] 110 111 def cancel(self): 112 self.action("cancel") 113 return self 114 115 def stop(self): 116 self.stopped = True 117 118 def sink_to(self, sink): 119 url = f"{self._base_url}/{self._resource_name}/{self.id()}/sinks" 120 self._logger.debug(f"post {url}") 121 sinkRequest = {"sink_id": sink.id()} 122 try: 123 r = requests.post(f"{url}", json=sinkRequest, headers=self._headers) 124 if r.status_code < 200 or r.status_code > 299: 125 err_msg = f"failed to add sink {sink.id()} to query {self.id()} {r.status_code} {r.text}" 126 raise TimeplusAPIError("post", r.status_code, err_msg) 127 else: 128 self._logger.debug(f"add sink {sink.id()} to query {self.id()} success") 129 return self 130 except Exception as e: 131 self._logger.error(f"failed to add sink {e}") 132 raise e 133 134 def show_query_result(self, count=10): 135 ws_schema = "ws" 136 if self._env.schema() == "https": 137 ws_schema = "wss" 138 ws = create_connection( 139 f"{ws_schema}://{self._env.host()}:{self._env.port()}/ws/queries/{self.id()}" 140 ) 141 for i in range(count): 142 result = ws.recv() 143 self._logger.info(result) 144 145 # TODO: refactor this complex method 146 def _query_op(self): # noqa: C901 147 def __query_op(observer, scheduler): 148 # TODO : use WebSocketApp 149 ws_schema = "ws" 150 if self._env.schema() == "https": 151 ws_schema = "wss" 152 ws = create_connection( 153 f"{ws_schema}://{self._env.host()}:{self._env.port()}/ws/queries/{self.id()}" 154 ) 155 try: 156 while True: 157 if self.stopped: 158 break 159 result = ws.recv() 160 # convert string object to json(array) 161 # todo convert by header type 162 record = json.loads(result) 163 164 for index, col in enumerate(self.header()): 165 if col["type"].startswith(Type.Tuple.value): 166 record[index] = tuple(record[index]) 167 elif col["type"].startswith(Type.Date.value): 168 try: 169 record[index] = dateutil.parser.isoparse(record[index]) 170 except Exception as e: 171 self._logger.error("failed to parse datetime ", e) 172 173 observer.on_next(record) 174 observer.on_complete() 175 except Exception: 176 pass 177 178 return __query_op 179 180 def get_result_stream(self): 181 strem_query_ob = rx.create(self._query_op()) 182 return strem_query_ob
View Source
21class Query(ResourceBase): 22 """ 23 Query class defines query object. 24 """ 25 26 _resource_name = "queries" 27 28 def __init__(self, env=None): 29 ResourceBase.__init__(self, env) 30 self.stopped = False 31 32 @classmethod 33 def build(cls, query, env=None): 34 obj = cls(env=env) 35 obj._data = query 36 return obj 37 38 @classmethod 39 def execSQL(cls, sql, timeout=1000, env=None): 40 if env is None: 41 env = Env.current() 42 43 headers = env.headers() 44 base_url = env.base_url() 45 46 url = f"{base_url}/sql" 47 env.logger().debug(f"post {url}") 48 sqlRequest = {"sql": sql, "timeout": timeout} 49 50 try: 51 r = requests.post(f"{url}", json=sqlRequest, headers=headers) 52 if r.status_code < 200 or r.status_code > 299: 53 err_msg = f"failed to run sql due to {r.text}" 54 raise TimeplusAPIError("post", r.status_code, err_msg) 55 else: 56 return r.json() 57 except Exception as e: 58 env.logger.error(f"failed to run sql {e}") 59 raise e 60 61 @classmethod 62 def exec(cls, sql, env=None): 63 if env is None: 64 env = Env.current() 65 headers = env.headers() 66 base_url = env.base_url() 67 68 url = f"{base_url}/exec" 69 env.logger.debug(f"post {url}") 70 sqlRequest = { 71 "sql": sql, 72 } 73 74 try: 75 r = requests.post(f"{url}", json=sqlRequest, headers=headers) 76 if r.status_code < 200 or r.status_code > 299: 77 err_msg = f"failed to run exec due to {r.text}" 78 raise TimeplusAPIError("post", r.status_code, err_msg) 79 else: 80 return r.json() 81 except Exception as e: 82 env.logger.error(f"failed to run exec {e}") 83 raise e 84 85 def name(self, *args): 86 return self.prop("name", *args) 87 88 def description(self, *args): 89 return self.prop("description", *args) 90 91 def sql(self, *args): 92 return self.prop("sql", *args) 93 94 def tags(self, *args): 95 return self.prop("tags", *args) 96 97 def id(self): 98 return self.prop("id") 99 100 def stat(self): 101 self.get() 102 return self.prop("stat") 103 104 def status(self): 105 self.get() 106 return self.prop("status") 107 108 def header(self): 109 self.get() 110 return self.prop("result")["header"] 111 112 def cancel(self): 113 self.action("cancel") 114 return self 115 116 def stop(self): 117 self.stopped = True 118 119 def sink_to(self, sink): 120 url = f"{self._base_url}/{self._resource_name}/{self.id()}/sinks" 121 self._logger.debug(f"post {url}") 122 sinkRequest = {"sink_id": sink.id()} 123 try: 124 r = requests.post(f"{url}", json=sinkRequest, headers=self._headers) 125 if r.status_code < 200 or r.status_code > 299: 126 err_msg = f"failed to add sink {sink.id()} to query {self.id()} {r.status_code} {r.text}" 127 raise TimeplusAPIError("post", r.status_code, err_msg) 128 else: 129 self._logger.debug(f"add sink {sink.id()} to query {self.id()} success") 130 return self 131 except Exception as e: 132 self._logger.error(f"failed to add sink {e}") 133 raise e 134 135 def show_query_result(self, count=10): 136 ws_schema = "ws" 137 if self._env.schema() == "https": 138 ws_schema = "wss" 139 ws = create_connection( 140 f"{ws_schema}://{self._env.host()}:{self._env.port()}/ws/queries/{self.id()}" 141 ) 142 for i in range(count): 143 result = ws.recv() 144 self._logger.info(result) 145 146 # TODO: refactor this complex method 147 def _query_op(self): # noqa: C901 148 def __query_op(observer, scheduler): 149 # TODO : use WebSocketApp 150 ws_schema = "ws" 151 if self._env.schema() == "https": 152 ws_schema = "wss" 153 ws = create_connection( 154 f"{ws_schema}://{self._env.host()}:{self._env.port()}/ws/queries/{self.id()}" 155 ) 156 try: 157 while True: 158 if self.stopped: 159 break 160 result = ws.recv() 161 # convert string object to json(array) 162 # todo convert by header type 163 record = json.loads(result) 164 165 for index, col in enumerate(self.header()): 166 if col["type"].startswith(Type.Tuple.value): 167 record[index] = tuple(record[index]) 168 elif col["type"].startswith(Type.Date.value): 169 try: 170 record[index] = dateutil.parser.isoparse(record[index]) 171 except Exception as e: 172 self._logger.error("failed to parse datetime ", e) 173 174 observer.on_next(record) 175 observer.on_complete() 176 except Exception: 177 pass 178 179 return __query_op 180 181 def get_result_stream(self): 182 strem_query_ob = rx.create(self._query_op()) 183 return strem_query_ob
Query class defines query object.
View Source
38 @classmethod 39 def execSQL(cls, sql, timeout=1000, env=None): 40 if env is None: 41 env = Env.current() 42 43 headers = env.headers() 44 base_url = env.base_url() 45 46 url = f"{base_url}/sql" 47 env.logger().debug(f"post {url}") 48 sqlRequest = {"sql": sql, "timeout": timeout} 49 50 try: 51 r = requests.post(f"{url}", json=sqlRequest, headers=headers) 52 if r.status_code < 200 or r.status_code > 299: 53 err_msg = f"failed to run sql due to {r.text}" 54 raise TimeplusAPIError("post", r.status_code, err_msg) 55 else: 56 return r.json() 57 except Exception as e: 58 env.logger.error(f"failed to run sql {e}") 59 raise e
View Source
61 @classmethod 62 def exec(cls, sql, env=None): 63 if env is None: 64 env = Env.current() 65 headers = env.headers() 66 base_url = env.base_url() 67 68 url = f"{base_url}/exec" 69 env.logger.debug(f"post {url}") 70 sqlRequest = { 71 "sql": sql, 72 } 73 74 try: 75 r = requests.post(f"{url}", json=sqlRequest, headers=headers) 76 if r.status_code < 200 or r.status_code > 299: 77 err_msg = f"failed to run exec due to {r.text}" 78 raise TimeplusAPIError("post", r.status_code, err_msg) 79 else: 80 return r.json() 81 except Exception as e: 82 env.logger.error(f"failed to run exec {e}") 83 raise e
View Source
119 def sink_to(self, sink): 120 url = f"{self._base_url}/{self._resource_name}/{self.id()}/sinks" 121 self._logger.debug(f"post {url}") 122 sinkRequest = {"sink_id": sink.id()} 123 try: 124 r = requests.post(f"{url}", json=sinkRequest, headers=self._headers) 125 if r.status_code < 200 or r.status_code > 299: 126 err_msg = f"failed to add sink {sink.id()} to query {self.id()} {r.status_code} {r.text}" 127 raise TimeplusAPIError("post", r.status_code, err_msg) 128 else: 129 self._logger.debug(f"add sink {sink.id()} to query {self.id()} success") 130 return self 131 except Exception as e: 132 self._logger.error(f"failed to add sink {e}") 133 raise e
View Source
135 def show_query_result(self, count=10): 136 ws_schema = "ws" 137 if self._env.schema() == "https": 138 ws_schema = "wss" 139 ws = create_connection( 140 f"{ws_schema}://{self._env.host()}:{self._env.port()}/ws/queries/{self.id()}" 141 ) 142 for i in range(count): 143 result = ws.recv() 144 self._logger.info(result)