def __init__(self, api, fields = {}):
dict.__init__(self, fields)
self.api = api
+ # run the class_init initializer once
+ cls=self.__class__
+ if not hasattr(cls,'class_inited'):
+ cls.class_init (api)
+ cls.class_inited=True # actual value does not matter
def validate(self):
"""
return dict ( [ (key,value) for (key,value) in obj.iteritems()
if key in self.tags and Row.is_writable(key,value,self.tags) ] )
- # takes in input a list of columns, returns three lists
+ # takes in input a list of columns, returns 2 dicts and one list
# fields, tags, rejected
@classmethod
def parse_columns (cls, columns):
- (fields,tags,rejected)=({},{},{})
+ (fields,tags,rejected)=({},{},[])
for column in columns:
if column in cls.fields: fields[column]=cls.fields[column]
elif column in cls.tags: tags[column]=cls.tags[column]
else: rejected.append(column)
return (fields,tags,rejected)
+ # given a dict (typically passed to an Update method), we check and sort
+ # them against a list of dicts, e.g. [Node.fields, Node.related_fields]
+ # return is a list that contains n+1 dicts, last one has the rejected fields
+ @staticmethod
+ def split_fields (fields, dicts):
+ result=[]
+ for x in dicts: result.append({})
+ rejected={}
+ for (field,value) in fields.iteritems():
+ found=False
+ for i in range(len(dicts)):
+ candidate_dict=dicts[i]
+ if field in candidate_dict.keys():
+ result[i][field]=value
+ found=True
+ break
+ if not found: rejected[field]=value
+ result.append(rejected)
+ return result
+
+ # compute the accepts part of an update method from a list of column names, and a (list of) fields dict
+ @staticmethod
+ def accepted_fields (can_update_columns, fields):
+ result={}
+ if not isinstance(fields,list): fields = [fields]
+ for dict in fields:
+ for (k,v) in dict.iteritems():
+ if k in can_update_columns:
+ result[k]=v
+ return result
+
+ ### class initialization : create tag-dependent cross view if needed
@classmethod
def tagvalue_view_name (cls, tagname):
return "tagvalue_view_%s_%s"%(cls.primary_key,tagname)
@classmethod
- def tagvalue_view_create (cls,tagname):
+ def tagvalue_view_create_sql (cls,tagname):
"""
- returns an SQL sentence that creates a view named after the primary_key and tagname,
+ returns a SQL sentence that creates a view named after the primary_key and tagname,
with 2 columns
- (*) column 1: name=self.primary_key
- (*) column 2: name=tagname value=tagvalue
+ (*) column 1: primary_key
+ (*) column 2: actual tag value, renamed into tagname
"""
- if not cls.view_tags_name: return ""
+ if not cls.view_tags_name:
+ raise Exception, 'WARNING: class %s needs to set view_tags_name'%cls.__name__
table_name=cls.table_name
primary_key=cls.primary_key
view_tags_name=cls.view_tags_name
tagvalue_view_name=cls.tagvalue_view_name(tagname)
return 'CREATE OR REPLACE VIEW %(tagvalue_view_name)s ' \
- 'as SELECT %(table_name)s.%(primary_key)s,%(view_tags_name)s.tagvalue as "%(tagname)s" ' \
+ 'as SELECT %(table_name)s.%(primary_key)s,%(view_tags_name)s.value as "%(tagname)s" ' \
'from %(table_name)s right join %(view_tags_name)s using (%(primary_key)s) ' \
'WHERE tagname = \'%(tagname)s\';'%locals()
@classmethod
- def tagvalue_views_create (cls):
+ def class_init (cls,api):
+ cls.tagvalue_views_create (api)
+
+ @classmethod
+ def tagvalue_views_create (cls,api):
if not cls.tags: return
- sql = []
- for (type,type_dict) in cls.tags.iteritems():
- for (tagname,details) in type_dict.iteritems():
- sql.append(cls.tagvalue_view_create (tagname))
- return sql
+ for tagname in cls.tags.keys():
+ api.db.do(cls.tagvalue_view_create_sql (tagname))
+ api.db.commit()
def __eq__(self, y):
"""
tag_columns={}
else:
(columns,tag_columns,rejected) = classobj.parse_columns(columns)
- if not columns:
+ if not columns and not tag_columns:
raise PLCInvalidArgument, "No valid return fields specified for class %s"%classobj.__name__
if rejected:
raise PLCInvalidArgument, "unknown column(s) specified %r in %s"%(rejected,classobj.__name__)