Add query input or function day-of-week

It would be great to be able to have queries depend on the day of the week, for example, on Monday to return blocks with the tag #Monday, on Tuesday to return blocks with #Tuesday, etc. This could be accomplished with a query input :day-of-week, or even better, a day-of-week function.

Actually I would like to see it possible based on date.
Eg. References to a date that is a Monday.

Like in Excel that we can ask, what day is today? And what day is in this cell? And are they the same?

So like that.

There is var-last-day-of-the-month, i am not sure but this library is used by logseq. We have to fork the library and add something like last-day-of-the-weak, first-day-of-the-weak, actually we can add anything, but rn there are only last-day-of-the-month and first-day-of-the-month

clj-time already has:

  • day-of-week
  • weekend?
  • weekday?
  • monday? … sunday?
  • january? … december?
  • last-day-of-month? or last-day-of-the-month?
  • first-day-of-month? or first-day-of-the-month?
  • nth-day-of-the-month?
  • and more

I wonder if this is implemented in queries though.
I just get errors of unknown function.
E.g. [(clj.core/days ?d)]
Idk if this is how to call it, but we do for example [(clojure.string/starts-with? ?c "test")]. So using the same form for this.
It’s probably something to use in a plugin.

As far as I know in queries we only have access to clojure.core and some clojure.string.
See datascript, which is the datalog implementation Logseq uses.

I too have encountered the unknown function error when trying to use functions like clojure.string/split and clojure.string/replace inside a query statement,
but I was able to use the same functions inside a pre-defined :result-transform function or :view function inside the config.edn.

Maybe the above problem can be solved by registering pre-defined functions in config.edn.

There is a difference between what can be used in a :where clause and what can be used in the :result-transform clause.
If we want to filter result data we do this in the :where clause. When we then want to change the result data in any way we use :result-transform
We don’t need to do so in the config file however. This can happen in the query itself.

For this use case we want to filter the result data based on day of the week. And for that we need some sort of time conversion logic. Unfortunately it seems to mentioned functions can’t be used in the :where part of a query.

As to split and replace, those are data transform functions and not data filter functions. Hence they are only made available in the :result-transform part.
However functions like str and subs are available in the :where. These are after all listed in the link I used.

I hope this clarifies what functions are available where.

To summarize, for the :where clause those functions listed in the link I added in my previous post.
For the :result-transform clause those functions from clojure.core and some from clojure.string. (but potentially not all of them, I’m not sure)
For the functions in :result-transform we can use them in the query itself and don’t need (but could!) to define them through the config file.

1 Like

How hard would it be to make the functions of clj-time available in queries? Unfortunately I know very little about the architecture of logseq.

I agree this would be great addition. As of now Query result shows only dates and have to open Calendar everytime to check which day it corresponds to.

I have query to show weekly task distribution but unfortunately. I am unable to get Day of the Week in Table.

#+BEGIN_QUERY
{:title [:h3 "🧭️ Weekly Distribution - Disable Page View"]
 :query [:find ?d (count ?b)
       :keys type number
       :in $ ?start ?end
       :where   
       (task ?b #{"LATER" "TODO" "DOING"})
       (or [?b :block/scheduled ?d] [?b :block/deadline ?d])
       [(> ?d ?start)]
       [(< ?d ?end)]
       ]
 :inputs [:-1w :+7d]
:collapsed? false
 :group-by ?d
 :view (fn [rows]
       [:table
        [:thead [:tr [:th "Day"] [:th "Count"]]]
        [:tbody
         (let [sorted-rows (sort-by :type rows)]
           (for [r sorted-rows]
             [:tr
              [:td (get-in r [:type])]
              [:td (get-in r [:number])]]))]])
}
#+END_QUERY

For whatever it’s worth, here is a query that contains a (very) long rule which:

  • expects two dates in the form YYYYMMDD
  • returns true only if they are on the same day of the week
#+BEGIN_QUERY
{
 :title [:b "sameWeekDay"]
 :inputs [:today]
 :rules [
  [(sameWeekDay ?date-a ?date-b)

   [(mod ?date-a 100) ?monthday-a]
   [(mod ?date-a 10000) ?mod-a]
   [(quot ?mod-a 100) ?month-a]
   [(- ?month-a 8) ?month8-a]
   [(quot ?month8-a 6) ?month6-a]
   [(* ?month6-a 12) ?month12-a]
   [(- ?month-a ?month12-a) ?monthnum-a]
   [(inc ?monthnum-a) ?monthinc-a]
   [(* 13 ?monthinc-a) ?month13-a]
   [(quot ?month13-a 5) ?month5-a]
   [(quot ?date-a 10000) ?year-a]
   [(+ ?year-a ?month6-a) ?year6-a]
   [(mod ?year6-a 100) ?yearnum-a]
   [(quot ?yearnum-a 4) ?year4-a]
   [(quot ?year6-a 100) ?century-a]
   [(quot ?century-a 4) ?century4-a]
   [(* 5 ?century-a) ?century5-a]
   [(+ ?monthday-a ?month5-a ?yearnum-a ?year4-a ?century4-a ?century5-a) ?sum-a]
   [(mod ?sum-a 7) ?d-a]

   [(mod ?date-b 100) ?monthday-b]
   [(mod ?date-b 10000) ?mod-b]
   [(quot ?mod-b 100) ?month-b]
   [(- ?month-b 8) ?month8-b]
   [(quot ?month8-b 6) ?month6-b]
   [(* ?month6-b 12) ?month12-b]
   [(- ?month-b ?month12-b) ?monthnum-b]
   [(inc ?monthnum-b) ?monthinc-b]
   [(* 13 ?monthinc-b) ?month13-b]
   [(quot ?month13-b 5) ?month5-b]
   [(quot ?date-b 10000) ?year-b]
   [(+ ?year-b ?month6-b) ?year6-b]
   [(mod ?year6-b 100) ?yearnum-b]
   [(quot ?yearnum-b 4) ?year4-b]
   [(quot ?year6-b 100) ?century-b]
   [(quot ?century-b 4) ?century4-b]
   [(* 5 ?century-b) ?century5-b]
   [(+ ?monthday-b ?month5-b ?yearnum-b ?year4-b ?century4-b ?century5-b) ?sum-b]
   [(mod ?sum-b 7) ?d-b]

   [(= ?d-a ?d-b)]
  ]
 ]
 :query [
  :find ?today
  :in $ ?today %
  :where
   (sameWeekDay ?today 20230806)
 ]
}
#+END_QUERY

This query should show the Day of the Week:

#+BEGIN_QUERY
{:title [:h3 "🧭️ Weekly Distribution - Disable Page View"]
 :query [:find ?d (count ?b)
       :keys date number
       :in $ ?start ?end
       :where   
       (task ?b #{"LATER" "TODO" "DOING"})
       (or [?b :block/scheduled ?d] [?b :block/deadline ?d])
       [(> ?d ?start)]
       [(< ?d ?end)]
       ]
 :inputs [:-1w :+7d]
 :collapsed? false
 :group-by ?d
 :view (fn [rows]
       [:table
        [:thead [:tr [:th "Day"] [:th "Count"]]]
        [:tbody
         (let [sorted-rows (sort-by :date rows)
           days {
            0 "Sat"
            1 "Sun"
            2 "Mon"
            3 "Tue"
            4 "Wed"
            5 "Thu"
            6 "Fri"
           }
           weekDay (fn [date]
             (def month (quot (mod date 10000) 100))
             (def month6 (quot (- month 8) 6))
             (def year6 (+ (quot date 10000) month6))
             (def yearnum (mod year6 100))
             (def century (quot year6 100))
             (def d (mod (+ (mod date 100) (quot (* 13 (inc (- month (* month6 12)))) 5) yearnum (quot yearnum 4) (quot century 4) (* 5 century)) 7))
             (get days d)
            )
          ]
           (for [r sorted-rows]
             [:tr
              [:td (str (get-in r [:date]) " " (weekDay (get-in r [:date])))]
              [:td (get-in r [:number])]]))]])
}
#+END_QUERY