|
23 | 23 | import calendar
|
24 | 24 | import heapq
|
25 | 25 | import io
|
26 |
| -import json |
27 | 26 | import logging
|
28 | 27 | import os
|
29 | 28 | import re
|
|
37 | 36 | from urllib.parse import urlparse
|
38 | 37 | from uuid import UUID
|
39 | 38 |
|
| 39 | +import orjson |
40 | 40 | import urllib3
|
41 | 41 | from urllib3 import connection_from_url
|
42 | 42 | from urllib3.connection import HTTPConnection
|
@@ -86,25 +86,31 @@ def super_len(o):
|
86 | 86 | return None
|
87 | 87 |
|
88 | 88 |
|
89 |
| -class CrateJsonEncoder(json.JSONEncoder): |
90 |
| - epoch_aware = datetime(1970, 1, 1, tzinfo=timezone.utc) |
91 |
| - epoch_naive = datetime(1970, 1, 1) |
92 |
| - |
93 |
| - def default(self, o): |
94 |
| - if isinstance(o, (Decimal, UUID)): |
95 |
| - return str(o) |
96 |
| - if isinstance(o, datetime): |
97 |
| - if o.tzinfo is not None: |
98 |
| - delta = o - self.epoch_aware |
99 |
| - else: |
100 |
| - delta = o - self.epoch_naive |
101 |
| - return int( |
102 |
| - delta.microseconds / 1000.0 |
103 |
| - + (delta.seconds + delta.days * 24 * 3600) * 1000.0 |
104 |
| - ) |
105 |
| - if isinstance(o, date): |
106 |
| - return calendar.timegm(o.timetuple()) * 1000 |
107 |
| - return json.JSONEncoder.default(self, o) |
| 89 | +epoch_aware = datetime(1970, 1, 1, tzinfo=timezone.utc) |
| 90 | +epoch_naive = datetime(1970, 1, 1) |
| 91 | + |
| 92 | + |
| 93 | +def cratedb_json_encoder(obj): |
| 94 | + """ |
| 95 | + Encoder function for orjson. |
| 96 | +
|
| 97 | + https://github.com/ijl/orjson#default |
| 98 | + https://github.com/ijl/orjson#opt_passthrough_datetime |
| 99 | + """ |
| 100 | + if isinstance(obj, (Decimal, UUID)): |
| 101 | + return str(obj) |
| 102 | + if isinstance(obj, datetime): |
| 103 | + if obj.tzinfo is not None: |
| 104 | + delta = obj - epoch_aware |
| 105 | + else: |
| 106 | + delta = obj - epoch_naive |
| 107 | + return int( |
| 108 | + delta.microseconds / 1000.0 |
| 109 | + + (delta.seconds + delta.days * 24 * 3600) * 1000.0 |
| 110 | + ) |
| 111 | + if isinstance(obj, date): |
| 112 | + return calendar.timegm(obj.timetuple()) * 1000 |
| 113 | + return obj |
108 | 114 |
|
109 | 115 |
|
110 | 116 | class Server:
|
@@ -180,7 +186,7 @@ def close(self):
|
180 | 186 |
|
181 | 187 | def _json_from_response(response):
|
182 | 188 | try:
|
183 |
| - return json.loads(response.data.decode("utf-8")) |
| 189 | + return orjson.loads(response.data) |
184 | 190 | except ValueError as ex:
|
185 | 191 | raise ProgrammingError(
|
186 | 192 | "Invalid server response of content-type '{}':\n{}".format(
|
@@ -223,7 +229,7 @@ def _raise_for_status_real(response):
|
223 | 229 | if response.status == 503:
|
224 | 230 | raise ConnectionError(message)
|
225 | 231 | if response.headers.get("content-type", "").startswith("application/json"):
|
226 |
| - data = json.loads(response.data.decode("utf-8")) |
| 232 | + data = orjson.loads(response.data) |
227 | 233 | error = data.get("error", {})
|
228 | 234 | error_trace = data.get("error_trace", None)
|
229 | 235 | if "results" in data:
|
@@ -334,7 +340,11 @@ def _create_sql_payload(stmt, args, bulk_args):
|
334 | 340 | data["args"] = args
|
335 | 341 | if bulk_args:
|
336 | 342 | data["bulk_args"] = bulk_args
|
337 |
| - return json.dumps(data, cls=CrateJsonEncoder) |
| 343 | + return orjson.dumps( |
| 344 | + data, |
| 345 | + default=cratedb_json_encoder, |
| 346 | + option=orjson.OPT_PASSTHROUGH_DATETIME, |
| 347 | + ) |
338 | 348 |
|
339 | 349 |
|
340 | 350 | def _get_socket_opts(
|
|
0 commit comments