Function: closql-dset

closql-dset is a byte-compiled function defined in closql.el.

Signature

(closql-dset OBJ SLOT VALUE &optional DROP-UNKNOWN)

Implementations

(closql-dset OBJ SLOT VALUE &optional DROP-UNKNOWN) in `closql.el'.

Undocumented

Source Code

;; Defined in ~/.emacs.d/elpa/closql-20260101.1828/closql.el
(cl-defgeneric closql-dset (obj slot value &optional drop-unknown)
  (let* ((db    (closql--oref obj 'closql-database))
         (key   (oref-default obj closql-primary-key))
         (id    (closql--oref obj key))
         (props (closql--slot-properties obj slot)))
    (cond-let
      ((alist-get :closql-class props)
       (error "Not implemented for closql-class slots: oset"))
      [[tables (alist-get :closql-tables props)]]
      ([table (or (alist-get :closql-table props)
                  (car tables))]
       (closql-with-transaction db
         (let ((columns (closql--table-columns db table)))
           ;; Caller might have modified value in place.
           (closql--oset obj slot eieio--unbound)
           (let ((list1 (closql-oref obj slot))
                 (list2 value)
                 elt1 elt2)
             (cond (tables
                    (setq list1 (mapcar (lambda (e) (list (car e))) list1))
                    (setq list2 (mapcar (if (atom (car list2))
                                            #'list
                                          (lambda (e) (list (car e))))
                                        list2)))
                   ((length= columns 2)
                    (setq list1 (mapcar #'list list1))
                    (setq list2 (mapcar #'list list2))))
             ;; `list2' may not be sorted at all and `list1' has to
             ;; be sorted because Elisp and SQLite sort differently.
             (setq list1 (cl-sort list1 #'string< :key #'car))
             (setq list2 (cl-sort list2 #'string< :key #'car))
             (while (progn (setq elt1 (car list1))
                           (setq elt2 (car list2))
                           (or elt1 elt2))
               (let ((key1 (car elt1))
                     (key2 (car elt2)))
                 (cond
                   ((and elt1 (or (not elt2) (string< key1 key2)))
                    (apply #'emacsql db
                           `[:delete-from $i1
                             :where ,(closql--where-equal (cons id elt1) 1)]
                           table
                           (cl-mapcan #'list columns (cons id elt1)))
                    (pop list1))
                   ((string= key1 key2)
                    (unless (equal elt1 elt2)
                      (cl-mapc
                       (lambda (col val1 val2)
                         (unless (equal val1 val2)
                           (emacsql db [:update $i1 :set (= $i2 $s3)
                                        :where (and (= $i4 $s5) (= $i6 $s7))]
                                    table col val2
                                    (car  columns) id
                                    (cadr columns) key2)))
                       (cddr columns)
                       (cdr  elt1)
                       (cdr  elt2)))
                    (pop list1)
                    (pop list2))
                   (drop-unknown
                    (ignore-errors
                      (emacsql db [:insert-into $i1 :values $v2]
                               table (vconcat (cons id elt2))))
                    (pop list2))
                   (t
                    (emacsql db [:insert-into $i1 :values $v2]
                             table (vconcat (cons id elt2)))
                    (pop list2)))))))))
      ((emacsql db [:update $i1 :set (= $i2 $s3) :where (= $i4 $s5)]
                (oref-default obj closql-table)
                slot
                (if (eq value eieio--unbound) 'eieio-unbound value)
                key id)))))