GithubHelp home page GithubHelp logo

ahmed-shariff / org-roam-ql Goto Github PK

View Code? Open in Web Editor NEW
76.0 4.0 5.0 5.12 MB

Query language for org-roam

License: GNU General Public License v3.0

Emacs Lisp 97.82% Makefile 2.18%
emacs org-mode org-roam query-language

org-roam-ql's Introduction

org-roam-ql - query language for org-roam

org-roam-ql
org-roam-ql-ql

This package is under active development.

This package provides an interface to easily query and display results from your org-roam database.

Contents

Screen-shots

You can query org-roam with org-roam-ql-search. The results are displayed in an org-roam-like buffer. org-roam-ql also comes with a transient that can be used to modify the results viewed. The transient can be activated with v. You can modify the title (t), query (q), sort (s) and specify if the query is a subquery (apply query on the results of the buffer) or query against the whole org-roam database (i). Refreshing the buffer (r) will display the updated results.

images/demo4.gif

The transient is available in the org-roam buffer as well, this allows you to start a query from the results in the org-roam buffer. You also can view the results in an agenda-like buffer.

images/demo3.gif

Installation/Setup

org-roam-ql can be installed from MELPA or with other package management tools like quelpa and straight

Example configuration:

(use-package org-roam-ql
  ;; If using straight
  :straight (org-roam-ql :type git :host github :repo "ahmed-shariff/org-roam-ql"
                         :files (:defaults (:exclude "org-roam-ql-ql.el")))
  ;; If using quelpa
  :quelpa (org-roam-ql :fetcher github :repo "ahmed-shariff/org-roam-ql"
                       :files (:defaults (:exclude "org-roam-ql-ql.el")))
  ;; Simple configuration
  :after (org-roam)
  :bind ((:map org-roam-mode-map
               ;; Have org-roam-ql's transient available in org-roam-mode buffers
               ("v" . org-roam-ql-buffer-dispatch)
               :map minibuffer-mode-map
               ;; Be able to add titles in queries while in minibuffer.
               ;; This is similar to `org-roam-node-insert', but adds
               ;; only title as a string.
               ("C-c n i" . org-roam-ql-insert-node-title))))

Usage

Commands/functions

org-roam-ql-search (SOURCE-OR-QUERY &optional TITLE SORT-FN)
This is an interactive command that creates a org-roam-ql buffer with the nodes of the corresponding SOURCE-OR-QUERY ([[#valid-values-for-source-or-query] with TITLE. An org-roam-ql buffer is functionally similar to the org-roam-buffer, but allows displaying any list of nodes (see screen-shots above). When called interactively, it will prompt for the SOURCE-OR-QUERY and TITLE. Note that when entering queries interactively either in org-roam-ql-search or in the transient, you can get completion-at-point with tab. SORT-FN is used for sorting the results. It can be a string name of a registered sort function or a predicate function that can be used to sort the nodes (should take two nodes as input and return a non-nil value if the first node should be before the second). By default the following sort function are registered: file-mtime, file-atime, deadline, scheduled, point, level, file-title, file and title. Each corresponds to the respective slot of an org-roam-node. It is possible to register new sort functions with org-roam-ql-register-sort-fn. These registered functions will also appear as options for completion in the transient.
org-roam-ql-nodes (SOURCE-OR-QUERY)
Given a SOURCE-OR-QUERY , return a list of nodes.
org-roam-ql-agenda-block (QUERY)
Meant to be used in org-agenda-custom-commands as a user-defined function. Insert items from processing QUERY (which is a SOURCE-OR-QUERY ) into current buffer. QUERY is the `match’ item in the custom command form. Currently this doesn’t respect agenda restrict. Example:
(setq org-agenda-custom-commands
      ("cr" "Node a" org-roam-ql-agenda-block '(title "Node a")))
    
org-roam-ql-nodes-files (SOURCE-OR-QUERY)
Given a SOURCE-OR-QUERY , returns a list of files of the nodes. Can be used in org-agenda-custom-commands. Example:
(setq org-agenda-custom-commands
      ("cr" "todo nodes" todo "TODO" ((org-agenda-files (org-roam-ql-nodes-files '(title "Node"))))))
    

Valid values for SOURCE-OR-QUERY

A list of org-roam-nodes
This should self explanatory.
A list of parameters that can be passed to org-roam-db-query
It should be a list of the form (QUERY ARG1 ARG2...). The result of calling org-roam-db-query with these parameters should return a list of records where the first element is the ID of a corresponding node. For example:
(org-roam-ql-nodes '([:select [id] :from nodes :where (= todo \"TODO\")]))
    
Buffer name
A buffer or buffer-name of a org-roam buffer, a org-roam-ql buffer or an agenda-like buffer displaying a list of org-roam nodes.
Function
A function that returns a list of org-roam-nodes
A QUERY
This is a predicate, similar to the predicates in org-ql. Returns all nodes that pass for the given predicate. For example, consider the following call to org-roam-ql-nodes:
(org-roam-ql-nodes '(and (todo "TODO") (tags "tag1" "tag2") "*org-roam*"))
    

In the above example, the result would contain any nodes whose todo state is TODO, have tags “tag1” and “tag2” and are in the org-roam buffer. The following are predicates available by default in org-roam-ql:

or (SOURCE-OR-QUERY1 SOURCE-OR-QUERY2 ...)
Tests if a node matches/contained-in any of the SOURCE-OR-QUERY’s.
and (SOURCE-OR-QUERY1 SOURCE-OR-QUERY2 ...)
Similar to or, but should satisfy all predicates or contained in all the results of SOURCE-OR-QUERY’s.
not (SOURCE-OR-QUERY)
Tests if a node doesn’t match the result or not contained in the result of SOURCE-OR-QUERY.
file (REGEXP &optional EXACT)
Test if nodes file name matches REGEXP. If EXACT is non-nil, the file slot should be an exact match to REGEXP. Note the slot file of an org-roam-node would contain the absolute path.
file-title (REGEXP &optional EXACT)
Similar to file, tests the file-title slot of a node.
id (ID)
Tests if the ID of a node is a match to the value passed.
level (LEVEL)
Tests if the level of a node is equal to LEVEL.
todo (REGEXP &optional EXACT)
Similar to file, tests the todo state of a node.
priority (REGEXP &optional EXACT)
Similar to file, tests the priority of a node.
scheduled
TBD
deadline
TBD
title (REGRXP &optional EXACT)
Similar to file, tests the title of a node.
properties (PROP PROP-VAL)
Tests if the value of the property of a node PROP is a match to PROP-VAL. PROP-VAL can be a regular expression.
tags (TAG1 TAG2 ...)
Tests if the tags of a node have TAG1, TAG2, etc.
refs (REGEXP &optional EXACT)
Similar to file, tests the nodes refs slot.
backlink-to (SOURCE-OR-QUERY)
Tests if the node has a backlink to any of the nodes from the results SOURCE-OR-QUERY.
backlink-from (SOURCE-OR-QUERY)
Similar to backlink-to, tests if there are any backlinks from (aka forwardlinks) the resulting nodes from SOURCE-OR-QUERY.
in-buffer (BUFFER-NAME)
This is similar to passing a buffer-name as SOURCE-OR-QUERY. Tests if a node is in the org-roam buffer named BUFFER-NAME.
nodes-list (NODES-LIST)
This is similar to passing a list of nodes as SOURCE-OR-QUERY. Tests if a node is in the NODES-LIST.
function (FUNC)
This is similar to passing a function as SOURCE-OR-QUERY. Tests if the node is in the result of executing the function FUNC.
funcall (FUNC)
Tests a node with the function FUNC, which takes an org-roam node as parameter. Test passes if the function returns non-nil.

Adding new predicates

There are two ways to add a new predicate to org-roam-ql:

org-roam-ql-defpred (NAME DOCSTRING EXTRACTION-FUNCTION COMPARISON-FUNCTION)
Creates a predicate that can be used as SOURCE-OR-QUERY. For example, for a predicate defined as follows:
(org-roam-ql-defpred sample "A sample predicate" extraction-function comparison-function)
    

When the following predicate is used as SOURCE-OR-QUERY :

(org-roam-ql-nodes '(sample arg1 arg2))
    

It tests each node in the whole org-roam database as follows:

(apply comparison-function (append (list (funcall extraction-function node)) arg1 arg2))
    

The EXTRACTION-FUNCTION takes an org-roam-node and returns a value that will be passed as the first parameter to COMPARISON-FUNCTION. The remainder of the parameters when calling the predicate is passed as remaining parameters to COMPARISON-FUNCTION. When the COMPARISON-FUNCTION returns a non-nil value, it will be included in the result.

org-roam-ql-defexpansion (NAME DOCSTRING EXPANSION-FUNCTION)
Adds an EXPANSION-FUNCTION which will be identified by NAME in a org-roam-ql query. The EXPANSION-FUNCTION should take the parameters passed in the query and return values that can be passed to org-roam-nodes.

Org dynamic block

Similar to org-ql, org-roam-ql also provides a dynamic block. The header parameters are as follows:

  • :query - A valid SOURCE-OR-QUERY
  • :columns - A list of columns to display. Each column name is a slot name of org-roam-nodes. For any function/accessor with a name of the form org-roam-node-<name>, which takes an org-roam-node as a parameter, <name> can also be used column name. For example, if there is a function named org-roam-node-short-title, short-title can be used as a column name, this will result in a column with the title short-title where the content of each row is the result of calling the respective function.
  • :sort - Name of a registered sort functions. See org-roam-ql-search for more info on the values for sort functions.
  • :take (optional) - If a positive integer N, take the first N elements, if a negative -N, take the last N nodes.
  • :no-link (optional) - If a non-nil value is set, the first column containing the links will be dropped.

If no-link is not provided as a parameter, the first column is a link to the node. Since it is an id link, it will be a backlink to the node.

Following is an example of a dynamic block and its result.

images/dynamic-block.jpg

Working with org-ql

Optionally, org-roam-ql results can be visualized with org-ql, available through the extension org-roam-ql-ql (naming things is hard!!). This also can be installed from MELPA or with other package management tools like quelpa and straight.

(use-package org-roam-ql-ql
  ;; If using straight
  :straight (org-roam-ql-ql :type git :host github :repo "ahmed-shariff/org-roam-ql"
                            :files (:defaults (:exclude "org-roam-ql.el")))
  ;; If using quelpa
  :quelpa (org-roam-ql-ql :fetcher github :repo "ahmed-shariff/org-roam-ql"
                          :files (:defaults (:exclude "org-roam-ql.el")))
  ;; Simple config
  :after (org-ql org-roam-ql)
  :config
  (org-roam-ql-ql-init))

Note that org-ql works only with org entries, i.e., `heading nodes`. Hence, if there are any file nodes in the result, they will not be displayed. To be clear about that, when org-roam-ql results are displayed in an org-ql-view buffer, a warning is added to the end mentioning how many file nodes were there in the result. If the extension is loaded, you may view the org-roam-ql results with Q from the org-roam-ql transient. An org-ql-view can be viewed in an org-roam-like buffer with R from the org-ql-view transient.

images/demo5.gif

org-roam-ql's People

Contributors

ahmed-shariff avatar hiecaq avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

org-roam-ql's Issues

Add support for lowercase properties in queries

Hi

In my Org-Roam notes, I tend to always favor lowercase properties-drawer, to avoid the "screaming at your face" of Org-Mode default.

For example:

:properties:
:id: foo
:country: Brazil
:end:
…

But then when I want to queries all nodes who have Brazil as a country, I'm forced to use uppercase COUNTRY:

#+begin: org-roam-ql :query (properties "COUNTRY" "Brazil") :columns (title) :no-link true
…
#+end

instead of country:

#+begin: org-roam-ql :query (properties "country" "Brazil") :columns (title) :no-link true
#+end

I would much appreciate if it could it be possible to handle the second case transparently to avoid surprise and inconsistency.

Thanks a lot for this package!

org-roam-ql-buffer-dispatch returns "Invalid format character %v"

Whenever I invoke the org-roam-ql-buffer-dispatch in the org-roam buffer, instead of showing the org-roam-ql-buffer constructed from the backlinks in the org-roam buffer, I receive a message which says "Invalid format character %v".

I have tested this out in Doom Emacs and vanilla Emacs, both show the same message.

Otherwise, I can launch the org-roam-ql buffer by running a query, just not through the org-roam buffer.

If you have any suggestions as to why this may be the case, or what I could do to fix it, that would be great.

I've enjoyed this package so far and I'm keen to get it fully working in my workflow. Keep up the great work!

`backlink-to` and `backlink-from` does not work for `:or` query correctly

Reproducible tests:

* A
:PROPERTIES:
:ID:       a314599e-48c1-44c6-9ffd-d18cf0b2467f
:END:
* B
:PROPERTIES:
:ID:       fc6f0315-f10d-4381-9615-ba6006eab957
:END:
* C
:PROPERTIES:
:ID:       3d613239-32f1-4171-9c52-b9d9c1f85a3e
:END:
[[id:a314599e-48c1-44c6-9ffd-d18cf0b2467f][link-to-A]]
[[id:fc6f0315-f10d-4381-9615-ba6006eab957][link-to-B]]
* D
:PROPERTIES:
:ID:       92c99f0a-7621-48ec-aa4e-1e74d5c08aa2
:END:
[[id:fc6f0315-f10d-4381-9615-ba6006eab957][link-to-B]]

* tests
#+begin_src emacs-lisp
  (org-roam-ql-nodes '(backlink-to (or (title "A" t) (title "B" t)) :combine :or))
#+end_src

Expect result is 2 nodes: both C and D.
Actual got: only 1 node, which is C.

add query option for full-text search

The Org-roam-ql approach to querying org-roam notes is great. There is just one missing piece to the puzzle - a query option to search the body of the notes.

There are always pieces of information that I did not think to capture as property drawers at the time of filing a note. I now have to choose to either go the org-roam-ql way and subset notes via title/tag/backlink or do a full text search (i.e. via deft). The possibility of combining the two would help tremendously.

How to write an "org-roam-ql" function that could produce an output in an org-roam file?

I tried hacking my way through and wrote the following:
(org-roam-ql-nodes '([:select [node-id] :from tags :where (= tag \"resources\")]))
which (in mind) is supposed to search the org-roam db for all nodes with the tags "resources" and displays only it's ID, but I get nothing.

I tried this one: (org-roam-ql-nodes '(tags "resources")) and indeed it produced an output, but it's not formatted.

License

Hi!

I like the project and think it's very useful for my use case. While experimenting with it, I probably would have some contributions to make in the coming week. However, I don't see the point of contributing to an emacs package which reuses quite some gpl3+ code but sets its license to MIT.

Would you be willing to relicense your code? Or accept contributions with another license?

Add more control over the title of columns in dynamic blocks

Hello

Currently, while using dynamic blocks, the titles of columns of the resulting org-table are generated like this:

              (insert "|"
                      (if no-link "" "|")
                      (string-join (--map (pcase it
                                            ((pred symbolp) (capitalize (symbol-name it)))
                                            (`(,_ ,name) name))
                                          columns)
                                   " | ")
                      "|\n|-\n")

In some situations these titles of columns can be quite long, but the content of each cells in the columns very short (like boolean value true, false), so it fees like a the horizontal space could be reduced by renaming columns.

Example where Year-of-birth is a bit too long and could be renamed to simply Year in this context:

| Name | Year-of-birth |
|------+---------------|
| John |          1985 |
| Mary |          1974 |


| Name | Year |
|------+------|
| John | 1985 |
| Mary | 1974 |

What about some kind of optional plist mapping initial column names to desired column names given as parameter to the dblock? Or maybe a transformer function?

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.