]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
Added date text loader
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Sun, 23 Aug 2020 18:20:53 +0000 (19:20 +0100)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Wed, 28 Oct 2020 03:19:24 +0000 (04:19 +0100)
THe loader can already deal with all the Postgres DateStyle

psycopg3/psycopg3/types/date.py
tests/types/test_date.py

index 1ce37f8d1fc5913376925b0f680333aa52d81605..adff96076c93a782db50b0942430544d64ef8219 100644 (file)
@@ -7,7 +7,8 @@ Adapters for date/time types.
 import codecs
 from datetime import date
 
-from ..adapt import Dumper
+from ..adapt import Dumper, Loader
+from ..proto import AdaptContext
 from .oids import builtins
 
 
@@ -25,3 +26,32 @@ class DateDumper(Dumper):
     @property
     def oid(self) -> int:
         return self.DATE_OID
+
+
+@Loader.text(builtins["date"].oid)
+class DateLoader(Loader):
+
+    _decode = codecs.lookup("ascii").decode
+
+    def __init__(self, oid: int, context: AdaptContext):
+        super().__init__(oid, context)
+
+        if self.connection:
+            ds = self.connection.pgconn.parameter_status(b"DateStyle")
+            if not ds or ds.startswith(b"ISO"):
+                pass
+            elif ds.startswith(b"German"):
+                self.load = self.load_dmy  # type: ignore
+            elif ds.startswith(b"SQL"):
+                self.load = self.load_mdy  # type: ignore
+            elif ds.startswith(b"Postgres"):
+                self.load = self.load_mdy  # type: ignore
+
+    def load(self, data: bytes) -> date:
+        return date(int(data[:4]), int(data[5:7]), int(data[8:]))
+
+    def load_dmy(self, data: bytes) -> date:
+        return date(int(data[6:]), int(data[3:5]), int(data[:2]))
+
+    def load_mdy(self, data: bytes) -> date:
+        return date(int(data[6:]), int(data[:2]), int(data[3:5]))
index 112d5b3d58f44361577dcdf6ca4a9c4029adfed8..07fe9a0cbb136ad2787c4551a229f2465ae40c64 100644 (file)
@@ -1,6 +1,8 @@
 import datetime as dt
 import pytest
 
+from psycopg3.adapt import Format
+
 
 @pytest.mark.parametrize(
     "val, expr",
@@ -34,3 +36,37 @@ def test_dump_date_datestyle(conn, datestyle_in):
     cur.execute(f"set datestyle = ISO, {datestyle_in}")
     cur.execute("select '2000-01-02'::date = %s", (dt.date(2000, 1, 2),))
     assert cur.fetchone()[0]
+
+
+@pytest.mark.parametrize(
+    "val, expr",
+    [
+        (dt.date(1, 1, 1), "'0001-01-01'::date"),
+        (dt.date(1000, 1, 1), "'1000-01-01'::date"),
+        (dt.date(2000, 1, 1), "'2000-01-01'::date"),
+        (dt.date(2000, 12, 31), "'2000-12-31'::date"),
+        (dt.date(3000, 1, 1), "'3000-01-01'::date"),
+    ],
+)
+def test_load_date(conn, val, expr):
+    cur = conn.cursor()
+    cur.execute("select %s" % expr)
+    assert cur.fetchone()[0] == val
+
+
+@pytest.mark.xfail  # TODO: binary load
+@pytest.mark.parametrize(
+    "val, expr", [(dt.date(2000, 1, 1), "'2000-01-01'::date")],
+)
+def test_load_date_binary(conn, val, expr):
+    cur = conn.cursor(format=Format.BINARY)
+    cur.execute("select %s" % expr)
+    assert cur.fetchone()[0] == val
+
+
+@pytest.mark.parametrize("datestyle_out", ["ISO", "Postgres", "SQL", "German"])
+def test_load_date_datestyle(conn, datestyle_out):
+    cur = conn.cursor()
+    cur.execute(f"set datestyle = {datestyle_out}, YMD")
+    cur.execute("select '2000-01-02'::date")
+    assert cur.fetchone()[0] == dt.date(2000, 1, 2)