Skip to content

Instantly share code, notes, and snippets.

@akashpal-21
Last active May 21, 2024 12:32
Show Gist options
  • Save akashpal-21/5991e99949af5feb0f75729374ce3d66 to your computer and use it in GitHub Desktop.
Save akashpal-21/5991e99949af5feb0f75729374ce3d66 to your computer and use it in GitHub Desktop.
org-roam-node-cache.el
;; org-roam-node-cache.el
;; When `org-roam-node-read' is called --
;; `org-roam-node-read--completions' is initiated which fetches the list of struct nodes, applies FILTER-FN if any,
;; then formats them as specified by `org-roam-node-display-template' and finally
;; after sorting according to `org-roam-node-default-sort' or user SORT-FN
;; passes this final list further down.
;; `org-roam-node-read--completions' makes two subcalls -
;; A. To `org-roam-node-list' which queries the db and generates a nodes struct for each node.
;; B. To `org-roam-node-read--to-candidate' which formats the struct nodes according to the display template
;; Processes ranked most expensive to least expensive
;; 1. `org-roam-node-read--to-candidate' -- final formatting
;; 2. `org-roam-node-list' -- initial formatting & db query
;; 3. rest of `org-roam-node-read--completions' (filtering and sorting)
;; By default Basic cache is enabled.
(defcustom org-roam-node-cache-level 1
"Level of caching for Org-roam nodes.
1: Basic cache (cache candidate formatting only).
2: Partial cache (cache candidate formatting & node list).
3: Full cache (cache candidate formatting, node list, filter-function & sort-function).
If changed when `org-roam-node-cache-mode' is active - restart mode."
:group 'org-roam
:type '(choice (const :tag "Basic cache" 1)
(const :tag "Partial cache" 2)
(const :tag "Full cache" 3)))
; Definitions
(defvar org-roam-node-cache-candidate-format (make-hash-table :test 'equal)
"The Cache of candidate formatting")
(defvar org-roam-node-cache-time nil
"Time when the node-cache was taken")
(defvar org-roam-node-cache-list nil
"The Cache of Org-roam nodes")
(defvar org-roam-node-cache-candidate-list nil
"The Cache of final candidate list")
(defvar org-roam-node-cache-prev-filter-fn nil
"Store the last FILTER-FN if any")
(defvar org-roam-node-cache-prev-sort-fn nil
"Store the last SORT-FN if any")
(defun cached/org-roam-node-read--to-candidate (fn &rest args)
(or (gethash args org-roam-node-cache-candidate-format)
(let ((result (apply fn args)))
(puthash args result org-roam-node-cache-candidate-format)
result)))
(defun cached/org-roam-node-list (fn &optional force-refresh &rest args)
;; Node list Cache nullification logic
(unless (and (not force-refresh)
org-roam-node-cache-time
org-roam-node-cache-list
(time-less-p
(file-attribute-modification-time (file-attributes org-roam-db-location))
org-roam-node-cache-time))
(setq org-roam-node-cache-list (apply fn args))
(setq org-roam-node-cache-time (current-time)))
org-roam-node-cache-list)
(defun cached/org-roam-node-read--completions (fn &optional filter-fn sort-fn &rest args)
(let ((sort-fn (or sort-fn
(when org-roam-node-default-sort
(intern (concat "org-roam-node-read-sort-by-"
(symbol-name org-roam-node-default-sort)))))))
;; Final Candidate cache nullification or changed FILTER-FN processing logic
(unless (and (eq filter-fn org-roam-node-cache-prev-filter-fn)
org-roam-node-cache-time
org-roam-node-cache-candidate-list
(time-less-p
(file-attribute-modification-time (file-attributes org-roam-db-location))
org-roam-node-cache-time))
(setq org-roam-node-cache-candidate-list (apply fn filter-fn sort-fn args))
(setq org-roam-node-cache-time (current-time))
(setq org-roam-node-cache-prev-filter-fn filter-fn)
(setq org-roam-node-cache-prev-sort-fn sort-fn))
;; Changed SORT-FN processing logic
(unless (eq sort-fn org-roam-node-cache-prev-sort-fn)
(when sort-fn
(setq org-roam-node-cache-candidate-list (funcall #'seq-sort sort-fn org-roam-node-cache-candidate-list))
(setq org-roam-node-cache-prev-sort-fn sort-fn)))
org-roam-node-cache-candidate-list))
(defun org-roam-node-cache-initialize (&optional level)
"Initialize Org-roam node caching based on `org-roam-node-cache-level'."
(org-roam-node-cache-deactivate) ; start at clean slate
(let ((cache-level (or level org-roam-node-cache-level)))
(when (>= cache-level 1)
;; Basic Cache
(advice-add 'org-roam-node-read--to-candidate :around #'cached/org-roam-node-read--to-candidate))
(when (>= cache-level 2)
;; Partial Cache
(advice-add 'org-roam-node-list :around #'cached/org-roam-node-list))
(when (>= cache-level 3)
;; Full Cache
(advice-add 'org-roam-node-read--completions :around #'cached/org-roam-node-read--completions))))
(defun org-roam-node-cache-deactivate ()
"Disable any node cache if active"
(advice-remove 'org-roam-node-read--to-candidate #'cached/org-roam-node-read--to-candidate)
(advice-remove 'org-roam-node-list #'cached/org-roam-node-list)
(advice-remove 'org-roam-node-read--completions #'cached/org-roam-node-read--completions))
;;;### autoload
(define-minor-mode org-roam-node-cache-mode
"Global minor mode to Cache org-roam nodes
Define cache level in `org-roam-node-cache-level'."
:init-value nil
:global t
(cond
(org-roam-node-cache-mode
(org-roam-node-cache-initialize))
(t
(org-roam-node-cache-deactivate))))
(provide 'org-roam-node-cache)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment