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?
orlast-day-of-the-month?
-
first-day-of-month?
orfirst-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.
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
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
-
the
weekDay
fn from this (#12) post -
or
sameWeekDay
from this (#11) post
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!
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,
- a
query-verbosity
property of a whole number, which is difficult to modify over time - enforcing a policy of task children must all be tasks and task details must be a reference.
- 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.
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.
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