from sqlalchemy.sql import select, and_
from sqlalchemy.schema import Index
from sqlalchemy.sql.expression import desc
+from sqlalchemy.exc import NoSuchTableError
from dbworker import DBWorker
+def create_tables(engine):
+ metadata = MetaData()
+ columns=[]
+ columns.append(Column('feature_id', Integer, primary_key=True))
+ columns.append(Column('path', String(2048)))
+ xfeatures = Table('xfeatures', metadata, *columns, mysql_engine='InnoDB')
+ # place an index on path
+ Index('idx_features_path', xfeatures.c.path, unique=True)
+
+ columns=[]
+ columns.append(Column('feature_id', Integer,
+ ForeignKey('xfeatures.feature_id',
+ ondelete='CASCADE'),
+ primary_key=True))
+ columns.append(Column('key', Integer, primary_key=True,
+ autoincrement=False))
+ columns.append(Column('value', String(256), primary_key=True))
+ xfeaturevals = Table('xfeaturevals', metadata, *columns, mysql_engine='InnoDB')
+
+ metadata.create_all(engine)
+ return metadata.sorted_tables
class XFeatures(DBWorker):
"""XFeatures are path properties that allow non-nested
def __init__(self, **params):
DBWorker.__init__(self, **params)
- metadata = MetaData()
- columns=[]
- columns.append(Column('feature_id', Integer, primary_key=True))
- columns.append(Column('path', String(2048)))
- self.xfeatures = Table('xfeatures', metadata, *columns, mysql_engine='InnoDB')
- # place an index on path
- Index('idx_features_path', self.xfeatures.c.path, unique=True)
-
- columns=[]
- columns.append(Column('feature_id', Integer,
- ForeignKey('xfeatures.feature_id',
- ondelete='CASCADE'),
- primary_key=True))
- columns.append(Column('key', Integer, primary_key=True,
- autoincrement=False))
- columns.append(Column('value', String(255), primary_key=True))
- self.xfeaturevals = Table('xfeaturevals', metadata, *columns, mysql_engine='InnoDB')
-
- metadata.create_all(self.engine)
+ try:
+ metadata = MetaData(self.engine)
+ self.xfeatures = Table('xfeatures', metadata, autoload=True)
+ self.xfeaturevals = Table('xfeaturevals', metadata, autoload=True)
+ except NoSuchTableError:
+ tables = create_tables(self.engine)
+ map(lambda t: self.__setattr__(t.name, t), tables)
- def xfeature_inherit(self, path):
- """Return the (path, feature) inherited by the path, or None."""
-
- s = select([self.xfeatures.c.path, self.xfeatures.c.feature_id])
- s = s.where(self.xfeatures.c.path <= path)
- s = s.order_by(desc(self.xfeatures.c.path)).limit(1)
- r = self.conn.execute(s)
- row = r.fetchone()
- r.close()
- if row and path.startswith(row[0]):
- return row
- else:
- return None
+# def xfeature_inherit(self, path):
+# """Return the (path, feature) inherited by the path, or None."""
+#
+# s = select([self.xfeatures.c.path, self.xfeatures.c.feature_id])
+# s = s.where(self.xfeatures.c.path <= path)
+# #s = s.where(self.xfeatures.c.path.like(self.escape_like(path) + '%', escape='\\')) # XXX: Implement reverse and escape like...
+# s = s.order_by(desc(self.xfeatures.c.path))
+# r = self.conn.execute(s)
+# l = r.fetchall()
+# r.close()
+# return l
- def xfeature_list(self, path):
- """Return the list of the (prefix, feature) pairs matching path.
- A prefix matches path if either the prefix includes the path,
- or the path includes the prefix.
- """
-
- inherited = self.xfeature_inherit(path)
- if inherited:
- return [inherited]
+ def xfeature_get(self, path):
+ """Return feature for path."""
- s = select([self.xfeatures.c.path, self.xfeatures.c.feature_id])
- s = s.where(and_(self.xfeatures.c.path.like(self.escape_like(path) + '%', escape='\\'),
- self.xfeatures.c.path != path))
+ s = select([self.xfeatures.c.feature_id])
+ s = s.where(self.xfeatures.c.path == path)
s = s.order_by(self.xfeatures.c.path)
r = self.conn.execute(s)
- l = r.fetchall()
+ row = r.fetchone()
r.close()
- return l
+ if row:
+ return row[0]
+ return None
def xfeature_create(self, path):
"""Create and return a feature for path.
- If the path already inherits a feature or
- bestows to paths already inheriting a feature,
- create no feature and return None.
If the path has a feature, return it.
"""
- prefixes = self.xfeature_list(path)
- pl = len(prefixes)
- if (pl > 1) or (pl == 1 and prefixes[0][0] != path):
- return None
- if pl == 1 and prefixes[0][0] == path:
- return prefixes[0][1]
+ feature = self.xfeature_get(path)
+ if feature is not None:
+ return feature
s = self.xfeatures.insert()
r = self.conn.execute(s, path=path)
inserted_primary_key = r.inserted_primary_key[0]
r = self.conn.execute(s)
r.close()
+ def xfeature_destroy_bulk(self, paths):
+ """Destroy features and all their key, value pairs."""
+
+ s = self.xfeatures.delete().where(self.xfeatures.c.path.in_(paths))
+ r = self.conn.execute(s)
+ r.close()
+
def feature_dict(self, feature):
"""Return a dict mapping keys to list of values for feature."""