]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
Add documentation for range types
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Sat, 28 Aug 2021 03:51:16 +0000 (05:51 +0200)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Sat, 28 Aug 2021 03:51:16 +0000 (05:51 +0200)
docs/api/types.rst
docs/basic/adapt.rst
docs/basic/index.rst
docs/basic/pgtypes.rst [new file with mode: 0644]
psycopg/psycopg/types/range.py

index 94c73474315b4652331bdae90c3ff7757e7875c4..6414e71c8a71bda1c45ddca3712a0b962c1d58aa 100644 (file)
@@ -88,13 +88,9 @@ can extend the behaviour of the adapters: if you create a loader for
         database as a list of the base type.
 
 
-The following `!TypeInfo` subclasses allow to fetch more specialised
-information from certain class of PostgreSQL types.
-
-.. autoclass:: psycopg.types.composite.CompositeInfo
-
-.. autoclass:: psycopg.types.range.RangeInfo
-
+For recursive types, Psycopg offers a few `!TypeInfo` subclasses which can be
+used to extract more complete information, for instance
+`~psycopg.types.composite.CompositeInfo` and `~psycopg.types.range.RangeInfo`.
 
 `!TypeInfo` objects are collected in `TypesRegistry` instances, which help type
 information lookup. Every `~psycopg.adapt.AdaptersMap` expose its type map on
index 9dcc9ff164c9d32511536f54aa670e363b36e3c8..26c55512cd1340df6f3dfa775e6a9809427b5d9c 100644 (file)
@@ -7,8 +7,8 @@
 
 .. _types-adaptation:
 
-Adaptation between Python and PostgreSQL types
-==============================================
+Adapting basic Python types
+===========================
 
 Many standard Python types are adapted into SQL and returned as Python
 objects when a query is executed.
@@ -32,8 +32,6 @@ TODO: complete table
     +--------------------+-------------------------+--------------------------+
     | `!dict`            | :sql:`hstore`           | :ref:`adapt-hstore`      |
     +--------------------+-------------------------+--------------------------+
-    | Psycopg's `!Range` | :sql:`range`            | :ref:`adapt-range`       |
-    +--------------------+-------------------------+--------------------------+
 
 
 .. index::
@@ -377,7 +375,6 @@ address types`__:
 
 .. _adapt-composite:
 .. _adapt-hstore:
-.. _adapt-range:
 
 
 TODO adaptation
index 33f78ff9a04ffc15bc36eb575e71f4156961ea78..d7c559186765bf9381d432cb2d4c8983da8fdc7a 100644 (file)
@@ -15,6 +15,7 @@ the database <usage>` or :ref:`loading data using COPY <copy>`.
     usage
     params
     adapt
+    pgtypes
     transactions
     copy
     from_pg2
diff --git a/docs/basic/pgtypes.rst b/docs/basic/pgtypes.rst
new file mode 100644 (file)
index 0000000..7c4bd03
--- /dev/null
@@ -0,0 +1,83 @@
+.. currentmodule:: psycopg
+
+.. index::
+    single: Adaptation
+    pair: Objects; Adaptation
+    single: Data types; Adaptation
+
+.. _extra-adaptation:
+
+Adapting other PostgreSQL types
+===============================
+
+PostgreSQL offers other data types which don't map to native Python types.
+Psycopg offers wrappers and conversion functions to allow their use.
+
+
+.. _adapt-range:
+
+Range adaptation
+----------------
+
+PostgreSQL `range types`__ are a family of data types representing a range of
+value between two elements. The type of the element is called the range
+*subtype*. PostgreSQL offers a few built-in range types and allows the
+definition of custom ones.
+
+.. __: https://www.postgresql.org/docs/current/rangetypes.html
+
+All the PostgreSQL range types are loaded as the `~psycopg.types.range.Range`
+Python type, which is a `~typing.Generic` type and can hold bounds of
+different types.
+
+.. autoclass:: psycopg.types.range.Range
+
+    This Python type is only used to pass and retrieve range values to and
+    from PostgreSQL and doesn't attempt to replicate the PostgreSQL range
+    features: it doesn't perform normalization and doesn't implement all the
+    operators__ supported by the database.
+
+    .. __: https://www.postgresql.org/docs/current/static/functions-range.html#RANGE-OPERATORS-TABLE
+
+    `!Range` objects are immutable, hashable, and support the ``in`` operator
+    (checking if an element is within the range). They can be tested for
+    equivalence. Empty ranges evaluate to `!False` in boolean context,
+    nonempty evaluate to `!True`.
+
+    `!Range` objects have the following attributes:
+
+    .. autoattribute:: isempty
+    .. autoattribute:: lower
+    .. autoattribute:: upper
+    .. autoattribute:: lower_inc
+    .. autoattribute:: upper_inc
+    .. autoattribute:: lower_inf
+    .. autoattribute:: upper_inf
+
+The built-in range objects are adapted automatically: if a `!Range` objects
+contains `~datetime.date` bounds, it is dumped using the :sql:`daterange` OID,
+and of course :sql:`daterange` values are loaded back as `!Range[date]`.
+
+If you create your own range type you can use `~psycopg.types.range.RangeInfo`
+and `~psycopg.types.range.register_range()` to associate the range type with
+its subtype and make it work like the builtin ones.
+
+.. autoclass:: psycopg.types.range.RangeInfo
+
+   `~RangeInfo` is a `~psycopg.types.TypeInfo` subclass: check its
+   documentation for generic details.
+
+.. autofunction:: psycopg.types.range.register_range
+
+Example::
+
+    >>> conn.execute("create type strrange as range (subtype = text)")
+
+    >>> info = RangeInfo.fetch(conn, "strrange")
+    >>> register_range(info, conn)
+
+    >>> conn.execute("select pg_typeof(%s)", [Range("a", "z")]).fetchone()[0]
+    'strrange'
+
+    >>> conn.execute("select '[a,z]'::strrange").fetchone()[0]
+     Range('a', 'z', '[]')
index 5c16527599a6f744b4e448028969d18c0e21cbc8..a9f32cdc23b1171557ddf68499c65a8ff0ae00a4 100644 (file)
@@ -31,7 +31,7 @@ T = TypeVar("T")
 
 
 class Range(Generic[T]):
-    """Python representation for a PostgreSQL |range|_ type.
+    """Python representation for a PostgreSQL range type.
 
     :param lower: lower bound for the range. `!None` means unbound
     :param upper: upper bound for the range. `!None` means unbound
@@ -441,9 +441,8 @@ def register_range(
     """
     Register custom range adapters on a context.
 
-    Just register loaders associated to the range oid, loading bounds of the
-    right subtype. Dumping the range just works, navigating from tye Python
-    type to the type oid, to the range oid.
+    Register loaders so that loading data of this type will result in a `Range`
+    with bounds parsed as the right subtype.
     """
 
     # Register arrays and type info