2020# software solely pursuant to the terms of the relevant commercial agreement.
2121
2222
23- import calendar
2423import heapq
2524import io
26- import json
2725import logging
2826import os
2927import re
3028import socket
3129import ssl
3230import threading
31+ import typing as t
3332from base64 import b64encode
34- from datetime import date , datetime , timezone
3533from decimal import Decimal
3634from time import time
3735from urllib .parse import urlparse
38- from uuid import UUID
3936
37+ import orjson
4038import urllib3
4139from urllib3 import connection_from_url
4240from urllib3 .connection import HTTPConnection
@@ -86,25 +84,33 @@ def super_len(o):
8684 return None
8785
8886
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_NON_STR_KEYS | orjson .OPT_SERIALIZE_NUMPY ),
113+ )
108114
109115
110116class Server :
@@ -180,7 +186,7 @@ def close(self):
180186
181187def _json_from_response (response ):
182188 try :
183- return json .loads (response .data . decode ( "utf-8" ) )
189+ return orjson .loads (response .data )
184190 except ValueError as ex :
185191 raise ProgrammingError (
186192 "Invalid server response of content-type '{}':\n {}" .format (
@@ -223,7 +229,7 @@ def _raise_for_status_real(response):
223229 if response .status == 503 :
224230 raise ConnectionError (message )
225231 if response .headers .get ("content-type" , "" ).startswith ("application/json" ):
226- data = json .loads (response .data . decode ( "utf-8" ) )
232+ data = orjson .loads (response .data )
227233 error = data .get ("error" , {})
228234 error_trace = data .get ("error_trace" , None )
229235 if "results" in data :
@@ -323,7 +329,7 @@ def _update_pool_kwargs_for_ssl_minimum_version(server, kwargs):
323329 kwargs ["ssl_minimum_version" ] = ssl .TLSVersion .MINIMUM_SUPPORTED
324330
325331
326- def _create_sql_payload (stmt , args , bulk_args ):
332+ def _create_sql_payload (stmt , args , bulk_args ) -> bytes :
327333 if not isinstance (stmt , str ):
328334 raise ValueError ("stmt is not a string" )
329335 if args and bulk_args :
@@ -334,7 +340,7 @@ def _create_sql_payload(stmt, args, bulk_args):
334340 data ["args" ] = args
335341 if bulk_args :
336342 data ["bulk_args" ] = bulk_args
337- return json . dumps (data , cls = CrateJsonEncoder )
343+ return json_dumps (data )
338344
339345
340346def _get_socket_opts (
0 commit comments