|
5 | 5 | # the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0
|
6 | 6 |
|
7 | 7 |
|
| 8 | +from collections.abc import Mapping as MappingABC |
| 9 | + |
8 | 10 | from asyncpg import exceptions
|
9 | 11 |
|
10 | 12 |
|
@@ -43,12 +45,13 @@ cdef class Codec:
|
43 | 45 | self.element_type_oids = element_type_oids
|
44 | 46 | self.element_codecs = element_codecs
|
45 | 47 | self.element_delimiter = element_delimiter
|
| 48 | + self.element_names = element_names |
46 | 49 |
|
47 | 50 | if element_names is not None:
|
48 |
| - self.element_names = record.ApgRecordDesc_New( |
| 51 | + self.record_desc = record.ApgRecordDesc_New( |
49 | 52 | element_names, tuple(element_names))
|
50 | 53 | else:
|
51 |
| - self.element_names = None |
| 54 | + self.record_desc = None |
52 | 55 |
|
53 | 56 | if type == CODEC_C:
|
54 | 57 | self.encoder = <codec_encode_func>&self.encode_scalar
|
@@ -125,6 +128,31 @@ cdef class Codec:
|
125 | 128 | int i
|
126 | 129 | list elem_codecs = self.element_codecs
|
127 | 130 | ssize_t count
|
| 131 | + ssize_t composite_size |
| 132 | + tuple rec |
| 133 | + |
| 134 | + if isinstance(obj, MappingABC): |
| 135 | + # Input is dict-like, form a tuple |
| 136 | + composite_size = len(self.element_type_oids) |
| 137 | + rec = cpython.PyTuple_New(composite_size) |
| 138 | + |
| 139 | + for i in range(composite_size): |
| 140 | + cpython.Py_INCREF(None) |
| 141 | + cpython.PyTuple_SET_ITEM(rec, i, None) |
| 142 | + |
| 143 | + for field in obj: |
| 144 | + try: |
| 145 | + i = self.element_names[field] |
| 146 | + except KeyError: |
| 147 | + raise ValueError( |
| 148 | + '{!r} is not a valid element of composite ' |
| 149 | + 'type {}'.format(field, self.name)) from None |
| 150 | + |
| 151 | + item = obj[field] |
| 152 | + cpython.Py_INCREF(item) |
| 153 | + cpython.PyTuple_SET_ITEM(rec, i, item) |
| 154 | + |
| 155 | + obj = rec |
128 | 156 |
|
129 | 157 | count = len(obj)
|
130 | 158 | if count > _MAXINT32:
|
@@ -204,7 +232,7 @@ cdef class Codec:
|
204 | 232 | schema=self.schema,
|
205 | 233 | data_type=self.name,
|
206 | 234 | )
|
207 |
| - result = record.ApgRecord_New(self.element_names, elem_count) |
| 235 | + result = record.ApgRecord_New(self.record_desc, elem_count) |
208 | 236 | for i in range(elem_count):
|
209 | 237 | elem_typ = self.element_type_oids[i]
|
210 | 238 | received_elem_typ = <uint32_t>hton.unpack_int32(buf.read(4))
|
|
0 commit comments