Mercurial > hg > amuse
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)))) |