-(defun update-objects-joins (objects &key (slots t) (force-p t)
- class-name (max-len
- *default-update-objects-max-len*))
- "Updates from the records of the appropriate database tables
-the join slots specified by SLOTS in the supplied list of View
-Class instances OBJECTS. SLOTS is t by default which means that
-all join slots with :retrieval :immediate are updated. CLASS-NAME
-is used to specify the View Class of all instance in OBJECTS and
-default to nil which means that the class of the first instance
-in OBJECTS is used. FORCE-P is t by default which means that all
-join slots are updated whereas a value of nil means that only
-unbound join slots are updated. MAX-LEN defaults to
-*DEFAULT-UPDATE-OBJECTS-MAX-LEN* and when non-nil specifies that
-UPDATE-OBJECT-JOINS may issue multiple database queries with a
-maximum of MAX-LEN instances updated in each query."
+(defun %update-objects-joins-slot-defs (class slot-names)
+ "Get the slot definitions for the joins slots specified as slot-names
+ if slot-names is :immediate, :deferred or (or :all t) return all of
+ that type of slot definitions"
+ (setf class (to-class class))
+ (when (eq t slot-names) (setf slot-names :all))
+ (etypecase slot-names
+ (null nil)
+ (keyword
+ ;; slot-names is the retrieval type of the join-slot or :all
+ (get-join-slots class slot-names))
+ ((or symbol list)
+ (loop for slot in (listify slot-names)
+ for def = (find-slot-by-name class slot)
+ when (and def (join-slot-p def))
+ collecting def
+ unless (and def (join-slot-p def))
+ do (warn "Unable to find join slot named ~S in class ~S." slot class)))))
+
+(defun get-joined-objects (objects slotdef &key force-p
+ (batch-size *default-update-objects-max-len*))
+ "Given a list of objects and a join slot-def get the objects that need to be
+ joined to the input objects
+
+ we will query in batches as large as batch-size"
+ (when (join-slot-p slotdef)
+ (let* ((slot-name (to-slot-name slotdef))
+ (join-class (join-slot-class-name slotdef))
+ (home-key (join-slot-info-value slotdef :home-key))
+ (foreign-key (join-slot-info-value slotdef :foreign-key))
+ (foreign-key-values
+ (remove-duplicates
+ (loop for object in (listify objects)
+ for hk = (slot-value object home-key)
+ when (or force-p
+ (not (slot-boundp object slot-name)))
+ collect hk)
+ :test #'equal)))
+ ;; we want to retrieve at most batch-size objects per query
+ (flet ((fetch (keys)
+ (find-all
+ (list join-class)
+ :where (make-instance
+ 'sql-relational-exp
+ :operator 'in
+ :sub-expressions (list (sql-expression :attribute foreign-key)
+ keys))
+ :result-types :auto
+ :flatp t)))
+ (if (null batch-size)
+ (fetch foreign-key-values)
+ (loop
+ for keys = (pop-n foreign-key-values batch-size)
+ while keys
+ nconcing (fetch keys)))))))
+
+(defun %object-joins-from-list (object slot joins force-p )
+ "Given a list of objects that we are trying to join to, pull the correct
+ ones for this object"
+ (when (or force-p (not (slot-boundp object (to-slot-name slot))))
+ (let ((home-key (join-slot-info-value slot :home-key))
+ (foreign-key (join-slot-info-value slot :foreign-key)))
+ (loop for join in joins
+ when (equal (slot-value join foreign-key)
+ (slot-value object home-key))
+ collect join))))
+
+(defun update-objects-joins (objects &key (slots :immediate) (force-p t)
+ class-name (max-len *default-update-objects-max-len*))
+ "Updates from the records of the appropriate database tables the join slots
+ specified by SLOTS in the supplied list of View Class instances OBJECTS.
+
+ A simpler method of causing a join-slot to be requeried is to set it to
+ unbound, then request it again. This function has efficiency gains where
+ join-objects are shared among the `objects` (querying all join-objects,
+ then attaching them appropriately to each of the `objects`)
+
+ SLOTS can be one of:
+
+ * :immediate (DEFAULT) - refresh join slots created with :retrieval :immediate
+ * :deferred - refresh join slots created with :retrieval :deferred
+ * :all,t - refresh all join slots regardless of :retrieval
+ * list of symbols - which explicit slots to refresh
+ * a single symobl - what slot to refresh
+
+ CLASS-NAME is used to specify the View Class of all instance in OBJECTS and
+ default to nil which means that the class of the first instance in OBJECTS
+ is used.
+
+ FORCE-P is t by default which means that all join slots are updated whereas
+ a value of nil means that only unbound join slots are updated.
+
+ MAX-LEN defaults to *DEFAULT-UPDATE-OBJECTS-MAX-LEN* When non-nil this is
+ essentially a batch size for the max number of objects to query from the
+ database at a time. If we need more than max-len we loop till we have all
+ the objects"