Package gavo :: Package dm :: Module annotations
[frames] | no frames]

Source Code for Module gavo.dm.annotations

  1  """ 
  2  The specialised annotations for the various entities of VO-DML. 
  3   
  4  As it's needed for the definition of models, the annotation of immediate 
  5  atoms is already defined in common; also see there for the base class 
  6  of these. 
  7  """ 
  8   
  9  #c Copyright 2008-2019, the GAVO project 
 10  #c 
 11  #c This program is free software, covered by the GNU GPL.  See the 
 12  #c COPYING file in the source distribution. 
 13   
 14   
 15  # topnote[1]: copying TableRelativeAnnotations is probably not useful in 
 16  # the typical case; when you copy an annotation, that's probably because 
 17  # you copied a table, and hence your columns and params are different 
 18  # from the original table.  When copying the annotations, they will 
 19  # still point to the old instances.  Still, for consistency, I'm 
 20  # implementing the copy methods here. 
 21   
 22   
 23  import weakref 
 24   
 25  from gavo.dm import common 
 26  from gavo.votable import V 
27 28 29 -class ColumnAnnotation(common.TableRelativeAnnotation):
30 """An annotation of a table column. 31 32 These reference DaCHS columns. 33 """
34 - def __init__(self, name, column, instance):
35 common.TableRelativeAnnotation.__init__(self, name, instance) 36 self.weakref = weakref.ref(column) 37 column.dmRoles.append(weakref.ref(self))
38 39 @property
40 - def value(self):
41 return self.weakref()
42
43 - def copy(self, newInstance):
44 # see topnote(1) 45 return self.__class__(self.name, self.weakref(), newInstance)
46
47 - def getVOT(self, ctx, instance):
48 return V.COLUMN(ref=ctx.getOrMakeIdFor(self.value))
49
50 51 -class ParamAnnotation(common.TableRelativeAnnotation):
52 """An annotation of a table param. 53 54 NOTE: in getVOT, container MUST be the table itself, as the table has 55 params of its own and does *not* share tableDef's one. 56 """
57 - def __init__(self, name, param, instance):
58 common.TableRelativeAnnotation.__init__(self, name, instance) 59 self.weakref = weakref.ref(param) 60 param.dmRoles.append(weakref.ref(self))
61 62 @property
63 - def value(self):
64 return self.weakref()
65
66 - def copy(self, newInstance):
67 # see topnote(1) 68 return self.__class__(self.name, self.weakref(), newInstance)
69
70 - def getVOT(self, ctx, container):
71 referenced = container.getParamByName(self.value.name) 72 res = V.CONSTANT(ref=ctx.getOrMakeIdFor(referenced)) 73 return res
74
75 76 -def _the(gen):
77 """returns the first thing the generator gen spits out and makes sure 78 there's nothing more 79 """ 80 res = gen.next() 81 try: 82 extra = gen.next() 83 except StopIteration: 84 return res 85 raise TypeError("Generator expected to only return one thing returned" 86 " extra %s"%repr(extra))
87
88 89 -class GroupRefAnnotation(common.TableRelativeAnnotation):
90 """An annotation always referencing a group that's not lexically 91 within the parent. 92 """
93 - def __init__(self, name, objectReferenced, instance):
94 common.TableRelativeAnnotation.__init__(self, name, instance) 95 self.objectReferenced = objectReferenced
96
97 - def copy(self, newInstance):
98 # see topnote(1) 99 return self.__class__(self.name, self.objectReferenced, newInstance)
100
101 - def getVOT(self, ctx, instance):
102 if id(self.objectReferenced) not in ctx.groupIdsInTree: 103 ctx.getEnclosingContainer()[ 104 _the(# fix this: dmvot.getSubtrees(ctx, self.objectReferenced))( 105 ID=ctx.getOrMakeIdFor(self.objectReferenced))] 106 ctx.groupIdsInTree.add(id(self.objectReferenced)) 107 108 return V.REFERENCE[ 109 V.IDREF[ctx.getIdFor(self.objectReferenced)]]
110
111 112 -class ForeignKeyAnnotation(common.TableRelativeAnnotation):
113 """An annotation pointing to an annotation in a different table. 114 115 These are constructed with the attribute name and the foreign key RD 116 object. 117 """
118 - def __init__(self, name, fk, instance):
119 common.TableRelativeAnnotation.__init__(self, name, instance) 120 self.value = weakref.proxy(fk)
121
122 - def copy(self, newInstance):
123 return self.__class__(self.name, self.value, newInstance)
124
125 - def getVOT(self, ctx, instance):
126 # the main trouble here is: What if there's multiple foreign keys 127 # into destTD? To prevent multiple inclusions of a single 128 # table, we add a reference to our serialised VOTable stan in 129 # destTD's _FKR_serializedVOT attribute. That will fail 130 # if we produce two VOTables from the same table at the same time, 131 # but let's worry about that later. 132 133 destTD = self.value.inTable 134 srcTD = self.value.parent 135 136 raise NotImplementedError("Do not know how to annotate a foreign key") 137 pkDecl = V.GROUP(dmrole="vo-dml:ObjectTypeInstance.ID")[[ 138 V.FIELDref(ref=ctx.getOrMakeIdFor( 139 destTD.tableDef.getColumnByName(colName))) 140 for colName in self.foreignKey.dest]] 141 pkDecl(ID=ctx.getOrMakeIdFor(pkDecl)) 142 143 fkDecl = V.GROUP(ref=ctx.getOrMakeIdFor(pkDecl), 144 dmtype="vo-dml:ORMReference")[ 145 [V.FIELDref(ref=ctx.getIdFor(srcTD.getColumnByName(colName))) 146 for colName in self.foreignKey.source]] 147 148 targetVOT = getattr(destTD, "_FKR_serializedVOT", 149 lambda: None)() 150 # weakrefs are None if expired 151 if targetVOT is None: 152 targetVOT = ctx.makeTable(destTD) 153 destTD._FKR_serializedVOT = weakref.ref(targetVOT) 154 ctx.getEnclosingResource()[targetVOT] 155 156 targetVOT[pkDecl] 157 158 return fkDecl
159