summaryrefslogtreecommitdiff
path: root/lib/extras.py
blob: 3116aedce4890b847ee6909d0c72448e1b76ada7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
"""Miscellaneous goodies for psycopg

This module is a generic place used to hold little helper function
and classes untill a better place in the distribution is found.
"""
# psycopg/extras.py - miscellaneous extra goodies for psycopg
#
# Copyright (C) 2003-2004 Federico Di Gregorio  <fog@debian.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
# for more details.

from psycopg.extensions import cursor as _cursor
from psycopg.extensions import register_adapter as _RA
from psycopg.extensions import adapt as _A


class DictCursor(_cursor):
    """A cursor that keeps a list of column name -> index mappings."""

    __query_executed = 0
    
    def execute(self, query, vars=None, async=0):
        self.row_factory = DictRow
        self.index = {}
        self.__query_executed = 1
        return _cursor.execute(self, query, vars, async)

    def _build_index(self):
        if self.__query_executed == 1 and self.description:
            for i in range(len(self.description)):
                self.index[self.description[i][0]] = i
            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
        
class DictRow(list):
    """A row object that allow by-colun-name access to data."""

    def __init__(self, cursor):
        self._cursor = cursor
        self[:] = [None] * len(cursor.description)

    def __getitem__(self, x):
        if type(x) != int:
            x = self._cursor.index[x]
        return list.__getitem__(self, x)



class AsIs(object):
    """An adapter that just return the object 'as is'.

    psycopg 1.99.9 has some optimizations that make impossible to call adapt()
    without adding some basic adapters externally. This limitation will be
    lifted in a future release. In the meantime you can use the AsIs adapter.
    """
    def __init__(self, obj):
        self.__obj = obj
    def getquoted(self):
        return self.__obj
    def prepare(self, conn):
	pass
    __str__ = getquoted

class SQL_IN(object):
    """Adapt any iterable to an SQL quotable object."""
    
    def __init__(self, seq):
	self._seq = seq
	
    def prepare(self, conn):
	pass
    
    def getquoted(self):
        # this is the important line: note how every object in the
        # list is adapted and then how getquoted() is called on it
	qobjs = [str(_A(o).getquoted()) for o in self._seq]

	return '(' + ', '.join(qobjs) + ')'
	
    __str__ = getquoted


_RA(tuple, SQL_IN)
_RA(int, AsIs)
_RA(float, AsIs)