comparison base/database/charm/database-functions.lisp @ 318:c4e792b9b898

Add some ideas for charm constituents. Not particularly useful in its own right, but contains some possibly useful ideas related to the generalisation of db-compositions.
author Jamie Forth <j.forth@gold.ac.uk>
date Thu, 30 Sep 2010 15:35:15 +0100
parents
children
comparison
equal deleted inserted replaced
317:46dd71ef9ab3 318:c4e792b9b898
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 specift 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 impl-package)
211 ;; (loop for row in particle-rows
212 ;; collect (make-charm-particle-identifier impl-package (car row))
213 ;; into particles
214 ;; finally (return particles)))
215
216 (defun %init-particle-rows (particle-rows parent)
217 (select-events-by-ids parent
218 (loop for row in particle-rows
219 collect (car row)
220 into ids
221 finally (return ids))))