- (database *default-database*))
- (let* ((database (or (view-database obj) database))
- (vct (view-table (class-of obj)))
- (sds (slotdefs-for-slots-with-class slots (class-of obj)))
- (avps (mapcar #'(lambda (s)
- (let ((val (slot-value
- obj (slot-definition-name s))))
- (check-slot-type s val)
- (list (sql-expression
- :attribute (view-class-slot-column s))
- (db-value-from-slot s val database))))
- sds)))
- (cond ((and avps (view-database obj))
- (update-records (sql-expression :table vct)
- :av-pairs avps
- :where (key-qualifier-for-instance
- obj :database database)
- :database database))
- ((and avps (not (view-database obj)))
- (insert-records :into (sql-expression :table vct)
- :av-pairs avps
- :database database)
- (setf (slot-value obj 'view-database) database))
- (t
- (error "Unable to update records"))))
- (values))
+ (database *default-database*))
+ (let ((database (or database (view-database obj) *default-database*))
+ (pk nil))
+ (labels
+ ((sstoredp (slot) (member (view-class-slot-db-kind slot) '(:base :key)))
+ (sboundp (slot) (slot-boundp obj (slot-definition-name slot)))
+ (slot-value-list (slot)
+ (let ((value (slot-value obj (slot-definition-name slot))))
+ (check-slot-type slot value)
+ (list (sql-expression :attribute (view-class-slot-column slot))
+ (db-value-from-slot slot value database))))
+
+ (save-slots-for-class (view-class stored-slot-defs)
+ (let ((pk-slot (car (keyslots-for-class view-class)))
+ (table (sql-expression :table (view-table view-class)))
+ (pclass (car (class-direct-superclasses view-class)))
+
+ direct-slots ; the slots to save on this iteration
+ parent-slots ; slots to handle recursively
+ )
+ (if (normalizedp view-class)
+ (let ((cdsn (mapcar #'slot-definition-name
+ (class-direct-slots view-class))))
+ (dolist (s stored-slot-defs)
+ (if (member (slot-definition-name s) cdsn)
+ (push s direct-slots)
+ (push s parent-slots))))
+ ;;not normalized, do everything now.
+ (setf direct-slots stored-slot-defs))
+ '(break "Class:~a ~%direct-slots:~a ~%parent-slots:~a ~%~a"
+ view-class direct-slots parent-slots
+ (class-direct-slots view-class))
+ (when parent-slots
+ ;;call recursively, collect primary key if we have it
+ (save-slots-for-class pclass parent-slots)
+ (when (and pk pk-slot)
+ (setf (slot-value obj (slot-definition-name pk-slot)) pk)))
+
+ ;;we've delayed doing the unbound test till here because
+ ;;the keys are sometimes only bound while updating the pclass
+ (let ((av-pairs (mapcar #'slot-value-list
+ (remove-if-not #'sboundp direct-slots))))
+ (cond
+ ((null av-pairs) nil)
+ ((view-database obj)
+ (update-records table
+ :av-pairs av-pairs
+ :where (key-qualifier-for-instance
+ obj :database database
+ :this-class view-class)
+ :database database)
+ (when (and pk-slot (not pk))
+ (setf pk (slot-value obj (slot-definition-name pk-slot))))
+ pk)
+ (t
+ (insert-records :into table
+ :av-pairs av-pairs
+ :database database)
+ (when (and pk-slot (not pk))
+ (setf pk (if (member :auto-increment (listify (view-class-slot-db-constraints pk-slot)))
+ (setf (slot-value obj (slot-definition-name pk-slot))
+ (database-last-autoincrement-id database
+ table
+ pk-slot))))
+
+ )
+ pk))))))
+
+
+ (save-slots-for-class
+ (class-of obj)
+ ;;convert to slot-defs, remove any non-stored.
+ (loop for s in slots
+ for sd = (etypecase s
+ (symbol (slotdef-for-slot-with-class s (class-of obj)))
+ (slot-definition s))
+ when (sstoredp sd)
+ collect sd))
+ ;;this may just be a NOP.
+ (setf (slot-value obj 'view-database) database)))