annotate hyperdb.py @ 1:fddc8af9f541

Added stuff to help with release generation. . Makefile has the release tgz builder in it . dummy_config.py is an empty config file that replaces the config.py in the release
author Richard Jones <richard@users.sourceforge.net>
date Thu, 19 Jul 2001 03:11:24 +0000
parents 5e92642cd1f8
children 97559f7bae2e
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
1 import bsddb, os, cPickle, re, string
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
2
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
3 import date
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
4 #
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
5 # Types
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
6 #
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
7 class BaseType:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
8 isStringType = 0
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
9 isDateType = 0
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
10 isIntervalType = 0
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
11 isLinkType = 0
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
12 isMultilinkType = 0
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
13
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
14 class String(BaseType):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
15 def __init__(self):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
16 """An object designating a String property."""
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
17 pass
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
18 def __repr__(self):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
19 return '<%s>'%self.__class__
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
20 isStringType = 1
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
21
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
22 class Date(BaseType, String):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
23 isDateType = 1
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
24
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
25 class Interval(BaseType, String):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
26 isIntervalType = 1
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
27
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
28 class Link(BaseType):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
29 def __init__(self, classname):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
30 """An object designating a Link property that links to
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
31 nodes in a specified class."""
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
32 self.classname = classname
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
33 def __repr__(self):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
34 return '<%s to "%s">'%(self.__class__, self.classname)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
35 isLinkType = 1
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
36
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
37 class Multilink(BaseType, Link):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
38 """An object designating a Multilink property that links
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
39 to nodes in a specified class.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
40 """
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
41 isMultilinkType = 1
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
42
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
43 class DatabaseError(ValueError):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
44 pass
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
45
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
46 #
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
47 # Now the database
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
48 #
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
49 RETIRED_FLAG = '__hyperdb_retired'
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
50 class Database:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
51 """A database for storing records containing flexible data types."""
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
52
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
53 def __init__(self, storagelocator, journaltag=None):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
54 """Open a hyperdatabase given a specifier to some storage.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
55
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
56 The meaning of 'storagelocator' depends on the particular
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
57 implementation of the hyperdatabase. It could be a file name,
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
58 a directory path, a socket descriptor for a connection to a
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
59 database over the network, etc.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
60
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
61 The 'journaltag' is a token that will be attached to the journal
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
62 entries for any edits done on the database. If 'journaltag' is
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
63 None, the database is opened in read-only mode: the Class.create(),
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
64 Class.set(), and Class.retire() methods are disabled.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
65 """
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
66 self.dir, self.journaltag = storagelocator, journaltag
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
67 self.classes = {}
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
68
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
69 #
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
70 # Classes
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
71 #
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
72 def __getattr__(self, classname):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
73 """A convenient way of calling self.getclass(classname)."""
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
74 return self.classes[classname]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
75
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
76 def addclass(self, cl):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
77 cn = cl.classname
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
78 if self.classes.has_key(cn):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
79 raise ValueError, cn
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
80 self.classes[cn] = cl
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
81
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
82 def getclasses(self):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
83 """Return a list of the names of all existing classes."""
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
84 l = self.classes.keys()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
85 l.sort()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
86 return l
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
87
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
88 def getclass(self, classname):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
89 """Get the Class object representing a particular class.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
90
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
91 If 'classname' is not a valid class name, a KeyError is raised.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
92 """
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
93 return self.classes[classname]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
94
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
95 #
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
96 # Class DBs
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
97 #
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
98 def clear(self):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
99 for cn in self.classes.keys():
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
100 db = os.path.join(self.dir, 'nodes.%s'%cn)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
101 bsddb.btopen(db, 'n')
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
102 db = os.path.join(self.dir, 'journals.%s'%cn)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
103 bsddb.btopen(db, 'n')
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
104
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
105 def getclassdb(self, classname, mode='r'):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
106 ''' grab a connection to the class db that will be used for
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
107 multiple actions
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
108 '''
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
109 path = os.path.join(os.getcwd(), self.dir, 'nodes.%s'%classname)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
110 return bsddb.btopen(path, mode)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
111
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
112 def addnode(self, classname, nodeid, node):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
113 ''' add the specified node to its class's db
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
114 '''
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
115 db = self.getclassdb(classname, 'c')
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
116 db[nodeid] = cPickle.dumps(node, 1)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
117 db.close()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
118 setnode = addnode
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
119
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
120 def getnode(self, classname, nodeid, cldb=None):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
121 ''' add the specified node to its class's db
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
122 '''
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
123 db = cldb or self.getclassdb(classname)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
124 if not db.has_key(nodeid):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
125 raise IndexError, nodeid
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
126 res = cPickle.loads(db[nodeid])
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
127 if not cldb: db.close()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
128 return res
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
129
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
130 def hasnode(self, classname, nodeid, cldb=None):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
131 ''' add the specified node to its class's db
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
132 '''
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
133 db = cldb or self.getclassdb(classname)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
134 res = db.has_key(nodeid)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
135 if not cldb: db.close()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
136 return res
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
137
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
138 def countnodes(self, classname, cldb=None):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
139 db = cldb or self.getclassdb(classname)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
140 return len(db.keys())
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
141 if not cldb: db.close()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
142 return res
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
143
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
144 def getnodeids(self, classname, cldb=None):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
145 db = cldb or self.getclassdb(classname)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
146 res = db.keys()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
147 if not cldb: db.close()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
148 return res
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
149
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
150 #
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
151 # Journal
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
152 #
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
153 def addjournal(self, classname, nodeid, action, params):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
154 ''' Journal the Action
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
155 'action' may be:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
156
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
157 'create' or 'set' -- 'params' is a dictionary of property values
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
158 'link' or 'unlink' -- 'params' is (classname, nodeid, propname)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
159 'retire' -- 'params' is None
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
160 '''
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
161 entry = (nodeid, date.Date(), self.journaltag, action, params)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
162 db = bsddb.btopen(os.path.join(self.dir, 'journals.%s'%classname), 'c')
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
163 if db.has_key(nodeid):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
164 s = db[nodeid]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
165 l = cPickle.loads(db[nodeid])
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
166 l.append(entry)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
167 else:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
168 l = [entry]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
169 db[nodeid] = cPickle.dumps(l)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
170 db.close()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
171
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
172 def getjournal(self, classname, nodeid):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
173 ''' get the journal for id
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
174 '''
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
175 db = bsddb.btopen(os.path.join(self.dir, 'journals.%s'%classname), 'r')
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
176 res = cPickle.loads(db[nodeid])
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
177 db.close()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
178 return res
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
179
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
180 def close(self):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
181 ''' Close the Database - we must release the circular refs so that
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
182 we can be del'ed and the underlying bsddb connections closed
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
183 cleanly.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
184 '''
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
185 self.classes = None
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
186
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
187
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
188 #
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
189 # Basic transaction support
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
190 #
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
191 # TODO: well, write these methods (and then use them in other code)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
192 def register_action(self):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
193 ''' Register an action to the transaction undo log
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
194 '''
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
195
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
196 def commit(self):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
197 ''' Commit the current transaction, start a new one
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
198 '''
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
199
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
200 def rollback(self):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
201 ''' Reverse all actions from the current transaction
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
202 '''
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
203
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
204
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
205 class Class:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
206 """The handle to a particular class of nodes in a hyperdatabase."""
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
207
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
208 def __init__(self, db, classname, **properties):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
209 """Create a new class with a given name and property specification.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
210
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
211 'classname' must not collide with the name of an existing class,
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
212 or a ValueError is raised. The keyword arguments in 'properties'
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
213 must map names to property objects, or a TypeError is raised.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
214 """
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
215 self.classname = classname
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
216 self.properties = properties
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
217 self.db = db
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
218 self.key = ''
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
219
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
220 # do the db-related init stuff
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
221 db.addclass(self)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
222
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
223 # Editing nodes:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
224
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
225 def create(self, **propvalues):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
226 """Create a new node of this class and return its id.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
227
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
228 The keyword arguments in 'propvalues' map property names to values.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
229
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
230 The values of arguments must be acceptable for the types of their
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
231 corresponding properties or a TypeError is raised.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
232
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
233 If this class has a key property, it must be present and its value
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
234 must not collide with other key strings or a ValueError is raised.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
235
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
236 Any other properties on this class that are missing from the
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
237 'propvalues' dictionary are set to None.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
238
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
239 If an id in a link or multilink property does not refer to a valid
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
240 node, an IndexError is raised.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
241 """
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
242 if self.db.journaltag is None:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
243 raise DatabaseError, 'Database open read-only'
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
244 newid = str(self.count() + 1)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
245
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
246 # validate propvalues
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
247 num_re = re.compile('^\d+$')
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
248 for key, value in propvalues.items():
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
249 if key == self.key:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
250 try:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
251 self.lookup(value)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
252 except KeyError:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
253 pass
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
254 else:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
255 raise ValueError, 'node with key "%s" exists'%value
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
256
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
257 prop = self.properties[key]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
258
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
259 if prop.isLinkType:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
260 value = str(value)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
261 link_class = self.properties[key].classname
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
262 if not num_re.match(value):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
263 try:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
264 value = self.db.classes[link_class].lookup(value)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
265 except:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
266 raise ValueError, 'new property "%s": %s not a %s'%(
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
267 key, value, self.properties[key].classname)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
268 propvalues[key] = value
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
269 if not self.db.hasnode(link_class, value):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
270 raise ValueError, '%s has no node %s'%(link_class, value)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
271
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
272 # register the link with the newly linked node
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
273 self.db.addjournal(link_class, value, 'link',
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
274 (self.classname, newid, key))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
275
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
276 elif prop.isMultilinkType:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
277 if type(value) != type([]):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
278 raise TypeError, 'new property "%s" not a list of ids'%key
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
279 link_class = self.properties[key].classname
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
280 l = []
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
281 for entry in map(str, value):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
282 if not num_re.match(entry):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
283 try:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
284 entry = self.db.classes[link_class].lookup(entry)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
285 except:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
286 raise ValueError, 'new property "%s": %s not a %s'%(
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
287 key, entry, self.properties[key].classname)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
288 l.append(entry)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
289 value = l
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
290 propvalues[key] = value
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
291
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
292 # handle additions
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
293 for id in value:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
294 if not self.db.hasnode(link_class, id):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
295 raise ValueError, '%s has no node %s'%(link_class, id)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
296 # register the link with the newly linked node
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
297 self.db.addjournal(link_class, id, 'link',
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
298 (self.classname, newid, key))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
299
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
300 elif prop.isStringType:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
301 if type(value) != type(''):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
302 raise TypeError, 'new property "%s" not a string'%key
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
303
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
304 elif prop.isDateType:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
305 if not hasattr(value, 'isDate'):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
306 raise TypeError, 'new property "%s" not a Date'% key
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
307
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
308 elif prop.isIntervalType:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
309 if not hasattr(value, 'isInterval'):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
310 raise TypeError, 'new property "%s" not an Interval'% key
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
311
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
312 for key,prop in self.properties.items():
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
313 if propvalues.has_key(str(key)):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
314 continue
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
315 if prop.isMultilinkType:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
316 propvalues[key] = []
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
317 else:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
318 propvalues[key] = None
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
319
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
320 # done
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
321 self.db.addnode(self.classname, newid, propvalues)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
322 self.db.addjournal(self.classname, newid, 'create', propvalues)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
323 return newid
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
324
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
325 def get(self, nodeid, propname):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
326 """Get the value of a property on an existing node of this class.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
327
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
328 'nodeid' must be the id of an existing node of this class or an
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
329 IndexError is raised. 'propname' must be the name of a property
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
330 of this class or a KeyError is raised.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
331 """
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
332 d = self.db.getnode(self.classname, str(nodeid))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
333 return d[propname]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
334
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
335 # XXX not in spec
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
336 def getnode(self, nodeid):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
337 ''' Return a convenience wrapper for the node
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
338 '''
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
339 return Node(self, nodeid)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
340
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
341 def set(self, nodeid, **propvalues):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
342 """Modify a property on an existing node of this class.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
343
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
344 'nodeid' must be the id of an existing node of this class or an
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
345 IndexError is raised.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
346
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
347 Each key in 'propvalues' must be the name of a property of this
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
348 class or a KeyError is raised.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
349
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
350 All values in 'propvalues' must be acceptable types for their
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
351 corresponding properties or a TypeError is raised.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
352
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
353 If the value of the key property is set, it must not collide with
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
354 other key strings or a ValueError is raised.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
355
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
356 If the value of a Link or Multilink property contains an invalid
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
357 node id, a ValueError is raised.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
358 """
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
359 if not propvalues:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
360 return
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
361 if self.db.journaltag is None:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
362 raise DatabaseError, 'Database open read-only'
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
363 nodeid = str(nodeid)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
364 node = self.db.getnode(self.classname, nodeid)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
365 if node.has_key(RETIRED_FLAG):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
366 raise IndexError
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
367 num_re = re.compile('^\d+$')
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
368 for key, value in propvalues.items():
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
369 if not node.has_key(key):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
370 raise KeyError, key
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
371
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
372 if key == self.key:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
373 try:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
374 self.lookup(value)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
375 except KeyError:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
376 pass
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
377 else:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
378 raise ValueError, 'node with key "%s" exists'%value
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
379
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
380 prop = self.properties[key]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
381
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
382 if prop.isLinkType:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
383 value = str(value)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
384 link_class = self.properties[key].classname
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
385 if not num_re.match(value):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
386 try:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
387 value = self.db.classes[link_class].lookup(value)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
388 except:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
389 raise ValueError, 'new property "%s": %s not a %s'%(
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
390 key, value, self.properties[key].classname)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
391
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
392 if not self.db.hasnode(link_class, value):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
393 raise ValueError, '%s has no node %s'%(link_class, value)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
394
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
395 # register the unlink with the old linked node
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
396 if node[key] is not None:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
397 self.db.addjournal(link_class, node[key], 'unlink',
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
398 (self.classname, nodeid, key))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
399
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
400 # register the link with the newly linked node
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
401 if value is not None:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
402 self.db.addjournal(link_class, value, 'link',
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
403 (self.classname, nodeid, key))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
404
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
405 elif prop.isMultilinkType:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
406 if type(value) != type([]):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
407 raise TypeError, 'new property "%s" not a list of ids'%key
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
408 link_class = self.properties[key].classname
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
409 l = []
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
410 for entry in map(str, value):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
411 if not num_re.match(entry):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
412 try:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
413 entry = self.db.classes[link_class].lookup(entry)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
414 except:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
415 raise ValueError, 'new property "%s": %s not a %s'%(
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
416 key, entry, self.properties[key].classname)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
417 l.append(entry)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
418 value = l
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
419 propvalues[key] = value
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
420
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
421 #handle removals
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
422 l = node[key]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
423 for id in l[:]:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
424 if id in value:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
425 continue
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
426 # register the unlink with the old linked node
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
427 self.db.addjournal(link_class, id, 'unlink',
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
428 (self.classname, nodeid, key))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
429 l.remove(id)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
430
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
431 # handle additions
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
432 for id in value:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
433 if not self.db.hasnode(link_class, id):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
434 raise ValueError, '%s has no node %s'%(link_class, id)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
435 if id in l:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
436 continue
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
437 # register the link with the newly linked node
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
438 self.db.addjournal(link_class, id, 'link',
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
439 (self.classname, nodeid, key))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
440 l.append(id)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
441
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
442 elif prop.isStringType:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
443 if value is not None and type(value) != type(''):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
444 raise TypeError, 'new property "%s" not a string'%key
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
445
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
446 elif prop.isDateType:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
447 if not hasattr(value, 'isDate'):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
448 raise TypeError, 'new property "%s" not a Date'% key
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
449
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
450 elif prop.isIntervalType:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
451 if not hasattr(value, 'isInterval'):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
452 raise TypeError, 'new property "%s" not an Interval'% key
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
453
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
454 node[key] = value
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
455
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
456 self.db.setnode(self.classname, nodeid, node)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
457 self.db.addjournal(self.classname, nodeid, 'set', propvalues)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
458
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
459 def retire(self, nodeid):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
460 """Retire a node.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
461
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
462 The properties on the node remain available from the get() method,
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
463 and the node's id is never reused.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
464
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
465 Retired nodes are not returned by the find(), list(), or lookup()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
466 methods, and other nodes may reuse the values of their key properties.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
467 """
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
468 nodeid = str(nodeid)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
469 if self.db.journaltag is None:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
470 raise DatabaseError, 'Database open read-only'
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
471 node = self.db.getnode(self.classname, nodeid)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
472 node[RETIRED_FLAG] = 1
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
473 self.db.setnode(self.classname, nodeid, node)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
474 self.db.addjournal(self.classname, nodeid, 'retired', None)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
475
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
476 def history(self, nodeid):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
477 """Retrieve the journal of edits on a particular node.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
478
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
479 'nodeid' must be the id of an existing node of this class or an
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
480 IndexError is raised.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
481
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
482 The returned list contains tuples of the form
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
483
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
484 (date, tag, action, params)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
485
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
486 'date' is a Timestamp object specifying the time of the change and
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
487 'tag' is the journaltag specified when the database was opened.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
488 """
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
489 return self.db.getjournal(self.classname, nodeid)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
490
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
491 # Locating nodes:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
492
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
493 def setkey(self, propname):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
494 """Select a String property of this class to be the key property.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
495
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
496 'propname' must be the name of a String property of this class or
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
497 None, or a TypeError is raised. The values of the key property on
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
498 all existing nodes must be unique or a ValueError is raised.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
499 """
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
500 self.key = propname
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
501
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
502 def getkey(self):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
503 """Return the name of the key property for this class or None."""
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
504 return self.key
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
505
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
506 # TODO: set up a separate index db file for this? profile?
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
507 def lookup(self, keyvalue):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
508 """Locate a particular node by its key property and return its id.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
509
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
510 If this class has no key property, a TypeError is raised. If the
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
511 'keyvalue' matches one of the values for the key property among
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
512 the nodes in this class, the matching node's id is returned;
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
513 otherwise a KeyError is raised.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
514 """
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
515 cldb = self.db.getclassdb(self.classname)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
516 for nodeid in self.db.getnodeids(self.classname, cldb):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
517 node = self.db.getnode(self.classname, nodeid, cldb)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
518 if node.has_key(RETIRED_FLAG):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
519 continue
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
520 if node[self.key] == keyvalue:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
521 return nodeid
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
522 cldb.close()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
523 raise KeyError, keyvalue
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
524
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
525 # XXX: change from spec - allows multiple props to match
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
526 def find(self, **propspec):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
527 """Get the ids of nodes in this class which link to a given node.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
528
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
529 'propspec' consists of keyword args propname=nodeid
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
530 'propname' must be the name of a property in this class, or a
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
531 KeyError is raised. That property must be a Link or Multilink
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
532 property, or a TypeError is raised.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
533
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
534 'nodeid' must be the id of an existing node in the class linked
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
535 to by the given property, or an IndexError is raised.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
536 """
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
537 propspec = propspec.items()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
538 for propname, nodeid in propspec:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
539 nodeid = str(nodeid)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
540 # check the prop is OK
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
541 prop = self.properties[propname]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
542 if not prop.isLinkType and not prop.isMultilinkType:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
543 raise TypeError, "'%s' not a Link/Multilink property"%propname
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
544 if not self.db.hasnode(prop.classname, nodeid):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
545 raise ValueError, '%s has no node %s'%(link_class, nodeid)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
546
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
547 # ok, now do the find
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
548 cldb = self.db.getclassdb(self.classname)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
549 l = []
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
550 for id in self.db.getnodeids(self.classname, cldb):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
551 node = self.db.getnode(self.classname, id, cldb)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
552 if node.has_key(RETIRED_FLAG):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
553 continue
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
554 for propname, nodeid in propspec:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
555 nodeid = str(nodeid)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
556 property = node[propname]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
557 if prop.isLinkType and nodeid == property:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
558 l.append(id)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
559 elif prop.isMultilinkType and nodeid in property:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
560 l.append(id)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
561 cldb.close()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
562 return l
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
563
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
564 def stringFind(self, **requirements):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
565 """Locate a particular node by matching a set of its String properties.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
566
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
567 If the property is not a String property, a TypeError is raised.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
568
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
569 The return is a list of the id of all nodes that match.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
570 """
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
571 for propname in requirements.keys():
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
572 prop = self.properties[propname]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
573 if not prop.isStringType:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
574 raise TypeError, "'%s' not a String property"%propname
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
575 l = []
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
576 cldb = self.db.getclassdb(self.classname)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
577 for nodeid in self.db.getnodeids(self.classname, cldb):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
578 node = self.db.getnode(self.classname, nodeid, cldb)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
579 if node.has_key(RETIRED_FLAG):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
580 continue
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
581 for key, value in requirements.items():
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
582 if node[key] != value:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
583 break
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
584 else:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
585 l.append(nodeid)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
586 cldb.close()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
587 return l
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
588
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
589 def list(self):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
590 """Return a list of the ids of the active nodes in this class."""
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
591 l = []
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
592 cn = self.classname
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
593 cldb = self.db.getclassdb(cn)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
594 for nodeid in self.db.getnodeids(cn, cldb):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
595 node = self.db.getnode(cn, nodeid, cldb)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
596 if node.has_key(RETIRED_FLAG):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
597 continue
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
598 l.append(nodeid)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
599 l.sort()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
600 cldb.close()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
601 return l
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
602
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
603 # XXX not in spec
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
604 def filter(self, filterspec, sort, group, num_re = re.compile('^\d+$')):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
605 ''' Return a list of the ids of the active nodes in this class that
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
606 match the 'filter' spec, sorted by the group spec and then the
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
607 sort spec
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
608 '''
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
609 cn = self.classname
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
610
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
611 # optimise filterspec
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
612 l = []
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
613 props = self.getprops()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
614 for k, v in filterspec.items():
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
615 propclass = props[k]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
616 if propclass.isLinkType:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
617 if type(v) is not type([]):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
618 v = [v]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
619 # replace key values with node ids
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
620 u = []
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
621 link_class = self.db.classes[propclass.classname]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
622 for entry in v:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
623 if not num_re.match(entry):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
624 try:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
625 entry = link_class.lookup(entry)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
626 except:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
627 raise ValueError, 'new property "%s": %s not a %s'%(
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
628 key, entry, self.properties[key].classname)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
629 u.append(entry)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
630
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
631 l.append((0, k, u))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
632 elif propclass.isMultilinkType:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
633 if type(v) is not type([]):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
634 v = [v]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
635 # replace key values with node ids
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
636 u = []
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
637 link_class = self.db.classes[propclass.classname]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
638 for entry in v:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
639 if not num_re.match(entry):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
640 try:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
641 entry = link_class.lookup(entry)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
642 except:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
643 raise ValueError, 'new property "%s": %s not a %s'%(
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
644 key, entry, self.properties[key].classname)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
645 u.append(entry)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
646 l.append((1, k, u))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
647 elif propclass.isStringType:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
648 v = v[0]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
649 if '*' in v or '?' in v:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
650 # simple glob searching
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
651 v = v.replace(v, '?', '.')
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
652 v = v.replace(v, '*', '.*?')
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
653 l.append((2, k, v))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
654 elif v[0] == '^':
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
655 # start-anchored
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
656 if v[-1] == '$':
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
657 # _and_ end-anchored
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
658 l.append((6, k, v[1:-1]))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
659 l.append((3, k, v[1:]))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
660 elif v[-1] == '$':
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
661 # end-anchored
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
662 l.append((4, k, v[:-1]))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
663 else:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
664 # substring
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
665 l.append((5, k, v))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
666 else:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
667 l.append((6, k, v))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
668 filterspec = l
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
669
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
670 # now, find all the nodes that are active and pass filtering
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
671 l = []
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
672 cldb = self.db.getclassdb(cn)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
673 for nodeid in self.db.getnodeids(cn, cldb):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
674 node = self.db.getnode(cn, nodeid, cldb)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
675 if node.has_key(RETIRED_FLAG):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
676 continue
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
677 # apply filter
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
678 for t, k, v in filterspec:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
679 if t == 0 and node[k] not in v:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
680 # link - if this node'd property doesn't appear in the
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
681 # filterspec's nodeid list, skip it
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
682 break
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
683 elif t == 1:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
684 # multilink - if any of the nodeids required by the
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
685 # filterspec aren't in this node's property, then skip
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
686 # it
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
687 for value in v:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
688 if value not in node[k]:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
689 break
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
690 else:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
691 continue
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
692 break
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
693 elif t == 2 and not v.match(node[k]):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
694 # RE search
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
695 break
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
696 elif t == 3 and node[k][:len(v)] != v:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
697 # start anchored
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
698 break
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
699 elif t == 4 and node[k][-len(v):] != v:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
700 # end anchored
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
701 break
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
702 elif t == 5 and node[k].find(v) == -1:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
703 # substring search
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
704 break
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
705 elif t == 6 and node[k] != v:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
706 # straight value comparison for the other types
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
707 break
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
708 else:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
709 l.append((nodeid, node))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
710 l.sort()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
711 cldb.close()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
712
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
713 # optimise sort
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
714 m = []
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
715 for entry in sort:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
716 if entry[0] != '-':
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
717 m.append(('+', entry))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
718 else:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
719 m.append((entry[0], entry[1:]))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
720 sort = m
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
721
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
722 # optimise group
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
723 m = []
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
724 for entry in group:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
725 if entry[0] != '-':
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
726 m.append(('+', entry))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
727 else:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
728 m.append((entry[0], entry[1:]))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
729 group = m
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
730
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
731 # now, sort the result
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
732 def sortfun(a, b, sort=sort, group=group, properties=self.getprops(),
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
733 db = self.db, cl=self):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
734 a_id, an = a
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
735 b_id, bn = b
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
736 for list in group, sort:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
737 for dir, prop in list:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
738 # handle the properties that might be "faked"
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
739 if not an.has_key(prop):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
740 an[prop] = cl.get(a_id, prop)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
741 av = an[prop]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
742 if not bn.has_key(prop):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
743 bn[prop] = cl.get(b_id, prop)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
744 bv = bn[prop]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
745
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
746 # sorting is class-specific
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
747 propclass = properties[prop]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
748
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
749 # String and Date values are sorted in the natural way
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
750 if propclass.isStringType:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
751 # make sure that case doesn't get involved
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
752 if av[0] in string.uppercase:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
753 av = an[prop] = av.lower()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
754 if bv[0] in string.uppercase:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
755 bv = bn[prop] = bv.lower()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
756 if propclass.isStringType or propclass.isDateType:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
757 if dir == '+':
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
758 r = cmp(av, bv)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
759 if r != 0: return r
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
760 elif dir == '-':
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
761 r = cmp(bv, av)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
762 if r != 0: return r
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
763
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
764 # Link properties are sorted according to the value of
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
765 # the "order" property on the linked nodes if it is
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
766 # present; or otherwise on the key string of the linked
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
767 # nodes; or finally on the node ids.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
768 elif propclass.isLinkType:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
769 link = db.classes[propclass.classname]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
770 if link.getprops().has_key('order'):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
771 if dir == '+':
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
772 r = cmp(link.get(av, 'order'),
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
773 link.get(bv, 'order'))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
774 if r != 0: return r
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
775 elif dir == '-':
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
776 r = cmp(link.get(bv, 'order'),
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
777 link.get(av, 'order'))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
778 if r != 0: return r
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
779 elif link.getkey():
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
780 key = link.getkey()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
781 if dir == '+':
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
782 r = cmp(link.get(av, key), link.get(bv, key))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
783 if r != 0: return r
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
784 elif dir == '-':
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
785 r = cmp(link.get(bv, key), link.get(av, key))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
786 if r != 0: return r
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
787 else:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
788 if dir == '+':
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
789 r = cmp(av, bv)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
790 if r != 0: return r
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
791 elif dir == '-':
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
792 r = cmp(bv, av)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
793 if r != 0: return r
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
794
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
795 # Multilink properties are sorted according to how many
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
796 # links are present.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
797 elif propclass.isMultilinkType:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
798 if dir == '+':
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
799 r = cmp(len(av), len(bv))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
800 if r != 0: return r
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
801 elif dir == '-':
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
802 r = cmp(len(bv), len(av))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
803 if r != 0: return r
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
804 return cmp(a[0], b[0])
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
805 l.sort(sortfun)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
806 return [i[0] for i in l]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
807
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
808 def count(self):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
809 """Get the number of nodes in this class.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
810
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
811 If the returned integer is 'numnodes', the ids of all the nodes
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
812 in this class run from 1 to numnodes, and numnodes+1 will be the
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
813 id of the next node to be created in this class.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
814 """
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
815 return self.db.countnodes(self.classname)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
816
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
817 # Manipulating properties:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
818
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
819 def getprops(self):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
820 """Return a dictionary mapping property names to property objects."""
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
821 return self.properties
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
822
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
823 def addprop(self, **properties):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
824 """Add properties to this class.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
825
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
826 The keyword arguments in 'properties' must map names to property
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
827 objects, or a TypeError is raised. None of the keys in 'properties'
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
828 may collide with the names of existing properties, or a ValueError
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
829 is raised before any properties have been added.
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
830 """
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
831 for key in properties.keys():
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
832 if self.properties.has_key(key):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
833 raise ValueError, key
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
834 self.properties.update(properties)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
835
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
836
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
837 # XXX not in spec
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
838 class Node:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
839 ''' A convenience wrapper for the given node
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
840 '''
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
841 def __init__(self, cl, nodeid):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
842 self.__dict__['cl'] = cl
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
843 self.__dict__['nodeid'] = nodeid
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
844 def keys(self):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
845 return self.cl.getprops().keys()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
846 def has_key(self, name):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
847 return self.cl.getprops().has_key(name)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
848 def __getattr__(self, name):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
849 if self.__dict__.has_key(name):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
850 return self.__dict__['name']
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
851 try:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
852 return self.cl.get(self.nodeid, name)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
853 except KeyError, value:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
854 raise AttributeError, str(value)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
855 def __getitem__(self, name):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
856 return self.cl.get(self.nodeid, name)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
857 def __setattr__(self, name, value):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
858 try:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
859 return self.cl.set(self.nodeid, **{name: value})
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
860 except KeyError, value:
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
861 raise AttributeError, str(value)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
862 def __setitem__(self, name, value):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
863 self.cl.set(self.nodeid, **{name: value})
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
864 def history(self):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
865 return self.cl.history(self.nodeid)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
866 def retire(self):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
867 return self.cl.retire(self.nodeid)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
868
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
869
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
870 def Choice(name, *options):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
871 cl = Class(db, name, name=hyperdb.String(), order=hyperdb.String())
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
872 for i in range(len(options)):
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
873 cl.create(name=option[i], order=i)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
874 return hyperdb.Link(name)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
875
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
876
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
877 if __name__ == '__main__':
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
878 import pprint
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
879 db = Database("test_db", "richard")
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
880 status = Class(db, "status", name=String())
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
881 status.setkey("name")
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
882 print db.status.create(name="unread")
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
883 print db.status.create(name="in-progress")
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
884 print db.status.create(name="testing")
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
885 print db.status.create(name="resolved")
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
886 print db.status.count()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
887 print db.status.list()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
888 print db.status.lookup("in-progress")
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
889 db.status.retire(3)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
890 print db.status.list()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
891 issue = Class(db, "issue", title=String(), status=Link("status"))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
892 db.issue.create(title="spam", status=1)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
893 db.issue.create(title="eggs", status=2)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
894 db.issue.create(title="ham", status=4)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
895 db.issue.create(title="arguments", status=2)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
896 db.issue.create(title="abuse", status=1)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
897 user = Class(db, "user", username=String(), password=String())
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
898 user.setkey("username")
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
899 db.issue.addprop(fixer=Link("user"))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
900 print db.issue.getprops()
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
901 #{"title": <hyperdb.String>, "status": <hyperdb.Link to "status">,
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
902 #"user": <hyperdb.Link to "user">}
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
903 db.issue.set(5, status=2)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
904 print db.issue.get(5, "status")
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
905 print db.status.get(2, "name")
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
906 print db.issue.get(5, "title")
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
907 print db.issue.find(status = db.status.lookup("in-progress"))
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
908 print db.issue.history(5)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
909 # [(<Date 2000-06-28.19:09:43>, "ping", "create", {"title": "abuse", "status": 1}),
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
910 # (<Date 2000-06-28.19:11:04>, "ping", "set", {"status": 2})]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
911 print db.status.history(1)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
912 # [(<Date 2000-06-28.19:09:43>, "ping", "link", ("issue", 5, "status")),
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
913 # (<Date 2000-06-28.19:11:04>, "ping", "unlink", ("issue", 5, "status"))]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
914 print db.status.history(2)
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
915 # [(<Date 2000-06-28.19:11:04>, "ping", "link", ("issue", 5, "status"))]
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
916
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
917 # TODO: set up some filter tests
5e92642cd1f8 Initial import of code
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
918

Roundup Issue Tracker: http://roundup-tracker.org/