commit c700e9be8e93b4b7f0ae633d71bc84ef8640702b
parent 941e93ec5c8cda918668e7871ab9ef3d78e6c3bf
Author: Tomas Hlavaty <tom@logand.com>
Date: Tue, 23 Aug 2011 00:15:16 +0200
more mop fixes
- move mop.lisp back to orm.lisp due to compilation inter-dependencies
- introduce %persistent-object due to compute-effective-slot-definition
where slotd is expected to be persistent-slot-definition
- fix make-pinstance and instance except associations/fkeys
Diffstat:
M | cl-2sql.asd | | | 1 | - |
D | mop.lisp | | | 319 | ------------------------------------------------------------------------------- |
M | orm.lisp | | | 367 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- |
3 files changed, 348 insertions(+), 339 deletions(-)
diff --git a/cl-2sql.asd b/cl-2sql.asd
@@ -26,5 +26,4 @@
(:file "macros")
;;#+(or postgresql sqlite) (:file "backend")
(:file "backend")
- (:file "mop")
(:file "orm")))
diff --git a/mop.lisp b/mop.lisp
@@ -1,319 +0,0 @@
-(in-package :2sql-orm)
-
-(defparameter *instance-cache* nil)
-
-(defmacro with-instance-cache (args &body body)
- (declare (ignore args))
- `(let ((*instance-cache* (make-hash-table)))
- ,@body))
-
-;; 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 (#+nil standard-object)
- ((oid :type oid :initarg :oid :accessor oid))
- (:metaclass persistent-class))
-
-;;(c2mop:ensure-finalized (find-class 'persistent-object))
-;;(c2mop:class-slots (find-class 'persistent-object))
-
-;; http://www.cliki.net/MOP%20design%20patterns
-#+nil ;; TODO add persistent-object superclass automatically
-(defmacro init-instance ()
- `(call-next-method)
- #+nil
- `(if (or #+nil(eq 'persistent-class (class-name class))
- (loop
- for x in direct-superclasses
- thereis (subtypep x (find-class 'persistent-object))))
- ;; already one of the (indirect) superclasses
- (call-next-method)
- ;; not one of the superclasses, so we have to add it
- (apply #'call-next-method class
- :direct-superclasses (append direct-superclasses
- (list (find-class 'persistent-object)))
- initargs)))
-
-;; http://www.cliki.net/MOP%20design%20patterns
-#+nil ;; TODO add persistent-object superclass automatically
-(defmethod initialize-instance :around ((class persistent-class) &rest initargs
- &key direct-superclasses)
- (declare (dynamic-extent initargs))
- (init-instance))
-
-;; http://www.cliki.net/MOP%20design%20patterns
-#+nil ;; TODO add persistent-object superclass automatically
-(defmethod reinitialize-instance :around
- ((class persistent-class) &rest initargs
- &key (direct-superclasses '() direct-superclasses-p))
- (declare (dynamic-extent initargs))
- (if direct-superclasses-p
- ;; if direct superclasses are explicitly passed this is exactly
- ;; like above
- (init-instance)
- ;; if direct superclasses are not explicitly passed we _must_
- ;; not change anything
- (call-next-method)))
-
-(defparameter *initializing-instance* nil)
-
-(defun check-cached-instance (a)
- (unless *initializing-instance*
- (assert (eq a (gethash (oid a) *instance-cache*)))))
-
-(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 c2mop:slot-value-using-class :before ((class persistent-class)
- (a persistent-object)
- slotd)
- (unless (eq 'oid (c2mop:slot-definition-name slotd))
- (check-cached-instance a)))
-
-(defmethod (setf c2mop:slot-value-using-class) :before (value
- (class persistent-class)
- (a persistent-object)
- slotd)
- (unless (eq 'oid (c2mop:slot-definition-name slotd))
- (check-cached-instance a)))
-
-(defstruct proxy oid)
-
-(defmethod c2mop:slot-value-using-class :around ((class persistent-class)
- (a persistent-object)
- slotd)
- (let ((a (call-next-method)))
- a
- #+nil ;; TODO only for proxy slots
- (etypecase a
- (proxy (error "TODO maybe-dereference-proxy ~s" a))
- (persistent-object a))))
-
-(defmethod (setf c2mop:slot-value-using-class) :around (value
- (class persistent-class)
- (a persistent-object)
- slotd)
- (call-next-method)
- #+nil(error "TODO (setf c2mop:slot-value-using-class) :around"))
-
-;;; persistent slots
-
-(defclass persistent-slot-definition ()
- ((ltype :reader ltype) ;; remember unexpanded
- (ptype :reader ptype) ;; remember computed
- (nullable :reader nullable)
- (transient :type boolean :initarg :transient :initform nil :accessor transient)))
-
-(defclass persistent-direct-slot-definition
- (persistent-slot-definition c2mop:standard-direct-slot-definition)
- ())
-
-(defclass persistent-effective-slot-definition
- (persistent-slot-definition c2mop:standard-effective-slot-definition)
- ())
-
-(defmethod c2mop:direct-slot-definition-class :around
- ((class persistent-class) &rest initargs)
- ;;(print (list :@@@-direct-slot-definition-class initargs))
- (find-class 'persistent-direct-slot-definition))
-
-(defmethod c2mop:effective-slot-definition-class
- ((class persistent-class) &rest initargs)
- ;;(format t "getting eff class. initargs=~s~%" initargs)
- (find-class 'persistent-effective-slot-definition))
-
-#+nil
-(defmethod c2mop:compute-effective-slot-definition
- ((class persistent-class) slot-name direct-slots)
- (call-next-method)
- #+nil
- (format t "computing slot definition: class=~s name=~s slots=~s~%"
- class slot-name direct-slots)
- #+nil
- (let ((result (call-next-method)))
- ;;(break "~s" result)
- #+nil
- (format t " result: ~s~%" result)
- result))
-
-(defmethod initialize-instance :before
- ((class persistent-direct-slot-definition) &rest initargs
- &key direct-superclasses)
- (declare (ignore direct-superclasses))
- (with-slots (ltype ptype nullable) class ;; TODO transient
- (setq ltype (getf initargs :type)
- ptype (lisp-type-to-ptype ltype)
- nullable (unless (eql 'boolean ltype)
- (typep nil ltype)))))
-
-(defmethod c2mop:compute-effective-slot-definition :around
- ((class persistent-class) name direct-slot-definitions)
- (let ((x (call-next-method)))
- (assert (not (cdr direct-slot-definitions))) ;; TODO
- (let ((slotd (car direct-slot-definitions)))
- (if (or (typep slotd 'persistent-direct-slot-definition)
- (typep slotd 'persistent-effective-slot-definition))
- (with-slots (ltype ptype nullable) x
- (setq ltype (ltype slotd)
- ptype (ptype slotd)
- nullable (nullable slotd)))
- (error "OOPS ~s" slotd)
- #+nil
- (with-slots (transient) x
- (setq transient t))))
- x))
-
-#+nil
-(defmethod initialize-instance :around
- ((class persistent-direct-slot-definition) &rest initargs
- &key direct-superclasses)
- ;;(declare (ignore direct-superclasses))
- #+nil
- (with-slots (ltype ptype nullable) class
- (setq ltype (getf initargs :type)
- ptype (lisp-type-to-ptype ltype)
- nullable (unless (eql 'boolean ltype)
- (typep nil ltype))))
- (call-next-method)
- #+nil
- (let ((ltype (getf initargs :type)))
- (apply #'call-next-method
- class
- `(:ltype ,ltype
- :ptype ,(lisp-type-to-ptype ltype)
- :nullable ,(unless (eql 'boolean ltype)
- (typep nil ltype))
- ,@initargs)
- direct-superclasses)))
-
-#+nil
-(defclass foo ()
- ((hi :initarg :hi)))
-
-;;(c2mop:class-slots (find-class 'foo))
-
-#+nil
-(defclass person (#+nil persistent-object foo)
- ((name :type string :initarg :name #+nil :transient #+nil t)
- (age :type natural0 :initarg :age))
- (:metaclass persistent-class))
-
-;;(slot-value (make-instance 'person :age 12) 'age)
-
-;;(c2mop:class-slots (find-class 'person))
-
-#+nil
-(defclass person2 (persistent-object foo)
- ((name :type string :initarg :name #+nil :transient #+nil t)
- (age :type natural0 :initarg :age))
- (:metaclass persistent-class))
-
-;;(c2mop:ensure-finalized (find-class 'person2))
-;;(c2mop:class-slots (find-class 'person2))
-
-#+nil
-(let ((x (make-instance 'person :hi "cus" :name "John" :age 12)))
- (dolist (s (c2mop:class-slots (class-of x)))
- (format t "slot ~s = ~s~%"
- (c2mop:slot-definition-name s)
- (slot-value x (c2mop:slot-definition-name s)))))
-
-#+nil
-(defun persistent-slot-p (slot)
- (when (typep slot 'persistent-slot)
- (transient slot)))
-
-#+nil
-(defun list-pslots2 (class)
- (c2mop:class-slots class)
- #+nil
- (remove-if 'transient (c2mop:class-slots class)))
-
-;;(list-pslots (find-class 'person))
-;;(list-pslots (class-of (make-instance 'person :hi "cus" :name "John" :age 12)))
-
-
-
-
-;; TODO revert to defmethod or hook initialize-instance, ccl expands types too early:-{
-(defun list-pslots (class)
- (c2mop:class-slots (if (symbolp class) (find-class class) class)))
-
-(defun pslot-name (a)
- (c2mop:slot-definition-name a))
-
-(defun pslot-ltype (a)
- (ltype a))
-
-(defun pslot-initargs (a)
- (c2mop:slot-definition-initargs a))
-
-(defun pslot-initform (a)
- (c2mop:slot-definition-initform a))
-
-(defun pslot-ptype (a)
- (ptype a))
-
-(defun pslot-nullable (a)
- (nullable a))
-
-;; (pslot-ptype (cadr (list-pslots (find-class 'person))))
-
-#+nil
-(defpclass bar ()
- ((slot1 :initarg :slot1 :accessor slot1)
- (slot2 :initarg :slot2 :accessor slot2)))
-
-;;(with-instance-cache () (slot2 (make-pinstance 'bar :oid 123 :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)
-
-#+nil
-(defpclass person ()
- ((name :type string :initarg :name)
- (age :type natural0 :initarg :age))
- #+nil
- (:metaclass persistent-class))
-
-#+nil
-(defpclass person ()
- ((name :type string :initarg :name)
- (birth-date :type pdate :initarg :birth-date))
- #+nil
- (:metaclass persistent-class))
-
-
-
-;;; http://www.b9.com/blog/archives/000084.html
-;;
-;; Also, special thanks to Christophe Rhodes, frequent contributor to
-;; SBCL's MOP, for his excellent suggestion in response to a question
-;; for improving CLSQL's MOP internals: CLSQL object definitions use
-;; custom slot types. For example, a CLSQL slot may have :type
-;; (varchar 10) specified which gets translated to a lisp type of (or
-;; null string). Rather than parsing and then re-storing the type
-;; atrribute of a slot in compute-effective-slot-definiton, Christophe
-;; suggested performing the type parsing in initialize-instance
-;; :around of the CLSQL direct-slot-definition object. Then, the real
-;; type attribute is stored in the both the direct and effective slot
-;; definition from the beginning.This is more AMOP complaint since
-;; AMOP doesn't specify that one may change the type attribute of a
-;; slot. This is clearly seen since CLSQL no longer needs to modify
-;; OpenMCL's ccl:type-predicate slot attribute after the type was
-;; changed in compute-effective-slot-definition.
diff --git a/orm.lisp b/orm.lisp
@@ -2,6 +2,8 @@
(in-package :2sql-orm)
+;;; orm types
+
;; string => string | clob
;; string 3 => char 3
;; text 5 &optional 2 => varchar 5 (no "" allowed, due to oracle)
@@ -113,9 +115,331 @@
(defptype oid () 'natural1)
+;;; persistent-object
+
+(defparameter *instance-cache* nil)
+
+(defmacro with-instance-cache (args &body body)
+ (declare (ignore args))
+ `(let ((*instance-cache* (make-hash-table)))
+ ,@body))
+
+;; 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 (#+nil standard-object)
+ ()
+ (:metaclass persistent-class))
+
+;;(c2mop:ensure-finalized (find-class 'persistent-object))
+;;(c2mop:class-slots (find-class 'persistent-object))
+
+;; http://www.cliki.net/MOP%20design%20patterns
+#+nil ;; TODO add persistent-object superclass automatically
+(defmacro init-instance ()
+ `(call-next-method)
+ #+nil
+ `(if (or #+nil(eq 'persistent-class (class-name class))
+ (loop
+ for x in direct-superclasses
+ thereis (subtypep x (find-class 'persistent-object))))
+ ;; already one of the (indirect) superclasses
+ (call-next-method)
+ ;; not one of the superclasses, so we have to add it
+ (apply #'call-next-method class
+ :direct-superclasses (append direct-superclasses
+ (list (find-class 'persistent-object)))
+ initargs)))
+
+;; http://www.cliki.net/MOP%20design%20patterns
+#+nil ;; TODO add persistent-object superclass automatically
+(defmethod initialize-instance :around ((class persistent-class) &rest initargs
+ &key direct-superclasses)
+ (declare (dynamic-extent initargs))
+ (init-instance))
+
+;; http://www.cliki.net/MOP%20design%20patterns
+#+nil ;; TODO add persistent-object superclass automatically
+(defmethod reinitialize-instance :around
+ ((class persistent-class) &rest initargs
+ &key (direct-superclasses '() direct-superclasses-p))
+ (declare (dynamic-extent initargs))
+ (if direct-superclasses-p
+ ;; if direct superclasses are explicitly passed this is exactly
+ ;; like above
+ (init-instance)
+ ;; if direct superclasses are not explicitly passed we _must_
+ ;; not change anything
+ (call-next-method)))
+
+(defparameter *initializing-instance* nil)
+
+(defun check-cached-instance (a)
+ (unless *initializing-instance*
+ (assert (eq a (gethash (oid a) *instance-cache*)))))
+
+(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 c2mop:slot-value-using-class :before ((class persistent-class)
+ (a %persistent-object)
+ slotd)
+ (unless (eq 'oid (c2mop:slot-definition-name slotd))
+ (check-cached-instance a)))
+
+(defmethod (setf c2mop:slot-value-using-class) :before (value
+ (class persistent-class)
+ (a %persistent-object)
+ slotd)
+ (unless (eq 'oid (c2mop:slot-definition-name slotd))
+ (check-cached-instance a)))
+
+(defstruct proxy oid)
+
+(defmethod c2mop:slot-value-using-class :around ((class persistent-class)
+ (a %persistent-object)
+ slotd)
+ (let ((a (call-next-method)))
+ a
+ #+nil ;; TODO only for proxy slots
+ (etypecase a
+ (proxy (error "TODO maybe-dereference-proxy ~s" a))
+ (%persistent-object a))))
+
+(defmethod (setf c2mop:slot-value-using-class) :around (value
+ (class persistent-class)
+ (a %persistent-object)
+ slotd)
+ (call-next-method)
+ #+nil(error "TODO (setf c2mop:slot-value-using-class) :around"))
+
+;;; persistent slots
+
+(defclass persistent-slot-definition ()
+ ((ltype :reader ltype) ;; remember unexpanded
+ (ptype :reader ptype) ;; remember computed
+ (nullable :reader nullable)
+ (transient :type boolean :initarg :transient :initform nil :accessor transient)))
+
+(defclass persistent-direct-slot-definition
+ (persistent-slot-definition c2mop:standard-direct-slot-definition)
+ ())
+
+(defclass persistent-effective-slot-definition
+ (persistent-slot-definition c2mop:standard-effective-slot-definition)
+ ())
+
+(defmethod c2mop:direct-slot-definition-class :around
+ ((class persistent-class) &rest initargs)
+ ;;(print (list :@@@-direct-slot-definition-class initargs))
+ (find-class 'persistent-direct-slot-definition))
+
+(defmethod c2mop:effective-slot-definition-class
+ ((class persistent-class) &rest initargs)
+ ;;(format t "getting eff class. initargs=~s~%" initargs)
+ (find-class 'persistent-effective-slot-definition))
+
+#+nil
+(defmethod c2mop:compute-effective-slot-definition
+ ((class persistent-class) slot-name direct-slots)
+ (call-next-method)
+ #+nil
+ (format t "computing slot definition: class=~s name=~s slots=~s~%"
+ class slot-name direct-slots)
+ #+nil
+ (let ((result (call-next-method)))
+ ;;(break "~s" result)
+ #+nil
+ (format t " result: ~s~%" result)
+ result))
+
+(defmethod initialize-instance :before
+ ((class persistent-direct-slot-definition) &rest initargs
+ &key direct-superclasses)
+ (declare (ignore direct-superclasses))
+ (with-slots (ltype ptype nullable) class ;; TODO transient
+ (setq ltype (getf initargs :type)
+ ptype (lisp-type-to-ptype ltype)
+ nullable (unless (eql 'boolean ltype)
+ (typep nil ltype)))))
+
+(defmethod c2mop:compute-effective-slot-definition :around
+ ((class persistent-class) name direct-slot-definitions)
+ (let ((x (call-next-method)))
+ (assert (not (cdr direct-slot-definitions))) ;; TODO
+ (let ((slotd (car direct-slot-definitions)))
+ (assert (typep slotd 'persistent-slot-definition))
+ (with-slots (ltype ptype nullable) x ;; TODO transient
+ (setq ltype (ltype slotd)
+ ptype (ptype slotd)
+ nullable (nullable slotd))))
+ x))
+
+#+nil
+(defmethod initialize-instance :around
+ ((class persistent-direct-slot-definition) &rest initargs
+ &key direct-superclasses)
+ ;;(declare (ignore direct-superclasses))
+ #+nil
+ (with-slots (ltype ptype nullable) class
+ (setq ltype (getf initargs :type)
+ ptype (lisp-type-to-ptype ltype)
+ nullable (unless (eql 'boolean ltype)
+ (typep nil ltype))))
+ (call-next-method)
+ #+nil
+ (let ((ltype (getf initargs :type)))
+ (apply #'call-next-method
+ class
+ `(:ltype ,ltype
+ :ptype ,(lisp-type-to-ptype ltype)
+ :nullable ,(unless (eql 'boolean ltype)
+ (typep nil ltype))
+ ,@initargs)
+ direct-superclasses)))
+
+#+nil
+(defclass foo ()
+ ((hi :initarg :hi)))
+
+;;(c2mop:class-slots (find-class 'foo))
+
+#+nil
+(defclass person (#+nil persistent-object foo)
+ ((name :type string :initarg :name #+nil :transient #+nil t)
+ (age :type natural0 :initarg :age))
+ (:metaclass persistent-class))
+
+;;(slot-value (make-instance 'person :age 12) 'age)
+
+;;(c2mop:class-slots (find-class 'person))
+
+#+nil
+(defclass person2 (persistent-object foo)
+ ((name :type string :initarg :name #+nil :transient #+nil t)
+ (age :type natural0 :initarg :age))
+ (:metaclass persistent-class))
+
+;;(c2mop:ensure-finalized (find-class 'person2))
+;;(c2mop:class-slots (find-class 'person2))
+
+#+nil
+(let ((x (make-instance 'person :hi "cus" :name "John" :age 12)))
+ (dolist (s (c2mop:class-slots (class-of x)))
+ (format t "slot ~s = ~s~%"
+ (c2mop:slot-definition-name s)
+ (slot-value x (c2mop:slot-definition-name s)))))
+
+#+nil
+(defun persistent-slot-p (slot)
+ (when (typep slot 'persistent-slot)
+ (transient slot)))
+
+#+nil
+(defun list-pslots2 (class)
+ (c2mop:class-slots class)
+ #+nil
+ (remove-if 'transient (c2mop:class-slots class)))
+
+;;(list-pslots (find-class 'person))
+;;(list-pslots (class-of (make-instance 'person :hi "cus" :name "John" :age 12)))
+
+
+
+
+;; TODO revert to defmethod or hook initialize-instance, ccl expands types too early:-{
+(defun list-pslots (class)
+ (c2mop:class-slots (if (symbolp class) (find-class class) class)))
+
+(defun pslot-name (a)
+ (c2mop:slot-definition-name a))
+
+(defun pslot-ltype (a)
+ (ltype a))
+
+(defun pslot-initargs (a)
+ (c2mop:slot-definition-initargs a))
+
+(defun pslot-initform (a)
+ (c2mop:slot-definition-initform a))
+
+(defun pslot-ptype (a)
+ (ptype a))
+
+(defun pslot-nullable (a)
+ (nullable a))
+
+;; (pslot-ptype (cadr (list-pslots (find-class 'person))))
+
+#+nil
+(defpclass bar ()
+ ((slot1 :initarg :slot1 :accessor slot1)
+ (slot2 :initarg :slot2 :accessor slot2)))
+
+;;(with-instance-cache () (slot2 (make-pinstance 'bar :oid 123 :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)
+
+#+nil
+(defpclass person ()
+ ((name :type string :initarg :name)
+ (age :type natural0 :initarg :age))
+ #+nil
+ (:metaclass persistent-class))
+
+#+nil
+(defpclass person ()
+ ((name :type string :initarg :name)
+ (birth-date :type pdate :initarg :birth-date))
+ #+nil
+ (:metaclass persistent-class))
+
+
+
+;;; http://www.b9.com/blog/archives/000084.html
+;;
+;; Also, special thanks to Christophe Rhodes, frequent contributor to
+;; SBCL's MOP, for his excellent suggestion in response to a question
+;; for improving CLSQL's MOP internals: CLSQL object definitions use
+;; custom slot types. For example, a CLSQL slot may have :type
+;; (varchar 10) specified which gets translated to a lisp type of (or
+;; null string). Rather than parsing and then re-storing the type
+;; atrribute of a slot in compute-effective-slot-definiton, Christophe
+;; suggested performing the type parsing in initialize-instance
+;; :around of the CLSQL direct-slot-definition object. Then, the real
+;; type attribute is stored in the both the direct and effective slot
+;; definition from the beginning.This is more AMOP complaint since
+;; AMOP doesn't specify that one may change the type attribute of a
+;; slot. This is clearly seen since CLSQL no longer needs to modify
+;; OpenMCL's ccl:type-predicate slot attribute after the type was
+;; changed in compute-effective-slot-definition.
+
+
+(defclass persistent-object (%persistent-object)
+ ((oid :type oid :initarg :oid :accessor oid))
+ (:metaclass persistent-class))
+
(defmethod cl-postgres:to-sql-string ((a persistent-object))
(cl-postgres:to-sql-string (oid a)))
+;;; db stuff
+
(defconstant +class-id-bit-size+ 16)
(defmacro oid-exp (class-id)
@@ -158,7 +482,7 @@
(q:returning ,returning-cols))))
(defun assert-type (value type)
- (print (list :assert-type1 value type (type-of value)))
+ ;;(print (list :assert-type1 value type (type-of value)))
(unless (typep value type)
(cond ;; TODO more cases
((typep value 'string)
@@ -172,10 +496,14 @@
:timezone nil))))
((subtypep type 'persistent-object)
(error "TODO assert-type persistent-object"))))
- (print (list :assert-type2 value type (type-of value)))
+ ;;(print (list :assert-type2 value type (type-of value)))
(assert (typep value type))
value)
+(defun cache-pinstance (a)
+ (assert (not (gethash (oid a) *instance-cache*)))
+ (setf (gethash (oid a) *instance-cache*) a))
+
(defun make-pinstance (class-name &rest args)
(multiple-value-bind (known unknown)
(loop
@@ -187,20 +515,19 @@
if c collect (list (cadr c) name initarg ltype) into known
else collect (list name initarg ltype) into unknown
finally (return (values known unknown)))
- (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 unknown
- for v in (car
- (insert-into class-name (mapcar #'cadr known)
- (mapcar #'car known)
- (mapcar #'car unknown)))
- appending (list initarg (assert-type v ltype)))))))
- (assert (not (gethash (oid x) *instance-cache*)))
- (setf (gethash (oid x) *instance-cache*) x))))
+ (cache-pinstance
+ (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 unknown
+ for v in (car
+ (insert-into class-name (mapcar #'cadr known)
+ (mapcar #'car known)
+ (mapcar #'car unknown)))
+ appending (list initarg (assert-type v ltype))))))))
(defparameter *instance-collector-cache* nil) ;; equal form->fn
@@ -239,12 +566,14 @@
(defmacro instance (tab &optional alias) ;; use inside 2sql queries
(let ((pslots (list-pslots tab)))
(push (lambda (row)
- (values (let ((oid (pop row))
+ (values (let ((oid (car row))
(args (loop
for x in pslots
- appending (list (car (pslot-initargs x)) (pop row))))) ;; TODO resolve pclassp foreign ref (lazy foreign reference?)
+ appending (list (car (pslot-initargs x))
+ (assert-type (pop row) (pslot-ltype x)))))) ;; TODO resolve pclassp foreign ref (lazy foreign reference?)
+ ;;(print (list :@@@ (mapcar (lambda (x) (cons x (type-of x))) args)))
(or (gethash oid *instance-cache*)
- (apply #'make-pinstance tab :oid oid args)) ;; TODO test this case
+ (cache-pinstance (apply #'make-instance tab args)))
#+nil
(unless (eq :null oid)
;; TODO uniq oid->instance cache