20
20
# software solely pursuant to the terms of the relevant commercial agreement.
21
21
22
22
23
- import calendar
24
23
import heapq
25
24
import io
26
- import json
27
25
import logging
28
26
import os
29
27
import re
30
28
import socket
31
29
import ssl
32
30
import threading
31
+ import typing as t
33
32
from base64 import b64encode
34
- from datetime import date , datetime , timezone
35
33
from decimal import Decimal
36
34
from time import time
37
35
from urllib .parse import urlparse
38
- from uuid import UUID
39
36
37
+ import orjson
40
38
import urllib3
41
39
from urllib3 import connection_from_url
42
40
from urllib3 .connection import HTTPConnection
@@ -86,25 +84,33 @@ def super_len(o):
86
84
return None
87
85
88
86
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 )
87
+ def cratedb_json_encoder (obj : t .Any ) -> str :
88
+ """
89
+ Encoder function for orjson, with additional type support.
90
+
91
+ - Python's `Decimal` type.
92
+ - freezegun's `FakeDatetime` type.
93
+
94
+ https://github.com/ijl/orjson#default
95
+ """
96
+ if isinstance (obj , Decimal ):
97
+ return str (obj )
98
+ elif hasattr (obj , "isoformat" ):
99
+ return obj .isoformat ()
100
+ raise TypeError
101
+
102
+
103
+ def json_dumps (obj : t .Any ) -> bytes :
104
+ """
105
+ Serialize to JSON format, using `orjson`, with additional type support.
106
+
107
+ https://github.com/ijl/orjson
108
+ """
109
+ return orjson .dumps (
110
+ obj ,
111
+ default = cratedb_json_encoder ,
112
+ option = orjson .OPT_SERIALIZE_NUMPY ,
113
+ )
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 :
@@ -323,7 +329,7 @@ def _update_pool_kwargs_for_ssl_minimum_version(server, kwargs):
323
329
kwargs ["ssl_minimum_version" ] = ssl .TLSVersion .MINIMUM_SUPPORTED
324
330
325
331
326
- def _create_sql_payload (stmt , args , bulk_args ):
332
+ def _create_sql_payload (stmt , args , bulk_args ) -> bytes :
327
333
if not isinstance (stmt , str ):
328
334
raise ValueError ("stmt is not a string" )
329
335
if args and bulk_args :
@@ -334,7 +340,7 @@ 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 json_dumps (data )
338
344
339
345
340
346
def _get_socket_opts (
0 commit comments