dumper = self._tx.get_dumper(item, PyFormat.from_pq(self.format))
ad = dumper.dump(item)
- if not ad:
+ if ad is None:
+ ad = b""
+ elif not ad:
ad = b'""'
elif self._re_needs_quotes.search(ad):
ad = b'"' + self._re_esc.sub(rb"\1\1", ad) + b'"'
oid = _oids.JSONB_OID
def dump(self, obj: Any) -> Optional[Buffer]:
- return b"\x01" + super().dump(obj)
+ obj_bytes = super().dump(obj)
+ if obj_bytes is not None:
+ return b"\x01" + obj_bytes
+ else:
+ return None
class _JsonLoader(Loader):
def dump_item(item: Any) -> Buffer:
ad = dump(item)
- if not ad:
+ if ad is None:
+ return b""
+ elif not ad:
return b'""'
elif _re_needs_quotes.search(ad):
return b'"' + _re_esc.sub(rb"\1\1", ad) + b'"'
from ..utils import eur
from ..fix_crdb import is_crdb, crdb_skip_message
+from ..test_adapt import StrNoneDumper, StrNoneBinaryDumper
pytestmark = pytest.mark.crdb_skip("composite")
assert res == obj
+def test_dump_tuple_null(conn):
+ cur = conn.cursor()
+ cur.execute(
+ """
+ drop type if exists tmptype;
+ create type tmptype as (f1 text, f2 text);
+ """
+ )
+ info = CompositeInfo.fetch(conn, "tmptype")
+ register_composite(info, conn)
+ conn.adapters.register_dumper(str, StrNoneDumper)
+ conn.adapters.register_dumper(str, StrNoneBinaryDumper)
+
+ res = conn.execute("select %s::tmptype", [("foo", "")]).fetchone()[0]
+ assert res == ("foo", None)
+
+
@pytest.mark.parametrize("fmt_out", pq.Format)
def test_load_all_chars(conn, fmt_out):
cur = conn.cursor(binary=fmt_out)
from ..utils import eur
from .test_range import create_test_range
+from ..test_adapt import StrNoneDumper, StrNoneBinaryDumper
pytestmark = [
pytest.mark.pg(">= 14"),
assert cur.fetchone()[0] is True
+@pytest.mark.parametrize("fmt_in", PyFormat)
+def test_dump_custom_none(conn, fmt_in):
+ info = MultirangeInfo.fetch(conn, "testmultirange")
+ register_multirange(info, conn)
+ conn.adapters.register_dumper(str, StrNoneDumper)
+ conn.adapters.register_dumper(str, StrNoneBinaryDumper)
+
+ r = Multirange[str]()
+ cur = conn.execute("select '{}'::testmultirange = %s", (r,))
+ assert cur.fetchone()[0] is True
+
+
@pytest.mark.parametrize("fmt_out", pq.Format)
def test_load_custom_empty(conn, testmr, fmt_out):
info = MultirangeInfo.fetch(conn, "testmultirange")
from ..utils import eur
from ..fix_crdb import is_crdb, crdb_skip_message
+from ..test_adapt import StrNoneDumper, StrNoneBinaryDumper
pytestmark = pytest.mark.crdb_skip("range")
assert cur.fetchone()[0] is True
+@pytest.mark.parametrize("fmt_in", PyFormat)
+def test_dump_custom_null(conn, testrange, fmt_in):
+ info = RangeInfo.fetch(conn, "testrange")
+ register_range(info, conn)
+ conn.adapters.register_dumper(str, StrNoneDumper)
+ conn.adapters.register_dumper(str, StrNoneBinaryDumper)
+
+ r = Range[str]("", "foo")
+ cur = conn.execute(f"select %{fmt_in.value}::testrange", (r,))
+ r1 = cur.fetchone()[0]
+ assert r1.lower is None
+ assert r1.upper == "foo"
+
+
def test_dump_quoting(conn, testrange):
info = RangeInfo.fetch(conn, "testrange")
register_range(info, conn)