Merge branch 'merge-python3-port'
[mediagoblin.git] / mediagoblin / db / extratypes.py
CommitLineData
fbad3a9f 1# GNU MediaGoblin -- federated, autonomous media hosting
7f4ebeed 2# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
fbad3a9f
E
3#
4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU Affero General Public License as published by
6# the Free Software Foundation, either version 3 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU Affero General Public License for more details.
13#
14# You should have received a copy of the GNU Affero General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17
7f9d3ca7 18from sqlalchemy.ext.mutable import Mutable
1e3a0e0c 19from sqlalchemy.types import TypeDecorator, Unicode, TEXT
cf27accc 20import json
02db7e0a
E
21
22
23class PathTupleWithSlashes(TypeDecorator):
24 "Represents a Tuple of strings as a slash separated string."
25
26 impl = Unicode
27
28 def process_bind_param(self, value, dialect):
29 if value is not None:
51fba991
E
30 if len(value) == 0:
31 value = None
32 else:
33 value = '/'.join(value)
02db7e0a
E
34 return value
35
36 def process_result_value(self, value, dialect):
37 if value is not None:
38 value = tuple(value.split('/'))
39 return value
cf27accc
E
40
41
7f9d3ca7 42# The following two classes and only these two classes is in very
cf27accc
E
43# large parts based on example code from sqlalchemy.
44#
45# The original copyright notice and license follows:
46# Copyright (C) 2005-2011 the SQLAlchemy authors and contributors <see AUTHORS file>
47#
48# This module is part of SQLAlchemy and is released under
49# the MIT License: http://www.opensource.org/licenses/mit-license.php
50#
51class JSONEncoded(TypeDecorator):
52 "Represents an immutable structure as a json-encoded string."
53
1e3a0e0c 54 impl = TEXT
cf27accc
E
55
56 def process_bind_param(self, value, dialect):
57 if value is not None:
58 value = json.dumps(value)
59 return value
60
61 def process_result_value(self, value, dialect):
62 if value is not None:
63 value = json.loads(value)
64 return value
7f9d3ca7
RE
65
66
67class MutationDict(Mutable, dict):
68 @classmethod
69 def coerce(cls, key, value):
70 "Convert plain dictionaries to MutationDict."
71
72 if not isinstance(value, MutationDict):
73 if isinstance(value, dict):
74 return MutationDict(value)
75
76 # this call will raise ValueError
77 return Mutable.coerce(key, value)
78 else:
79 return value
80
81 def __setitem__(self, key, value):
82 "Detect dictionary set events and emit change events."
83
84 dict.__setitem__(self, key, value)
85 self.changed()
86
87 def __delitem__(self, key):
88 "Detect dictionary del events and emit change events."
89
90 dict.__delitem__(self, key)
91 self.changed()