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.

#   Query(env=None)
View Source
28    def __init__(self, env=None):
29        ResourceBase.__init__(self, env)
30        self.stopped = False
#  
@classmethod
def build(cls, query, env=None):
View Source
32    @classmethod
33    def build(cls, query, env=None):
34        obj = cls(env=env)
35        obj._data = query
36        return obj
#  
@classmethod
def execSQL(cls, sql, timeout=1000, env=None):
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
#  
@classmethod
def exec(cls, sql, env=None):
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
#   def name(self, *args):
View Source
85    def name(self, *args):
86        return self.prop("name", *args)
#   def description(self, *args):
View Source
88    def description(self, *args):
89        return self.prop("description", *args)
#   def sql(self, *args):
View Source
91    def sql(self, *args):
92        return self.prop("sql", *args)
#   def tags(self, *args):
View Source
94    def tags(self, *args):
95        return self.prop("tags", *args)
#   def id(self):
View Source
97    def id(self):
98        return self.prop("id")
#   def stat(self):
View Source
100    def stat(self):
101        self.get()
102        return self.prop("stat")
#   def status(self):
View Source
104    def status(self):
105        self.get()
106        return self.prop("status")
#   def header(self):
View Source
108    def header(self):
109        self.get()
110        return self.prop("result")["header"]
#   def cancel(self):
View Source
112    def cancel(self):
113        self.action("cancel")
114        return self
#   def stop(self):
View Source
116    def stop(self):
117        self.stopped = True
#   def sink_to(self, sink):
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
#   def show_query_result(self, count=10):
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)
#   def get_result_stream(self):
View Source
181    def get_result_stream(self):
182        strem_query_ob = rx.create(self._query_op())
183        return strem_query_ob