- def _build_select(self, table, kvfilter=None, kvout=None, columns=None):
- SELECT = "SELECT %(cols)s FROM %(table)s %(where)s"
- cols = "*"
- if columns:
- cols = ",".join(columns)
- where = ""
- if kvfilter is not None:
- where = self._build_where(kvfilter, kvout)
- return SELECT % {'table': table, 'cols': cols, 'where': where}
-
- def _select(self, cursor, table, kvfilter=None, columns=None):
- kv = dict()
- select = self._build_select(table, kvfilter, kv, columns)
- cursor.execute(select, kv)
- return cursor.fetchall()
-
- def _create(self, cursor, table, columns):
- CREATE = "CREATE TABLE IF NOT EXISTS %(table)s(%(cols)s)"
- cols = ",".join(columns)
- create = CREATE % {'table': table, 'cols': cols}
- cursor.execute(create)
-
- def _update(self, cursor, table, values, kvfilter):
- UPDATE = "UPDATE %(table)s SET %(setval)s %(where)s"
- kv = dict()
-
- setval = ""
- sep = ""
- for k in values:
- mk = "setval_%s" % k
- kv[mk] = values[k]
- setval += "%s%s=:%s" % (sep, k, mk)
- sep = " , "
-
- where = self._build_where(kvfilter, kv)
-
- update = UPDATE % {'table': table, 'setval': setval, 'where': where}
- cursor.execute(update, kv)
-
- def _insert(self, cursor, table, values):
- INSERT = "INSERT INTO %(table)s VALUES(%(values)s)"
- vals = ""
- sep = ""
- for _ in values:
- vals += "%s?" % sep
- sep = ","
- insert = INSERT % {'table': table, 'values': vals}
- cursor.execute(insert, values)
-
- def _delete(self, cursor, table, kvfilter):
- DELETE = "DELETE FROM %(table)s %(where)s"
- kv = dict()
- where = self._build_where(kvfilter, kv)
- delete = DELETE % {'table': table, 'where': where}
- cursor.execute(delete, kv)
+ def _columns(self, columns=None):
+ cols = None
+ if columns is not None:
+ cols = []
+ for c in columns:
+ cols.append(self._table.columns[c])
+ else:
+ cols = self._table.columns
+ return cols
+
+ def rollback(self):
+ self._trans.rollback()
+
+ def commit(self):
+ self._trans.commit()
+
+ def create(self):
+ self._table.create(checkfirst=True)
+
+ def drop(self):
+ self._table.drop(checkfirst=True)
+
+ @SqlAutotable
+ def select(self, kvfilter=None, columns=None):
+ return self._con.execute(select(self._columns(columns),
+ self._where(kvfilter)))
+
+ @SqlAutotable
+ def insert(self, values):
+ self._con.execute(self._table.insert(values))
+
+ @SqlAutotable
+ def update(self, values, kvfilter):
+ self._con.execute(self._table.update(self._where(kvfilter), values))
+
+ @SqlAutotable
+ def delete(self, kvfilter):
+ self._con.execute(self._table.delete(self._where(kvfilter)))
+
+
+class FileStore(Log):
+
+ def __init__(self, name):
+ self._filename = name
+ self.is_readonly = True
+ self._timestamp = None
+ self._config = None
+
+ def get_config(self):
+ try:
+ stat = os.stat(self._filename)
+ except OSError, e:
+ self.error("Unable to check config file %s: [%s]" % (
+ self._filename, e))
+ self._config = None
+ raise
+ timestamp = stat.st_mtime
+ if self._config is None or timestamp > self._timestamp:
+ self._config = ConfigParser.RawConfigParser()
+ self._config.optionxform = str
+ self._config.read(self._filename)
+ return self._config
+
+
+class FileQuery(Log):
+
+ def __init__(self, fstore, table, columns, trans=True):
+ self._fstore = fstore
+ self._config = fstore.get_config()
+ self._section = table
+ if len(columns) > 3 or columns[-1] != 'value':
+ raise ValueError('Unsupported configuration format')
+ self._columns = columns
+
+ def rollback(self):
+ return
+
+ def commit(self):
+ return
+
+ def create(self):
+ raise NotImplementedError
+
+ def drop(self):
+ raise NotImplementedError
+
+ def select(self, kvfilter=None, columns=None):
+ if self._section not in self._config.sections():
+ return []
+
+ opts = self._config.options(self._section)
+
+ prefix = None
+ prefix_ = ''
+ if self._columns[0] in kvfilter:
+ prefix = kvfilter[self._columns[0]]
+ prefix_ = prefix + ' '
+
+ name = None
+ if len(self._columns) == 3 and self._columns[1] in kvfilter:
+ name = kvfilter[self._columns[1]]
+
+ value = None
+ if self._columns[-1] in kvfilter:
+ value = kvfilter[self._columns[-1]]
+
+ res = []
+ for o in opts:
+ if len(self._columns) == 3:
+ # 3 cols
+ if prefix and not o.startswith(prefix_):
+ continue
+
+ col1, col2 = o.split(' ', 1)
+ if name and col2 != name:
+ continue
+
+ col3 = self._config.get(self._section, o)
+ if value and col3 != value:
+ continue
+
+ r = [col1, col2, col3]
+ else:
+ # 2 cols
+ if prefix and o != prefix:
+ continue
+ r = [o, self._config.get(self._section, o)]
+
+ if columns:
+ s = []
+ for c in columns:
+ s.append(r[self._columns.index(c)])
+ res.append(s)
+ else:
+ res.append(r)
+
+ self.debug('SELECT(%s, %s, %s) -> %s' % (self._section,
+ repr(kvfilter),
+ repr(columns),
+ repr(res)))
+ return res
+
+ def insert(self, values):
+ raise NotImplementedError
+
+ def update(self, values, kvfilter):
+ raise NotImplementedError
+
+ def delete(self, kvfilter):
+ raise NotImplementedError
+
+
+class Store(Log):
+ def __init__(self, config_name=None, database_url=None):
+ if config_name is None and database_url is None:
+ raise ValueError('config_name or database_url must be provided')
+ if config_name:
+ if config_name not in cherrypy.config:
+ raise NameError('Unknown database %s' % config_name)
+ name = cherrypy.config[config_name]
+ else:
+ name = database_url
+ if name.startswith('configfile://'):
+ _, filename = name.split('://')
+ self._db = FileStore(filename)
+ self._query = FileQuery
+ else:
+ self._db = SqlStore.get_connection(name)
+ self._query = SqlQuery
+
+ @property
+ def is_readonly(self):
+ return self._db.is_readonly