Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-backend / pithos / backends / lib / sqlalchemy / xfeatures.py @ 8c306eab

History | View | Annotate | Download (7.9 kB)

1 4f917833 Sofia Papagiannaki
# Copyright 2011 GRNET S.A. All rights reserved.
2 4f917833 Sofia Papagiannaki
# 
3 4f917833 Sofia Papagiannaki
# Redistribution and use in source and binary forms, with or
4 4f917833 Sofia Papagiannaki
# without modification, are permitted provided that the following
5 4f917833 Sofia Papagiannaki
# conditions are met:
6 4f917833 Sofia Papagiannaki
# 
7 4f917833 Sofia Papagiannaki
#   1. Redistributions of source code must retain the above
8 4f917833 Sofia Papagiannaki
#      copyright notice, this list of conditions and the following
9 4f917833 Sofia Papagiannaki
#      disclaimer.
10 4f917833 Sofia Papagiannaki
# 
11 4f917833 Sofia Papagiannaki
#   2. Redistributions in binary form must reproduce the above
12 4f917833 Sofia Papagiannaki
#      copyright notice, this list of conditions and the following
13 4f917833 Sofia Papagiannaki
#      disclaimer in the documentation and/or other materials
14 4f917833 Sofia Papagiannaki
#      provided with the distribution.
15 4f917833 Sofia Papagiannaki
# 
16 4f917833 Sofia Papagiannaki
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 4f917833 Sofia Papagiannaki
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 4f917833 Sofia Papagiannaki
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 4f917833 Sofia Papagiannaki
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 4f917833 Sofia Papagiannaki
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 4f917833 Sofia Papagiannaki
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 4f917833 Sofia Papagiannaki
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 4f917833 Sofia Papagiannaki
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 4f917833 Sofia Papagiannaki
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 4f917833 Sofia Papagiannaki
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 4f917833 Sofia Papagiannaki
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 4f917833 Sofia Papagiannaki
# POSSIBILITY OF SUCH DAMAGE.
28 4f917833 Sofia Papagiannaki
# 
29 4f917833 Sofia Papagiannaki
# The views and conclusions contained in the software and
30 4f917833 Sofia Papagiannaki
# documentation are those of the authors and should not be
31 4f917833 Sofia Papagiannaki
# interpreted as representing official policies, either expressed
32 4f917833 Sofia Papagiannaki
# or implied, of GRNET S.A.
33 4f917833 Sofia Papagiannaki
34 4f917833 Sofia Papagiannaki
from collections import defaultdict
35 4f917833 Sofia Papagiannaki
from sqlalchemy import Table, Column, String, Integer, MetaData, ForeignKey
36 4f917833 Sofia Papagiannaki
from sqlalchemy.sql import select, and_
37 4f917833 Sofia Papagiannaki
from sqlalchemy.schema import Index
38 4f917833 Sofia Papagiannaki
from sqlalchemy.sql.expression import desc
39 4f917833 Sofia Papagiannaki
40 4f917833 Sofia Papagiannaki
from dbworker import DBWorker
41 4f917833 Sofia Papagiannaki
42 4f917833 Sofia Papagiannaki
43 4f917833 Sofia Papagiannaki
class XFeatures(DBWorker):
44 4f917833 Sofia Papagiannaki
    """XFeatures are path properties that allow non-nested
45 4f917833 Sofia Papagiannaki
       inheritance patterns. Currently used for storing permissions.
46 4f917833 Sofia Papagiannaki
    """
47 4f917833 Sofia Papagiannaki
    
48 4f917833 Sofia Papagiannaki
    def __init__(self, **params):
49 4f917833 Sofia Papagiannaki
        DBWorker.__init__(self, **params)
50 4f917833 Sofia Papagiannaki
        metadata = MetaData()
51 4f917833 Sofia Papagiannaki
        columns=[]
52 4f917833 Sofia Papagiannaki
        columns.append(Column('feature_id', Integer, primary_key=True))
53 4f917833 Sofia Papagiannaki
        columns.append(Column('path', String(2048)))
54 8af4c26d Antony Chazapis
        self.xfeatures = Table('xfeatures', metadata, *columns, mysql_engine='InnoDB')
