Author: andrej Date: Tue Apr 30 14:39:00 2013 New Revision: 1477664 URL: http://svn.apache.org/r1477664 Log: adding detailed column specification functionality to bhdashboard.Model - towards bhrelations
Modified: bloodhound/trunk/bloodhound_dashboard/bhdashboard/model.py Modified: bloodhound/trunk/bloodhound_dashboard/bhdashboard/model.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_dashboard/bhdashboard/model.py?rev=1477664&r1=1477663&r2=1477664&view=diff ============================================================================== --- bloodhound/trunk/bloodhound_dashboard/bhdashboard/model.py (original) +++ bloodhound/trunk/bloodhound_dashboard/bhdashboard/model.py Tue Apr 30 14:39:00 2013 @@ -46,9 +46,20 @@ class ModelBase(object): _meta = {'table_name':'mytable', 'object_name':'WhatIWillCallMyselfInMessages', 'key_fields':['id','id2'], - 'non_key_fields':['thing','anotherthing'], + 'non_key_fields':[ + 'thing', + { + name:"field_name_x", + type='int64', + size=None, + key_size=None, + auto_increment=False + }], 'auto_inc_fields': ['id',], } + key_fields and non_key_fields parameters may contain field name only (for + text columns) or dict with detailed column specification. In case of + detailed column specification 'name' parameter is obligatory). """ def __init__(self, env, keys=None): @@ -61,13 +72,18 @@ class ModelBase(object): self._data = {} self._exists = False self._env = env - self._all_fields = self._meta['key_fields'] + \ - self._meta['non_key_fields'] + self._key_fields = self._get_field_names(self._meta['key_fields']) + self._non_key_fields = self._get_field_names( + self._meta['non_key_fields']) + self._all_fields = self._key_fields + self._non_key_fields + self._unique_fields = self._meta['unique_fields'] + self._auto_inc_fields = self._get_auto_inc_field_names() + if keys is not None: self._get_row(keys) else: self._update_from_row(None) - + def update_field_dict(self, field_dict): """Updates the object's copy of the db fields (no db transaction)""" self._data.update(field_dict) @@ -93,7 +109,7 @@ class ModelBase(object): def _update_from_row(self, row = None): """uses a provided database row to update the model""" - fields = self._meta['key_fields']+self._meta['non_key_fields'] + fields = self._all_fields self._exists = row is not None if row is None: row = [None]*len(fields) @@ -104,8 +120,8 @@ class ModelBase(object): def _get_row(self, keys): """queries the database and stores the result in the model""" row = None - where, values = fields_to_kv_str(self._meta['key_fields'], keys) - fields = ','.join(self._meta['key_fields']+self._meta['non_key_fields']) + where, values = fields_to_kv_str(self._key_fields, keys) + fields = ','.join(self._all_fields) sdata = {'fields':fields, 'where':where} sdata.update(self._meta) @@ -125,7 +141,7 @@ class ModelBase(object): """Deletes the matching record from the database""" if not self._exists: raise TracError('%(object_name)s does not exist' % self._meta) - where, values = fields_to_kv_str(self._meta['key_fields'], self._data) + where, values = fields_to_kv_str(self._key_fields, self._data) sdata = {'where': where} sdata.update(self._meta) sql = """DELETE FROM %(table_name)s @@ -144,33 +160,29 @@ class ModelBase(object): sdata = None if self._exists or len(self.select(self._env, where = dict([(k,self._data[k]) - for k in self._meta['key_fields']]))): + for k in self._key_fields]))): sdata = {'keys':','.join(["%s='%s'" % (k, self._data[k]) - for k in self._meta['key_fields']])} - elif self._meta['unique_fields'] and len(self.select(self._env, where = + for k in self._key_fields])} + elif self._unique_fields and len(self.select(self._env, where = dict([(k,self._data[k]) - for k in self._meta['unique_fields']]))): + for k in self._unique_fields]))): sdata = {'keys':','.join(["%s='%s'" % (k, self._data[k]) - for k in self._meta['unique_fields']])} + for k in self._unique_fields])} if sdata: sdata.update(self._meta) sdata['values'] = self._data raise TracError('%(object_name)s %(keys)s already exists %(values)s' % sdata) - auto_inc = self._meta.get('auto_inc_fields', []) - for key in self._meta['key_fields']: - if self._data[key] is None and key not in auto_inc: + for key in self._key_fields: + if self._data[key] is None and key not in self._auto_inc_fields: sdata = {'key':key} sdata.update(self._meta) raise TracError('%(key)s required for %(object_name)s' % sdata) - auto_inc = self._meta.get('auto_inc_fields', []) - non_auto_increment_key_fields = [ - field for field in self._meta['key_fields'] - if field not in auto_inc] - fields = non_auto_increment_key_fields + self._meta['non_key_fields'] + fields = [field for field in self._all_fields + if field not in self._auto_inc_fields] sdata = {'fields':','.join(fields), 'values':','.join(['%s'] * len(fields))} sdata.update(self._meta) @@ -180,7 +192,7 @@ class ModelBase(object): with self._env.db_transaction as db: cursor = db.cursor() cursor.execute(sql, [self._data[f] for f in fields]) - for auto_in_field in auto_inc: + for auto_in_field in self._auto_inc_fields: self._data[auto_in_field] = db.get_last_id( cursor, sdata["table_name"], auto_in_field) @@ -202,14 +214,14 @@ class ModelBase(object): for key in self._meta['no_change_fields']: if self._data[key] != self._old_data[key]: raise TracError('%s cannot be changed' % key) - for key in self._meta['key_fields'] + self._meta['unique_fields']: + for key in self._key_fields + self._unique_fields: if self._data[key] != self._old_data[key]: if len(self.select(self._env, where = {key:self._data[key]})): raise TracError('%s already exists' % key) - - setsql, setvalues = fields_to_kv_str(self._meta['non_key_fields'], - self._data, sep=',') - where, values = fields_to_kv_str(self._meta['key_fields'], self._data) + + setsql, setvalues = fields_to_kv_str( + self._non_key_fields, self._data, sep=',') + where, values = fields_to_kv_str(self._key_fields, self._data) sdata = {'where': where, 'values': setsql} @@ -235,7 +247,7 @@ class ModelBase(object): ("asc" or "desc") e.g. ["field1", "field2 desc"] """ rows = [] - fields = cls._meta['key_fields']+cls._meta['non_key_fields'] + fields = cls._get_all_field_names() sdata = {'fields':','.join(fields),} sdata.update(cls._meta) @@ -256,17 +268,54 @@ class ModelBase(object): model.__init__(env, data) rows.append(model) return rows - + @classmethod - def _get_fields(cls): - return cls._meta['key_fields']+cls._meta['non_key_fields'] - + def _get_all_field_names(cls): + return cls._get_field_names( + cls._meta['key_fields']+cls._meta['non_key_fields']) + + @classmethod + def _get_field_names(cls, field_specs): + def get_field_name(field_spec): + if isinstance(field_spec, dict): + return field_spec["name"] + return field_spec + return [get_field_name(field_spec) for field_spec in field_specs] + + @classmethod + def _get_all_field_columns(cls): + auto_inc = cls._meta.get('auto_inc_fields', []) + columns = [] + all_fields_spec = cls._meta['key_fields'] + cls._meta['non_key_fields'] + for field_spec in all_fields_spec: + #field_spec can be field name string or dictionary with detailed + #column specification + if isinstance(field_spec, dict): + column_spec = field_spec + else: + column_spec = dict( + name = field_spec, + auto_increment=field_spec in auto_inc) + columns.append(column_spec) + return columns + + @classmethod + def _get_auto_inc_field_names(cls): + return [field_spec["name"] for field_spec + in cls._get_all_field_columns() + if field_spec.get("auto_increment")] + + @classmethod def _get_schema(cls): """Generate schema from the class meta data""" - auto_inc = cls._meta.get('auto_inc_fields', []) - fields = [Column(f, auto_increment=f in auto_inc) - for f in cls._get_fields()] + fields = [Column( + column_spec["name"], + type=column_spec.get("type", "text"), + size=column_spec.get("size"), + key_size=column_spec.get("key_size"), + auto_increment=column_spec.get("auto_increment", False)) + for column_spec in cls._get_all_field_columns()] return Table(cls._meta['table_name'], key=set(cls._meta['key_fields'] + cls._meta['unique_fields'])) [fields]