diff --git a/org-roam-db.el b/org-roam-db.el index bf833a5..98146e7 100644 --- a/org-roam-db.el +++ b/org-roam-db.el @@ -57,7 +57,7 @@ when used with multiple Org-roam instances." :type 'string :group 'org-roam) -(defconst org-roam-db--version 4) +(defconst org-roam-db--version 5) (defconst org-roam-db--sqlite-available-p (with-demoted-errors "Org-roam initialization: %S" (emacsql-sqlite-ensure-binary) @@ -121,7 +121,7 @@ SQL can be either the emacsql vector representation, or a string." '((files [(file :unique :primary-key) (hash :not-null) - (last-modified :not-null)]) + (meta :not-null)]) (links [(from :not-null) @@ -206,6 +206,13 @@ This is equivalent to removing the node from the graph." file)))) ;;;;; Insertion +(defun org-roam-db--insert-meta (file hash meta) + "Insert HASH and META for a FILE into the Org-roam cache." + (org-roam-db-query + [:insert :into files + :values $v1] + (list (vector file hash meta)))) + (defun org-roam-db--insert-links (links) "Insert LINKS into the Org-roam cache." (org-roam-db-query @@ -306,6 +313,18 @@ connections, nil is returned." files)) ;;;;; Updating +(defun org-roam-db--update-meta () + "Update the metadata of the current buffer into the cache." + (let* ((file (file-truename (buffer-file-name))) + (attr (file-attributes file)) + (atime (file-attribute-access-time attr)) + (mtime (file-attribute-modification-time attr)) + (hash (secure-hash 'sha1 (current-buffer)))) + (org-roam-db-query [:delete :from files + :where (= file $s1)] + file) + (org-roam-db--insert-meta file hash (list :atime atime :mtime mtime)))) + (defun org-roam-db--update-titles () "Update the title of the current buffer into the cache." (let* ((file (file-truename (buffer-file-name))) @@ -350,6 +369,7 @@ connections, nil is returned." (current-buffer)))) (with-current-buffer buf (save-excursion + (org-roam-db--update-meta) (org-roam-db--update-tags) (org-roam-db--update-titles) (org-roam-db--update-refs) @@ -365,28 +385,31 @@ If FORCE, force a rebuild of the cache from scratch." (org-roam-db) ;; To initialize the database, no-op if already initialized (let* ((org-roam-files (org-roam--list-all-files)) (current-files (org-roam-db--get-current-files)) - (time (current-time)) all-files all-links all-titles all-refs all-tags) (dolist (file org-roam-files) - (org-roam--with-temp-buffer - (insert-file-contents file) - (let ((contents-hash (secure-hash 'sha1 (current-buffer)))) - (unless (string= (gethash file current-files) - contents-hash) - (org-roam-db--clear-file file) - (push (vector file contents-hash time) - all-files) - (when-let (links (org-roam--extract-links file)) - (push links all-links)) - (when-let (tags (org-roam--extract-tags file)) - (push (vector file tags) all-tags)) - (let ((titles (org-roam--extract-titles))) - (push (vector file titles) all-titles)) - (when-let* ((ref (org-roam--extract-ref)) - (type (car ref)) - (key (cdr ref))) - (setq all-refs (cons (vector key file type) all-refs)))) - (remhash file current-files)))) + (let* ((attr (file-attributes file)) + (atime (file-attribute-access-time attr)) + (mtime (file-attribute-modification-time attr))) + (org-roam--with-temp-buffer + (insert-file-contents file) + (let ((contents-hash (secure-hash 'sha1 (current-buffer)))) + (unless (string= (gethash file current-files) + contents-hash) + (org-roam-db--clear-file file) + (push (vector file contents-hash (list :atime atime :mtime mtime)) + all-files) + (when-let (links (org-roam--extract-links file)) + (push links all-links)) + (when-let (tags (org-roam--extract-tags file)) + (push (vector file tags) all-tags)) + (let ((titles (org-roam--extract-titles))) + (push (vector file titles) + all-titles)) + (when-let* ((ref (org-roam--extract-ref)) + (type (car ref)) + (key (cdr ref))) + (setq all-refs (cons (vector key file type) all-refs)))) + (remhash file current-files))))) (dolist (file (hash-table-keys current-files)) ;; These files are no longer around, remove from cache... (org-roam-db--clear-file file)) diff --git a/org-roam.el b/org-roam.el index 1413897..8111a26 100644 --- a/org-roam.el +++ b/org-roam.el @@ -582,12 +582,18 @@ Only relevant when `org-roam-tag-sources' is non-nil." (defun org-roam--get-title-path-completions () "Return an alist for completion. -The car is the displayed title for completion, and the cdr is a -plist containing the path to the file, and the original title." - (let* ((rows (org-roam-db-query [:select [titles:file titles:titles tags:tags] :from titles +The car is the displayed title for completion, and the cdr is the +to the file." + (let* ((rows (org-roam-db-query [:select [titles:file titles:titles tags:tags files:meta] :from titles :left :join tags - :on (= titles:file tags:file)])) + :on (= titles:file tags:file) + :left :join files + :on (= titles:file files:file)])) completions) + (seq-sort-by (lambda (x) + (plist-get (nth 3 x) :mtime)) + #'time-less-p + rows) (dolist (row rows completions) (pcase-let ((`(,file-path ,titles ,tags) row)) (let ((titles (or titles (list (org-roam--path-to-slug file-path))))) @@ -697,10 +703,16 @@ candidates (e.g. \"cite\" ,\"website\" ,etc.) takes three arguments: the type, the ref, and the file of the current candidate. It should return t if that candidate is to be included as a candidate." - (let ((rows (org-roam-db-query [:select [type ref file] :from refs])) + (let ((rows (org-roam-db-query [:select [refs:type refs:ref refs:file ] :from refs + :left :join files + :on (= refs:file files:file)])) (include-type (and interactive org-roam-include-type-in-ref-path-completions)) completions) + (seq-sort-by (lambda (x) + (plist-get (nth 3 x) :mtime)) + #'time-less-p + rows) (dolist (row rows completions) (pcase-let ((`(,type ,ref ,file-path) row)) (when (pcase filter