55 4f917833 Sofia Papagiannaki
        # place an index on path
56 9e9615fe Sofia Papagiannaki
        Index('idx_features_path', self.xfeatures.c.path, unique=True)
57 4f917833 Sofia Papagiannaki
        
58 4f917833 Sofia Papagiannaki
        columns=[]
59 4f917833 Sofia Papagiannaki
        columns.append(Column('feature_id', Integer,
60 4f917833 Sofia Papagiannaki
                              ForeignKey('xfeatures.feature_id',
61 4f917833 Sofia Papagiannaki
                                         ondelete='CASCADE'),
62 4f917833 Sofia Papagiannaki
                              primary_key=True))
63 d3be972a Sofia Papagiannaki
        columns.append(Column('key', Integer, primary_key=True,
64 d3be972a Sofia Papagiannaki
                              autoincrement=False))
65 4f917833 Sofia Papagiannaki
        columns.append(Column('value', String(255), primary_key=True))
66 8af4c26d Antony Chazapis
        self.xfeaturevals = Table('xfeaturevals', metadata, *columns, mysql_engine='InnoDB')
67 4f917833 Sofia Papagiannaki
        
68 4f917833 Sofia Papagiannaki
        metadata.create_all(self.engine)
69 4f917833 Sofia Papagiannaki
    
70 4f917833 Sofia Papagiannaki
    def xfeature_inherit(self, path):
71 4f917833 Sofia Papagiannaki
        """Return the (path, feature) inherited by the path, or None."""
72 4f917833 Sofia Papagiannaki
        
73 4f917833 Sofia Papagiannaki
        s = select([self.xfeatures.c.path, self.xfeatures.c.feature_id])
74 4f917833 Sofia Papagiannaki
        s = s.where(self.xfeatures.c.path <= path)
75 4f917833 Sofia Papagiannaki
        s = s.order_by(desc(self.xfeatures.c.path)).limit(1)
76 4f917833 Sofia Papagiannaki
        r = self.conn.execute(s)
77 4f917833 Sofia Papagiannaki
        row = r.fetchone()
78 4f917833 Sofia Papagiannaki
        r.close()
79 4f917833 Sofia Papagiannaki
        if row and path.startswith(row[0]):
80 4f917833 Sofia Papagiannaki
            return row
81 4f917833 Sofia Papagiannaki
        else:
82 4f917833 Sofia Papagiannaki
            return None
83 4f917833 Sofia Papagiannaki
    
84 4f917833 Sofia Papagiannaki
    def xfeature_list(self, path):
85 4f917833 Sofia Papagiannaki
        """Return the list of the (prefix, feature) pairs matching path.
86 4f917833 Sofia Papagiannaki
           A prefix matches path if either the prefix includes the path,
87 4f917833 Sofia Papagiannaki
           or the path includes the prefix.
88 4f917833 Sofia Papagiannaki
        """
89 4f917833 Sofia Papagiannaki
        
90 4f917833 Sofia Papagiannaki
        inherited = self.xfeature_inherit(path)
91 4f917833 Sofia Papagiannaki
        if inherited:
92 4f917833 Sofia Papagiannaki
            return [inherited]
93 4f917833 Sofia Papagiannaki
        
94 4f917833 Sofia Papagiannaki
        s = select([self.xfeatures.c.path, self.xfeatures.c.feature_id])
95 7759260d Antony Chazapis
        s = s.where(and_(self.xfeatures.c.path.like(self.escape_like(path) + '%', escape='\\'),
96 4f917833 Sofia Papagiannaki
                     self.xfeatures.c.path != path))
97 4f917833 Sofia Papagiannaki
        s = s.order_by(self.xfeatures.c.path)
98 4f917833 Sofia Papagiannaki
        r = self.conn.execute(s)
99 4f917833 Sofia Papagiannaki
        l = r.fetchall()
100 4f917833 Sofia Papagiannaki
        r.close()
101 4f917833 Sofia Papagiannaki
        return l
102 4f917833 Sofia Papagiannaki
    
103 4f917833 Sofia Papagiannaki
    def xfeature_create(self, path):
104 4f917833 Sofia Papagiannaki
        """Create and return a feature for path.
105 4f917833 Sofia Papagiannaki
           If the path already inherits a feature or
106 4f917833 Sofia Papagiannaki
           bestows to paths already inheriting a feature,
107 4f917833 Sofia Papagiannaki
           create no feature and return None.
108 4f917833 Sofia Papagiannaki
           If the path has a feature, return it.
109 4f917833 Sofia Papagiannaki
        """
110 4f917833 Sofia Papagiannaki
        
111 4f917833 Sofia Papagiannaki
        prefixes = self.xfeature_list(path)
112 4f917833 Sofia Papagiannaki
        pl = len(prefixes)
113 4f917833 Sofia Papagiannaki
        if (pl > 1) or (pl == 1 and prefixes[0][0] != path):
114 4f917833 Sofia Papagiannaki
            return None
115 4f917833 Sofia Papagiannaki
        if pl == 1 and prefixes[0][0] == path:
116 4f917833 Sofia Papagiannaki
            return prefixes[0][1]
117 4f917833 Sofia Papagiannaki
        s = self.xfeatures.insert()
118 4f917833 Sofia Papagiannaki
        r = self.conn.execute(s, path=path)
119 4f917833 Sofia Papagiannaki
        inserted_primary_key = r.inserted_primary_key[0]
120 4f917833 Sofia Papagiannaki
        r.close()
121 4f917833 Sofia Papagiannaki
        return inserted_primary_key
122 4f917833 Sofia Papagiannaki
    
123 4f917833 Sofia Papagiannaki
    def xfeature_destroy(self, path):
124 4f917833 Sofia Papagiannaki
        """Destroy a feature and all its key, value pairs."""
125 4f917833 Sofia Papagiannaki
        
126 4f917833 Sofia Papagiannaki
        s = self.xfeatures.delete().where(self.xfeatures.c.path == path)
127 4f917833 Sofia Papagiannaki
        r = self.conn.execute(s)
128 4f917833 Sofia Papagiannaki
        r.close()
129 4f917833 Sofia Papagiannaki
    
130 4f917833 Sofia Papagiannaki
    def feature_dict(self, feature):
131 4f917833 Sofia Papagiannaki
        """Return a dict mapping keys to list of values for feature."""
132 4f917833 Sofia Papagiannaki
        
133 4f917833 Sofia Papagiannaki
        s = select([self.xfeaturevals.c.key, self.xfeaturevals.c.value])
134 4f917833 Sofia Papagiannaki
        s = s.where(self.xfeaturevals.c.feature_id == feature)
135 4f917833 Sofia Papagiannaki
        r = self.conn.execute(s)
136 4f917833 Sofia Papagiannaki
        d = defaultdict(list)
137 4f917833 Sofia Papagiannaki
        for key, value in r.fetchall():
138 4f917833 Sofia Papagiannaki
            d[key].append(value)
139 4f917833 Sofia Papagiannaki
        r.close()
140 4f917833 Sofia Papagiannaki
        return d
141 4f917833 Sofia Papagiannaki
    
142 4f917833 Sofia Papagiannaki
    def feature_set(self, feature, key, value):
143 4f917833 Sofia Papagiannaki
        """Associate a key, value pair with a feature."""
144 4f917833 Sofia Papagiannaki
        
145 2ce96391 Sofia Papagiannaki
        s = self.xfeaturevals.select()
146 2ce96391 Sofia Papagiannaki
        s = s.where(self.xfeaturevals.c.feature_id == feature)
147 2ce96391 Sofia Papagiannaki
        s = s.where(self.xfeaturevals.c.key == key)
148 a68d51a4 Sofia Papagiannaki
        s = s.where(self.xfeaturevals.c.value == value)
149 2ce96391 Sofia Papagiannaki
        r = self.conn.execute(s)
150 2ce96391 Sofia Papagiannaki
        xfeaturevals = r.fetchall()
151 4f917833 Sofia Papagiannaki
        r.close()
152 2ce96391 Sofia Papagiannaki
        if len(xfeaturevals) == 0:
153 2ce96391 Sofia Papagiannaki
            s = self.xfeaturevals.insert()
154 2ce96391 Sofia Papagiannaki
            r = self.conn.execute(s, feature_id=feature, key=key, value=value)
155 2ce96391 Sofia Papagiannaki
            r.close()
156 4f917833 Sofia Papagiannaki
    
157 4f917833 Sofia Papagiannaki
    def feature_setmany(self, feature, key, values):
158 4f917833 Sofia Papagiannaki
        """Associate the given key, and values with a feature."""
159 4f917833 Sofia Papagiannaki
        
160 2ce96391 Sofia Papagiannaki
        #TODO: more efficient way to do it
161 2ce96391 Sofia Papagiannaki
        for v in values:
162 2ce96391 Sofia Papagiannaki
            self.feature_set(feature, key, v)
163 4f917833 Sofia Papagiannaki
    
164 4f917833 Sofia Papagiannaki
    def feature_unset(self, feature, key, value):
165 4f917833 Sofia Papagiannaki
        """Disassociate a key, value pair from a feature."""
166 4f917833 Sofia Papagiannaki
        
167 4f917833 Sofia Papagiannaki
        s = self.xfeaturevals.delete()
168 4f917833 Sofia Papagiannaki
        s = s.where(and_(self.xfeaturevals.c.feature_id == feature,
169 4f917833 Sofia Papagiannaki
                     self.xfeaturevals.c.key == key,
170 4f917833 Sofia Papagiannaki
                     self.xfeaturevals.c.value == value))
171 4f917833 Sofia Papagiannaki
        r = self.conn.execute(s)
172 4f917833 Sofia Papagiannaki
        r.close()
173 4f917833 Sofia Papagiannaki
    
174 4f917833 Sofia Papagiannaki
    def feature_unsetmany(self, feature, key, values):
175 4f917833 Sofia Papagiannaki
        """Disassociate the key for the values given, from a feature."""
176 4f917833 Sofia Papagiannaki
        
177 4f917833 Sofia Papagiannaki
        for v in values:
178 4f917833 Sofia Papagiannaki
            conditional = and_(self.xfeaturevals.c.feature_id == feature,
179 4f917833 Sofia Papagiannaki
                               self.xfeaturevals.c.key == key,
180 4f917833 Sofia Papagiannaki
                               self.xfeaturevals.c.value == v)
181 4f917833 Sofia Papagiannaki
            s = self.xfeaturevals.delete().where(conditional)
182 4f917833 Sofia Papagiannaki
            r = self.conn.execute(s)
183 4f917833 Sofia Papagiannaki
            r.close()
184 4f917833 Sofia Papagiannaki
        
185 4f917833 Sofia Papagiannaki
    def feature_get(self, feature, key):
186 4f917833 Sofia Papagiannaki
        """Return the list of values for a key of a feature."""
187 4f917833 Sofia Papagiannaki
        
188 4f917833 Sofia Papagiannaki
        s = select([self.xfeaturevals.c.value])
189 4f917833 Sofia Papagiannaki
        s = s.where(and_(self.xfeaturevals.c.feature_id == feature,
190 4f917833 Sofia Papagiannaki
                     self.xfeaturevals.c.key == key))
191 4f917833 Sofia Papagiannaki
        r = self.conn.execute(s)
192 4f917833 Sofia Papagiannaki
        l = [row[0] for row in r.fetchall()]
193 4f917833 Sofia Papagiannaki
        r.close()
194 4f917833 Sofia Papagiannaki
        return l
195 4f917833 Sofia Papagiannaki
    
196 4f917833 Sofia Papagiannaki
    def feature_clear(self, feature, key):
197 4f917833 Sofia Papagiannaki
        """Delete all key, value pairs for a key of a feature."""
198 4f917833 Sofia Papagiannaki
        
199 4f917833 Sofia Papagiannaki
        s = self.xfeaturevals.delete()
200 4f917833 Sofia Papagiannaki
        s = s.where(and_(self.xfeaturevals.c.feature_id == feature,
201 4f917833 Sofia Papagiannaki
                     self.xfeaturevals.c.key == key))
202 4f917833 Sofia Papagiannaki
        r = self.conn.execute(s)
203 4f917833 Sofia Papagiannaki
        r.close()