Add query input or function day-of-week

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
1 Like

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
4 Likes

Thanks a Lot @mentaloid . It worked perfectly fine.

Although i didnā€™t completely understand the code but it seems weekDay Function Generates Index from date and then Maps the day via days Map.

It is working fine as shown in screenshot below.

Is there a way to register either

into the config.edn so that it can be used without copy-paste (so I can track it/change it all in one place)? Would it work as a macro if itā€™s inside the where part of a query?

The weekday seems to use a view for most of the logic.

So if the query returns the same type result (whatā€™s used in :find and :keys), we can use a custom view as defined in config.edn for the same.

Find the line: ;; Pre-defined :view function to use with advanced queries
You should see an example underneath.

Syntax follows:

:<name of view>
<View logic>

The view logic would be everything after the :view part of the query.

To use it:
:view :<name of view>
In your advanced query.

If you need further help let me know!

1 Like

Thanks for the suggestion @Siferiax, I mostly wanted to have a getWeekDay function to use within :where to only find certain days. Iā€™m not sure if the view supports filtering, but even if it does, I suppose thatā€™s a little bit of a hack since why pass through the query if I filter it out of the view?

I wanted the function to return short day names, so I could display a block if it has a property preview-on-day-of-week with value as a string for each day of the week, so that I could find blocks that have this property with value matching (getWeekDay :today), which I implemented via a query, where I stole @mentaloidā€™s weekday implementation and got the string value from the day of week numeric key.

