cl-2sql

Lisp to SQL compiler for Common Lisp
git clone https://logand.com/git/cl-2sql.git/
Log | Files | Refs | README | LICENSE

commit 6e943ad7636b7b1d0ba300a5091790a9e9e049cd
parent 21d61b90e19c0b8ed2bc79215d08149d4f73a17a
Author: Tomas Hlavaty <tom@logand.com>
Date:   Sun, 14 Aug 2011 22:26:57 +0200

introduced mop and instance cache

Diffstat:
Mcl-2sql.asd | 1+
Morm.lisp | 122++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Mpackages.lisp | 1+
3 files changed, 102 insertions(+), 22 deletions(-)

diff --git a/cl-2sql.asd b/cl-2sql.asd @@ -17,6 +17,7 @@ ;;#+sqlite :sqlite :cl-postgres :sqlite + :closer-mop ) :serial t :components ((:file "packages") diff --git a/orm.lisp b/orm.lisp @@ -67,9 +67,6 @@ (defgeneric ptype-macroexpand (type)) -(defgeneric pclassp (class-name) - (:method (a))) - (defun lisp-type-to-ptype (type) ;; TODO more types (if (atom type) (case type @@ -82,7 +79,7 @@ (octet-vector '(q:blob-type)) (t (cond - ((pclassp type) (lisp-type-to-ptype 'oid)) + ((subtypep type 'persistent-object) (lisp-type-to-ptype 'oid)) (t (let ((x (ptype-macroexpand type))) (assert (not (eq x type))) (lisp-type-to-ptype x)))))) @@ -120,13 +117,75 @@ (defgeneric list-pslots (class-name)) +;; http://users.encs.concordia.ca/~haarslev/publications/jvlc92/node6.html +;; http://objectmix.com/lisp/725624-help-creating-clos-meta-classes.html +;; http://www.lispworks.com/documentation/lw50/LWRM/html/lwref-71.htm +;; http://paste.lisp.org/display/123125 +;; http://www.cliki.net/MOP%20design%20patterns +;; http://bc.tech.coop/blog/040412.html + +(defclass persistent-class (standard-class) + ()) + +(defmethod c2mop:validate-superclass ((class persistent-class) + (superclass standard-class)) + t) + +(defclass persistent-object (standard-object) + () + (:metaclass persistent-class)) + +(defparameter *instance-cache* nil) + +(defmacro with-instance-cache (args &body body) + (declare (ignore args)) + `(let ((*instance-cache* (make-hash-table))) + ,@body)) + +(defun check-cached-instance (a) + (unless *initializing-instance* + (assert (eq a (gethash (oid a) *instance-cache*))))) + +(defmethod c2mop:slot-value-using-class :before ((class persistent-class) + (a persistent-object) + slotd) + (unless (eq 'oid (c2mop:slot-definition-name slotd)) + ;;(describe slotd) + (check-cached-instance a))) + +(defparameter *initializing-instance* nil) + +(defmethod c2mop::shared-initialize :around ((object persistent-object) + slot-names + &rest initargs + &key &allow-other-keys) + (declare (ignore initargs)) + (let ((*initializing-instance* t)) + (call-next-method))) + +(defmethod (setf c2mop:slot-value-using-class) :before (value + (class persistent-class) + (a persistent-object) + slotd) + (unless (eq 'oid (c2mop:slot-definition-name slotd)) + ;;(describe slotd) + (check-cached-instance a))) + +#+nil +(defpclass bar () + ((slot1 :initarg :slot1 :accessor slot1) + (slot2 :initarg :slot2 :accessor slot2))) + +;;(slot2 (make-instance 'bar :slot2 2)) +;;(setf (slot2 (make-instance 'bar :slot2 2)) 3) +;;(slot-value (make-instance 'bar :slot2 2) 'slot2) +;;(setf (slot-value (make-instance 'bar :slot2 2) 'slot2) 3) + (defmacro defpclass (name direct-superclasses direct-slots &rest options) `(progn - (defclass ,name ,direct-superclasses + (defclass ,name ,(cons 'persistent-object direct-superclasses) ,(cons '(oid :type oid :initarg :oid :accessor oid) direct-slots) - ,@options) - (defmethod pclassp ((class-name (eql ',name))) - t) + ,@(cons '(:metaclass persistent-class) options)) (defmethod cl-postgres:to-sql-string ((a ,name)) (cl-postgres:to-sql-string (oid a))) (let ((cache nil)) @@ -182,6 +241,21 @@ (q:returning ,returning-cols)))) (defun assert-type (value type) + (print (list :assert-type1 value type (type-of value))) + (unless (typep value type) + (cond ;; TODO more cases + ((typep value 'string) + (setq value (coerce value 'simple-string))) + ((typep value 'simple-date:timestamp) + (setq value (multiple-value-bind (y m d hh mm ss ms) + (simple-date:decode-timestamp value) + (make-ptimestamp-with-timezone + :date (make-pdate :y y :m m :d d) + :time (make-ptime :hh hh :mm mm :ss ss :ms ms) + :timezone nil)))) + ((subtypep type 'persistent-object) + (error "TODO assert-type persistent-object")))) + (print (list :assert-type2 value type (type-of value))) (assert (typep value type)) value) @@ -197,18 +271,20 @@ else collect (list name initarg ltype) into unknown finally (return (values known unknown))) ;; TODO cache eql oid->instance - (apply #'make-instance class-name - (nconc - (loop - for (v name initarg ltype) in known - appending (list initarg (assert-type v ltype))) - (loop - for (name initarg ltype) in (cons (list 'oid :oid 'oid) unknown) - for v in (car - (insert-into class-name (mapcar #'cadr known) - (mapcar #'car known) - (cons 'oid (mapcar #'car unknown)))) - appending (list initarg (assert-type v ltype))))))) + (let ((x (apply #'make-instance class-name + (nconc + (loop + for (v name initarg ltype) in known + appending (list initarg (assert-type v ltype))) + (loop + for (name initarg ltype) in (cons (list 'oid :oid 'oid) unknown) + for v in (car + (insert-into class-name (mapcar #'cadr known) + (mapcar #'car known) + (cons 'oid (mapcar #'car unknown)))) + appending (list initarg (assert-type v ltype))))))) + (assert (not (gethash (oid x) *instance-cache*))) + (setf (gethash (oid x) *instance-cache*) x)))) (defparameter *instance-collector-cache* nil) ;; equal form->fn @@ -251,6 +327,9 @@ (args (loop for x in pslots appending (list (pslot-initarg x) (pop row))))) ;; TODO resolve pclassp foreign ref (lazy foreign reference?) + (or (gethash oid *instance-cache*) + (apply #'make-pinstance tab :oid oid args)) ;; TODO test this case + #+nil (unless (eq :null oid) ;; TODO uniq oid->instance cache (apply #'make-instance tab :oid oid args))) ;; TODO fix values from rdbms backend to lisp, e.g. :null :true :false pclasp @@ -281,4 +360,4 @@ (unwind-protect ,(rec (cdr x)) (2sql:query () '(q:drop-sequence ,(car x) t)))) `(progn ,@body)))) - (rec names))) -\ No newline at end of file + (rec names))) diff --git a/packages.lisp b/packages.lisp @@ -45,6 +45,7 @@ #:defptype #:defpclass #:setup-pclass + #:with-instance-cache #:make-pinstance #:with-pinstance-collector-cache #:query