Skip to content

Commit 1734f2a

Browse files
committed
Added Cursor.to_dict()
1 parent 237f6f3 commit 1734f2a

File tree

3 files changed

+37
-0
lines changed

3 files changed

+37
-0
lines changed

docs/changelog.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
Changelog
33
#########
44

5+
Development Version 1.7.0 [unreleased]
6+
======================================
7+
8+
* New: `.Cursor.to_dict` method.
9+
10+
511
Version 1.6.0
612
=============
713

firebird/driver/core.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2655,13 +2655,16 @@ def __init__(self, connection: Connection, stmt: iStatement, sql: str, dialect:
26552655
self._out_cnt: int = meta.get_count()
26562656
self._out_buffer: bytes = None
26572657
self._out_desc: List[ItemMetadata] = None
2658+
self._names: List[str] = None
26582659
if self._out_cnt == 0:
26592660
meta.release()
26602661
self._out_desc = []
2662+
self._names = []
26612663
else:
26622664
self._out_meta = meta
26632665
self._out_buffer = create_string_buffer(meta.get_message_length())
26642666
self._out_desc = create_meta_descriptors(meta)
2667+
self._names = [meta.field if meta.field == meta.alias else meta.alias for meta in self._out_desc]
26652668
def __enter__(self) -> Statement:
26662669
return self
26672670
def __exit__(self, exc_type, exc_value, traceback) -> None:
@@ -3888,6 +3891,21 @@ def is_bof(self) -> bool:
38883891
"""
38893892
assert self._result is not None
38903893
return self._result.is_bof()
3894+
def to_dict(self, row: Tuple, into: Dict=None) -> Dict:
3895+
"""Return row tuple as dictionary with field names as keys. Returns new dictionary
3896+
if `into` argument is not provided, otherwise returns `into` dictionary updated
3897+
with row data.
3898+
3899+
Arguments:
3900+
row: Row data returned by fetch_* method.
3901+
into: Dictionary that shouold be updated with row data.
3902+
"""
3903+
assert len(self._stmt._names) == len(row), "Length of data must match number of fields"
3904+
if into is None:
3905+
into = dict(zip(self._stmt._names, row))
3906+
else:
3907+
into.update(zip(self._stmt._names, row))
3908+
return into
38913909
# Properties
38923910
@property
38933911
def connection(self) -> Connection:

test/test_driver.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,6 +1047,19 @@ def test_use_after_close(self):
10471047
with self.assertRaises(InterfaceError) as cm:
10481048
cur.fetchone()
10491049
self.assertTupleEqual(cm.exception.args, ('Cannot fetch from cursor that did not executed a statement.',))
1050+
def to_dict(self):
1051+
cmd = 'select * from country'
1052+
sample = {'COUNTRY': 'USA', 'CURRENCY': 'Dollar'}
1053+
with self.con.cursor() as cur:
1054+
cur.execute(cmd)
1055+
row = cur.fetchone()
1056+
d = cur.to_dict(row)
1057+
self.assertEqual(len(d), 2)
1058+
self.assertDictEqual(d, sample)
1059+
d = {'COUNTRY': 'UNKNOWN', 'CURRENCY': 'UNKNOWN'}
1060+
d2 = cur.to_dict(row, d)
1061+
self.assertDictEqual(d2, sample)
1062+
self.assertIs(d, d2)
10501063

10511064
class TestScrollableCursor(DriverTestBase):
10521065
def setUp(self):

0 commit comments

Comments
 (0)