Mercurial > hg > amuse
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base/database/charm/database-functions.lisp Thu Sep 30 15:35:15 2010 +0100 @@ -0,0 +1,221 @@ +(cl:in-package #:amuse-charm) + +;;;===================================================================== +;;; API for inserting and retrieving constituents +;;;===================================================================== + +(defun store-charm-constituent (constituent database) + "Given a charm-constituent, store it in the database (after first +checking for a previously added identical constituent - this needs +doing properly), and then update the database related +slots (identifier, owner, version, and timestamps). + +FIXME: What to do about constituent start and duration slots? +Currently all implementations use integer time in the database, but +then typically convert to a real number line in Lisp, e.g. geerdes +divides by the MIDI timebase. So what should the start and duration +slots mean? Should they be the real values or the database integer +values? If the latter, then each implementation should provide a +'convert-to-integer-time' function. Or the other extreme, do we +specift these database columns as string so that we can store what +ever we want (e.g. Lisp ratios instead of forcing conversion to +floating point). For the moment, I'm ignoring this." + (unless nil ;(constituent-header-exists-p constituent database) + (%insert-new-constituent constituent database) + (format t "New constituent added: id ~A." + (id constituent)) + (identifier constituent))) + +(defun get-charm-constituent (constituent-identifier database) + (let ((header (%get-constituent-header constituent-identifier + database))) + (destructuring-bind (parent ext-properties int-properties owner + version creation-timestamp + deletion-timestamp) header + (make-standard-charm-constituent (%get-constituent-particles + constituent-identifier parent + database) parent + ext-properties int-properties + :constituent-identifier + constituent-identifier + :owner owner + :version version + :creation-timestamp creation-timestamp + :deletion-timestamp + deletion-timestamp)))) + +;; (defun cache-charm-particles (charm-constituent) +;; "This could/should also re-compute the time and duration slots. Or, +;; unless we can come up with a general way of storing these values in +;; the constituent headers." +;; (%cache-charm-particles (implementation-package (parent-identifier +;; charm-constituent)) +;; charm-constituent)) + +;(defun delete-constituent (constituent-identifier database) + + +(defun constituent-header-exists-p (constituent database) + (with-slots (time interval extrinsic-properties + intrinsic-properties) + constituent + (let ((exists + (car + (clsql:query (format nil " +SELECT constituent_header_exists(~S, ~S, '~A', '~A')" + time + interval + (object->db-string + extrinsic-properties) + (object->db-string + intrinsic-properties)) + :database database + :flatp t + :field-names nil)))) + (if (eq exists 1) + (progn (setf exists t) + (format t "Constituent header exists.~%")) + (progn (setf exists nil) + (format t "Constituent header does not exist.~%"))) + exists))) + +;(defun constituent-particle-list-exists-p (constituent) nil) + + +;;;===================================================================== +;;; Helper functions +;;;===================================================================== + +(defun %insert-new-constituent (constituent database) + "Constituent-identifier, owner, version, and timestamps are added as +side effects." + (clsql:with-transaction (:database database) + (%insert-constituent-header constituent database) + (%insert-particles constituent database))) + +(defun %insert-constituent-header (constituent database) + (with-slots (parent extrinsic-properties intrinsic-properties) + constituent + (clsql:execute-command (concatenate 'string " +INSERT INTO charm_constituent_headers SET +implementation_id := (SELECT get_impl_id('" (implementation-namestring + parent) "')), +parent_id := " (princ-to-string (id parent)) ", +ext_properties := '" (object->db-string extrinsic-properties) "', +int_properties := '" (object->db-string intrinsic-properties) "';") + :database database) + (%update-header-slots constituent database))) + +(defun %update-header-slots (constituent database) + (let ((db-row-data (clsql:query " +SELECT last_insert_id(), owner, version, creation_timestamp, deletion_timestamp +FROM charm_constituent_headers +WHERE constituent_id = last_insert_id();" + :database database + :flatp t + :field-names nil))) + (destructuring-bind (const-id own ver create delete) (car db-row-data) + (setf (identifier constituent) (make-charm-constituent-identifier + const-id) + (owner constituent) own + (version constituent) ver + (creation-timestamp constituent) create + (deletion-timestamp constituent) delete))) + constituent) + +(defgeneric %insert-particles (constituent database)) + +(defmethod %insert-particles ((constituent standard-charm-event-constituent) + database) + (if (write-particles constituent) + (clsql:execute-command + "LOAD DATA LOCAL INFILE '/tmp/particles' +INTO TABLE charm_constituent_particles" + :database database) + (error "file not written")) + (delete-file "/tmp/particles")) + +(defmethod %insert-particles ((constituent standard-charm-constituent) + database) + (sequence:dosequence (particle constituent t) + (store-charm-constituent particle database))) + +(defun write-particles (constituent) + (with-open-file (particle-stream (pathname "/tmp/particles") + :direction :output + :if-exists :supersede) + (loop for particle in (%list-slot-sequence-data constituent) + do (write-sequence (concatenate + 'string ;;FIXME SET @constituent_id server side? + (princ-to-string (id constituent)) + '(#\tab) + (princ-to-string (id particle)) + '(#\tab) + (object->db-string (identifier particle)) ; type + '(#\tab) + "1" ; version - defaults to 1 + '(#\nl)) + particle-stream) + finally (return t)))) + + +;;;===================================================================== +;;; Retrieving +;;;===================================================================== + +(defun %get-constituent-header (constituent-identifier database) + "Basic low-level retrieval of constituents. Just takes an identifier +and returns a header without any checking of version or deletion +fields." + (let ((header-row (clsql:query (concatenate 'string " +SELECT implementation_name, parent_id, ext_properties, int_properties, +owner, version, creation_timestamp, deletion_timestamp +FROM charm_constituent_headers +LEFT JOIN amuse_implementations +USING (implementation_id) +WHERE constituent_id = " (princ-to-string (id constituent-identifier))) + :flatp t + :field-names nil + :database database))) + (%init-header (car header-row)))) + +(defun %init-header (header-row) + (destructuring-bind (impl-name parent ext-properties int-properties + owner version creation-timestamp + deletion-timestamp) header-row + (setf ext-properties (make-charm-property-list (read-from-string + ext-properties))) + (setf int-properties (make-charm-property-list (read-from-string + int-properties))) + (setf impl-name (find-package impl-name)) + (setf parent + (get-charm-parent + (make-charm-parent-identifier impl-name parent))) + ;; FIXME: probable should turn timestamps into objects + (list parent ext-properties int-properties owner version + creation-timestamp deletion-timestamp))) + +(defun %get-constituent-particles (constituent-identifier parent + database) + (let ((particle-rows (clsql:query (concatenate 'string " +SELECT particle_id, version_added, version_removed +FROM charm_constituent_particles +WHERE constituent_id = " (princ-to-string + (id constituent-identifier))) + :database database + :flatp t + :field-names nil))) + (%init-particle-rows particle-rows parent))) + +;; (defun %init-particle-rows (particle-rows impl-package) +;; (loop for row in particle-rows +;; collect (make-charm-particle-identifier impl-package (car row)) +;; into particles +;; finally (return particles))) + +(defun %init-particle-rows (particle-rows parent) + (select-events-by-ids parent + (loop for row in particle-rows + collect (car row) + into ids + finally (return ids))))