described in this page is useful if you intend to *customise* the
adaptation rules.
-The `Dumper` is the base object to perform conversion from a Python object to
-a `!bytes` string understood by PostgreSQL. The string returned *shouldn't be
-quoted*: the value will be passed to the database using functions such as
-:pq:`PQexecParams()` so quoting and quotes escaping is not necessary.
+- The `~psycopg3.types.TypeInfo` object allows to query type information from
+ a database, which can be used by the adapters: for instance to make them
+ able to decode arrays of base types or composite types.
-The `Loader` is the base object to perform the opposite operation: to read a
-`!bytes` string from PostgreSQL and create a Python object.
+- The `Dumper` is the base object to perform conversion from a Python object
+ to a `!bytes` string understood by PostgreSQL. The string returned
+ *shouldn't be quoted*: the value will be passed to the database using
+ functions such as :pq:`PQexecParams()` so quoting and quotes escaping is not
+ necessary.
+
+- The `Loader` is the base object to perform the opposite operation: to read a
+ `!bytes` string from PostgreSQL and create a Python object.
`!Dumper` and `!Loader` are abstract classes: concrete classes must implement
the `~Dumper.dump()` and `~Loader.load()` methods. `!psycopg3` provides
implementation for several builtin Python and PostgreSQL types.
-.. admonition:: TODO
-
- Document the builtin adapters, where are they?
+Psycopg provides adapters for several builtin types, which can be used as the
+base to build more complex ones: they all live in the `psycopg3.types`
+package.
Dumpers and loaders configuration
`!Connection`, the `!Cursor`.
- For every Python type passed as query argument, the `!Transformer` will
- instantiate a `!Dumper`. All the objects of the same type will be converted
- by the same dumper.
+ instantiate a `!Dumper`. Usually all the objects of the same type will be
+ converted by the same dumper; certain dumpers may be used in more than one
+ instance, because the same Python type maps to more than one PostgreSQL type
+ (for instance, a Python `int` might be better dumped as a PostgreSQL
+ :sql:`integer`, :sql:`bigint`, :sql:`smallint` according to its value).
- For every OID returned by the query, the `!Transformer` will instantiate a
`!Loader`. All the values with the same OID will be converted by the same
--- /dev/null
+.. currentmodule:: psycopg3.types
+
+.. _psycopg3.types:
+
+`!types` -- types mapping and adaptation
+========================================
+
+.. module:: psycopg3.types
+
+The `!psycopg3.types` package exposes the concrete implementation of `Loader`
+and `Dumper` to manage builtin objects, together with objects to describe
+PostgreSQL types and wrappers to help or customise the types conversion.
+
+
+Types information
+-----------------
+
+The `TypeInfo` object describes simple information about a PostgreSQL data
+type, such as its name, oid and array oid. The class can be used to query a
+database for custom data types: this allows for instance to load automatically
+arrays of a custom type, once a loader for the base type has been registered.
+
+The `!TypeInfo` object doesn't instruct `!psycopg3` to convert a PostgreSQL
+type into a Python type: this is the role of a `Loader`. However it can extend
+the behaviour of the adapters: if you create a loader for `!MyType`, using
+`TypeInfo` you will be able to manage seamlessly arrays of `!MyType` or ranges
+and composite types using it as a subtypes.
+
+.. seealso:: :ref:`adaptation` describes about how to convert from Python
+ types to PostgreSQL types and back.
+
+.. code:: python
+
+ from psycopg3.adapt import Loader
+ from psycopg3.types import TypeInfo
+
+ t = TypeInfo.fetch(conn, "mytype")
+ t.register(conn)
+
+ for record in conn.execute("select mytypearray from mytable"):
+ # records will return lists of "mytype" as string
+
+ class MyTypeLoader(Loader):
+ def load(self, data):
+ # parse the data and return a MyType instance
+
+ MyTypeLoader.register(conn)
+
+ for record in conn.execute("select mytypearray from mytable"):
+ # records will return lists of MyType instances
+
+
+.. autoclass:: TypeInfo
+
+ .. automethod:: fetch
+ .. automethod:: fetch_async
+ .. automethod:: register
+
+ The *context* can be a `~psycopg3.Connection` or `~psycopg3.Cursor`.
+ Specifying no context will register the `!TypeInfo` globally.
+
+ Registering the `TypeInfo` in a context allows the adapters of that
+ context to look up type information: for instance it allows to
+ recognise automatically arrays of that type and load them from the
+ database as a list of the base type (how the base type is converted to
+ Python is demanded to a `Loader`.
+
+
+The following `!TypeInfo` subclasses allow to fetch more specialised
+information from certain class of PostgreSQL types and to create more
+specialised adapters configurations.
+
+
+.. autoclass:: CompositeInfo
+
+ .. automethod:: register
+
+ Using `!CompositeInfo.register()` will also register a specialised
+ loader to fetch the composite type as a Python named tuple, or a
+ custom object if *factory* is specified.
+
+
+.. autoclass:: RangeInfo
+
+ .. automethod:: register
+
+ Using `!RangeInfo.register()` will also register a specialised loaders
+ and dumpers. For instance, if you create a PostgreSQL range on the
+ type :sql:`inet`, loading these object with the database will use the
+ loader for the :sql:`inet` type to parse the range bounds - either the
+ builtin ones or any one you might have configured.
+
+ The type information will also be used by the `Range` dumper so that
+ if you dump a `!Range(address1, address2)` object it will use the
+ correct oid for your :sql:`inetrange` type.
+
+
+Objects wrappers
+----------------
+
+.. admonition:: TODO
+
+ Document the various objects wrappers
+
+ - Int2, Int4, Int8, ...
+ - Json, Jsonb
+ - Range