org-ql/examples.org
Adam Porter 94f9e6f303 Add/Change: reverse sorter, and reverse sorting order
This is a breaking change of sorts in that searches using multiple
sorting methods will have to have the order of the sorters reversed to
get the same result.  Unfortunate, but I think it's worth it in the
end, and this is pre-1.0, anyway.

Fixes #143.
2021-07-12 21:33:24 -05:00

8.8 KiB

org-ql examples

Custom predicates

Agenda-like view

Show an agenda-like view, similar to a "traditional" Org Agenda with Log Mode turned on.

  (org-ql-search (org-agenda-files)
    '(or (and (not (done))
              (or (habit)
                  (deadline auto)
                  (scheduled :to today)
                  (ts-active :on today)))
         (closed :on today))
    :sort '(todo priority date))

Another example, showing grouping with org-super-agenda:

  (org-ql-search "~/src/emacs/org-super-agenda/test/test.org"
    '(and (or (ts-active :on today)
              (deadline auto)
              (scheduled :to today))
          (not (done)))
    :title "My Agenda View"
    ;; The `org-super-agenda-groups' setting is used automatically when set, or it
    ;; may be overriden by specifying it here:
    :super-groups '((:name "Bills"
                           :tag "bills")
                    (:todo ("SOMEDAY" "TO-READ" "CHECK" "TO-WATCH" "WATCHING")
                           :order 7)
                    (:name "Personal"
                           :habit t
                           :tag "personal"
                           :order 3)
                    (:todo "WAITING"
                           :order 6)
                    (:priority "A" :order 1)
                    (:priority "B" :order 2)
                    (:priority "C" :order 2)))

Which displays this buffer:

/jiri/org-ql/media/commit/b7d4856f926cb71e01427a940dc948a48b0a702d/images/screenshot.png

Entries from the past week

Show entries that have any timestamp within the past week. Group by date using org-super-agenda with the :auto-ts group.

  (org-ql-search (org-agenda-files)
    '(ts :from -7 :to today)
    :title "Recent Items"
    :sort '(todo priority date)
    :super-groups '((:auto-ts t)))

Find entries matching a certain CUSTOM_ID

Since queries can contain both built-in org-ql predicate expressions and arbitrary expressions, they can be combined in useful ways. This example uses the built-in property predicate to quickly locate entries that have the CUSTOM_ID property set, and then compares the value of that property to the string issue.

  (org-ql-query
    :select #'org-get-heading
    :from "~/org/tickets.org"
    :where '(and (property "CUSTOM_ID")
                 (string-match "issue" (org-entry-get (point) "CUSTOM_ID"))))

Using the property predicate as the first clause of the two clauses joined with and allows org-ql to optimize the query by searching through the buffer directly to entries that set the CUSTOM_ID property, which is much faster than testing every entry in a buffer. Also, If the query were only the string-match call, it would signal an error on entries that didn't have the property set, because org-entry-get would return nil.

Listing bills coming due

This uses the example in the readme file, but maps across the elements returned by org-ql to present a simple list of titles and deadlines.

  (org-ql-query
    :select '(list (substring-no-properties (org-get-heading t t))
                   (org-entry-get (point) "DEADLINE"))
    :from (org-agenda-files)
    :where '(and (not (done))
                 (tags "bills")
                 (deadline auto))
    :order-by 'deadline)
  ;;=> (("Electric bill" "<2018-08-23 Thu +1m>")
  ;; ("Rent" "<2018-09-01 Sat +1m>"))

This could also be put in a script, which could use desktop notifications to remind of bills coming due: org-bills-due.el.

Music database

If you kept a database of music in an Org file, you could run a query like this to find tracks composed by Chopin that do not have their key recorded in the database.

  (org-ql-search "~/org/music.org"
    '(and (property "genre" "classical")
          (property "composer" "Chopin")
          (not (property "key"))))

Return Org elements

Return a list of Org entry elements in the file ~/org/main.org which have the SOMEDAY to-do keyword, are tagged Emacs, and have priority B or higher. org-ql is the macro version of org-ql-select; it does not require quoting the query sexp.

  (org-ql "~/org/main.org"
    (and (todo "SOMEDAY")
         (tags "Emacs")
         (priority >= "B")))
  ;;=> ((headline (:raw-value "org-board" :begin 1220270 :end 1220403 ...)) ...)

Set tags on certain entries

Set the tag Emacs on every entry in the inbox file that mentions Emacs. The bare-string query "Emacs" is equivalent to (regexp "Emacs").

  (org-ql-select "~/org/inbox.org"
    "Emacs"
    :action '(org-toggle-tag "Emacs" 'on))

Show entries with recent timestamps

You can also access these views with the command org-ql-view.

  ;; Show entries with any timestamp from last 7 days:
  (org-ql-view-recent-items 7)

  ;; Show entries clocked in last 30 days:
  (org-ql-view-recent-items 30 'clocked)

  ;; Show entries closed in last 30 days:
  (org-ql-view-recent-items 30 'closed)

Stuck projects block agenda

Reddit user emptymatrix shared this example of replacing a traditional org-stuck-projects view like:

  (setq org-stuck-projects
        '("+@project/-DONE" ("NEXT") nil "SCHEDULED:"))

With this org-ql-block agenda view, like:

  (setq org-agenda-custom-commands
        '(("s" "Stuck Projects"
           ((org-ql-block '(and (tags "@project")
                                (not (done))
                                (not (descendants (todo "NEXT")))
                                (not (descendants (scheduled))))
                          ((org-ql-block-header "Stuck Projects")))))))

Subproject and subtask queries

  ;; Search for subprojects.
  (org-ql-search (org-agenda-files)
    '(and (todo "PROJECT")
          (ancestors (todo "PROJECT"))))

  ;; Search for all subtasks of projects, grouped by parent heading.
  (org-ql-search (org-agenda-files)
    '(and (todo)
          (ancestors (todo "PROJECT")))
    :super-groups '((:auto-parent t)))

  ;; Search for direct top-level tasks of projects.
  (org-ql-search (org-agenda-files)
    '(and (todo)
          (parent (todo "PROJECT")))
    :super-groups '((:auto-parent t)))

Of course, all of those presume using a PROJECT keyword to define projects. If one defines a project as any task which has an ancestor task, one could use queries like:

  ;; Search for all subtasks of top-level projects, grouped by parent heading.
  (org-ql-search (org-agenda-files)
    '(and (todo)
          (ancestors
           (and (todo)
                (not (parent)))))
    :super-groups '((:auto-parent t)))

  ;; Search for all subtasks of all projects, including subprojects, grouped by project.
  (org-ql-search (org-agenda-files)
    '(and (todo)
          (ancestors (todo)))
    :super-groups '((:auto-parent t)))

Other interesting queries:

  ;; Subtasks of upcoming deadline items.
  (org-ql-search (org-agenda-files)
    '(and (todo)
          (ancestors
           (and (not (done))
                (deadline auto))))
    :super-groups '((:auto-parent t)))

  ;; TODO items whose ancestor is already DONE, and should therefore be
  ;; either marked DONE or CANCELLED.
  (org-ql-search (org-agenda-files)
    '(and (todo)
          (ancestors (done)))
    :super-groups '((:auto-parent t)))

Task list for files in subdirectories

/jiri/org-ql/media/commit/b7d4856f926cb71e01427a940dc948a48b0a702d/images/org-ql-search-snippet.png