Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-backend / pithos / backends / lib / sqlalchemy / xfeatures.py @ 4a7b190f

History | View | Annotate | Download (8.2 kB)

1 2e662088 Antony Chazapis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 2715ade4 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 2715ade4 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 2715ade4 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 2715ade4 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 2715ade4 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 6a82f89f Sofia Papagiannaki
from sqlalchemy.exc import NoSuchTableError
39 4f917833 Sofia Papagiannaki
40 4f917833 Sofia Papagiannaki
from dbworker import DBWorker
41 4f917833 Sofia Papagiannaki
42 2715ade4 Sofia Papagiannaki
43 6a82f89f Sofia Papagiannaki
def create_tables(engine):
44 6a82f89f Sofia Papagiannaki
    metadata = MetaData()
45 2715ade4 Sofia Papagiannaki
    columns = []
46 6a82f89f Sofia Papagiannaki
    columns.append(Column('feature_id', Integer, primary_key=True))
47 6a82f89f Sofia Papagiannaki
    columns.append(Column('path', String(2048)))
48 6a82f89f Sofia Papagiannaki
    xfeatures = Table('xfeatures', metadata, *columns, mysql_engine='InnoDB')
49 6a82f89f Sofia Papagiannaki
    # place an index on path
50 6a82f89f Sofia Papagiannaki
    Index('idx_features_path', xfeatures.c.path, unique=True)
51 2715ade4 Sofia Papagiannaki
52 2715ade4 Sofia Papagiannaki
    columns = []
53 6a82f89f Sofia Papagiannaki
    columns.append(Column('feature_id', Integer,
54 6a82f89f Sofia Papagiannaki
                          ForeignKey('xfeatures.feature_id',
55 6a82f89f Sofia Papagiannaki
                                     ondelete='CASCADE'),
56 6a82f89f Sofia Papagiannaki
                          primary_key=True))
57 6a82f89f Sofia Papagiannaki
    columns.append(Column('key', Integer, primary_key=True,
58 6a82f89f Sofia Papagiannaki
                          autoincrement=False))
59 6a82f89f Sofia Papagiannaki
    columns.append(Column('value', String(256), primary_key=True))
60 29148653 Sofia Papagiannaki
    Table('xfeaturevals', metadata, *columns, mysql_engine='InnoDB')
61 2715ade4 Sofia Papagiannaki
62 6a82f89f Sofia Papagiannaki
    metadata.create_all(engine)
63 6a82f89f Sofia Papagiannaki
    return metadata.sorted_tables
64 4f917833 Sofia Papagiannaki
65 2715ade4 Sofia Papagiannaki
66 4f917833 Sofia Papagiannaki
class XFeatures(DBWorker):
67 4f917833 Sofia Papagiannaki
    """XFeatures are path properties that allow non-nested
68 4f917833 Sofia Papagiannaki
       inheritance patterns. Currently used for storing permissions.
69 4f917833 Sofia Papagiannaki
    """
70 2715ade4 Sofia Papagiannaki
71 4f917833 Sofia Papagiannaki
    def __init__(self, **params):
72 4f917833 Sofia Papagiannaki
        DBWorker.__init__(self, **params)
73 6a82f89f Sofia Papagiannaki
        try:
74 6a82f89f Sofia Papagiannaki
            metadata = MetaData(self.engine)
75 6a82f89f Sofia Papagiannaki
            self.xfeatures = Table('xfeatures', metadata, autoload=True)
76 6a82f89f Sofia Papagiannaki
            self.xfeaturevals = Table('xfeaturevals', metadata, autoload=True)
77 6a82f89f Sofia Papagiannaki
        except NoSuchTableError:
78 6a82f89f Sofia Papagiannaki
            tables = create_tables(self.engine)
79 6a82f89f Sofia Papagiannaki
            map(lambda t: self.__setattr__(t.name, t), tables)
80 2715ade4 Sofia Papagiannaki
81 d83c93c9 Antony Chazapis
#     def xfeature_inherit(self, path):
82 d83c93c9 Antony Chazapis
#         """Return the (path, feature) inherited by the path, or None."""
83 2715ade4 Sofia Papagiannaki
#
84 d83c93c9 Antony Chazapis
#         s = select([self.xfeatures.c.path, self.xfeatures.c.feature_id])
85 d83c93c9 Antony Chazapis
#         s = s.where(self.xfeatures.c.path <= path)
86 29148653 Sofia Papagiannaki
#         s = s.where(self.xfeatures.c.path.like(
87 29148653 Sofia Papagiannaki
#           self.escape_like(path) + '%', escape='\\'))  # XXX: Escape like...
88 d83c93c9 Antony Chazapis
#         s = s.order_by(desc(self.xfeatures.c.path))
89 d83c93c9 Antony Chazapis
#         r = self.conn.execute(s)
90 d83c93c9 Antony Chazapis
#         l = r.fetchall()
91 d83c93c9 Antony Chazapis
#         r.close()
92 d83c93c9 Antony Chazapis
#         return l
93 2715ade4 Sofia Papagiannaki
94 cf341da4 Antony Chazapis
    def xfeature_get(self, path):
95 cf341da4 Antony Chazapis
        """Return feature for path."""
96 2715ade4 Sofia Papagiannaki
97 cf341da4 Antony Chazapis
        s = select([self.xfeatures.c.feature_id])
98 cf341da4 Antony Chazapis
        s = s.where(self.xfeatures.c.path == path)
99 4f917833 Sofia Papagiannaki
        s = s.order_by(self.xfeatures.c.path)
100 4f917833 Sofia Papagiannaki
        r = self.conn.execute(s)
101 cf341da4 Antony Chazapis
        row = r.fetchone()
102 4f917833 Sofia Papagiannaki
        r.close()
103 cf341da4 Antony Chazapis
        if row:
104 cf341da4 Antony Chazapis
            return row[0]
105 cf341da4 Antony Chazapis
        return None
106 2715ade4 Sofia Papagiannaki
107 dc88754b Nanakos Chrysostomos
    def xfeature_get_bulk(self, paths):
108 dc88754b Nanakos Chrysostomos
        """Return features for paths."""
109 4a7b190f Nanakos Chrysostomos
        paths = list(set(paths))
110 dc88754b Nanakos Chrysostomos
        s = select([self.xfeatures.c.feature_id, self.xfeatures.c.path])
111 dc88754b Nanakos Chrysostomos
        s = s.where(self.xfeatures.c.path.in_(paths))
112 dc88754b Nanakos Chrysostomos
        s = s.order_by(self.xfeatures.c.path)
113 dc88754b Nanakos Chrysostomos
        r = self.conn.execute(s)
114 dc88754b Nanakos Chrysostomos
        row = r.fetchall()
115 dc88754b Nanakos Chrysostomos
        r.close()
116 dc88754b Nanakos Chrysostomos
        if row:
117 dc88754b Nanakos Chrysostomos
            return row
118 dc88754b Nanakos Chrysostomos
        return None
119 dc88754b Nanakos Chrysostomos
120 4f917833 Sofia Papagiannaki
    def xfeature_create(self, path):
121 4f917833 Sofia Papagiannaki
        """Create and return a feature for path.
122 4f917833 Sofia Papagiannaki
           If the path has a feature, return it.
123 4f917833 Sofia Papagiannaki
        """
124 2715ade4 Sofia Papagiannaki
125 cf341da4 Antony Chazapis
        feature = self.xfeature_get(path)
126 cf341da4 Antony Chazapis
        if feature is not None:
127 cf341da4 Antony Chazapis
            return feature
128 4f917833 Sofia Papagiannaki
        s = self.xfeatures.insert()
129 4f917833 Sofia Papagiannaki
        r = self.conn.execute(s, path=path)
130 4f917833 Sofia Papagiannaki
        inserted_primary_key = r.inserted_primary_key[0]
131 4f917833 Sofia Papagiannaki
        r.close()
132 4f917833 Sofia Papagiannaki
        return inserted_primary_key
133 2715ade4 Sofia Papagiannaki
134 4f917833 Sofia Papagiannaki
    def xfeature_destroy(self, path):
135 4f917833 Sofia Papagiannaki
        """Destroy a feature and all its key, value pairs."""
136 2715ade4 Sofia Papagiannaki
137 4f917833 Sofia Papagiannaki
        s = self.xfeatures.delete().where(self.xfeatures.c.path == path)
138 4f917833 Sofia Papagiannaki
        r = self.conn.execute(s)
139 4f917833 Sofia Papagiannaki
        r.close()
140 2715ade4 Sofia Papagiannaki
141 8221c89d Sofia Papagiannaki
    def xfeature_destroy_bulk(self, paths):
142 8221c89d Sofia Papagiannaki
        """Destroy features and all their key, value pairs."""
143 29148653 Sofia Papagiannaki
144 c53502b1 Sofia Papagiannaki
        if not paths:
145 c53502b1 Sofia Papagiannaki
            return
146 8221c89d Sofia Papagiannaki
        s = self.xfeatures.delete().where(self.xfeatures.c.path.in_(paths))
147 8221c89d Sofia Papagiannaki
        r = self.conn.execute(s)
148 8221c89d Sofia Papagiannaki
        r.close()
149 2715ade4 Sofia Papagiannaki
150 4f917833 Sofia Papagiannaki
    def feature_dict(self, feature):
151 4f917833 Sofia Papagiannaki
        """Return a dict mapping keys to list of values for feature."""
152 2715ade4 Sofia Papagiannaki
153 4f917833 Sofia Papagiannaki
        s = select([self.xfeaturevals.c.key, self.xfeaturevals.c.value])
154 4f917833 Sofia Papagiannaki
        s = s.where(self.xfeaturevals.c.feature_id == feature)
155 4f917833 Sofia Papagiannaki
        r = self.conn.execute(s)
156 4f917833 Sofia Papagiannaki
        d = defaultdict(list)
157 4f917833 Sofia Papagiannaki
        for key, value in r.fetchall():
158 4f917833 Sofia Papagiannaki
            d[key].append(value)
159 4f917833 Sofia Papagiannaki
        r.close()
160 4f917833 Sofia Papagiannaki
        return d
161 2715ade4 Sofia Papagiannaki
162 4f917833 Sofia Papagiannaki
    def feature_set(self, feature, key, value):
163 4f917833 Sofia Papagiannaki
        """Associate a key, value pair with a feature."""
164 2715ade4 Sofia Papagiannaki
165 2ce96391 Sofia Papagiannaki
        s = self.xfeaturevals.select()
166 2ce96391 Sofia Papagiannaki
        s = s.where(self.xfeaturevals.c.feature_id == feature)
167 2ce96391 Sofia Papagiannaki
        s = s.where(self.xfeaturevals.c.key == key)
168 a68d51a4 Sofia Papagiannaki
        s = s.where(self.xfeaturevals.c.value == value)
169 2ce96391 Sofia Papagiannaki
        r = self.conn.execute(s)
170 2ce96391 Sofia Papagiannaki
        xfeaturevals = r.fetchall()
171 4f917833 Sofia Papagiannaki
        r.close()
172 2ce96391 Sofia Papagiannaki
        if len(xfeaturevals) == 0:
173 2ce96391 Sofia Papagiannaki
            s = self.xfeaturevals.insert()
174 2ce96391 Sofia Papagiannaki
            r = self.conn.execute(s, feature_id=feature, key=key, value=value)
175 2ce96391 Sofia Papagiannaki
            r.close()
176 2715ade4 Sofia Papagiannaki
177 4f917833 Sofia Papagiannaki
    def feature_setmany(self, feature, key, values):
178 4f917833 Sofia Papagiannaki
        """Associate the given key, and values with a feature."""
179 2715ade4 Sofia Papagiannaki
180 2ce96391 Sofia Papagiannaki
        #TODO: more efficient way to do it
181 2ce96391 Sofia Papagiannaki
        for v in values:
182 2ce96391 Sofia Papagiannaki
            self.feature_set(feature, key, v)
183 2715ade4 Sofia Papagiannaki
184 4f917833 Sofia Papagiannaki
    def feature_unset(self, feature, key, value):
185 4f917833 Sofia Papagiannaki
        """Disassociate a key, value pair from a feature."""
186 2715ade4 Sofia Papagiannaki
187 4f917833 Sofia Papagiannaki
        s = self.xfeaturevals.delete()
188 4f917833 Sofia Papagiannaki
        s = s.where(and_(self.xfeaturevals.c.feature_id == feature,
189 2715ade4 Sofia Papagiannaki
                         self.xfeaturevals.c.key == key,
190 2715ade4 Sofia Papagiannaki
                         self.xfeaturevals.c.value == value))
191 4f917833 Sofia Papagiannaki
        r = self.conn.execute(s)
192 4f917833 Sofia Papagiannaki
        r.close()
193 2715ade4 Sofia Papagiannaki
194 4f917833 Sofia Papagiannaki
    def feature_unsetmany(self, feature, key, values):
195 4f917833 Sofia Papagiannaki
        """Disassociate the key for the values given, from a feature."""
196 2715ade4 Sofia Papagiannaki
197 4f917833 Sofia Papagiannaki
        for v in values:
198 4f917833 Sofia Papagiannaki
            conditional = and_(self.xfeaturevals.c.feature_id == feature,
199 4f917833 Sofia Papagiannaki
                               self.xfeaturevals.c.key == key,
200 4f917833 Sofia Papagiannaki
                               self.xfeaturevals.c.value == v)
201 4f917833 Sofia Papagiannaki
            s = self.xfeaturevals.delete().where(conditional)
202 4f917833 Sofia Papagiannaki
            r = self.conn.execute(s)
203 4f917833 Sofia Papagiannaki
            r.close()
204 2715ade4 Sofia Papagiannaki
205 4f917833 Sofia Papagiannaki
    def feature_get(self, feature, key):
206 4f917833 Sofia Papagiannaki
        """Return the list of values for a key of a feature."""
207 2715ade4 Sofia Papagiannaki
208 4f917833 Sofia Papagiannaki
        s = select([self.xfeaturevals.c.value])
209 4f917833 Sofia Papagiannaki
        s = s.where(and_(self.xfeaturevals.c.feature_id == feature,
210 2715ade4 Sofia Papagiannaki
                         self.xfeaturevals.c.key == key))
211 4f917833 Sofia Papagiannaki
        r = self.conn.execute(s)
212 4f917833 Sofia Papagiannaki
        l = [row[0] for row in r.fetchall()]
213 4f917833 Sofia Papagiannaki
        r.close()
214 4f917833 Sofia Papagiannaki
        return l
215 2715ade4 Sofia Papagiannaki
216 4f917833 Sofia Papagiannaki
    def feature_clear(self, feature, key):
217 4f917833 Sofia Papagiannaki
        """Delete all key, value pairs for a key of a feature."""
218 2715ade4 Sofia Papagiannaki
219 4f917833 Sofia Papagiannaki
        s = self.xfeaturevals.delete()
220 4f917833 Sofia Papagiannaki
        s = s.where(and_(self.xfeaturevals.c.feature_id == feature,
221 2715ade4 Sofia Papagiannaki
                         self.xfeaturevals.c.key == key))
222 4f917833 Sofia Papagiannaki
        r = self.conn.execute(s)
223 4f917833 Sofia Papagiannaki
        r.close()