1 from types import StringTypes
2 from datetime import datetime
4 from sqlalchemy import Column, Integer, String, DateTime
5 from sqlalchemy import Table, Column, MetaData, join, ForeignKey
6 from sqlalchemy.orm import relationship, backref
7 from sqlalchemy.orm import column_property
8 from sqlalchemy.orm import object_mapper
9 from sqlalchemy.ext.declarative import declarative_base
11 from sfa.util.sfalogging import logger
13 from sfa.trust.gid import GID
15 ##############################
16 Base=declarative_base()
21 # historically the front end to the db dealt with dicts, so the code was only dealing with dicts
22 # sqlalchemy however offers an object interface, meaning that you write obj.id instead of obj['id']
23 # which is admittedly much nicer
24 # however we still need to deal with dictionaries if only for the xmlrpc layer
26 # here are a few utilities for this
28 # (*) first off, when an old pieve of code needs to be used as-is, if only temporarily, the simplest trick
29 # is to use obj.__dict__
30 # this behaves exactly like required, i.e. obj.__dict__['field']='new value' does change obj.field
31 # however this depends on sqlalchemy's implementation so it should be avoided
33 # (*) second, when an object needs to be exposed to the xmlrpc layer, we need to convert it into a dict
34 # remember though that writing the resulting dictionary won't change the object
35 # essentially obj.__dict__ would be fine too, except that we want to discard alchemy private keys starting with '_'
36 # 2 ways are provided for that:
39 # the former dict(obj) relies on __iter__() and next() below, and does not rely on the fields names
40 # although it seems to work fine, I've found cases where it issues a weird python error that I could not get right
41 # so the latter obj.todict() seems more reliable but more hacky as is relies on the form of fields, so this can probably be improved
43 # (*) finally for converting a dictionary into an sqlalchemy object, we provide
44 # obj.set_from_dict(dict)
48 self._i = iter(object_mapper(self).columns)
51 n = self._i.next().name
52 return n, getattr(self, n)
55 keys=[k for k in d.keys() if not k.startswith('_')]
56 return dict ( [ (k,d[k]) for k in keys ] )
57 def set_from_dict (self, d):
58 for (k,v) in d.iteritems():
60 if isinstance(v, StringTypes):
61 if v.lower() in ['true']: v=True
62 if v.lower() in ['false']: v=False
65 ##############################
67 __table__ = Table ('types', Base.metadata,
68 Column ('type',String, primary_key=True)
70 def __init__ (self, type): self.type=type
71 def __repr__ (self): return "<Type %s>"%self.type
73 #BUILTIN_TYPES = [ 'authority', 'slice', 'node', 'user' ]
74 # xxx for compat but sounds useless
75 BUILTIN_TYPES = [ 'authority', 'slice', 'node', 'user',
76 'authority+sa', 'authority+am', 'authority+sm' ]
78 def insert_builtin_types(dbsession):
79 for type in BUILTIN_TYPES :
80 count = dbsession.query (Type).filter_by (type=type).count()
82 dbsession.add (Type (type))
85 ##############################
86 class RegRecord (Base,AlchemyObj):
87 # xxx tmp would be 'records'
88 __table__ = Table ('records', Base.metadata,
89 Column ('record_id', Integer, primary_key=True),
90 Column ('type', String, ForeignKey ("types.type")),
91 Column ('hrn',String),
92 Column ('gid',String),
93 Column ('authority',String),
94 Column ('peer_authority',String),
95 Column ('pointer',Integer,default=-1),
96 Column ('date_created',DateTime),
97 Column ('last_updated',DateTime),
99 def __init__ (self, type, hrn=None, gid=None, authority=None, peer_authority=None, pointer=-1):
103 if isinstance(gid, StringTypes): self.gid=gid
104 else: self.gid=gid.save_to_string(save_parents=True)
105 if authority: self.authority=authority
106 if peer_authority: self.peer_authority=peer_authority
110 result="[Record(record_id=%s, hrn=%s, type=%s, authority=%s, pointer=%s" % \
111 (self.record_id, self.hrn, self.type, self.authority, self.pointer)
112 if self.gid: result+=" %s..."%self.gid[:10]
113 else: result+=" no-gid"
117 def get_gid_object (self):
118 if not self.gid: return None
119 else: return GID(string=self.gid)
121 def just_created (self):
123 self.date_created=now
124 self.last_updated=now
126 def just_updated (self):
128 self.last_updated=now
130 ##############################
132 __table__ = Table ('users', Base.metadata,
133 Column ('user_id', Integer, primary_key=True),
134 Column ('record_id',Integer, ForeignKey('records.record_id')),
135 Column ('email', String),
137 def __init__ (self, email):
139 def __repr__ (self): return "<User(%d) %s, record_id=%d>"%(self.user_id,self.email,self.record_id,)
141 record_table = RegRecord.__table__
142 user_table = User.__table__
143 record_user_join = join (record_table, user_table)
145 class UserRecord (Base):
146 __table__ = record_user_join
147 record_id = column_property (record_table.c.record_id, user_table.c.record_id)
148 user_id = user_table.c.user_id
149 def __init__ (self, gid, email):
153 def __repr__ (self): return "<UserRecord %s %s>"%(self.email,self.gid)
155 ##############################
156 def init_tables(dbsession):
157 logger.info("Initializing db schema and builtin types")
158 engine=dbsession.get_bind()
159 Base.metadata.create_all(engine)
160 insert_builtin_types(dbsession)
162 def drop_tables(dbsession):
163 logger.info("Dropping tables")
164 engine=dbsession.get_bind()
165 Base.metadata.drop_all(engine)