Re: Generic casters for composite types - Mailing list psycopg

From Ronan Dunklau
Subject Re: Generic casters for composite types
Date
Msg-id 4EEA2480.5040406@gmail.com
Whole thread Raw
In response to Re: Generic casters for composite types  (Daniele Varrazzo <daniele.varrazzo@gmail.com>)
List psycopg
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 15/12/2011 17:21, Daniele Varrazzo wrote:
> On Thu, Dec 15, 2011 at 3:17 PM, Ronan Dunklau <rdunklau@gmail.com>
> wrote:
>
>> I think it may be interesting to add a generic mechanism for
>> registering composite type casters.
>
> Such as this one? :)
> http://initd.org/psycopg/docs/extras.html#composite-types-casting

How can I have missed that ?! ;)
Sorry for bothering you with something I could have found in the docs.

> The register_composite() does *almost* what you want. Without the
> "almost", the result, after committing the tables created in your
> example, is:
>
>>>> import psycopg2 import psycopg2.extras cnn =
>>>> psycopg2.connect('dbname=test')
>>>> psycopg2.extras.register_composite('test2', cnn)
>>>> psycopg2.extras.register_composite('test1', cnn) cur =
>>>> cnn.cursor() cur.execute("""select test1, array_agg(test2) as
>>>> test2s from
> test1 inner join test2 on test1.id = test2.test_id group by
> test1;""")
>>>> cur.fetchone()
> (test1(id=1, label='test1'), [test2(id=1, label='testa',
> test_id=1), test2(id=2, label='testb', test_id=1)])
>>>> cur.fetchone()
> (test1(id=2, label='test2'), [test2(id=3, label='testc',
> test_id=2), test2(id=4, label='testd', test_id=2)])
>
> Why the "almost"? The query to introspect the database was tested
> on composite types created by CREATE TYPE, not on the ones created
> after the tables, and it doesn't account for dropped fields and
> hidden columns (cmin, xmin ecc.). Plus, there was an error raising
> the error message after the column count mismatch. With the
> following patch, the above works as expected. It takes psycopg
> 2.4.3 as previous version didn't support arrays of composites:
>
> diff --git a/lib/extras.py b/lib/extras.py index 491a390..d9c2ab9
> 100644 --- a/lib/extras.py +++ b/lib/extras.py @@ -841,8 +841,8 @@
> class CompositeCaster(object): tokens = self.tokenize(s) if
> len(tokens) != len(self.atttypes): raise psycopg2.DataError( -
> "expecting %d components for the type %s, %d found instead", -
> (len(self.atttypes), self.name, len(self.tokens))) +
> "expecting %d components for the type %s, %d found instead" +
> % (len(self.atttypes), self.name, len(tokens)))
>
> attrs = [ curs.cast(oid, token) for oid, token in
> zip(self.atttypes, tokens) ] @@ -914,6 +914,8 @@ FROM pg_type t
> JOIN pg_namespace ns ON typnamespace = ns.oid JOIN pg_attribute a
> ON attrelid = typrelid WHERE typname = %%s and nspname = %%s +AND
> NOT attisdropped +AND attnum > 0 ORDER BY attnum; """ % typarray,
> (tname, schema))

Thank you for such a detailed answer.

> So, thank you very much for your test case: I will include it in
> the test suite together with the above patch to make sure the
> composite adapter works with tables too.

You're welcome, I'm glad this mail turned out to be useful.


- --
Ronan Dunklau
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.18 (GNU/Linux)

iQEcBAEBAgAGBQJO6iR8AAoJECTYLCgFy323QOAH/i9X+K9VF2IDTgtx1+qTsqvJ
xPdUgJYNuKZeO7EquNFJb3mBHLW+V9N4ov6FGW/Y+jzSvFLfm1WBjAThISBnsdda
TWiJU2p9YOcQXC1sPtTTwgjuAAmze6KIG3QnGqtF1Kjk4Lwx/7wuPAO0wpgPCIdW
kRl0lOJEpx9/UpBkCzq8UirtluQwVi2gdUJrf+pGng17mG1rHEJrlmk62Tkr36CR
Any6TG6oNHYR/rPqpEBTVj4qL0V9PUPoldhn8Uc0sYsuNGxoqE+QPQu1nYvBz3Q9
XhGExwqp4tyWEmUIc4JCDzUhv6PR+99H8XpKw5QZAHti7SDPl9fG5cmpEBrBxB8=
=OcDB
-----END PGP SIGNATURE-----

psycopg by date:

Previous
From: Daniele Varrazzo
Date:
Subject: Re: Generic casters for composite types
Next
From: Daniele Varrazzo
Date:
Subject: Re: [snafu] isolation-level change in 2.4.2