2 """A simple dict-derived class that allows bag.key and bag['key']"""
3 def __getattr__(self
, key
):
6 def __setattr__(self
, key
, value
):
9 def __delattr__(self
, key
):
12 class rows_ref(object):
13 """A lazy reference to a set of rows.
15 Again, this should not be instantiated by hand; use table.rows(...)
17 def __init__(self
, con
, table
, where_clause
, args
):
18 self
.con
, self
.table
, self
.where_clause
, self
.args
= con
, table
, where_clause
, args
20 def _set_clause(self
, **kwargs
):
21 return ', '.join('%s = %s' % (column
, self
.con
.placeholder
) for column
in kwargs
.keys())
23 def select(self
, *args
):
24 """Returns all rows in this rows_ref. If arguments are given, they are the columns selected."""
25 return self
.con
.query('SELECT %s FROM %s WHERE %s' % (
26 ', '.join(args
) if args
else '*',
33 def select_one(self
, *args
):
34 """Returns the first row in this rows_ref. If arguments are given, they are the columns selected."""
35 return self
.con
.query_one('SELECT %s FROM %s WHERE %s' % (
36 ', '.join(args
) if args
else '*',
43 def select_column(self
, column
):
44 """Returns the values in the specified column as a list."""
45 results
= self
.con
.query('SELECT %s FROM %s WHERE %s' % (
56 return [row
[column
] for row
in result
]
58 def select_value(self
, column
):
59 """Returns the value in the specified column."""
60 result
= self
.con
.query_one('SELECT %s FROM %s WHERE %s' % (
73 def update(self
, _clause
= '', *args
, **values
):
74 """Updates rows in this rows_ref.
76 Note: this uses similar arguments to table.select()"""
77 self
.con
.execute('UPDATE %s SET %s WHERE %s' % (
79 _clause
if _clause
else self
._set
_clause
(**values
),
81 *((args
if _clause
else tuple(values
.values())) + tuple(self
.args
))
85 """Deletes all rows in this rows_ref"""
86 self
.con
.execute('DELETE FROM %s WHERE %s' % (self
.table
.name
, self
.where_clause
), *self
.args
)
89 """Returns whether this is an empty set"""
90 return self
.table
.select_one(self
.where_clause
, *self
.args
) != None
92 class table_ref(object):
93 """A reference to a table.
95 Note that you shouldn't instantiate this yourself; use wrapper['table-name'] or wrapper.table_name instead.
97 def __init__(self
, con
, name
):
98 self
.con
, self
.name
= con
, name
100 def _where_clause(self
, *args
, **criteria
):
101 return ' AND '.join(('%s = ' + ('%' + self
.con
.placeholder
if self
.con
.placeholder
.startswith('%') else self
.con
.placeholder
) if value
is not None else '%s IS NULL') % column
for column
, value
in zip(criteria
.keys(), args
or criteria
.values()))
103 def _create_clause(self
, _query
, args
, criteria
):
104 return _query
if _query
else self
._where
_clause
(*args
, **criteria
)
106 def insert(self
, _columns
= [], _clause
= '', *args
, **values
):
107 """INSERTs a row into the table.
109 If columns and _clause are given, they will be placed into the SQL statement; otherwise, the columns and VALUES will be automatically generated.
110 Note that columns _must_ be given if clause is.
113 self
.con
.execute('INSERT INTO %s(%s) %s' % (self
.name
, ', '.join(_columns
if _columns
else values
.keys()), _clause
if _clause
else 'VALUES(%s)' % ', '.join([self
.con
.placeholder
] * len(args
if args
else values
))), *(values
.values() if values
else args
))
116 """Returns the whole table"""
118 return self
.con
.query('SELECT * FROM %s' % self
.name
)
120 def select(self
, _query
= '', *args
, **criteria
):
121 """SELECTs from the table.
123 If _query is specified, it will be used as the where clause; otherwise, one will be generated from the keyword arguments.
126 return self
.rows(_query
, *args
, **criteria
).select()
128 def select_one(self
, _query
= '', *args
, **criteria
):
129 """SELECTs from the table.
131 If _query is specified, it will be used as the where clause; otherwise, one will be generated from the keyword arguments.
133 return self
.rows(_query
, *args
, **criteria
).select_one()
135 def rows(self
, _query
= '', *args
, **criteria
):
136 """Returns a rows_ref object; uses same arguments as select()."""
137 return rows_ref(self
.con
, self
, self
._create
_clause
(_query
, args
, criteria
), (args
if _query
else tuple(x
for x
in criteria
.values() if x
is not None)))
139 class wrapper(object):
140 """A wrapper for a DB-API connection. You MUST specify the placeholder for parameters in the call to __init__; this is ? for most libraries and %s for MySQLdb.
142 NOTE: If your table names are not valid Python identifiers, use wrapper['table-name'].
144 def __init__(self
, con
, placeholder
, debug
= False):
145 self
.con
, self
.debug
= con
, debug
146 self
.placeholder
= placeholder
148 def __getattr__(self
, key
):
149 """Returns a table object"""
150 return self
.__dict
__[key
] if key
in self
.__dict
__ else table_ref(self
, key
)
153 """Commits the transaction"""
156 def execute(self
, query
, *args
):
157 """Runs self.con.cursor().execute(query, *args), and returns the cursor"""
159 if self
.debug
: print query
, args
161 cur
= self
.con
.cursor()
162 cur
.execute(query
, args
)
165 def execute_script(self
, filename
):
166 """Runs the SQL script in 'filename'"""
168 script
= file(filename
, 'r')
172 while not data
.rstrip().endswith(';'):
173 data
+= script
.readline()
174 if data
== '': return
178 def query(self
, query
, *args
):
179 """Wrapper similar to execute for SELECT statements, that returns a list of dicts."""
186 cur
= self
.execute(query
, *args
)
189 cur
= self
.execute(query
, *args
)
191 results
= cur
.fetchall()
192 if cur
.description
and results
:
193 # all SELECTs should have a description, but we shouldn't choke as the result of idiots
194 columns
= [desc
[0] for desc
in cur
.description
]
195 return [bag(zip(columns
, result
)) for result
in results
]
198 def query_one(self
, query
, *args
):
199 """Derivative of query for one-row SELECTs."""
206 cur
= self
.execute(query
, *args
)
209 cur
= self
.execute(query
, *args
)
211 result
= cur
.fetchone()
212 if cur
.description
and result
:
213 columns
= (desc
[0] for desc
in cur
.description
)
214 return bag(zip(columns
, result
))
218 __getitem__
= __getattr__