mirror of
https://github.com/psycopg/psycopg2.git
synced 2025-01-31 09:24:07 +03:00
Added RealDictCursor from #143.
This commit is contained in:
parent
5c425f5294
commit
f43a52f781
|
@ -1,5 +1,10 @@
|
||||||
2007-01-16 Federico Di Gregorio <fog@initd.org>
|
2007-01-16 Federico Di Gregorio <fog@initd.org>
|
||||||
|
|
||||||
|
* lib/extras.py: merged DictCursor from #143 and renamed it RealDictCursor
|
||||||
|
because allows access by cursor keys _only_. Also cleaned up a little bit
|
||||||
|
the implementation of both DictCursor and RealDictCursor by introducing
|
||||||
|
DictCursorBase.
|
||||||
|
|
||||||
* psycopg/pqpath.cs: new checks for NULL values (meaning an
|
* psycopg/pqpath.cs: new checks for NULL values (meaning an
|
||||||
exception was raised) in all method calls (fixes #134).
|
exception was raised) in all method calls (fixes #134).
|
||||||
|
|
||||||
|
|
|
@ -32,14 +32,34 @@ print "Encoding for this connection is", conn.encoding
|
||||||
|
|
||||||
curs = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
|
curs = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
|
||||||
curs.execute("SELECT 1 AS foo, 'cip' AS bar, date(now()) as zot")
|
curs.execute("SELECT 1 AS foo, 'cip' AS bar, date(now()) as zot")
|
||||||
|
print "Cursor's row factory is", curs.row_factory
|
||||||
|
|
||||||
data = curs.fetchone()
|
data = curs.fetchone()
|
||||||
|
print "The type of the data row is", type(data)
|
||||||
print "Some data accessed both as tuple and dict:"
|
print "Some data accessed both as tuple and dict:"
|
||||||
print " ", data['foo'], data['bar'], data['zot']
|
print " ", data['foo'], data['bar'], data['zot']
|
||||||
print " ", data[0], data[1], data[2]
|
print " ", data[0], data[1], data[2]
|
||||||
|
|
||||||
# execute another query and demostrate we can still access the row
|
# execute another query and demostrate we can still access the row
|
||||||
curs.execute("SELECT 2 AS foo")
|
curs.execute("SELECT 2 AS foo")
|
||||||
|
print "The type of the data row is", type(data)
|
||||||
print "Some more data accessed both as tuple and dict:"
|
print "Some more data accessed both as tuple and dict:"
|
||||||
print " ", data['foo'], data['bar'], data['zot']
|
print " ", data['foo'], data['bar'], data['zot']
|
||||||
print " ", data[0], data[1], data[2]
|
print " ", data[0], data[1], data[2]
|
||||||
|
|
||||||
|
curs = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
|
||||||
|
curs.execute("SELECT 1 AS foo, 'cip' AS bar, date(now()) as zot")
|
||||||
|
print "Cursor's row factory is", curs.row_factory
|
||||||
|
|
||||||
|
data = curs.fetchone()
|
||||||
|
print "The type of the data row is", type(data)
|
||||||
|
print "Some data accessed both as tuple and dict:"
|
||||||
|
print " ", data['foo'], data['bar'], data['zot']
|
||||||
|
print " ", "No access using indices: this is a specialized cursor."
|
||||||
|
|
||||||
|
# execute another query and demostrate we can still access the row
|
||||||
|
curs.execute("SELECT 2 AS foo")
|
||||||
|
print "The type of the data row is", type(data)
|
||||||
|
print "Some more data accessed both as tuple and dict:"
|
||||||
|
print " ", data['foo'], data['bar'], data['zot']
|
||||||
|
print " ", "No access using indices: this is a specialized cursor."
|
||||||
|
|
126
lib/extras.py
126
lib/extras.py
|
@ -30,59 +30,70 @@ from psycopg2.extensions import connection as _connection
|
||||||
from psycopg2.extensions import adapt as _A
|
from psycopg2.extensions import adapt as _A
|
||||||
|
|
||||||
|
|
||||||
|
class DictCursorBase(_cursor):
|
||||||
|
"""Base class for all dict-like cursors."""
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
if kwargs.has_key('row_factory'):
|
||||||
|
row_factory = kwargs['row_factory']
|
||||||
|
del kwargs['row_factory']
|
||||||
|
else:
|
||||||
|
raise NotImplementedError(
|
||||||
|
"DictCursorBase can't be instantiated without a row factory.")
|
||||||
|
_cursor.__init__(self, *args, **kwargs)
|
||||||
|
self._query_executed = 0
|
||||||
|
self.row_factory = row_factory
|
||||||
|
|
||||||
|
def fetchone(self):
|
||||||
|
if self._query_executed:
|
||||||
|
self._build_index()
|
||||||
|
return _cursor.fetchone(self)
|
||||||
|
|
||||||
|
def fetchmany(self, size=None):
|
||||||
|
if self._query_executed:
|
||||||
|
self._build_index()
|
||||||
|
return _cursor.fetchmany(self, size)
|
||||||
|
|
||||||
|
def fetchall(self):
|
||||||
|
if self._query_executed:
|
||||||
|
self._build_index()
|
||||||
|
return _cursor.fetchall(self)
|
||||||
|
|
||||||
|
def next(self):
|
||||||
|
if self._query_executed:
|
||||||
|
self._build_index()
|
||||||
|
res = _cursor.fetchone(self)
|
||||||
|
if res is None:
|
||||||
|
raise StopIteration()
|
||||||
|
return res
|
||||||
|
|
||||||
class DictConnection(_connection):
|
class DictConnection(_connection):
|
||||||
"""A connection that uses DictCursor automatically."""
|
"""A connection that uses DictCursor automatically."""
|
||||||
def cursor(self):
|
def cursor(self):
|
||||||
return _connection.cursor(self, cursor_factory=DictCursor)
|
return _connection.cursor(self, cursor_factory=DictCursor)
|
||||||
|
|
||||||
class DictCursor(_cursor):
|
class DictCursor(DictCursorBase):
|
||||||
"""A cursor that keeps a list of column name -> index mappings."""
|
"""A cursor that keeps a list of column name -> index mappings."""
|
||||||
|
|
||||||
__query_executed = 0
|
def __init__(self, *args, **kwargs):
|
||||||
|
kwargs['row_factory'] = DictRow
|
||||||
|
DictCursorBase.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
def execute(self, query, vars=None, async=0):
|
def execute(self, query, vars=None, async=0):
|
||||||
self.row_factory = DictRow
|
|
||||||
self.index = {}
|
self.index = {}
|
||||||
self.__query_executed = 1
|
self._query_executed = 1
|
||||||
return _cursor.execute(self, query, vars, async)
|
return _cursor.execute(self, query, vars, async)
|
||||||
|
|
||||||
def callproc(self, procname, vars=None):
|
def callproc(self, procname, vars=None):
|
||||||
self.row_factory = DictRow
|
|
||||||
self.index = {}
|
self.index = {}
|
||||||
self.__query_executed = 1
|
self._query_executed = 1
|
||||||
return _cursor.callproc(self, procname, vars)
|
return _cursor.callproc(self, procname, vars)
|
||||||
|
|
||||||
def _build_index(self):
|
def _build_index(self):
|
||||||
if self.__query_executed == 1 and self.description:
|
if self._query_executed == 1 and self.description:
|
||||||
for i in range(len(self.description)):
|
for i in range(len(self.description)):
|
||||||
self.index[self.description[i][0]] = i
|
self.index[self.description[i][0]] = i
|
||||||
self.__query_executed = 0
|
self._query_executed = 0
|
||||||
|
|
||||||
def fetchone(self):
|
|
||||||
res = _cursor.fetchone(self)
|
|
||||||
if self.__query_executed:
|
|
||||||
self._build_index()
|
|
||||||
return res
|
|
||||||
|
|
||||||
def fetchmany(self, size=None):
|
|
||||||
res = _cursor.fetchmany(self, size)
|
|
||||||
if self.__query_executed:
|
|
||||||
self._build_index()
|
|
||||||
return res
|
|
||||||
|
|
||||||
def fetchall(self):
|
|
||||||
res = _cursor.fetchall(self)
|
|
||||||
if self.__query_executed:
|
|
||||||
self._build_index()
|
|
||||||
return res
|
|
||||||
|
|
||||||
def next(self):
|
|
||||||
res = _cursor.fetchone(self)
|
|
||||||
if res is None:
|
|
||||||
raise StopIteration()
|
|
||||||
if self.__query_executed:
|
|
||||||
self._build_index()
|
|
||||||
return res
|
|
||||||
|
|
||||||
class DictRow(list):
|
class DictRow(list):
|
||||||
"""A row object that allow by-colun-name access to data."""
|
"""A row object that allow by-colun-name access to data."""
|
||||||
|
@ -121,7 +132,52 @@ class DictRow(list):
|
||||||
for n, v in self._index.items():
|
for n, v in self._index.items():
|
||||||
yield n, list.__getitem__(self, v)
|
yield n, list.__getitem__(self, v)
|
||||||
|
|
||||||
|
|
||||||
|
class RealDictConnection(_connection):
|
||||||
|
"""A connection that uses RealDictCursor automatically."""
|
||||||
|
def cursor(self):
|
||||||
|
return _connection.cursor(self, cursor_factory=RealDictCursor)
|
||||||
|
|
||||||
|
class RealDictCursor(DictCursorBase):
|
||||||
|
"""A cursor that uses a real dict as the base type for rows.
|
||||||
|
|
||||||
|
Note that this cursor is extremely specialized and does not allow
|
||||||
|
the normal access (using integer indices) to fetched data. If you need
|
||||||
|
to access database rows both as a dictionary and a list, then use
|
||||||
|
the generic DictCursor instead of RealDictCursor.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
kwargs['row_factory'] = RealDictRow
|
||||||
|
DictCursorBase.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
|
def execute(self, query, vars=None, async=0):
|
||||||
|
self.column_mapping = []
|
||||||
|
self._query_executed = 1
|
||||||
|
return _cursor.execute(self, query, vars, async)
|
||||||
|
|
||||||
|
def callproc(self, procname, vars=None):
|
||||||
|
self.column_mapping = []
|
||||||
|
self._query_executed = 1
|
||||||
|
return _cursor.callproc(self, procname, vars)
|
||||||
|
|
||||||
|
def _build_index(self):
|
||||||
|
if self._query_executed == 1 and self.description:
|
||||||
|
for item in self.description:
|
||||||
|
self.column_mapping.append(item[0])
|
||||||
|
self._query_executed = 0
|
||||||
|
|
||||||
|
class RealDictRow(dict):
|
||||||
|
def __init__(self, cursor):
|
||||||
|
dict.__init__(self)
|
||||||
|
self._column_mapping = cursor.column_mapping
|
||||||
|
|
||||||
|
def __setitem__(self, name, value):
|
||||||
|
if type(name) == type(0):
|
||||||
|
name = self._column_mapping[name]
|
||||||
|
return dict.__setitem__(self, name, value)
|
||||||
|
|
||||||
|
|
||||||
class LoggingConnection(_connection):
|
class LoggingConnection(_connection):
|
||||||
"""A connection that logs all queries to a file or logger object."""
|
"""A connection that logs all queries to a file or logger object."""
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user