{:title "šŸ” PERIODIC"
 :rules [
         [(getWeekDay ?date-a)
         [(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]
         [(get {
                0 "Sat"
                1 "Sun"
                2 "Mon"
                3 "Tue"
                4 "Wed"
                5 "Thu"
                6 "Fri"
                } ?d)]]
        ]
:query [:find (pull ?h [*])
        :in $ ?query-pg
        :where
        (has-property ?h :preview-on-day-of-week)
        [(property ?h :preview-on-day-of-week) ?day]
        [?query-pg :block/journal-date ?query-date]
        [(getWeekDay ?query-date) ?query-day]
        (= ?query-day ?day)
        ]
:inputs [:query-page]
:group-by-page? false
:collapsed? false}

which does not work as I expect, but Iā€™m able to get this to work for literals, like so

:query [:find (pull ?h [*])
        :where
        (has-property ?h :preview-on-day-of-week)
        [property ?h :preview-on-day-of-week "Sun"]
        ]

So I expect Iā€™m reading the property in ?day correctly, but Iā€™m not sure how I debug the function that returns the string for the day of the date input, as having the target day of week be specified by the journal date from where the query is called instead of using a literal.


but maybe I should backtrack.
My use case where I want to see something that appears on a weekly schedule: itā€™s my workout routine. I schedule a routine each day of the week that I modify every 4-6 months because of the seasons. I initially set this to be a task as itā€™s something thatā€™s not done that I wish to do, but as itā€™s recurring and itā€™s a description, it really fills up my general todo list queries.

While Iā€™d like to figure out how to write these queries without feeling like itā€™s all trial and error, I also want to learn how else I might be able to accomplish this otherwise, I think my use case question is,

How might I have tasks annotated in detail without having long list (in screen space, not in number) query results?

I considered,

  1. a query-verbosity property of a whole number, which is difficult to modify over time
  2. enforcing a policy of task children must all be tasks and task details must be a reference.
  3. default task query results as collapsed.

Numbers 2. and 3. seem within the logseq philosophy

The syntax [(property ?h :preview-on-day-of-week) ?day] is not valid. This short hand is only able to filter on a literal as you experience. It is not a get value.
The correct syntax uses the advanced syntax.

[?h :block/properties ?prop]
[(get ?prop :preview-on-day-of-week) ?day]

I would split the task ā€œdo workoutā€ from the description of what the workout is exactly.
For example you would write out the workout you wish to do in a block. Then copy the block reference. And then make a task as:
TODO Do [workout x](((block-id)))
This makes a link out of workout x that points to the block with the description in it. Then you can schedule the task as you please.

Hope that helps / gives some ideas.

1 Like

I appreciate the input, thanks for the clarification with property for filtering against literals.


Iā€™ll try it out this way, separating a task from the details.

1 Like

Hi @mentaloid @Siferiax
Do you have a query to find the TODO for the NEXT week?
thanks in advance

One way is to:

  • check the next 7 dates for the desired first day of the week
  • add 7 to the found date
  • use this range to filter the TODOs
1 Like

Thanks. But Iā€™m lost I do not know how to do thatā€¦ :cry::cry::cry:

Something like this:

#+BEGIN_QUERY
{
 :inputs [:today :+7d :+13d]
 :query [:find (pull ?b [*])
 :in $ ?today ?next7 ?next13 %
 :where
   (or
     (and [(+ ?today 1) ?weekBegin] (isWeekDay ?weekBegin 1))
     (and [(+ ?today 2) ?weekBegin] (isWeekDay ?weekBegin 1))
     (and [(+ ?today 3) ?weekBegin] (isWeekDay ?weekBegin 1))
     (and [(+ ?today 4) ?weekBegin] (isWeekDay ?weekBegin 1))
     (and [(+ ?today 5) ?weekBegin] (isWeekDay ?weekBegin 1))
     (and [(+ ?today 6) ?weekBegin] (isWeekDay ?weekBegin 1))
     (and [(+ ?today 7) ?weekBegin] (isWeekDay ?weekBegin 1))
     (and [(- ?next7 6) ?weekBegin] (isWeekDay ?weekBegin 1))
     (and [(- ?next7 5) ?weekBegin] (isWeekDay ?weekBegin 1))
     (and [(- ?next7 4) ?weekBegin] (isWeekDay ?weekBegin 1))
     (and [(- ?next7 3) ?weekBegin] (isWeekDay ?weekBegin 1))
     (and [(- ?next7 2) ?weekBegin] (isWeekDay ?weekBegin 1))
     (and [(- ?next7 1) ?weekBegin] (isWeekDay ?weekBegin 1))
     (and [(- ?next7 0) ?weekBegin] (isWeekDay ?weekBegin 1))
   )

   (or
     (and [(+ ?next7 0) ?weekEnd] (isWeekDay ?weekEnd 0))
     (and [(+ ?next7 1) ?weekEnd] (isWeekDay ?weekEnd 0))
     (and [(+ ?next7 2) ?weekEnd] (isWeekDay ?weekEnd 0))
     (and [(+ ?next7 3) ?weekEnd] (isWeekDay ?weekEnd 0))
     (and [(+ ?next7 4) ?weekEnd] (isWeekDay ?weekEnd 0))
     (and [(+ ?next7 5) ?weekEnd] (isWeekDay ?weekEnd 0))
     (and [(+ ?next7 6) ?weekEnd] (isWeekDay ?weekEnd 0))
     (and [(- ?next13 6) ?weekEnd] (isWeekDay ?weekEnd 0))
     (and [(- ?next13 5) ?weekEnd] (isWeekDay ?weekEnd 0))
     (and [(- ?next13 4) ?weekEnd] (isWeekDay ?weekEnd 0))
     (and [(- ?next13 3) ?weekEnd] (isWeekDay ?weekEnd 0))
     (and [(- ?next13 2) ?weekEnd] (isWeekDay ?weekEnd 0))
     (and [(- ?next13 1) ?weekEnd] (isWeekDay ?weekEnd 0))
     (and [(- ?next13 0) ?weekEnd] (isWeekDay ?weekEnd 0))
   )

   (task ?b #{"TODO"})
   (or
     [?b :block/scheduled ?date]
     [?b :block/deadline ?date]
   )
   [(>= ?date ?weekBegin)]
   [(<= ?date ?weekEnd)]
 ]

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

The above code:

  • turned out double than it should, in the effort to cover the cases when the month (or even the year) changes during the week
  • is relatively slow
  • assumes that a week:
    • begins on Sunday (all the (isWeekDay ?weekBegin 1) )
    • ends on Saturday (all the (isWeekDay ?weekEnd 0) )
2 Likes

Thanks.
I tried and it works perfectly. The down side, as you said, it is very slow.
Do you know if the Lgoseq team is thinking on introducing a better calendar structure with Year month days and also weeks? this would make this kind of query much easier.

I edited the query to move some lines around. Now it should be faster.

I donā€™t have any internal team knowledge.

1 Like

It is working perfectly thanks!!!