Skip to content

store a list of daos in a slot #177

@hermanhel

Description

@hermanhel

The following should allow usage of :daos in :col-type which accepts a list of dao that have already been mito:save-dao-ed to the same db.

(defun mito-id (obj)
  (slot-value obj 'mito.dao.mixin::id))

(defun daos-to-table-ids (daos)
  (if daos
      (format nil "~A" (mapcar (lambda (dao) (list (type-of dao) (mito-id dao))) daos))
      "()"))

(defun table-ids-to-daos (str)
  (mapcar (lambda (elt)
            (let ((class (first elt))
                  (id (second elt)))
              (mito:find-dao class :id id)))
          (read-from-string (or str "()")))

(defmethod mito.dao.column:deflate-for-col-type ((col-type (eql :daos)) value)
  (pat2::daos-to-table-ids value))

(defmethod mito.dao.column:inflate-for-col-type ((col-type (eql :daos)) value)
    (pat2::table-ids-to-daos value))

For example

(deftable foo ()
  ())
(deftable bar ()
  ((foos :accessor foos
         :initform nil
         :col-type (or :null :daos))))

(let ((foo1 (make-instance 'foo))
      (bar1 (make-instance 'bar)))
  (connect-toplevel :sqlite3 :database-name ":memory:")
  (ensure-table-exists 'foo)
  (ensure-table-exists 'bar)
  (push foo1 (foos bar1))
  (save-dao foo1)
  (save-dao bar1)
  (foos (car (select-dao 'bar))))
;; => (#<FOO {100ABBF303}>)

couple of gotchas:

  • type-of do not return symbol with package name, so any class you use in the :daos slot need to be imported and available in the current package, otherwise find-dao will complain.
  • in table schema and create-table the slot's column will be of type daos. This is fine in sqlite3 and the column is stored as text (or blob, not sure). May pose problem in mysql/postgresql. I imagine this could be solved with an :around on mito.class.column:table-column-info, or redefinition of the main adding a cond clause for each driver-type, maping :col-type :dao to :varchar or something.
  • the objects in :daos slot need to be saved before the object with :daos slot is saved. with the example above, foo objects in (foos bar1) needs to be save-dao-ed before bar1 is save-daoed, as the foo object is refered to with its id, which is filled in save-dao.

One more thing is that similar custom col-type can be made easily with defmethod on the above 2 methods. I imagine it would be useful for repeated slot definition with the same set of :inflate and :deflate, which is what I did before this.

2 other examples are :ignored col-type with both methods defined to return nil, hence its column in table is always null, and retrived dao nil. I used that on slots with mostly functions that I reset with other functions in code; and :princ col-type that uses princ-to-string and read-from-string for deflate and inflate, used on list of printable objects, as currently list in slot will result in error in sxql.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions