X-Git-Url: http://git.kpe.io/?p=clsql.git;a=blobdiff_plain;f=sql%2Fobjects.lisp;h=8fa98903a85450c436d20258b91cdb4c81345c68;hp=ce6022c131130cc7ced8137419c468c8ee77c071;hb=155c60b5195d618ef93541699694d57a21be3246;hpb=8a8ee2d7d791b7a3efaed06420802a925d16fca3 diff --git a/sql/objects.lisp b/sql/objects.lisp index ce6022c..8fa9890 100644 --- a/sql/objects.lisp +++ b/sql/objects.lisp @@ -806,16 +806,61 @@ superclass of the newly-defined View Class." (defun update-object-joins (objects &key (slots t) (force-p t) class-name (max-len *default-update-objects-max-len*)) - "Updates the remote join slots, that is those slots defined without :retrieval :immediate." + "Updates the remote join slots, that is those slots defined without +:retrieval :immediate." + (assert (or (null max-len) (plusp max-len))) (when objects (unless class-name - (class-name (class-of (first objects)))) + (setq class-name (class-name (class-of (first objects))))) (let* ((class (find-class class-name)) - (deferred-joins (generate-retrieval-joins-list class :deferred))) - (when deferred-joins - (warn "not yet implemented.") - )))) - + (class-slots (ordered-class-slots class)) + (slotdefs + (if (eq t slots) + (generate-retrieval-joins-list class :deferred) + (remove-if #'null + (mapcar #'(lambda (name) + (let ((slotdef (find name class-slots :key #'slot-definition-name))) + (unless slotdef + (warn "Unable to find slot named ~S in class ~S." name class)) + slotdef)) + slots))))) + (dolist (slotdef slotdefs) + (let* ((dbi (view-class-slot-db-info slotdef)) + (slotdef-name (slot-definition-name slotdef)) + (foreign-key (gethash :foreign-key dbi)) + (home-key (gethash :home-key dbi)) + (object-keys + (remove-duplicates + (if force-p + (mapcar #'(lambda (o) (slot-value o home-key)) objects) + (remove-if #'null + (mapcar + #'(lambda (o) (if (slot-boundp o slotdef-name) + nil + (slot-value o home-key))) + objects))))) + (n-object-keys (length object-keys)) + (query-len (or max-len n-object-keys))) + + (do ((i 0 (+ i query-len))) + ((>= i n-object-keys)) + (let* ((keys (if max-len + (subseq object-keys i (min (+ i query-len) n-object-keys)) + object-keys)) + (results (find-all (list (gethash :join-class dbi)) + :where (make-instance 'sql-relational-exp + :operator 'in + :sub-expressions (list (sql-expression :attribute foreign-key) + keys)) + :flatp t))) + (dolist (object objects) + (when (or force-p (not (slot-boundp object slotdef-name))) + (let ((res (find (slot-value object home-key) results + :key #'(lambda (res) (slot-value res foreign-key)) + :test #'equal))) + (when res + (setf (slot-value object slotdef-name) res))))))))))) + (values)) (defun fault-join-slot-raw (class object slot-def) (let* ((dbi (view-class-slot-db-info slot-def)) @@ -882,49 +927,51 @@ superclass of the newly-defined View Class." ;; For example, for (select 'employee-address) in test suite => ;; select addr.*,ea_join.* FROM addr,ea_join WHERE ea_join.aaddressid=addr.addressid\g -(defun build-objects (vals sclasses immediate-join-classes sels immediate-joins database refresh flatp) +(defun build-objects (vals sclasses immediate-join-classes sels immediate-joins database refresh flatp instances) "Used by find-all to build objects." - (labels ((build-object (vals vclass jclasses selects immediate-selects) - (let* ((class-name (class-name vclass)) - (db-vals (butlast vals (- (list-length vals) + (labels ((build-object (vals vclass jclasses selects immediate-selects instance) + (let* ((db-vals (butlast vals (- (list-length vals) (list-length selects)))) + (obj (if instance instance (make-instance (class-name vclass) :view-database database))) (join-vals (subseq vals (list-length selects))) - (obj (make-instance class-name :view-database database)) (joins (mapcar #'(lambda (c) (when c (make-instance c :view-database database))) jclasses))) ;;(format t "db-vals: ~S, join-values: ~S~%" db-vals join-vals) ;; use refresh keyword here - (setf obj (get-slot-values-from-view obj (mapcar #'car selects) - db-vals)) + (setf obj (get-slot-values-from-view obj (mapcar #'car selects) db-vals)) (mapc #'(lambda (jc) (get-slot-values-from-view jc (mapcar #'car immediate-selects) join-vals)) joins) (mapc - #'(lambda (jc) (let ((slot (find (class-name (class-of jc)) (class-slots vclass) - :key #'(lambda (slot) (when (and (eq :join (view-class-slot-db-kind slot)) - (eq (slot-definition-name slot) - (gethash :join-class (view-class-slot-db-info slot)))) - (slot-definition-name slot)))))) - (when slot - (setf (slot-value obj (slot-definition-name slot)) jc)))) - + #'(lambda (jc) + (let ((slot (find (class-name (class-of jc)) (class-slots vclass) + :key #'(lambda (slot) + (when (and (eq :join (view-class-slot-db-kind slot)) + (eq (slot-definition-name slot) + (gethash :join-class (view-class-slot-db-info slot)))) + (slot-definition-name slot)))))) + (when slot + (setf (slot-value obj (slot-definition-name slot)) jc)))) joins) (when refresh (instance-refreshed obj)) obj))) - (let ((objects (mapcar #'(lambda (sclass jclass sel immediate-join) - (prog1 (build-object vals sclass jclass sel immediate-join) - (setf vals (nthcdr (+ (list-length sel) (list-length immediate-join)) - vals)))) - sclasses immediate-join-classes sels immediate-joins))) + (let* ((objects + (mapcar #'(lambda (sclass jclass sel immediate-join instance) + (prog1 + (build-object vals sclass jclass sel immediate-join instance) + (setf vals (nthcdr (+ (list-length sel) (list-length immediate-join)) + vals)))) + sclasses immediate-join-classes sels immediate-joins instances))) (if (and flatp (= (length sclasses) 1)) (car objects) - objects)))) + objects)))) (defun find-all (view-classes &rest args &key all set-operation distinct from where group-by having - order-by order-by-descending offset limit refresh - flatp result-types inner-join on - (database *default-database*)) + order-by offset limit refresh flatp result-types + inner-join on + (database *default-database*) + instances) "Called by SELECT to generate object query results when the View Classes VIEW-CLASSES are passed as arguments to SELECT." (declare (ignore all set-operation group-by having offset limit inner-join on) @@ -943,14 +990,17 @@ superclass of the newly-defined View Class." (remf args :flatp) (remf args :additional-fields) (remf args :result-types) + (remf args :instances) (let* ((*db-deserializing* t) (sclasses (mapcar #'find-class view-classes)) - (immediate-join-slots (mapcar #'(lambda (c) (generate-retrieval-joins-list c :immediate)) sclasses)) - (immediate-join-classes (mapcar #'(lambda (jcs) - (mapcar #'(lambda (slotdef) - (find-class (gethash :join-class (view-class-slot-db-info slotdef)))) - jcs)) - immediate-join-slots)) + (immediate-join-slots + (mapcar #'(lambda (c) (generate-retrieval-joins-list c :immediate)) sclasses)) + (immediate-join-classes + (mapcar #'(lambda (jcs) + (mapcar #'(lambda (slotdef) + (find-class (gethash :join-class (view-class-slot-db-info slotdef)))) + jcs)) + immediate-join-slots)) (immediate-join-sels (mapcar #'generate-immediate-joins-selection-list sclasses)) (sels (mapcar #'generate-selection-list sclasses)) (fullsels (apply #'append (mapcar #'append sels immediate-join-sels))) @@ -970,12 +1020,6 @@ superclass of the newly-defined View Class." (setq fullsels (append fullsels (mapcar #'(lambda (att) (cons nil att)) (listify ob)))))) - (dolist (ob (listify order-by-descending)) - (when (and ob (not (member ob (mapcar #'cdr fullsels) - :test #'ref-equal))) - (setq fullsels - (append fullsels (mapcar #'(lambda (att) (cons nil att)) - (listify ob)))))) (dolist (ob (listify distinct)) (when (and (typep ob 'sql-ident) (not (member ob (mapcar #'cdr fullsels) @@ -1008,10 +1052,22 @@ superclass of the newly-defined View Class." (list :result-types result-types) (when where (list :where where)) args))) + (instances-to-add (- (length rows) (length instances))) + (perhaps-extended-instances + (if (plusp instances-to-add) + (append instances (do ((i 0 (1+ i)) + (res nil)) + ((= i instances-to-add) res) + (push (make-list (length sclasses) :initial-element nil) res))) + instances)) (objects (mapcar - #'(lambda (r) - (build-objects r sclasses immediate-join-classes sels immediate-join-sels database refresh flatp)) - rows))) + #'(lambda (row instance) + (build-objects row sclasses immediate-join-classes sels + immediate-join-sels database refresh flatp + (if (and flatp (atom instance)) + (list instance) + instance))) + rows perhaps-extended-instances))) objects)))) (defmethod instance-refreshed ((instance standard-db-object))) @@ -1057,8 +1113,8 @@ ENABLE-SQL-READER-SYNTAX." (query-get-selections select-all-args) (cond ((select-objects target-args) - (let ((caching (getf qualifier-args :caching)) - (refresh (getf qualifier-args :refresh)) + (let ((caching (getf qualifier-args :caching t)) + (refresh (getf qualifier-args :refresh nil)) (database (or (getf qualifier-args :database) *default-database*))) (remf qualifier-args :caching) (remf qualifier-args :refresh) @@ -1071,7 +1127,9 @@ ENABLE-SQL-READER-SYNTAX." ((and cached (not refresh)) cached) ((and cached refresh) - (update-cached-results target-args qualifier-args database)) + (let ((results (apply #'find-all (append (list target-args) qualifier-args `(:instances ,cached))))) + (setf (records-cache-results target-args qualifier-args database) results) + results)) (t (let ((results (apply #'find-all target-args qualifier-args))) (setf (records-cache-results target-args qualifier-args database) results)