comparison base/charm/database-functions.lisp @ 253:b5ffec94ae6d

some very sketchy Charm constituent code
author Jamie Forth <j.forth@gold.ac.uk>
date Thu, 24 Feb 2011 11:23:18 +0000
parents
children
comparison
equal deleted inserted replaced
252:b518b9f904e3 253:b5ffec94ae6d
1 (cl:in-package #:amuse-charm)
2
3 ;;;=====================================================================
4 ;;; API for inserting and retrieving constituents
5 ;;;=====================================================================
6
7 (defun store-charm-constituent (constituent database)
8 "Given a charm-constituent, store it in the database (after first
9 checking for a previously added identical constituent - this needs
10 doing properly), and then update the database related
11 slots (identifier, owner, version, and timestamps).
12
13 FIXME: What to do about constituent start and duration slots?
14 Currently all implementations use integer time in the database, but
15 then typically convert to a real number line in Lisp, e.g. geerdes
16 divides by the MIDI timebase. So what should the start and duration
17 slots mean? Should they be the real values or the database integer
18 values? If the latter, then each implementation should provide a
19 'convert-to-integer-time' function. Or the other extreme, do we
20 specify these database columns as string so that we can store what
21 ever we want (e.g. Lisp ratios instead of forcing conversion to
22 floating point). For the moment, I'm ignoring this."
23 (unless nil ;(constituent-header-exists-p constituent database)
24 (%insert-new-constituent constituent database)
25 (format t "New constituent added: id ~A."
26 (id constituent))
27 (identifier constituent)))
28
29 (defun get-charm-constituent (constituent-identifier database)
30 (let ((header (%get-constituent-header constituent-identifier
31 database)))
32 (destructuring-bind (parent ext-properties int-properties owner
33 version creation-timestamp
34 deletion-timestamp) header
35 (make-standard-charm-constituent (%get-constituent-particles
36 constituent-identifier parent
37 database) parent
38 ext-properties int-properties
39 :constituent-identifier
40 constituent-identifier
41 :owner owner
42 :version version
43 :creation-timestamp creation-timestamp
44 :deletion-timestamp
45 deletion-timestamp))))
46
47 ;; (defun cache-charm-particles (charm-constituent)
48 ;; "This could/should also re-compute the time and duration slots. Or,
49 ;; unless we can come up with a general way of storing these values in
50 ;; the constituent headers."
51 ;; (%cache-charm-particles (implementation-package (parent-identifier
52 ;; charm-constituent))
53 ;; charm-constituent))
54
55 ;(defun delete-constituent (constituent-identifier database)
56
57
58 (defun constituent-header-exists-p (constituent database)
59 (with-slots (time interval extrinsic-properties
60 intrinsic-properties)
61 constituent
62 (let ((exists
63 (car
64 (clsql:query (format nil "
65 SELECT constituent_header_exists(~S, ~S, '~A', '~A')"
66 time
67 interval
68 (object->db-string
69 extrinsic-properties)
70 (object->db-string
71 intrinsic-properties))
72 :database database
73 :flatp t
74 :field-names nil))))
75 (if (eq exists 1)
76 (progn (setf exists t)
77 (format t "Constituent header exists.~%"))
78 (progn (setf exists nil)
79 (format t "Constituent header does not exist.~%")))
80 exists)))
81
82 ;(defun constituent-particle-list-exists-p (constituent) nil)
83
84
85 ;;;=====================================================================
86 ;;; Helper functions
87 ;;;=====================================================================
88
89 (defun %insert-new-constituent (constituent database)
90 "Constituent-identifier, owner, version, and timestamps are added as
91 side effects."
92 (clsql:with-transaction (:database database)
93 (%insert-constituent-header constituent database)
94 (%insert-particles constituent database)))
95
96 (defun %insert-constituent-header (constituent database)
97 (with-slots (parent extrinsic-properties intrinsic-properties)
98 constituent
99 (clsql:execute-command (concatenate 'string "
100 INSERT INTO charm_constituent_headers SET
101 implementation_id := (SELECT get_impl_id('" (implementation-namestring
102 parent) "')),
103 parent_id := " (princ-to-string (id parent)) ",
104 ext_properties := '" (object->db-string extrinsic-properties) "',
105 int_properties := '" (object->db-string intrinsic-properties) "';")
106 :database database)
107 (%update-header-slots constituent database)))
108
109 (defun %update-header-slots (constituent database)
110 (let ((db-row-data (clsql:query "
111 SELECT last_insert_id(), owner, version, creation_timestamp, deletion_timestamp
112 FROM charm_constituent_headers
113 WHERE constituent_id = last_insert_id();"
114 :database database
115 :flatp t
116 :field-names nil)))
117 (destructuring-bind (const-id own ver create delete) (car db-row-data)
118 (setf (identifier constituent) (make-charm-constituent-identifier
119 const-id)
120 (owner constituent) own
121 (version constituent) ver
122 (creation-timestamp constituent) create
123 (deletion-timestamp constituent) delete)))
124 constituent)
125
126 (defgeneric %insert-particles (constituent database))
127
128 (defmethod %insert-particles ((constituent standard-charm-event-constituent)
129 database)
130 (if (write-particles constituent)
131 (clsql:execute-command
132 "LOAD DATA LOCAL INFILE '/tmp/particles'
133 INTO TABLE charm_constituent_particles"
134 :database database)
135 (error "file not written"))
136 (delete-file "/tmp/particles"))
137
138 (defmethod %insert-particles ((constituent standard-charm-constituent)
139 database)
140 (sequence:dosequence (particle constituent t)
141 (store-charm-constituent particle database)))
142
143 (defun write-particles (constituent)
144 (with-open-file (particle-stream (pathname "/tmp/particles")
145 :direction :output
146 :if-exists :supersede)
147 (loop for particle in (%list-slot-sequence-data constituent)
148 do (write-sequence (concatenate
149 'string ;;FIXME SET @constituent_id server side?
150 (princ-to-string (id constituent))
151 '(#\tab)
152 (princ-to-string (id particle))
153 '(#\tab)
154 (object->db-string (identifier particle)) ; type
155 '(#\tab)
156 "1" ; version - defaults to 1
157 '(#\nl))
158 particle-stream)
159 finally (return t))))
160
161
162 ;;;=====================================================================
163 ;;; Retrieving
164 ;;;=====================================================================
165
166 (defun %get-constituent-header (constituent-identifier database)
167 "Basic low-level retrieval of constituents. Just takes an identifier
168 and returns a header without any checking of version or deletion
169 fields."
170 (let ((header-row (clsql:query (concatenate 'string "
171 SELECT implementation_name, parent_id, ext_properties, int_properties,
172 owner, version, creation_timestamp, deletion_timestamp
173 FROM charm_constituent_headers
174 LEFT JOIN amuse_implementations
175 USING (implementation_id)
176 WHERE constituent_id = " (princ-to-string (id constituent-identifier)))
177 :flatp t
178 :field-names nil
179 :database database)))
180 (%init-header (car header-row))))
181
182 (defun %init-header (header-row)
183 (destructuring-bind (impl-name parent ext-properties int-properties
184 owner version creation-timestamp
185 deletion-timestamp) header-row
186 (setf ext-properties (make-charm-property-list (read-from-string
187 ext-properties)))
188 (setf int-properties (make-charm-property-list (read-from-string
189 int-properties)))
190 (setf impl-name (find-package impl-name))
191 (setf parent
192 (get-charm-parent
193 (make-charm-parent-identifier impl-name parent)))
194 ;; FIXME: probable should turn timestamps into objects
195 (list parent ext-properties int-properties owner version
196 creation-timestamp deletion-timestamp)))
197
198 (defun %get-constituent-particles (constituent-identifier parent
199 database)
200 (let ((particle-rows (clsql:query (concatenate 'string "
201 SELECT particle_id, version_added, version_removed
202 FROM charm_constituent_particles
203 WHERE constituent_id = " (princ-to-string
204 (id constituent-identifier)))
205 :database database
206 :flatp t
207 :field-names nil)))
208 (%init-particle-rows particle-rows parent)))
209
210 (defun %init-particle-rows (particle-rows parent)
211 (let ((impl-package (implementation-package parent)))
212 (loop for row in particle-rows
213 collect (make-charm-particle-identifier impl-package (car row))
214 into particles
215 finally (return particles))))
216
217 ;; (defun %init-particle-rows (particle-rows parent)
218 ;; "An alternative to above - would select-events-by-ids be useful?"
219 ;; (select-events-by-ids parent
220 ;; (loop for row in particle-rows
221 ;; collect (car row)
222 ;; into ids
223 ;; finally (return ids))))