--- /dev/null
+class Row(dict):
+ """
+ Representation of a row in a database table. To use, optionally
+ instantiate with a dict of values. Update as you would a
+ dict. Commit to the database with flush().
+ """
+
+ # Set this to a dict of the valid columns in this table. If a column
+ # name ends in 's' and the column value is set by referring to the
+ # column without the 's', it is assumed that the column values
+ # should be aggregated into lists. For example, if fields contains
+ # the column 'role_ids' and row['role_id'] is set repeatedly to
+ # different values, row['role_ids'] will contain a list of the set
+ # values.
+ fields = {}
+
+ # These fields are derived from join tables and are not actually
+ # in the sites table.
+ join_fields = {}
+
+ # These fields are derived from join tables and are not returned
+ # by default unless specified.
+ extra_fields = {}
+
+ def __init__(self, fields):
+ self.update(fields)
+
+ def update(self, fields):
+ for key, value in fields.iteritems():
+ self.__setitem__(key, value)
+
+ def __setitem__(self, key, value):
+ """
+ Magically takes care of aggregating certain variables into
+ lists.
+ """
+
+ # All known keys
+ all_fields = self.fields.keys() + \
+ self.join_fields.keys() + \
+ self.extra_fields.keys()
+
+ # Aggregate into lists
+ if (key + 's') in all_fields:
+ key += 's'
+ try:
+ if value not in self[key] and value is not None:
+ self[key].append(value)
+ except KeyError:
+ if value is None:
+ self[key] = []
+ else:
+ self[key] = [value]
+ return
+
+ elif key in all_fields:
+ dict.__setitem__(self, key, value)
+
+ def validate(self):
+ """
+ Validates values. Will validate a value with a custom function
+ if a function named 'validate_[key]' exists.
+ """
+
+ # Validate values before committing
+ # XXX Also truncate strings that are too long
+ for key, value in self.iteritems():
+ if value is not None and hasattr(self, 'validate_' + key):
+ validate = getattr(self, 'validate_' + key)
+ self[key] = validate(value)
+
+ def flush(self, commit = True):
+ """
+ Flush changes back to the database.
+ """
+
+ pass
+
+class Table(dict):
+ """
+ Representation of row(s) in a database table.
+ """
+
+ def flush(self, commit = True):
+ """
+ Flush changes back to the database.
+ """
+
+ for row in self.values():
+ row.flush(commit)