1 # Copyright 2011-2012 GRNET S.A. All rights reserved.
3 # Redistribution and use in source and binary forms, with or
4 # without modification, are permitted provided that the following
7 # 1. Redistributions of source code must retain the above
8 # copyright notice, this list of conditions and the following
11 # 2. Redistributions in binary form must reproduce the above
12 # copyright notice, this list of conditions and the following
13 # disclaimer in the documentation and/or other materials
14 # provided with the distribution.
16 # THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 # POSSIBILITY OF SUCH DAMAGE.
29 # The views and conclusions contained in the software and
30 # documentation are those of the authors and should not be
31 # interpreted as representing official policies, either expressed
32 # or implied, of GRNET S.A.
34 from collections import defaultdict
36 from dbworker import DBWorker
39 class XFeatures(DBWorker):
40 """XFeatures are path properties that allow non-nested
41 inheritance patterns. Currently used for storing permissions.
44 def __init__(self, **params):
45 DBWorker.__init__(self, **params)
46 execute = self.execute
48 execute(""" pragma foreign_keys = on """)
50 execute(""" create table if not exists xfeatures
51 ( feature_id integer primary key,
53 execute(""" create unique index if not exists idx_features_path
54 on xfeatures(path) """)
56 execute(""" create table if not exists xfeaturevals
60 primary key (feature_id, key, value)
61 foreign key (feature_id) references xfeatures(feature_id)
62 on delete cascade ) """)
64 # def xfeature_inherit(self, path):
65 # """Return the (path, feature) inherited by the path, or None."""
67 # q = ("select path, feature_id from xfeatures "
69 # "and ? like path || '%' " # XXX: Escape like...
70 # "order by path desc")
71 # self.execute(q, (path, path))
72 # return self.fetchall()
74 def xfeature_get(self, path):
75 """Return feature for path."""
77 q = "select feature_id from xfeatures where path = ?"
78 self.execute(q, (path,))
84 def xfeature_create(self, path):
85 """Create and return a feature for path.
86 If the path has a feature, return it.
89 feature = self.xfeature_get(path)
90 if feature is not None:
92 q = "insert into xfeatures (path) values (?)"
93 id = self.execute(q, (path,)).lastrowid
96 def xfeature_destroy(self, path):
97 """Destroy a feature and all its key, value pairs."""
99 q = "delete from xfeatures where path = ?"
100 self.execute(q, (path,))
102 def xfeature_destroy_bulk(self, paths):
103 """Destroy features and all their key, value pairs."""
105 placeholders = ','.join('?' for path in paths)
106 q = "delete from xfeatures where path in (%s)" % placeholders
107 self.execute(q, paths)
109 def feature_dict(self, feature):
110 """Return a dict mapping keys to list of values for feature."""
112 q = "select key, value from xfeaturevals where feature_id = ?"
113 self.execute(q, (feature,))
114 d = defaultdict(list)
115 for key, value in self.fetchall():
119 def feature_set(self, feature, key, value):
120 """Associate a key, value pair with a feature."""
122 q = "insert or ignore into xfeaturevals (feature_id, key, value) values (?, ?, ?)"
123 self.execute(q, (feature, key, value))
125 def feature_setmany(self, feature, key, values):
126 """Associate the given key, and values with a feature."""
128 q = "insert or ignore into xfeaturevals (feature_id, key, value) values (?, ?, ?)"
129 self.executemany(q, ((feature, key, v) for v in values))
131 def feature_unset(self, feature, key, value):
132 """Disassociate a key, value pair from a feature."""
134 q = ("delete from xfeaturevals where "
135 "feature_id = ? and key = ? and value = ?")
136 self.execute(q, (feature, key, value))
138 def feature_unsetmany(self, feature, key, values):
139 """Disassociate the key for the values given, from a feature."""
141 q = ("delete from xfeaturevals where "
142 "feature_id = ? and key = ? and value = ?")
143 self.executemany(q, ((feature, key, v) for v in values))
145 def feature_get(self, feature, key):
146 """Return the list of values for a key of a feature."""
148 q = "select value from xfeaturevals where feature_id = ? and key = ?"
149 self.execute(q, (feature, key))
150 return [r[0] for r in self.fetchall()]
152 def feature_clear(self, feature, key):
153 """Delete all key, value pairs for a key of a feature."""
155 q = "delete from xfeaturevals where feature_id = ? and key = ?"
156 self.execute(q, (feature, key))