]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
Added json text dump
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Tue, 27 Oct 2020 16:09:08 +0000 (17:09 +0100)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Wed, 28 Oct 2020 03:17:28 +0000 (04:17 +0100)
psycopg3/psycopg3/types/__init__.py
psycopg3/psycopg3/types/json.py [new file with mode: 0644]
tests/types/test_json.py [new file with mode: 0644]

index f578c651ca9f39e26cf85d321d15c4aa6a22b496..e0ce65c36084a1ce6f306fe539cf0b526678e11a 100644 (file)
@@ -8,7 +8,7 @@ psycopg3 types package
 from .oids import builtins
 
 # Register default adapters
-from . import array, composite, numeric, text  # noqa
+from . import array, json, composite, numeric, text  # noqa
 
 # Register associations with array oids
 array.register_all_arrays()
diff --git a/psycopg3/psycopg3/types/json.py b/psycopg3/psycopg3/types/json.py
new file mode 100644 (file)
index 0000000..0460aca
--- /dev/null
@@ -0,0 +1,60 @@
+"""
+Adapers for JSON types.
+"""
+
+# Copyright (C) 2020 The Psycopg Team
+
+import json
+import codecs
+from typing import Any, Callable, Optional
+
+from .oids import builtins
+from ..adapt import Dumper
+from ..proto import EncodeFunc
+
+_encode_utf8 = codecs.lookup("utf8").encode
+
+JSON_OID = builtins["json"].oid
+JSONB_OID = builtins["jsonb"].oid
+
+JsonDumpsFunction = Callable[[Any], str]
+
+
+class _JsonWrapper:
+    def __init__(self, obj: Any, dumps: Optional[JsonDumpsFunction] = None):
+        self.obj = obj
+        self._dumps: JsonDumpsFunction = dumps or json.dumps
+
+    def dumps(self) -> str:
+        return self._dumps(self.obj)
+
+
+class Json(_JsonWrapper):
+    pass
+
+
+class JsonB(_JsonWrapper):
+    pass
+
+
+class _JsonDumper(Dumper):
+    _oid: int
+
+    def dump(
+        self, obj: _JsonWrapper, __encode: EncodeFunc = _encode_utf8
+    ) -> bytes:
+        return __encode(obj.dumps())[0]
+
+    @property
+    def oid(self) -> int:
+        return self._oid
+
+
+@Dumper.text(Json)
+class JsonDumper(_JsonDumper):
+    _oid = JSON_OID
+
+
+@Dumper.text(JsonB)
+class JsonBDumper(_JsonDumper):
+    _oid = JSONB_OID
diff --git a/tests/types/test_json.py b/tests/types/test_json.py
new file mode 100644 (file)
index 0000000..9fca64c
--- /dev/null
@@ -0,0 +1,34 @@
+import json
+
+import pytest
+
+from psycopg3.types.json import Json, JsonB
+
+samples = [
+    "null",
+    "true",
+    '"te\'xt"',
+    '"\\u00e0\\u20ac"',
+    "123",
+    "123.45",
+    '["a", 100]',
+    '{"a": 100}',
+]
+
+
+@pytest.mark.parametrize("val", samples)
+def test_json_dump(conn, val):
+    obj = json.loads(val)
+    cur = conn.cursor()
+    cur.execute("select pg_typeof(%s) = 'json'::regtype", (Json(obj),))
+    assert cur.fetchone()[0] is True
+    cur.execute("select %s::text = %s::json::text", (Json(obj), val))
+    assert cur.fetchone()[0] is True
+
+
+@pytest.mark.parametrize("val", samples)
+def test_jsonb_dump(conn, val):
+    obj = json.loads(val)
+    cur = conn.cursor()
+    cur.execute("select %s = %s::jsonb", (JsonB(obj), val))
+    assert cur.fetchone()[0] is True