├── logseqTestGraph.zip
├── style.css
├── README.md
├── package.json
├── index.html
├── index.test.js
└── index.js
/logseqTestGraph.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adxsoft/logseqadvancedquerybuilder/HEAD/logseqTestGraph.zip
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 | /* theme colors */
2 |
3 | :root {
4 |
5 |
6 | /* Dark theme */
7 | --dark-bg: #00384d;
8 | --dark-fg: #b0e1f4c3;
9 |
10 | /* Light theme */
11 | --light-bg: #d1f0f995;
12 | --light-fg: rgb(59, 44, 44);
13 |
14 | /* Defaults
15 |
16 | For a dark theme use these lines
17 | --current-bg: var(--dark-bg);
18 | --current-fg: var(--dark-fg);
19 |
20 | For a light theme use these lines
21 | --current-bg: var(--light-bg);
22 | --current-fg: var(--light-fg);
23 |
24 | */
25 |
26 | --current-bg: var(--light-bg);
27 | --current-fg: var(--light-fg);
28 | }
29 |
30 |
31 | /* clear all padding, margins */
32 | * {
33 | padding: 0;
34 | margin: 0;
35 | box-sizing: border-box;
36 | }
37 |
38 | html {
39 | font-size: 14px;
40 | }
41 |
42 | body {
43 | padding: 1rem;
44 | font-family: 'Roboto', sans-serif;
45 | background-color: var(--current-bg);
46 | color: var(--current-fg);
47 | }
48 |
49 | a {
50 | background-color: var(--current-bg);
51 | color: var(--current-fg);
52 |
53 | }
54 |
55 |
56 | .title {
57 | margin-bottom: 2rem;
58 | font-size: 2rem;
59 | }
60 |
61 | h3 {
62 | font-family: 'Roboto', sans-serif;
63 | font-size: 1.1rem;
64 | color: var(--current-fg);
65 | }
66 |
67 | h5 {
68 | font-family: 'Roboto', sans-serif;
69 | font-size: 0.9rem;
70 | color: var(--current-fg);
71 | }
72 |
73 |
74 | hr {
75 | margin: 1rem 0;
76 | }
77 |
78 | /* Details/Summary Indentation levels */
79 |
80 | .level1 {
81 | /* list-style: disc; */
82 | background-color: var(--current-bg);
83 | color: var(--current-fg);
84 | padding: rem;
85 | font-size: 1rem;
86 | cursor: pointer;
87 | }
88 |
89 | .level2 {
90 | /* list-style: disc; */
91 | background-color: var(--current-bg);
92 | color: var(--current-fg);
93 | padding: rem;
94 | font-size: 1rem;
95 | cursor: pointer;
96 | margin-left: 1rem;
97 | }
98 |
99 | .level3 {
100 | /* list-style: disc; */
101 | background-color: var(--current-bg);
102 | color: var(--current-fg);
103 | padding: rem;
104 | font-size: 2rem;
105 | cursor: pointer;
106 | margin-left: 1rem;
107 | }
108 |
109 | .details-content {
110 | background-color: var(--current-bg);
111 | color: var(--current-fg);
112 | padding: 1rem;
113 | font-size: 0.8rem;
114 | overflow-wrap: break-word;
115 | cursor: pointer;
116 | }
117 |
118 | button {
119 | font-size: 0.9rem;
120 | padding: 3px 3px;
121 | background-color: rgb(215, 210, 206);
122 | border-radius: 6px;
123 | }
124 |
125 | select {
126 | font-size: 0.8rem;
127 | padding: 1px 1px;
128 | width: 25rem;
129 | background-color: #00384d;
130 | color: white;
131 | text-align: center;
132 | }
133 |
134 | textarea {
135 | color: rgb(7, 7, 0);
136 | width: 25rem;
137 | background-color: rgb(243, 239, 136);
138 | font-size: 0.8rem;
139 | font-weight: bold;
140 | font-family: 'Courier New', Courier, monospace;
141 | padding: 1px 1px;
142 | text-align: left;
143 | }
144 |
145 | .generatedquery {
146 | color: black;
147 | width: 25rem;
148 | background-color: rgb(203, 241, 165);
149 | font-size: 0.8rem;
150 | font-weight: bold;
151 | font-family: 'Courier New', Courier, monospace;
152 | text-align: left;
153 | }
154 |
155 |
156 |
157 | .checkbox {
158 | font-size: 0.8rem;
159 | }
160 |
161 | .statusbar {
162 | font-size: 0.9rem;
163 | padding: 4px 1px;
164 | background-color: var(--current-bg);
165 | color: var(--current-fg);
166 |
167 | text-align: left;
168 | border: 1;
169 |
170 | }
171 |
172 | blockquote {
173 | background-color: var(--current-bg);
174 | color: var(--current-fg);
175 | text-align: left;
176 | }
177 |
178 | table {
179 | background-color: var(--current-bg);
180 | color: var(--current-fg);
181 | border-collapse: collapse;
182 | border: 1px solid var(--current-fg);
183 | }
184 |
185 | th {
186 | padding: 2px;
187 | font-size: 1.8rem;
188 | border: 1px solid var(--current-fg);
189 | }
190 |
191 | td {
192 | padding: 2px;
193 | font-size: 0.8rem;
194 | border: 1px solid var(--current-fg);
195 | }
196 |
197 | /* zebra striping tbody tr:nth-child(odd) {
198 | background-color: var(--current-bg);
199 | color: var(--current-fg);
200 |
201 | }
202 |
203 | tbody tr:nth-child(even) {
204 | background-color: var(--current-bg);
205 | color: var(--current-fg);
206 | } */
207 |
208 | ul {
209 | list-style-type: disc !important;
210 | padding-left: 1em;
211 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # logseqadvancedquerybuilder
2 |
3 | An Experimental online tool to help Logseq Users build advanced queries from simple commands.
4 |
5 | **News Flash 3rd March 2023**
6 | Logseq plugin (**logseq-query-builder-plugin**) now officially in the Logseq Marketplace
7 |
8 | **News Flash 30th Dec 2022**
9 | **Logseq plugin with same functionality now developed.** You can get it [here](https://github.com/adxsoft/logseq-query-builder-plugin) and see it in action [here](https://youtu.be/EA2jLSQ_WMA)
10 |
11 | **Updated 14th Dec 2022 to v0.4 see Releases section below**
12 | **SITE HAS BEEN COMPLETELY REWRITTEN IN JAVASCRIPT FOR STABILITY**
13 |
14 | You can run this tool online at https://adxsoft.github.io/logseqadvancedquerybuilder/
15 |
16 | To include this tool in a logseq page use this line
17 | ```html
18 |
19 | ```
20 |
21 | See the FAQ for instructions and examples of how to use the tool
22 |
23 | Also see https://github.com/adxsoft/buildlogseqtestgraph for building a test graph to checkout the advanced queries you build with this tool
24 |
25 | ## Technical information
26 | The tool is built in javascript.
27 |
28 | To test locally set the mode variable to 'local'. Once this is set you can use Jest Testing Library with the included _index.tests.js_ file.
29 |
30 | To deploy to the web set the mode to 'website'
31 |
32 | 2. To input a set of simple commands to generate an advanced query, add the following code at the end of logseqquerybuilder.py
33 |
34 | ```python
35 | testQueryBuild("""yourcommands""")
36 | ```
37 |
38 | Where yourcommands could be for example
39 |
40 | ```python
41 | testQueryBuild("""title: blocktags and pages command combined - test 3
42 | - pages
43 | - test*
44 | - *2
45 | - not *age1
46 | - blocktags
47 | - tag1
48 | - not tag2
49 | - tag3
50 | - not tag4
51 | """)
52 | ```
53 | which will print the following advanced query that you can copy and paste (using Cmd/Ctrl Shift V) directly into Logseq
54 |
55 | ```clojure
56 | #+BEGIN_QUERY
57 | {
58 | :title [:b "blocktags and pages command combined - test 3"]
59 | :query [:find (pull ?block [*])
60 | :where
61 | [?block :block/content ?blockcontent]
62 | [?block :block/page ?page]
63 | [?page :block/name ?pagename]
64 | ( or
65 | [(clojure.string/starts-with? ?pagename "test")]
66 | [(clojure.string/ends-with? ?pagename "2")]
67 | )
68 | (not [(clojure.string/ends-with? ?pagename "age1")])
69 | ( or
70 | (page-ref ?block "tag1")
71 | (page-ref ?block "tag3")
72 | )
73 | (not (page-ref ?block "tag2"))
74 | (not (page-ref ?block "tag4"))
75 | ]
76 | }
77 | #+END_QUERY
78 | ```
79 | 3. To run the unit tests you must do step 1 above and then run *test.py*
80 |
81 | # Releases
82 | _Version 0.1_
83 | - Original release Oct 2022
84 |
85 |
86 | _Version 0.2_
87 | - clarify pages retrieval vs blocks retrieval in FAQ, Simple Commands
88 | - Added 'and' and 'or' keywords in arguments for a command, For example can now say
89 | ```
90 | - tagA
91 | - or tagA
92 | ```
93 | and also
94 | ```
95 | - property category, "fiction"
96 | - and property category, "western"
97 | ```
98 | - Added a logseq test graph download button to help user test advanced queries
99 | - Force user to choose either pages or block retrieval, Default to block retrieval
100 | - improved error messaging
101 | - improved descriptions for the generated advanced query lines
102 | - bug fixes
103 |
104 | _Version 0.3_ Dec 8th 2022
105 | - added the pagelinks command which will select blocks that have links to specific pages or journals
106 |
107 | Example: To select blocks referring to page1 OR page 2
108 | ```
109 | - blocks
110 | - *
111 | - pagelinks
112 | - page1
113 | - page2
114 | ```
115 | Example: To select blocks referring to page1 AND page 2
116 | ```
117 | - blocks
118 | - *
119 | - pagelinks
120 | - page1
121 | - and page2
122 | ```
123 | Example: To select blocks referring to Xmas day journal
124 | (assumes your date format is the default format)
125 | ```
126 | - blocks
127 | - *
128 | - pagelinks
129 | - Dec 25th, 2022
130 | ```
131 | If you use a different date format use that in the journal reference
132 |
133 | _Version 0.4_ Dec 14th 2022
134 | Redeveloped in Javascript for speed and stability
135 | - pyscript is still in alpha and early days so changes are happening all the time
136 | - javascript is stable
137 | - code base has been changed so that the core functions can operate in one of three ways
138 | (mode variable controls which operation is chosen _website_,_local_,_logseq-plugin_
139 | - as this website,
140 | - locally for testing
141 | - as a logseq plugin (distributed to a separate repository)
142 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "logseq-advanced-query-builder",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "functions.js",
6 | "directories": {
7 | "test": "test"
8 | },
9 | "dependencies": {
10 | "abortcontroller-polyfill": "^1.7.3",
11 | "acorn": "^8.8.0",
12 | "ansi-styles": "^4.3.0",
13 | "asn1.js": "^5.4.1",
14 | "assert": "^2.0.0",
15 | "available-typed-arrays": "^1.0.5",
16 | "base-x": "^3.0.9",
17 | "base64-js": "^1.5.1",
18 | "bn.js": "^4.12.0",
19 | "boolbase": "^1.0.0",
20 | "brorand": "^1.1.0",
21 | "browserify-aes": "^1.2.0",
22 | "browserify-cipher": "^1.0.1",
23 | "browserify-des": "^1.0.2",
24 | "browserify-rsa": "^4.1.0",
25 | "browserify-sign": "^4.2.1",
26 | "browserslist": "^4.21.4",
27 | "buffer": "^6.0.3",
28 | "buffer-from": "^1.1.2",
29 | "buffer-xor": "^1.0.3",
30 | "builtin-status-codes": "^3.0.0",
31 | "call-bind": "^1.0.2",
32 | "callsites": "^3.1.0",
33 | "caniuse-lite": "^1.0.30001418",
34 | "chalk": "^4.1.2",
35 | "chrome-trace-event": "^1.0.3",
36 | "cipher-base": "^1.0.4",
37 | "clone": "^2.1.2",
38 | "color-convert": "^2.0.1",
39 | "color-name": "^1.1.4",
40 | "commander": "^7.2.0",
41 | "cosmiconfig": "^7.0.1",
42 | "create-ecdh": "^4.0.4",
43 | "create-hash": "^1.2.0",
44 | "create-hmac": "^1.1.7",
45 | "crypto-browserify": "^3.12.0",
46 | "css-select": "^4.3.0",
47 | "css-tree": "^1.1.3",
48 | "css-what": "^6.1.0",
49 | "csso": "^4.2.0",
50 | "csstype": "^3.0.8",
51 | "debug": "^4.3.4",
52 | "define-properties": "^1.1.4",
53 | "des.js": "^1.0.1",
54 | "detect-libc": "^1.0.3",
55 | "diffie-hellman": "^5.0.3",
56 | "dom-serializer": "^1.4.1",
57 | "domelementtype": "^2.3.0",
58 | "domhandler": "^4.3.1",
59 | "dompurify": "^2.3.1",
60 | "domutils": "^2.8.0",
61 | "dot-case": "^3.0.4",
62 | "dotenv": "^7.0.0",
63 | "dotenv-expand": "^5.1.0",
64 | "electron-to-chromium": "^1.4.275",
65 | "elliptic": "^6.5.4",
66 | "engine.io-client": "^6.2.2",
67 | "engine.io-parser": "^5.0.4",
68 | "entities": "^3.0.1",
69 | "error-ex": "^1.3.2",
70 | "es-abstract": "^1.20.4",
71 | "es-to-primitive": "^1.2.1",
72 | "es6-object-assign": "^1.1.0",
73 | "escalade": "^3.1.1",
74 | "escape-string-regexp": "^1.0.5",
75 | "eventemitter3": "^4.0.7",
76 | "events": "^3.3.0",
77 | "evp_bytestokey": "^1.0.3",
78 | "fast-deep-equal": "^3.1.3",
79 | "for-each": "^0.3.3",
80 | "function-bind": "^1.1.1",
81 | "function.prototype.name": "^1.1.5",
82 | "functions-have-names": "^1.2.3",
83 | "get-intrinsic": "^1.1.3",
84 | "get-port": "^4.2.0",
85 | "get-symbol-description": "^1.0.0",
86 | "globals": "^13.17.0",
87 | "has": "^1.0.3",
88 | "has-bigints": "^1.0.2",
89 | "has-flag": "^4.0.0",
90 | "has-property-descriptors": "^1.0.0",
91 | "has-symbols": "^1.0.3",
92 | "has-tostringtag": "^1.0.0",
93 | "hash-base": "^3.1.0",
94 | "hash.js": "^1.1.7",
95 | "hmac-drbg": "^1.0.1",
96 | "htmlnano": "^2.0.2",
97 | "htmlparser2": "^7.2.0",
98 | "https-browserify": "^1.0.0",
99 | "ieee754": "^1.2.1",
100 | "import-fresh": "^3.3.0",
101 | "inherits": "^2.0.4",
102 | "internal-slot": "^1.0.3",
103 | "is-arguments": "^1.1.1",
104 | "is-arrayish": "^0.2.1",
105 | "is-bigint": "^1.0.4",
106 | "is-boolean-object": "^1.1.2",
107 | "is-callable": "^1.2.7",
108 | "is-date-object": "^1.0.5",
109 | "is-generator-function": "^1.0.10",
110 | "is-json": "^2.0.1",
111 | "is-nan": "^1.3.2",
112 | "is-negative-zero": "^2.0.2",
113 | "is-number-object": "^1.0.7",
114 | "is-regex": "^1.1.4",
115 | "is-shared-array-buffer": "^1.0.2",
116 | "is-string": "^1.0.7",
117 | "is-symbol": "^1.0.4",
118 | "is-typed-array": "^1.1.9",
119 | "is-weakref": "^1.0.2",
120 | "js-tokens": "^4.0.0",
121 | "json-parse-even-better-errors": "^2.3.1",
122 | "json5": "^2.2.1",
123 | "lightningcss": "^1.16.0",
124 | "lightningcss-darwin-x64": "^1.16.0",
125 | "lines-and-columns": "^1.2.4",
126 | "lmdb": "^2.5.2",
127 | "lodash-es": "^4.17.21",
128 | "lower-case": "^2.0.2",
129 | "md5.js": "^1.3.5",
130 | "mdn-data": "^2.0.14",
131 | "miller-rabin": "^4.0.1",
132 | "minimalistic-assert": "^1.0.1",
133 | "minimalistic-crypto-utils": "^1.0.1",
134 | "ms": "^2.1.2",
135 | "msgpackr": "^1.7.2",
136 | "msgpackr-extract": "^2.1.2",
137 | "no-case": "^3.0.4",
138 | "node-addon-api": "^3.2.1",
139 | "node-gyp-build": "^4.5.0",
140 | "node-gyp-build-optional-packages": "^5.0.3",
141 | "node-releases": "^2.0.6",
142 | "nth-check": "^2.1.1",
143 | "nullthrows": "^1.1.1",
144 | "object-inspect": "^1.12.2",
145 | "object-is": "^1.1.5",
146 | "object-keys": "^1.1.1",
147 | "object.assign": "^4.1.4",
148 | "ordered-binary": "^1.4.0",
149 | "parcel": "^2.7.0",
150 | "parent-module": "^1.0.1",
151 | "parse-asn1": "^5.1.6",
152 | "parse-json": "^5.2.0",
153 | "path": "^0.12.7",
154 | "path-type": "^4.0.0",
155 | "pbkdf2": "^3.1.2",
156 | "picocolors": "^1.0.0",
157 | "postcss-value-parser": "^4.2.0",
158 | "posthtml": "^0.16.6",
159 | "posthtml-parser": "^0.10.2",
160 | "posthtml-render": "^3.0.0",
161 | "process": "^0.11.10",
162 | "public-encrypt": "^4.0.3",
163 | "punycode": "^1.3.2",
164 | "querystring": "^0.2.0",
165 | "querystring-es3": "^0.2.1",
166 | "randombytes": "^2.1.0",
167 | "randomfill": "^1.0.4",
168 | "react-error-overlay": "^6.0.9",
169 | "react-refresh": "^0.9.0",
170 | "readable-stream": "^3.6.0",
171 | "regenerator-runtime": "^0.13.9",
172 | "regexp.prototype.flags": "^1.4.3",
173 | "resolve-from": "^4.0.0",
174 | "ripemd160": "^2.0.2",
175 | "safe-buffer": "^5.2.1",
176 | "safe-regex-test": "^1.0.0",
177 | "safer-buffer": "^2.1.2",
178 | "semver": "^5.7.1",
179 | "sha.js": "^2.4.11",
180 | "side-channel": "^1.0.4",
181 | "snake-case": "^3.0.4",
182 | "socket.io-client": "^4.5.2",
183 | "socket.io-parser": "^4.2.1",
184 | "source-map": "^0.6.1",
185 | "source-map-support": "^0.5.21",
186 | "stable": "^0.1.8",
187 | "stream-browserify": "^3.0.0",
188 | "stream-http": "^3.2.0",
189 | "string_decoder": "^1.3.0",
190 | "string.prototype.trimend": "^1.0.5",
191 | "string.prototype.trimstart": "^1.0.5",
192 | "supports-color": "^7.2.0",
193 | "svgo": "^2.8.0",
194 | "term-size": "^2.2.1",
195 | "terser": "^5.15.1",
196 | "timsort": "^0.3.0",
197 | "tslib": "^2.4.0",
198 | "type-fest": "^0.20.2",
199 | "unbox-primitive": "^1.0.2",
200 | "update-browserslist-db": "^1.0.10",
201 | "url": "^0.11.0",
202 | "util": "^0.12.4",
203 | "util-deprecate": "^1.0.2",
204 | "utility-types": "^3.10.0",
205 | "v8-compile-cache": "^2.3.0",
206 | "weak-lru-cache": "^1.2.2",
207 | "which-boxed-primitive": "^1.0.2",
208 | "which-typed-array": "^1.1.8",
209 | "ws": "^8.2.3",
210 | "xmlhttprequest-ssl": "^2.0.0",
211 | "xtend": "^4.0.2",
212 | "xxhash-wasm": "^0.4.2",
213 | "yaml": "^1.10.2"
214 | },
215 | "devDependencies": {
216 | "jest": "^29.3.1"
217 | },
218 | "scripts": {
219 | "test": "jest"
220 | },
221 | "keywords": [],
222 | "author": "",
223 | "license": "ISC"
224 | }
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Logseq Advanced Query Builder
5 | v0.5 Javascript Version
6 | Light Theme
7 | Dark Theme
8 | Download a test graph
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | Logseq Query Builder
18 |
19 |
20 |
21 |
22 |
23 | An Experimental online tool to help Logseq Users build advanced queries from simple commands.
24 |
25 |
26 |
27 |
28 | FAQ
29 |
30 | How to use
31 |
32 | The simple commands are entered as a text outline in the Command Input area
33 |
34 |
35 | - commandname
36 | - argument
37 | - argument
38 | Optionally arguments can begin with any of the words and ,or ,and ,
39 |
40 |
41 |
42 | Enter commands in the yellow area below or choose an example.
43 | Tick Include Query Comments to show query line comments
44 | Tick Copy as code block to wrap query in a Logseq code block
45 | Click the Generate Advanced Query button
46 | to build the query.
47 |
48 | Optionally you can include comments for each query line.
49 |
50 | Copy the generated advanced query to the clipboard>
51 |
52 | (if necessary scroll down to see the result)
53 |
54 |
55 | Paste into Logseq using Cmd(or Ctrl) Shift V
56 |
57 |
58 |
59 |
60 | Why did I build this tool
61 |
62 | The reason I created this query builder was for the following reasons
63 |
64 | Advanced Queries have a complicated syntax that causes errors eg. missing brackets
65 | For non developers they can build advanced queries and avoid having to learn programming in clojure and datalog
66 | Logseq users can learn by using the examples to generate queries with detailed comments
67 | As the generator is web based it can be accessed from desktop or mobile devices as generated queries are always copied to the clipboard
68 |
69 |
70 |
71 |
72 | Simple Command List
73 |
74 |
75 | Queries filter in two ways - pages or blocks
76 | pages command retrieves the special blocks that have ONLY the page information such as name, page tags, page properties
77 | - these page blocks are placed into the ?block variable
78 | blocks command retrieves every single block in the graph including the special page blocks
79 | - these page blocks are placed into the ?block variable and the page this block belongs to is placed in the ?page variable
80 | You must choose a pages command OR a blocks command (you cannot use noth together)
81 |
82 |
83 |
84 | Note. Wildcards can be full name or partial name using *
85 | test* - starts with text 'test'
86 | *end - ends with text 'end'
87 | *tax* - contains text 'tax'
88 |
89 |
90 |
91 | blocks select logseq blocks by wildcards
92 | blockproperties select blocks by property values
93 | blocktags select blocks by tag
94 | deadline select pages or blocks that have a deadline
95 | deadlinebetween select pages or blocks that have a deadline in a date range
96 | journalsbetween only select journal pages in a date range
97 | journalonly only select journal pages
98 | namespace select pages or blocks within a namespace
99 | pages select pages by wildcards
100 | pageproperties select pages by page properties
101 | pagetags select pages by tag
102 | pagelinks select blocks that have links to pages - note. Journal page link is your chosen format in your settings. For example Dec 25th, 2022
103 | tasks select tasks
104 | scheduled select pages or blocks that are scheduled
105 | scheduledbetween select pages or blocks that are scheduled in a date range
106 |
107 |
108 |
109 | About
110 |
111 | This web site is hosted on github pages
112 | source code is available
here
113 |
114 |
115 |
116 | Release History
117 |
118 | v0.1
119 |
120 | Original release
121 |
122 | v0.2
123 |
124 | clarify pages retrieval vs blocks retrieval in FAQ, Simple Commands
125 | Added 'and' and 'or' keywords in arguments for a command, For example
126 | can now say
127 | - tagA
128 | - or tagA
129 | and also
130 | - property category, "fiction"
131 | - and property category, "western"
132 |
133 | Added a logseq test graph for download to help user test advanced queries
134 | Force user to choose either pages or block retrieval, Default to block retrieval
135 | improved error messaging
136 | improved descriptions for the generated advanced query lines
137 | bug fixes
138 |
139 | v0.3
140 |
141 | Added pagelinks command to select blocks with specific pagelinks
142 |
143 | v0.4
144 |
145 | Conversion from pyscript to javascript
146 |
147 |
148 |
149 |
150 | Licence
151 |
152 | This tool is free to use by anyone. I built it for my own educational purposes to learn advanced queries and I'm still a novice so the generated queries reflect my current understanding of advanced queries that I have been able to test on Logseq 0.8.2 in October 2022
153 | The advanced queries generated are my interpretation of advanced queries from researching the logseq discord forum and links on the logseq site.
154 | I have not yet included the result-transform or view sections of advanced queries as I am still trying to understand them sufficiently to generate meaningful queries.
155 |
156 | DISCLAIMER
157 |
158 | logseqquerybuilder is distributed under GNU General Public License v3.
159 |
160 | This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to
161 | redistribute it under certain conditions.
162 |
163 | LICENSE
164 |
165 | This program is free software: you can redistribute it and/or modify
166 | it under the terms of the GNU General Public License as published by
167 | the Free Software Foundation, either version 3 of the License, or
168 | (at your option) any later version.
169 |
170 | This program is distributed in the hope that it will be useful,
171 | but WITHOUT ANY WARRANTY; without even the implied warranty of
172 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
173 |
174 | Please see http://www.gnu.org/licenses/ http://www.gnu.org/licenses/ for details.
175 |
176 | WARRANTY
177 |
178 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
179 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
180 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY
181 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
182 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
183 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
184 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
185 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
186 |
187 | LIABILITY
188 |
189 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL
190 | ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE
191 | PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
192 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
193 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
194 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
195 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
196 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
197 | SUCH DAMAGES.
198 |
199 |
200 |
201 |
202 |
203 | Command Input
204 |
205 | Choose Example..
206 | pages - select all pages
207 | pages - select specific pages
208 | pages - using wildcards(*)
209 | pages - ignore various pages
210 | blocks - content by wildcards
211 | blocktags - select and exclude block level tags
212 | blocktags and pages
213 | pagetags - page level tags
214 | pagetags - with pages selection
215 | pagetags - with pages selection using and or
216 | pagelinks - select blocks with links to pages
217 | tasks - select and exclude task types
218 | tasks - tasks and pages
219 | page properties - select pages using page property
220 | page properties - using prefixes and or
221 | block properties - select blocks using block property
222 | block properties - using prefixes and or
223 | namespace - only search pages in specific namespace
224 | namespace - find block properties in a namespace
225 | scheduled - find scheduled blocks in a date range
226 | deadline - find blocks with deadlines
227 | deadline - find deadline blocks in a date range
228 | journalonly - find journals only (not pages)
229 | journalsbetween - find future journals in a date range
230 | journalsbetween - find past journals in a date range
231 | collapse - collapse all found blocks
232 | expand - expand all found blocks
233 | showbreadcrumb - show breadcrumbs for all found blocks
234 | hidebreadcrumb - hide breadcrumbs for all found blocks
235 |
236 |
237 |
238 |
240 |
241 |
242 | Clear
243 |
244 | Generated Query
245 |
249 | Generate Advanced Query
250 | Copy Query to Clipboard
251 |
252 |
253 |
254 |
255 |
256 |
257 | Status
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
303 |
336 |
337 |
--------------------------------------------------------------------------------
/index.test.js:
--------------------------------------------------------------------------------
1 | const functions = require('./index');
2 | const fs = require('fs');
3 |
4 | //-------------------------------------------------------
5 | // local functions to assist testing
6 | //-------------------------------------------------------
7 |
8 | function saveAutomatedTestOutput(msg) {
9 | fs.writeFile('testing_results.txt', msg, function (err) {
10 | if (err)
11 | return console.log(err);
12 | console.log('Test Results written to testing_results.txt');
13 | });
14 | }
15 |
16 | function setGlobals({
17 | querygroup = 'blocks-querylines',
18 | showcommandcomments = false,
19 | codeblock = false } = {}) {
20 | functions.setquerygroup(querygroup)
21 | functions.setshowcommandcomments(showcommandcomments)
22 | functions.setcodeblock(codeblock)
23 | }
24 |
25 | function resetGlobalsToDefault() {
26 | setGlobals({
27 | querygroup: 'blocks-querylines',
28 | showcommandcoments: false,
29 | codeblock: false
30 | })
31 | }
32 |
33 | function gettestcommands(testno) {
34 | testcases = functions.getquerytestcases()
35 | var testdata = testcases[testno].split("#+BEGIN")
36 | return testdata[0].trim()
37 | }
38 |
39 |
40 | function gettestexpectedresults(testno) {
41 | testcases = functions.getquerytestcases()
42 | var testdata = testcases[testno].split("#+BEGIN")
43 | var expectedresult = "#+BEGIN" + testdata[1]
44 | returnval = expectedresult
45 | return returnval
46 | }
47 |
48 |
49 | //-------------------------------------------------------
50 | // test any old function
51 | //-------------------------------------------------------
52 |
53 |
54 | describe('junk tests', () => {
55 | test('add 2 numbers', () => {
56 | returnval = functions.add(1, 1)
57 | expect(returnval).toBe(2)
58 | })
59 | }) // end describe
60 |
61 | describe('Manual tests', () => {
62 | // ------------------------------------
63 |
64 |
65 | // ------------------------------------
66 |
67 | // ------------------------------------
68 | // ------------------------------------
69 |
70 |
71 | // ------------------------------------
72 |
73 |
74 |
75 | // ------------------------------------
76 | test('pages test 1', () => {
77 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
78 | setGlobals()
79 | commands = `title: pages command - select all pages
80 | - pages
81 | - *
82 | `
83 | expectedresults = `#+BEGIN_QUERY
84 | {
85 | :title [:b "pages command - select all pages"]
86 | :query [:find (pull ?block [*])
87 | :where
88 | [?block :block/name ?pagename]
89 | ]
90 | }
91 | #+END_QUERY
92 | `
93 | functions.initialiseQuery()
94 | functions.processCommandList(commands)
95 | advancedquery = functions.constructQuery()
96 | resetGlobalsToDefault()
97 | expect(advancedquery).toEqual(expectedresults)
98 | })
99 |
100 | // ------------------------------------
101 | test('pages - test 2', () => {
102 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
103 | setGlobals()
104 | commands = `title: pages command - pages by wildcards
105 | - pages
106 | - abc*
107 | - *de*
108 | - not 2*
109 | `
110 | expectedresults = `#+BEGIN_QUERY
111 | {
112 | :title [:b "pages command - pages by wildcards"]
113 | :query [:find (pull ?block [*])
114 | :where
115 | [?block :block/name ?pagename]
116 | ( or
117 | [(clojure.string/starts-with? ?pagename "abc")]
118 | [(clojure.string/includes? ?pagename "de")]
119 | )
120 | (not [(clojure.string/starts-with? ?pagename "2")])
121 | ]
122 | }
123 | #+END_QUERY
124 | `
125 | functions.initialiseQuery()
126 | functions.processCommandList(commands)
127 | advancedquery = functions.constructQuery()
128 | resetGlobalsToDefault()
129 | expect(advancedquery).toEqual(expectedresults)
130 | })
131 |
132 |
133 | // ------------------------------------
134 | test('pages - test 3', () => {
135 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
136 | setGlobals()
137 | commands = `title: pages - wildcards but exclude specific page
138 | - pages
139 | - testpage*
140 | - not testpage3
141 | `
142 | expectedresults = `#+BEGIN_QUERY
143 | {
144 | :title [:b "pages - wildcards but exclude specific page"]
145 | :query [:find (pull ?block [*])
146 | :where
147 | [?block :block/name ?pagename]
148 | [(clojure.string/starts-with? ?pagename "testpage")]
149 | (not [?block :block/name "testpage3"])
150 | ]
151 | }
152 | #+END_QUERY
153 | `
154 | functions.initialiseQuery()
155 | functions.processCommandList(commands)
156 | advancedquery = functions.constructQuery()
157 | resetGlobalsToDefault()
158 | expect(advancedquery).toEqual(expectedresults)
159 | })
160 |
161 | // ------------------------------------
162 | test('blocks - test 1', () => {
163 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
164 | setGlobals()
165 | commands = `title: blocks command - blocks by wildcards
166 | - blocks
167 | - testblock*
168 | - *123*
169 | - 6*
170 | - not *456*
171 | `
172 | expectedresults = `#+BEGIN_QUERY
173 | {
174 | :title [:b "blocks command - blocks by wildcards"]
175 | :query [:find (pull ?block [*])
176 | :where
177 | [?block :block/content ?blockcontent]
178 | [?block :block/page ?page]
179 | [?page :block/name ?pagename]
180 | ( or
181 | [(clojure.string/ends-with? ?blockcontent "testblock")]
182 | [(clojure.string/includes? ?blockcontent "123")]
183 | [(clojure.string/ends-with? ?blockcontent "6")]
184 | )
185 | (not [(clojure.string/includes? ?blockcontent "456")])
186 | ]
187 | }
188 | #+END_QUERY
189 | `
190 | functions.initialiseQuery()
191 | functions.processCommandList(commands)
192 | advancedquery = functions.constructQuery()
193 | resetGlobalsToDefault()
194 | expect(advancedquery).toEqual(expectedresults)
195 | })
196 |
197 | // ------------------------------------
198 |
199 |
200 |
201 | // ------------------------------------
202 |
203 |
204 | // ------------------------------------
205 |
206 |
207 | // ------------------------------------
208 | test('blocktags - test 4', () => {
209 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
210 | setGlobals()
211 | commands = `title: multiple blocks tags
212 | - blocks
213 | - *
214 | - blocktags
215 | - tag1
216 | - tag2
217 | - tag3
218 | - not tag2
219 | `
220 | expectedresults = `#+BEGIN_QUERY
221 | {
222 | :title [:b "multiple blocks tags"]
223 | :query [:find (pull ?block [*])
224 | :where
225 | [?block :block/content ?blockcontent]
226 | [?block :block/page ?page]
227 | [?page :block/name ?pagename]
228 | ( or
229 | (page-ref ?block "tag1")
230 | (page-ref ?block "tag2")
231 | (page-ref ?block "tag3")
232 | )
233 | (not (page-ref ?block "tag2"))
234 | ]
235 | }
236 | #+END_QUERY
237 | `
238 | functions.initialiseQuery()
239 | functions.processCommandList(commands)
240 | advancedquery = functions.constructQuery()
241 | resetGlobalsToDefault()
242 | expect(advancedquery).toEqual(expectedresults)
243 | })
244 |
245 | // ------------------------------------
246 |
247 |
248 | // ------------------------------------
249 | test('pagestags - test 2', () => {
250 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
251 | setGlobals()
252 | commands = `title: pagetags and pages combined - test 1
253 | - pages
254 | - not age7*
255 | - pagetags
256 | - pagetag1
257 | - pagetag2
258 | - not pagetag4
259 | `
260 | expectedresults = `#+BEGIN_QUERY
261 | {
262 | :title [:b "pagetags and pages combined - test 1"]
263 | :query [:find (pull ?block [*])
264 | :where
265 | [?block :block/name ?pagename]
266 | (not [(clojure.string/starts-with? ?pagename "age7")])
267 | [?block :block/journal? false]
268 | ( or
269 | (page-tags ?block #{"pagetag1"})
270 | (page-tags ?block #{"pagetag2"})
271 | )
272 | (not (page-tags ?block #{"pagetag4"}))
273 | ]
274 | }
275 | #+END_QUERY
276 | `
277 | functions.initialiseQuery()
278 | functions.processCommandList(commands)
279 | advancedquery = functions.constructQuery()
280 | setGlobals({ showcommandcomments: false }) // reset so other tests will be unaffected
281 | resetGlobalsToDefault()
282 | expect(advancedquery).toEqual(expectedresults)
283 | })
284 |
285 | // ------------------------------------
286 | test('pagetags - test 3', () => {
287 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
288 | setGlobals()
289 | commands = `title: pages with multiple tags
290 | - pages
291 | - *
292 | - pagetags
293 | - classA
294 | - classB
295 | `
296 | expectedresults = `#+BEGIN_QUERY
297 | {
298 | :title [:b "pages with multiple tags"]
299 | :query [:find (pull ?block [*])
300 | :where
301 | [?block :block/name ?pagename]
302 | [?block :block/journal? false]
303 | ( or
304 | (page-tags ?block #{"classa"})
305 | (page-tags ?block #{"classb"})
306 | )
307 | ]
308 | }
309 | #+END_QUERY
310 | `
311 | functions.initialiseQuery()
312 | functions.processCommandList(commands)
313 | advancedquery = functions.constructQuery()
314 | resetGlobalsToDefault()
315 | expect(advancedquery).toEqual(expectedresults)
316 | })
317 |
318 | // ------------------------------------
319 |
320 |
321 | // ------------------------------------
322 | test('pageproperties - test 1', () => {
323 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
324 | setGlobals()
325 | commands = `title: pageproperties - pagetype only missing pages command
326 | - pages
327 | - *
328 | - pageproperties
329 | - pagetype, "testA"
330 | `
331 | expectedresults = `#+BEGIN_QUERY
332 | {
333 | :title [:b "pageproperties - pagetype only missing pages command"]
334 | :query [:find (pull ?block [*])
335 | :where
336 | [?block :block/name ?pagename]
337 | (page-property ?block :pagetype "testA")
338 | ]
339 | }
340 | #+END_QUERY
341 | `
342 | functions.initialiseQuery()
343 | functions.processCommandList(commands)
344 | advancedquery = functions.constructQuery()
345 | resetGlobalsToDefault()
346 | expect(advancedquery).toEqual(expectedresults)
347 | })
348 |
349 |
350 | // ------------------------------------
351 | test('pageproperties - test 2', () => {
352 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
353 | setGlobals()
354 | commands = `title: pageproperties - pagetype testA and testB
355 | - pages
356 | - *
357 | - pageproperties
358 | - pagetype, "testA"
359 | - pagetype, "testB"
360 | `
361 | expectedresults = `#+BEGIN_QUERY
362 | {
363 | :title [:b "pageproperties - pagetype testA and testB"]
364 | :query [:find (pull ?block [*])
365 | :where
366 | [?block :block/name ?pagename]
367 | ( or
368 | (page-property ?block :pagetype "testA")
369 | (page-property ?block :pagetype "testB")
370 | )
371 | ]
372 | }
373 | #+END_QUERY
374 | `
375 | functions.initialiseQuery()
376 | functions.processCommandList(commands)
377 | advancedquery = functions.constructQuery()
378 | resetGlobalsToDefault()
379 | expect(advancedquery).toEqual(expectedresults)
380 | })
381 |
382 | // ------------------------------------
383 | test('pageproperties - test 3', () => {
384 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
385 | setGlobals()
386 | commands = `title: pageproperties - pagetype testA not testB
387 | - pages
388 | - *
389 | - pageproperties
390 | - pagetype, "testA"
391 | - not pagetype, "testB"
392 | `
393 | expectedresults = `#+BEGIN_QUERY
394 | {
395 | :title [:b "pageproperties - pagetype testA not testB"]
396 | :query [:find (pull ?block [*])
397 | :where
398 | [?block :block/name ?pagename]
399 | (page-property ?block :pagetype "testA")
400 | (not (page-property ?block :pagetype "testB"))
401 | ]
402 | }
403 | #+END_QUERY
404 | `
405 | functions.initialiseQuery()
406 | functions.processCommandList(commands)
407 | advancedquery = functions.constructQuery()
408 | resetGlobalsToDefault()
409 | expect(advancedquery).toEqual(expectedresults)
410 | })
411 | // ------------------------------------
412 |
413 | // ------------------------------------
414 | test('blockproperties - pagetype only', () => {
415 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
416 | setGlobals()
417 | commands = `title: blockproperties - pagetype only
418 | - blocks
419 | - *
420 | - pageproperties
421 | - pagetype, "testA"
422 | `
423 | expectedresults = `#+BEGIN_QUERY
424 | {
425 | :title [:b "blockproperties - pagetype only"]
426 | :query [:find (pull ?block [*])
427 | :where
428 | [?block :block/content ?blockcontent]
429 | [?block :block/page ?page]
430 | [?page :block/name ?pagename]
431 | (page-property ?page :pagetype "testA")
432 | ]
433 | }
434 | #+END_QUERY
435 | `
436 | functions.initialiseQuery()
437 | functions.processCommandList(commands)
438 | advancedquery = functions.constructQuery()
439 | resetGlobalsToDefault()
440 | expect(advancedquery).toEqual(expectedresults)
441 | })
442 |
443 | // ------------------------------------
444 | test('blockproperties - blockprop3 b1', () => {
445 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
446 | setGlobals()
447 | commands = `title: blockproperties - blockprop3 b1
448 | - blocks
449 | - *
450 | - blockproperties
451 | - blockprop3, "b1"
452 | `
453 | expectedresults = `#+BEGIN_QUERY
454 | {
455 | :title [:b "blockproperties - blockprop3 b1"]
456 | :query [:find (pull ?block [*])
457 | :where
458 | [?block :block/content ?blockcontent]
459 | [?block :block/page ?page]
460 | [?page :block/name ?pagename]
461 | (property ?block :blockprop3 "b1")
462 | ]
463 | }
464 | #+END_QUERY
465 | `
466 | functions.initialiseQuery()
467 | functions.processCommandList(commands)
468 | advancedquery = functions.constructQuery()
469 | resetGlobalsToDefault()
470 | expect(advancedquery).toEqual(expectedresults)
471 | })
472 |
473 | // ------------------------------------
474 | test('blockproperties - blockprop3 b1 and b2 and b3', () => {
475 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
476 | setGlobals()
477 | commands = `title: blockproperties - blockprop3 b1 and b2 and b3
478 | - blocks
479 | - *
480 | - blockproperties
481 | - blockprop3, "b1"
482 | - blockprop3, "b2"
483 | - blockprop3, "b3"
484 | `
485 | expectedresults = `#+BEGIN_QUERY
486 | {
487 | :title [:b "blockproperties - blockprop3 b1 and b2 and b3"]
488 | :query [:find (pull ?block [*])
489 | :where
490 | [?block :block/content ?blockcontent]
491 | [?block :block/page ?page]
492 | [?page :block/name ?pagename]
493 | ( or
494 | (property ?block :blockprop3 "b1")
495 | (property ?block :blockprop3 "b2")
496 | (property ?block :blockprop3 "b3")
497 | )
498 | ]
499 | }
500 | #+END_QUERY
501 | `
502 | functions.initialiseQuery()
503 | functions.processCommandList(commands)
504 | advancedquery = functions.constructQuery()
505 | resetGlobalsToDefault()
506 | expect(advancedquery).toEqual(expectedresults)
507 | })
508 |
509 | // ------------------------------------
510 | test('blockproperties - blockprop3 b1 and b2 not b3', () => {
511 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
512 | setGlobals()
513 | commands = `title: blockproperties - blockprop3 b1 and b2 not b3
514 | - blocks
515 | - *
516 | - blockproperties
517 | - blockprop3, "b1"
518 | - blockprop3, "b2"
519 | - not blockprop3, "b3"
520 | `
521 | expectedresults = `#+BEGIN_QUERY
522 | {
523 | :title [:b "blockproperties - blockprop3 b1 and b2 not b3"]
524 | :query [:find (pull ?block [*])
525 | :where
526 | [?block :block/content ?blockcontent]
527 | [?block :block/page ?page]
528 | [?page :block/name ?pagename]
529 | ( or
530 | (property ?block :blockprop3 "b1")
531 | (property ?block :blockprop3 "b2")
532 | )
533 | (not (property ?block :blockprop3 "b3"))
534 | ]
535 | }
536 | #+END_QUERY
537 | `
538 | functions.initialiseQuery()
539 | functions.processCommandList(commands)
540 | advancedquery = functions.constructQuery()
541 | resetGlobalsToDefault()
542 | expect(advancedquery).toEqual(expectedresults)
543 | })
544 |
545 | // ------------------------------------
546 | test('namespace1 block properties', () => {
547 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
548 | setGlobals()
549 | commands = `title: namespace1 block properties
550 | - blocks
551 | - *
552 | - namespace
553 | - namespace1
554 | - blockproperties
555 | - ns1p1blocktype, "nsp1blockvalue"
556 | - ns1p2blocktype, "nsp2blockvalue"
557 | `
558 | expectedresults = `#+BEGIN_QUERY
559 | {
560 | :title [:b "namespace1 block properties"]
561 | :query [:find (pull ?block [*])
562 | :where
563 | [?block :block/content ?blockcontent]
564 | [?block :block/page ?page]
565 | [?page :block/name ?pagename]
566 | (namespace ?page "namespace1")
567 | ( or
568 | (property ?block :ns1p1blocktype "nsp1blockvalue")
569 | (property ?block :ns1p2blocktype "nsp2blockvalue")
570 | )
571 | ]
572 | }
573 | #+END_QUERY
574 | `
575 | functions.initialiseQuery()
576 | functions.processCommandList(commands)
577 | advancedquery = functions.constructQuery()
578 | resetGlobalsToDefault()
579 | expect(advancedquery).toEqual(expectedresults)
580 | })
581 |
582 | // ------------------------------------
583 | test('not namespace1 block properties', () => {
584 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
585 | setGlobals()
586 | commands = `title: not namespace1 block properties
587 | - blocks
588 | - *
589 | - namespace
590 | - not namespace1
591 | - blockproperties
592 | - ns1p1blocktype, "nsp1blockvalue"
593 | - ns1p2blocktype, "nsp2blockvalue"
594 | `
595 | expectedresults = `#+BEGIN_QUERY
596 | {
597 | :title [:b "not namespace1 block properties"]
598 | :query [:find (pull ?block [*])
599 | :where
600 | [?block :block/content ?blockcontent]
601 | [?block :block/page ?page]
602 | [?page :block/name ?pagename]
603 | (not (namespace ?page "namespace1"))
604 | ( or
605 | (property ?block :ns1p1blocktype "nsp1blockvalue")
606 | (property ?block :ns1p2blocktype "nsp2blockvalue")
607 | )
608 | ]
609 | }
610 | #+END_QUERY
611 | `
612 | functions.initialiseQuery()
613 | functions.processCommandList(commands)
614 | advancedquery = functions.constructQuery()
615 | resetGlobalsToDefault()
616 | expect(advancedquery).toEqual(expectedresults)
617 | })
618 |
619 | // ------------------------------------
620 | test('namespace1 block properties that are scheduled', () => {
621 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
622 | setGlobals()
623 | commands = `title: namespace1 block properties that are scheduled
624 | - blocks
625 | - *
626 | - namespace
627 | - namespace1
628 | - blockproperties
629 | - ns1p1blocktype, "nsp1blockvalue"
630 | - ns1p2blocktype, "nsp2blockvalue"
631 | - ns1p3blocktype, "nsp3blockvalue"
632 | - scheduled
633 | `
634 | expectedresults = `#+BEGIN_QUERY
635 | {
636 | :title [:b "namespace1 block properties that are scheduled"]
637 | :query [:find (pull ?block [*])
638 | :where
639 | [?block :block/content ?blockcontent]
640 | [?block :block/page ?page]
641 | [?page :block/name ?pagename]
642 | (namespace ?page "namespace1")
643 | ( or
644 | (property ?block :ns1p1blocktype "nsp1blockvalue")
645 | (property ?block :ns1p2blocktype "nsp2blockvalue")
646 | (property ?block :ns1p3blocktype "nsp3blockvalue")
647 | )
648 | [?block :block/scheduled ?scheduleddate]
649 | ]
650 | }
651 | #+END_QUERY
652 | `
653 | functions.initialiseQuery()
654 | functions.processCommandList(commands)
655 | advancedquery = functions.constructQuery()
656 | resetGlobalsToDefault()
657 | expect(advancedquery).toEqual(expectedresults)
658 | })
659 |
660 | // ------------------------------------
661 | test('namespace1 block properties that have a deadline', () => {
662 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
663 | setGlobals()
664 | commands = `title: namespace1 block properties that have a deadline
665 | - blocks
666 | - *
667 | - namespace
668 | - namespace1
669 | - blockproperties
670 | - ns1p1blocktype, "nsp1blockvalue"
671 | - ns1p2blocktype, "nsp2blockvalue"
672 | - ns1p3blocktype, "nsp3blockvalue"
673 | - ns1p4blocktype, "nsp4blockvalue"
674 | - ns1p5blocktype, "nsp5blockvalue"
675 | - deadline
676 | `
677 | expectedresults = `#+BEGIN_QUERY
678 | {
679 | :title [:b "namespace1 block properties that have a deadline"]
680 | :query [:find (pull ?block [*])
681 | :where
682 | [?block :block/content ?blockcontent]
683 | [?block :block/page ?page]
684 | [?page :block/name ?pagename]
685 | (namespace ?page "namespace1")
686 | ( or
687 | (property ?block :ns1p1blocktype "nsp1blockvalue")
688 | (property ?block :ns1p2blocktype "nsp2blockvalue")
689 | (property ?block :ns1p3blocktype "nsp3blockvalue")
690 | (property ?block :ns1p4blocktype "nsp4blockvalue")
691 | (property ?block :ns1p5blocktype "nsp5blockvalue")
692 | )
693 | [?block :block/deadline ?deadlinedate]
694 | ]
695 | }
696 | #+END_QUERY
697 | `
698 | functions.initialiseQuery()
699 | functions.processCommandList(commands)
700 | advancedquery = functions.constructQuery()
701 | resetGlobalsToDefault()
702 | expect(advancedquery).toEqual(expectedresults)
703 | })
704 |
705 | // ------------------------------------
706 |
707 |
708 | // ------------------------------------
709 | test('deadline blocks in date range', () => {
710 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
711 | setGlobals()
712 | commands = `title: deadline blocks in date range
713 | - deadlinebetween
714 | - :today :30d-after
715 | `
716 | expectedresults = `#+BEGIN_QUERY
717 | ;; WARNING: Must have 'pages' command or 'blocks' Command
718 | ;; otherwise the query cannot get any information
719 | ;; Inserting a blocks command for you
720 |
721 | {
722 | :title [:b "deadline blocks in date range"]
723 | :query [:find (pull ?block [*])
724 | :in $ ?startdate ?enddate
725 | :where
726 | [?block :block/content ?blockcontent]
727 | [?block :block/page ?page]
728 | [?page :block/name ?pagename]
729 | [?block :block/deadline ?deadlinedate]
730 | [(>= ?deadlinedate ?startdate)]
731 | [(<= ?deadlinedate ?enddate)]
732 | ]
733 | :inputs [:today :30d-after]
734 | }
735 | #+END_QUERY
736 | `
737 | functions.initialiseQuery()
738 | functions.processCommandList(commands)
739 | advancedquery = functions.constructQuery()
740 | resetGlobalsToDefault()
741 | expect(advancedquery).toEqual(expectedresults)
742 | })
743 |
744 | // ------------------------------------
745 |
746 |
747 | // ------------------------------------
748 | test('find journals in a date range', () => {
749 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
750 | setGlobals()
751 | commands = `title: find journals in a date range
752 | - journalsbetween
753 | - :today :30d-after
754 | `
755 | expectedresults = `#+BEGIN_QUERY
756 | ;; WARNING: Must have 'pages' command or 'blocks' Command
757 | ;; otherwise the query cannot get any information
758 | ;; Inserting a blocks command for you
759 |
760 | {
761 | :title [:b "find journals in a date range"]
762 | :query [:find (pull ?block [*])
763 | :in $ ?startdate ?enddate
764 | :where
765 | [?block :block/content ?blockcontent]
766 | [?block :block/page ?page]
767 | [?page :block/name ?pagename]
768 | [?page :block/journal-day ?journaldate]
769 | [(>= ?journaldate ?startdate)]
770 | [(<= ?journaldate ?enddate)]
771 | ]
772 | :inputs [:today :30d-after]
773 | }
774 | #+END_QUERY
775 | `
776 | functions.initialiseQuery()
777 | functions.processCommandList(commands)
778 | advancedquery = functions.constructQuery()
779 | resetGlobalsToDefault()
780 | expect(advancedquery).toEqual(expectedresults)
781 | })
782 |
783 |
784 | // ------------------------------------
785 | test('collapse found blocks', () => {
786 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
787 | setGlobals()
788 | commands = `title: collapse found blocks
789 | - pages
790 | - *
791 | - collapse
792 | `
793 | expectedresults = `#+BEGIN_QUERY
794 | {
795 | :title [:b "collapse found blocks"]
796 | :query [:find (pull ?block [*])
797 | :where
798 | [?block :block/name ?pagename]
799 | ]
800 | :collapsed? true
801 | }
802 | #+END_QUERY
803 | `
804 | functions.initialiseQuery()
805 | functions.processCommandList(commands)
806 | advancedquery = functions.constructQuery()
807 | resetGlobalsToDefault()
808 | expect(advancedquery).toEqual(expectedresults)
809 | })
810 |
811 | // ------------------------------------
812 | test('expand found blocks', () => {
813 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
814 | setGlobals()
815 | commands = `title: expand found blocks
816 | - pages
817 | - *
818 | - expand
819 | `
820 | expectedresults = `#+BEGIN_QUERY
821 | {
822 | :title [:b "expand found blocks"]
823 | :query [:find (pull ?block [*])
824 | :where
825 | [?block :block/name ?pagename]
826 | ]
827 | :collapsed? false
828 | }
829 | #+END_QUERY
830 | `
831 | functions.initialiseQuery()
832 | functions.processCommandList(commands)
833 | advancedquery = functions.constructQuery()
834 | resetGlobalsToDefault()
835 | expect(advancedquery).toEqual(expectedresults)
836 | })
837 |
838 | // ------------------------------------
839 | test('show breadcrumb for found blocks', () => {
840 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
841 | setGlobals()
842 | commands = `title: show breadcrumb for found blocks
843 | - pages
844 | - *
845 | - showbreadcrumb
846 | `
847 | expectedresults = `#+BEGIN_QUERY
848 | {
849 | :title [:b "show breadcrumb for found blocks"]
850 | :query [:find (pull ?block [*])
851 | :where
852 | [?block :block/name ?pagename]
853 | ]
854 | :breadcrumb-show? true
855 | }
856 | #+END_QUERY
857 | `
858 | functions.initialiseQuery()
859 | functions.processCommandList(commands)
860 | advancedquery = functions.constructQuery()
861 | resetGlobalsToDefault()
862 | expect(advancedquery).toEqual(expectedresults)
863 | })
864 |
865 | // ------------------------------------
866 | test('hide breadcrumbs for found blocks', () => {
867 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
868 | setGlobals()
869 | commands = `title: hide breadcrumbs for found blocks
870 | - pages
871 | - *
872 | - hidebreadcrumb
873 | `
874 | expectedresults = `#+BEGIN_QUERY
875 | {
876 | :title [:b "hide breadcrumbs for found blocks"]
877 | :query [:find (pull ?block [*])
878 | :where
879 | [?block :block/name ?pagename]
880 | ]
881 | :breadcrumb-show? false
882 | }
883 | #+END_QUERY
884 | `
885 | functions.initialiseQuery()
886 | functions.processCommandList(commands)
887 | advancedquery = functions.constructQuery()
888 | resetGlobalsToDefault()
889 | expect(advancedquery).toEqual(expectedresults)
890 | })
891 |
892 | test('option command - show command comments', () => {
893 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
894 | setGlobals({ showcommandcomments: true })
895 | commands = `title: select blocks with links to journals
896 | option: includecomments
897 | - blocks
898 | - *
899 | - pagelinks
900 | - Dec 25th, 2022
901 | - Jan 1st, 2019
902 | `
903 | expectedresults = `#+BEGIN_QUERY
904 | {
905 | :title [:b "select blocks with links to journals"]
906 |
907 | ;; ---- Get every block into variable ?block
908 | :query [:find (pull ?block [*])
909 |
910 | ;; ---- filter command
911 | :where
912 |
913 | ;; ---- get block content into variable ?blockcontent
914 | [?block :block/content ?blockcontent]
915 |
916 | ;; ---- get page (special type of block) into variable ?page (used later)
917 | [?block :block/page ?page]
918 |
919 | ;; ---- get page name (lowercase) from the page block into variable ?pagename
920 | [?page :block/name ?pagename]
921 | ( or
922 |
923 | ;; ---- Select block if it has one or more links to other pages
924 | [?block :block/path-refs [:block/name "dec 25th, 2022"]]
925 | [?block :block/path-refs [:block/name "jan 1st, 2019"]]
926 | )
927 | ]
928 | }
929 | #+END_QUERY
930 | `
931 | functions.initialiseQuery()
932 | functions.processCommandList(commands)
933 | advancedquery = functions.constructQuery()
934 | expect(advancedquery).toEqual(expectedresults)
935 | resetGlobalsToDefault()
936 | })
937 |
938 | test('option command - bad option parameter', () => {
939 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
940 | setGlobals({ showcommandcomments: true })
941 | commands = `title: select blocks with links to journals
942 | option: iamabadoption
943 | - blocks
944 | - *
945 | - pagelinks
946 | - Dec 25th, 2022
947 | - Jan 1st, 2019
948 | `
949 | expectedresults = `#+BEGIN_QUERY
950 | ;; WARNING: 'option: iamabadoption' is not valid option.
951 | ;; Valid options: includecomments
952 | {
953 | :title [:b \"select blocks with links to journals\"]
954 |
955 | ;; ---- Get every block into variable ?block
956 | :query [:find (pull ?block [*])
957 |
958 | ;; ---- filter command
959 | :where
960 |
961 | ;; ---- get block content into variable ?blockcontent
962 | [?block :block/content ?blockcontent]
963 |
964 | ;; ---- get page (special type of block) into variable ?page (used later)
965 | [?block :block/page ?page]
966 |
967 | ;; ---- get page name (lowercase) from the page block into variable ?pagename
968 | [?page :block/name ?pagename]
969 | ( or
970 |
971 | ;; ---- Select block if it has one or more links to other pages
972 | [?block :block/path-refs [:block/name \"dec 25th, 2022\"]]
973 | [?block :block/path-refs [:block/name \"jan 1st, 2019\"]]
974 | )
975 | ]
976 | }
977 | #+END_QUERY
978 | `
979 | functions.initialiseQuery()
980 | functions.processCommandList(commands)
981 | advancedquery = functions.constructQuery()
982 | expect(advancedquery).toEqual(expectedresults)
983 | resetGlobalsToDefault()
984 | })
985 |
986 |
987 |
988 | }) // end manual tests
989 |
990 |
991 | describe('Positive function Tests', () => {
992 |
993 | test('initialiseQuery()', () => {
994 | returnval = functions.initialiseQuery()
995 | var expectedvariable = {
996 | "start": [],
997 | "errors": [],
998 | "open": [],
999 | "title": [],
1000 | "query": [],
1001 | "in": [],
1002 | "where": [],
1003 | "filters": [],
1004 | "closefind": [],
1005 | "inputs": [],
1006 | "view": [],
1007 | "options": [],
1008 | "closequery": [],
1009 | "end": []
1010 | }
1011 | expect(returnval).toEqual(
1012 | expectedvariable)
1013 | })
1014 |
1015 | test('queryTestDBRead queryTestDB', () => {
1016 | returnval = functions.test_queryTestDBRead()
1017 | expect(returnval).toEqual(
1018 | `title: pages command - select all pages
1019 | - pages
1020 | - *
1021 | #+BEGIN_QUERY
1022 | {
1023 | :title [:b "pages command - select all pages"]
1024 | :query [:find (pull ?block [*])
1025 | :where
1026 | [?block :block/name ?pagename]
1027 | ]
1028 | }
1029 | #+END_QUERY
1030 | `)
1031 | })
1032 |
1033 | //-------------------------------------------------------
1034 | // logseqadvancedqueryplugin function tests
1035 | //-------------------------------------------------------
1036 |
1037 |
1038 | test('checkCommandValid for querygroup pages-querylines', () => {
1039 | setGlobals({ querygroup: "pages-querylines" })
1040 | expect(functions.checkCommandValid("pages")).toEqual(
1041 | [true, ""])
1042 | expect(functions.checkCommandValid("blocktags")).toEqual(
1043 | [false, '\n' + ';; **ERROR: blocktags not valid with pages command use blocks command instead\n'])
1044 | expect(functions.checkCommandValid("tasks")).toEqual(
1045 | [false, '\n' + ';; **ERROR: tasks not valid with pages command use blocks command instead\n'])
1046 | resetGlobalsToDefault()
1047 | })
1048 |
1049 | test('checkCommandValid for querygroup blocks-querylines', () => {
1050 | // set global variables
1051 | setGlobals()
1052 | expect(functions.checkCommandValid("blocks")).toEqual(
1053 | [true, ""])
1054 | expect(functions.checkCommandValid("tasks")).toEqual(
1055 | [true, ""])
1056 | expect(functions.checkCommandValid("anyoldvalue")).toEqual(
1057 | [true, ""])
1058 | resetGlobalsToDefault()
1059 | })
1060 |
1061 | test('initialisteQueryLineDict', () => {
1062 | var tempDict = functions.initialisteQueryLineDict()
1063 | expect(tempDict['blocks-querylines']['where']).toEqual(
1064 | {
1065 | 'name': 'where',
1066 | 'useincommands': ['common'],
1067 | 'segment': 'where',
1068 | 'datalog': ':where',
1069 | 'comment': 'filter command'
1070 | }
1071 | )
1072 | })
1073 |
1074 | test('getQueryLine', () => {
1075 | setGlobals()
1076 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
1077 | expect(functions.getQueryLine('block_properties_are', "filters")).toEqual(
1078 | '(property ?block :$$ARG1 $$ARG2)'
1079 | )
1080 | resetGlobalsToDefault()
1081 | })
1082 |
1083 | test('getQueryLineSegment', () => {
1084 | setGlobals()
1085 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
1086 | resetGlobalsToDefault()
1087 | expect(functions.getQueryLineSegment('block_properties_are')).toEqual(["ok", "filters"])
1088 | })
1089 |
1090 | test('getQueryLineComment', () => {
1091 | setGlobals({ showcommandcomments: true })
1092 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
1093 | expect(functions.getQueryLineComment('block_properties_are')).toEqual(
1094 | ';; ---- Select if block has a single property (arg1) with value arg2'
1095 | )
1096 | resetGlobalsToDefault()
1097 | })
1098 |
1099 |
1100 |
1101 | test('getCommandQueryLineKeys', () => {
1102 | setGlobals({ querygroup: "pages-querylines" })
1103 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
1104 | expect(functions.getCommandQueryLineKeys('pages')).toEqual(
1105 | ['findblocks', 'where', 'pagename']
1106 | )
1107 | resetGlobalsToDefault()
1108 | })
1109 |
1110 | test('processCommandLists', () => {
1111 | setGlobals()
1112 | commandslists = '\ntitle: select and exclude blocks with block properties using and or\n- blocks\n - *\n- blockproperties\n - grade, "b-fiction"\n - or grade, "b-western"\n - and designation, "b-thriller"\n'
1113 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
1114 | functions.processCommandList(commandslists)
1115 | resetGlobalsToDefault()
1116 | expect(functions.constructQuery()).toEqual(
1117 | `#+BEGIN_QUERY
1118 | {
1119 | :title [:b "select and exclude blocks with block properties using and or"]
1120 | :query [:find (pull ?block [*])
1121 | :where
1122 | [?block :block/content ?blockcontent]
1123 | [?block :block/page ?page]
1124 | [?page :block/name ?pagename]
1125 | ( or
1126 | (property ?block :grade "b-fiction")
1127 | (property ?block :grade "b-western")
1128 | )
1129 | (property ?block :designation "b-thriller")
1130 | ]
1131 | }
1132 | #+END_QUERY
1133 | `
1134 | )
1135 | })
1136 |
1137 | //TODO: Add manual tests from py version here
1138 |
1139 |
1140 | }) // end describe
1141 |
1142 |
1143 | describe('Negative function Tests', () => {
1144 |
1145 | test('pageproperties - test 4', () => {
1146 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
1147 | setGlobals()
1148 | commands = `title: pageproperties - missing pages command
1149 | - pageproperties
1150 | - pagetype, "testA"
1151 | - pagetype, "testB"
1152 | - not pagekey, 1
1153 | `
1154 | expectedresults = `#+BEGIN_QUERY
1155 | ;; WARNING: Must have 'pages' command or 'blocks' Command
1156 | ;; otherwise the query cannot get any information
1157 | ;; Inserting a blocks command for you
1158 |
1159 | {
1160 | :title [:b "pageproperties - missing pages command"]
1161 | :query [:find (pull ?block [*])
1162 | :where
1163 | [?block :block/content ?blockcontent]
1164 | [?block :block/page ?page]
1165 | [?page :block/name ?pagename]
1166 | ( or
1167 | (page-property ?page :pagetype "testA")
1168 | (page-property ?page :pagetype "testB")
1169 | )
1170 | (not (page-property ?page :pagekey 1))
1171 | ]
1172 | }
1173 | #+END_QUERY
1174 | `
1175 | functions.initialiseQuery()
1176 | functions.processCommandList(commands)
1177 | advancedquery = functions.constructQuery()
1178 | resetGlobalsToDefault()
1179 | expect(advancedquery).toEqual(expectedresults)
1180 | })
1181 |
1182 | test('missing pages and blocks commands 1', () => {
1183 | commands = `title: missing pages and blocks commands`
1184 | expectedresults = `#+BEGIN_QUERY
1185 | ;; WARNING: Must have 'pages' command or 'blocks' Command
1186 | ;; otherwise the query cannot get any information
1187 | ;; Inserting a blocks command for you
1188 |
1189 | {
1190 | :title [:b "missing pages and blocks commands"]
1191 | :query [:find (pull ?block [*])
1192 | :where
1193 | [?block :block/content ?blockcontent]
1194 | [?block :block/page ?page]
1195 | [?page :block/name ?pagename]
1196 | ]
1197 | }
1198 | #+END_QUERY
1199 | `
1200 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
1201 | setGlobals()
1202 | functions.initialiseQuery()
1203 | functions.processCommandList(commands)
1204 | advancedquery = functions.constructQuery()
1205 | resetGlobalsToDefault()
1206 | expect(advancedquery).toEqual(expectedresults)
1207 | })
1208 |
1209 | test('bad commands', () => {
1210 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
1211 | setGlobals()
1212 | commands = `title: bad commands
1213 | - badcommand1
1214 | - badcommand2
1215 | forgottenthedash
1216 | `
1217 | expectedresults = `#+BEGIN_QUERY
1218 | ;; WARNING: Must have 'pages' command or 'blocks' Command
1219 | ;; otherwise the query cannot get any information
1220 | ;; Inserting a blocks command for you
1221 |
1222 | ;; WARNING: '- badcommand1' is not valid command.
1223 | ;; Either a mispelt command or no leading dash
1224 | ;; WARNING: '- badcommand2' is not valid command.
1225 | ;; Either a mispelt command or no leading dash
1226 | ;; WARNING: forgottenthedash has no leading hypen eg '- pages'
1227 | {
1228 | :title [:b "bad commands"]
1229 | :query [:find (pull ?block [*])
1230 | :where
1231 | [?block :block/content ?blockcontent]
1232 | [?block :block/page ?page]
1233 | [?page :block/name ?pagename]
1234 | ]
1235 | }
1236 | #+END_QUERY
1237 | `
1238 | functions.initialiseQuery()
1239 | functions.processCommandList(commands)
1240 | advancedquery = functions.constructQuery()
1241 | resetGlobalsToDefault()
1242 | expect(advancedquery).toEqual(expectedresults)
1243 | })
1244 |
1245 | test('bad title', () => {
1246 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
1247 | setGlobals()
1248 | commands = `title pages command - select all pages
1249 | - pages
1250 | - *
1251 | `
1252 | expectedresults = `#+BEGIN_QUERY
1253 | ;; WARNING: title line should start with title:
1254 | {
1255 | :query [:find (pull ?block [*])
1256 | :where
1257 | [?block :block/name ?pagename]
1258 | ]
1259 | }
1260 | #+END_QUERY
1261 | `
1262 | functions.initialiseQuery()
1263 | functions.processCommandList(commands)
1264 | advancedquery = functions.constructQuery()
1265 | resetGlobalsToDefault()
1266 | expect(advancedquery).toEqual(expectedresults)
1267 | })
1268 |
1269 | test('equal rather than dash', () => {
1270 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
1271 | setGlobals()
1272 | commands = `title: equal sign used instead of dash
1273 | - pages
1274 | = testpage00*
1275 | = pagetags
1276 | `
1277 | expectedresults = `#+BEGIN_QUERY
1278 | ;; WARNING: = testpage00* has no leading hypen eg '- pages'
1279 | ;; WARNING: = pagetags has no leading hypen eg '- pages'
1280 | {
1281 | :title [:b "equal sign used instead of dash"]
1282 | :query [:find (pull ?block [*])
1283 | :where
1284 | [?block :block/name ?pagename]
1285 | ]
1286 | }
1287 | #+END_QUERY
1288 | `
1289 | functions.initialiseQuery()
1290 | functions.processCommandList(commands)
1291 | advancedquery = functions.constructQuery()
1292 | resetGlobalsToDefault()
1293 | expect(advancedquery).toEqual(expectedresults)
1294 | })
1295 |
1296 | test('only an argument line', () => {
1297 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
1298 | setGlobals()
1299 | commands = `title: missing command
1300 | - testpage00*
1301 | `
1302 | expectedresults = `#+BEGIN_QUERY
1303 | ;; WARNING: Must have 'pages' command or 'blocks' Command
1304 | ;; otherwise the query cannot get any information
1305 | ;; Inserting a blocks command for you
1306 |
1307 | {
1308 | :title [:b "missing command"]
1309 | :query [:find (pull ?block [*])
1310 | :where
1311 | [?block :block/content ?blockcontent]
1312 | [?block :block/page ?page]
1313 | [?page :block/name ?pagename]
1314 | ( or
1315 | [(clojure.string/ends-with? ?blockcontent "testpage00")]
1316 | )
1317 | ]
1318 | }
1319 | #+END_QUERY
1320 | `
1321 | functions.initialiseQuery()
1322 | functions.processCommandList(commands)
1323 | advancedquery = functions.constructQuery()
1324 | resetGlobalsToDefault()
1325 | expect(advancedquery).toEqual(expectedresults)
1326 | })
1327 |
1328 | test('blocktags - test 1', () => {
1329 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
1330 | setGlobals()
1331 | commands = `title: blocktags command - test 1
1332 | - blocktags
1333 | - tag1
1334 | - tag2
1335 | - not tag3
1336 | `
1337 | expectedresults = `#+BEGIN_QUERY
1338 | ;; WARNING: Must have 'pages' command or 'blocks' Command
1339 | ;; otherwise the query cannot get any information
1340 | ;; Inserting a blocks command for you
1341 |
1342 | {
1343 | :title [:b "blocktags command - test 1"]
1344 | :query [:find (pull ?block [*])
1345 | :where
1346 | [?block :block/content ?blockcontent]
1347 | [?block :block/page ?page]
1348 | [?page :block/name ?pagename]
1349 | ( or
1350 | (page-ref ?block "tag1")
1351 | (page-ref ?block "tag2")
1352 | )
1353 | (not (page-ref ?block "tag3"))
1354 | ]
1355 | }
1356 | #+END_QUERY
1357 | `
1358 | functions.initialiseQuery()
1359 | functions.processCommandList(commands)
1360 | advancedquery = functions.constructQuery()
1361 | resetGlobalsToDefault()
1362 | expect(advancedquery).toEqual(expectedresults)
1363 | })
1364 |
1365 | test('blocktags - test 2', () => {
1366 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
1367 | setGlobals()
1368 | commands = `title: blocktags and pages command combined - test 2
1369 | - pages
1370 | - test*
1371 | - *an
1372 | - blocktags
1373 | - tag1
1374 | - tag2
1375 | `
1376 | expectedresults = `#+BEGIN_QUERY
1377 |
1378 | ;; **ERROR: blocktags not valid with pages command use blocks command instead
1379 |
1380 | {
1381 | :title [:b "blocktags and pages command combined - test 2"]
1382 | :query [:find (pull ?block [*])
1383 | :where
1384 | [?block :block/name ?pagename]
1385 | ( or
1386 | [(clojure.string/starts-with? ?pagename "test")]
1387 | [(clojure.string/ends-with? ?pagename "an")]
1388 | )
1389 | ]
1390 | }
1391 | #+END_QUERY
1392 | `
1393 | functions.initialiseQuery()
1394 | functions.processCommandList(commands)
1395 | advancedquery = functions.constructQuery()
1396 | resetGlobalsToDefault()
1397 | expect(advancedquery).toEqual(expectedresults)
1398 | })
1399 |
1400 | test('pagetags - test 1', () => {
1401 | commands = `title: pagetags - test 1
1402 | - pagetags
1403 | - pagetag1
1404 | - pagetag2
1405 | - not pagetag4
1406 | `
1407 | expectedresults = `#+BEGIN_QUERY
1408 | ;; WARNING: Must have 'pages' command or 'blocks' Command
1409 | ;; otherwise the query cannot get any information
1410 | ;; Inserting a blocks command for you
1411 |
1412 | {
1413 | :title [:b "pagetags - test 1"]
1414 | :query [:find (pull ?block [*])
1415 | :where
1416 | [?block :block/content ?blockcontent]
1417 | [?block :block/page ?page]
1418 | [?page :block/name ?pagename]
1419 | [?page :block/journal? false]
1420 | ( or
1421 | (page-tags ?page #{"pagetag1"})
1422 | (page-tags ?page #{"pagetag2"})
1423 | )
1424 | (not (page-tags ?page #{"pagetag4"}))
1425 | ]
1426 | }
1427 | #+END_QUERY
1428 | `
1429 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
1430 | setGlobals()
1431 | functions.initialiseQuery()
1432 | functions.processCommandList(commands)
1433 | advancedquery = functions.constructQuery()
1434 | resetGlobalsToDefault()
1435 | expect(advancedquery).toEqual(expectedresults)
1436 | })
1437 |
1438 |
1439 | test('blocktags - test 3', () => {
1440 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
1441 | setGlobals()
1442 | commands = `title: blocktags and pages command combined - test 3
1443 | - pages
1444 | - test*
1445 | - *2
1446 | - not *age1
1447 | - blocktags
1448 | - tag1
1449 | - not tag2
1450 | - tag3
1451 | - not tag4
1452 | `
1453 | expectedresults = `#+BEGIN_QUERY
1454 |
1455 | ;; **ERROR: blocktags not valid with pages command use blocks command instead
1456 |
1457 | {
1458 | :title [:b "blocktags and pages command combined - test 3"]
1459 | :query [:find (pull ?block [*])
1460 | :where
1461 | [?block :block/name ?pagename]
1462 | ( or
1463 | [(clojure.string/starts-with? ?pagename "test")]
1464 | [(clojure.string/ends-with? ?pagename "2")]
1465 | )
1466 | (not [(clojure.string/ends-with? ?pagename "age1")])
1467 | ]
1468 | }
1469 | #+END_QUERY
1470 | `
1471 | functions.initialiseQuery()
1472 | functions.processCommandList(commands)
1473 | advancedquery = functions.constructQuery()
1474 | resetGlobalsToDefault()
1475 | expect(advancedquery).toEqual(expectedresults)
1476 | })
1477 |
1478 | test('tasks - test 1', () => {
1479 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
1480 | setGlobals()
1481 | commands = `title: tasks - select and exclude task types
1482 | - tasks
1483 | - TODO
1484 | - not DOING
1485 | `
1486 | expectedresults = `#+BEGIN_QUERY
1487 | ;; WARNING: Must have 'pages' command or 'blocks' Command
1488 | ;; otherwise the query cannot get any information
1489 | ;; Inserting a blocks command for you
1490 |
1491 | {
1492 | :title [:b "tasks - select and exclude task types"]
1493 | :query [:find (pull ?block [*])
1494 | :where
1495 | [?block :block/content ?blockcontent]
1496 | [?block :block/page ?page]
1497 | [?page :block/name ?pagename]
1498 | [?block :block/marker ?marker]
1499 | [(contains? #{"TODO"} ?marker)]
1500 | (not [(contains? #{"DOING"} ?marker)])
1501 | ]
1502 | }
1503 | #+END_QUERY
1504 | `
1505 | functions.initialiseQuery()
1506 | functions.processCommandList(commands)
1507 | advancedquery = functions.constructQuery()
1508 | resetGlobalsToDefault()
1509 | expect(advancedquery).toEqual(expectedresults)
1510 | })
1511 |
1512 | // ------------------------------------
1513 | test('tasks - test 2', () => {
1514 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
1515 | setGlobals()
1516 | commands = `title: tasks and pages
1517 | - pages
1518 | - *7
1519 | - tasks
1520 | - TODO
1521 | - not DOING
1522 | `
1523 | expectedresults = `#+BEGIN_QUERY
1524 |
1525 | ;; **ERROR: tasks not valid with pages command use blocks command instead
1526 |
1527 | {
1528 | :title [:b "tasks and pages"]
1529 | :query [:find (pull ?block [*])
1530 | :where
1531 | [?block :block/name ?pagename]
1532 | [(clojure.string/ends-with? ?pagename "7")]
1533 | ]
1534 | }
1535 | #+END_QUERY
1536 | `
1537 | functions.initialiseQuery()
1538 | functions.processCommandList(commands)
1539 | advancedquery = functions.constructQuery()
1540 | resetGlobalsToDefault()
1541 | expect(advancedquery).toEqual(expectedresults)
1542 | })
1543 |
1544 |
1545 | test('scheduled blocks in date range', () => {
1546 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
1547 | setGlobals()
1548 | commands = `title: scheduled blocks in date range
1549 | - scheduledbetween
1550 | - :today :30d-after
1551 | `
1552 | expectedresults = `#+BEGIN_QUERY
1553 | ;; WARNING: Must have 'pages' command or 'blocks' Command
1554 | ;; otherwise the query cannot get any information
1555 | ;; Inserting a blocks command for you
1556 |
1557 | {
1558 | :title [:b "scheduled blocks in date range"]
1559 | :query [:find (pull ?block [*])
1560 | :in $ ?startdate ?enddate
1561 | :where
1562 | [?block :block/content ?blockcontent]
1563 | [?block :block/page ?page]
1564 | [?page :block/name ?pagename]
1565 | [?block :block/scheduled ?scheduleddate]
1566 | [(>= ?scheduleddate ?startdate)]
1567 | [(<= ?scheduleddate ?enddate)]
1568 | ]
1569 | :inputs [:today :30d-after]
1570 | }
1571 | #+END_QUERY
1572 | `
1573 | functions.initialiseQuery()
1574 | functions.processCommandList(commands)
1575 | advancedquery = functions.constructQuery()
1576 | resetGlobalsToDefault()
1577 | expect(advancedquery).toEqual(expectedresults)
1578 | })
1579 |
1580 | test('journal pages only', () => {
1581 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
1582 | setGlobals()
1583 | commands = `title: journal pages only
1584 | - journalonly
1585 | `
1586 | expectedresults = `#+BEGIN_QUERY
1587 | ;; WARNING: Must have 'pages' command or 'blocks' Command
1588 | ;; otherwise the query cannot get any information
1589 | ;; Inserting a blocks command for you
1590 |
1591 | {
1592 | :title [:b "journal pages only"]
1593 | :query [:find (pull ?block [*])
1594 | :where
1595 | [?block :block/content ?blockcontent]
1596 | [?block :block/page ?page]
1597 | [?page :block/name ?pagename]
1598 | [?page :block/journal? true]
1599 | ]
1600 | }
1601 | #+END_QUERY
1602 | `
1603 | functions.initialiseQuery()
1604 | functions.processCommandList(commands)
1605 | advancedquery = functions.constructQuery()
1606 | resetGlobalsToDefault()
1607 | expect(advancedquery).toEqual(expectedresults)
1608 | })
1609 |
1610 |
1611 |
1612 | }) // end describe
1613 |
1614 |
1615 | //-------------------------------------------------------
1616 | // automated test cases
1617 | //-------------------------------------------------------
1618 |
1619 | //TODO: use queryTestDB to run all the tests automatically
1620 | // note console.debug output is in the Jest Log not the Code Log
1621 | // see drop down at the top of the right panel (View, Output)
1622 |
1623 | test('automated testcases access', () => {
1624 | var msg = ''
1625 | console.log("****** AUTOMATED TESTS STARTED ******");
1626 | functions.setquerylineDBDict(functions.initialisteQueryLineDict())
1627 | setGlobals()
1628 | testcases = functions.getquerytestcases()
1629 | for (let testno = 0; testno < testcases.length; testno++) {
1630 | commands = gettestcommands(testno)
1631 | console.log(" - test " + (testno + 1) + " started ..." +
1632 | '\n---------------------------------' +
1633 | '\n' + commands +
1634 | '\n---------------------------------')
1635 | msg += " - test " + (testno + 1) + " started ..." +
1636 | '\n---------------------------------' +
1637 | '\n' + commands +
1638 | '\n---------------------------------'
1639 | expectedresults = gettestexpectedresults(testno)
1640 | functions.initialiseQuery()
1641 | functions.processCommandList(commands)
1642 | advancedquery = functions.constructQuery()
1643 | msg += advancedquery +
1644 | '\n---------------------------------\n\n'
1645 |
1646 | // if (testno == 44) {
1647 | // var a = 1
1648 | // }
1649 | resetGlobalsToDefault()
1650 | expect(advancedquery).toEqual(expectedresults)
1651 | console.log(" - test " + testno + " completed ok");
1652 |
1653 | }
1654 | saveAutomatedTestOutput(msg)
1655 |
1656 | })
1657 |
1658 | //-------------------------------------------------------
1659 | // test local functions
1660 | //-------------------------------------------------------
1661 |
1662 | describe('Housekeeping Tests', () => {
1663 | test('set globals', () => {
1664 | setGlobals(
1665 | {
1666 | querygroup: "abc",
1667 | showcommandcomments: true,
1668 | codeblock: false
1669 | })
1670 | returnval = functions.getquerygroup()
1671 | expect(returnval).toBe("abc")
1672 | returnval = functions.getshowcommandcomments()
1673 | expect(returnval).toBe(true)
1674 | returnval = functions.getcodeblock()
1675 | expect(returnval).toBe(false)
1676 | resetGlobalsToDefault()
1677 | })
1678 |
1679 | test('load global value querygroup', () => {
1680 | functions.setquerygroup("def")
1681 | returnval = functions.getquerygroup()
1682 | expect(returnval).toBe("def")
1683 | })
1684 |
1685 | test('remove last generated query', () => {
1686 | content = `- pages
1687 | - *
1688 | - blocktags
1689 | - mytag
1690 | `
1691 | expectedresult = content
1692 | content += `#+BEGIN_QUERY
1693 | {
1694 | :title [:b "Pages only - Access page properties"]
1695 | :query [:find (pull ?block [*])
1696 | :where
1697 | [?block :block/original-name ?originalpagename]
1698 | [?block :block/name ?pagename]
1699 | (page-property ?block :pagetype "p-minor")
1700 | ]
1701 | }
1702 | #+END_QUERY`
1703 |
1704 | returnval = functions.removeLastGeneratedQuery(content)
1705 | expect(returnval).toBe(expectedresult)
1706 | content = `- pages
1707 | - *
1708 | - blocktags
1709 | - mytag
1710 | `
1711 | expect(returnval).toBe(expectedresult)
1712 | })
1713 |
1714 |
1715 |
1716 | test('gettestcommands', () => {
1717 | var commands = gettestcommands(0)
1718 | expect(commands).toBe(
1719 | `title: pages command - select all pages
1720 | - pages
1721 | - *`
1722 | )
1723 | })
1724 |
1725 | test('gettestexpectedresults', () => {
1726 | var expectedresults = gettestexpectedresults(0)
1727 | expect(expectedresults).toBe(
1728 | `#+BEGIN_QUERY
1729 | {
1730 | :title [:b "pages command - select all pages"]
1731 | :query [:find (pull ?block [*])
1732 | :where
1733 | [?block :block/name ?pagename]
1734 | ]
1735 | }
1736 | #+END_QUERY
1737 | `
1738 | )
1739 | })
1740 |
1741 | //-------------------------------------------------------
1742 | // data access tests
1743 | //-------------------------------------------------------
1744 |
1745 | test('queryDBRead queryDB start entry', () => {
1746 | returnval = functions.test_queryDBRead("common-querylines", "start")
1747 | expect(returnval).toEqual(
1748 | `start
1749 | start
1750 | start
1751 | #+BEGIN_QUERY
1752 |
1753 | `)
1754 | })
1755 |
1756 | test('queryDBRead queryDB not_arg_pagename_contains entry', () => {
1757 | returnval = functions.test_queryDBRead("pages-querylines", "not_arg_pagename_contains")
1758 | expect(returnval).toEqual(
1759 | `not_arg_pagename_contains
1760 | filters
1761 | filters
1762 | (not [(clojure.string/includes? ?pagename "$$ARG1")])
1763 | Exclude if page title contains arg1
1764 | `)
1765 | })
1766 |
1767 |
1768 | }) // end describe
1769 |
1770 |
1771 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | // logseq-advanced-query-builder v0.1
2 | // set mode of execution at end of this script
3 | // 'local' mode for desktop testing with Jest Test framework
4 | // 'logseq-plugin' for operating as a plugin within logseq
5 |
6 | // Deployment
7 | // copy index.js to deploy folder
8 | // do not copy package.json to deploy folder as the main package.json
9 | // is configure for jest testing
10 |
11 | // Dictionary of query lines data
12 | var querylineDict = {
13 | 'common-querylines': {
14 | 'start':
15 | {
16 | 'name': 'start',
17 | 'useincommands': ['common'],
18 | 'segment': 'start',
19 | 'datalog': '#+BEGIN_QUERY',
20 | 'comment': ''
21 | },
22 | 'open':
23 | {
24 | 'name': 'open',
25 | 'useincommands': ['common'],
26 | 'segment': 'open',
27 | 'datalog': '{',
28 | 'comment': ''
29 | },
30 | 'title':
31 | {
32 | 'name': 'title',
33 | 'useincommands': ['common'],
34 | 'segment': 'title',
35 | 'datalog': ':title [:b "$$ARG1"]',
36 | 'comment': ''
37 | },
38 | 'findblocks':
39 | {
40 | 'name': 'findblocks',
41 | 'useincommands': ['common'],
42 | 'segment': 'query',
43 | 'datalog': ':query [:find (pull ?block [*])',
44 | 'comment': 'Get every block into variable ?block'
45 | },
46 | 'daterange':
47 | {
48 | 'name': 'daterange',
49 | 'useincommands': ['common'],
50 | 'segment': 'in',
51 | 'datalog': ':in $ ?startdate ?enddate',
52 | 'comment': 'give query the ?startdate variable and the ?enddate variable (set by :inputs)'
53 | },
54 | 'where':
55 | {
56 | 'name': 'where',
57 | 'useincommands': ['common'],
58 | 'segment': 'where',
59 | 'datalog': ':where',
60 | 'comment': 'filter command'
61 | },
62 | 'tasks_are':
63 | {
64 | 'name': 'tasks_are',
65 | 'useincommands': ['common'],
66 | 'segment': 'filters',
67 | 'datalog': '[(contains? #{"$$ARG1"} ?marker)]',
68 | 'comment': 'Select block if it has one or more tasks (TODO or DONE etc)'
69 | },
70 | 'not_tasks_are':
71 | {
72 | 'name': 'not_tasks_are',
73 | 'useincommands': ['common'],
74 | 'segment': 'filters',
75 | 'datalog': '(not [(contains? #{"$$ARG1"} ?marker)])',
76 | 'comment': 'Exclude block if it has one or more tasks'
77 | },
78 | 'pagelinks_are':
79 | {
80 | 'name': 'pagelinks_are',
81 | 'useincommands': ['common'],
82 | 'segment': 'filters',
83 | 'datalog': '[?block :block/path-refs [:block/name "$$ARG1"]]',
84 | 'comment': 'Select block if it has one or more links to other pages'
85 | },
86 | 'not_pagelinks_are':
87 | {
88 | 'name': 'not_pagelinks_are',
89 | 'useincommands': ['common'],
90 | 'segment': 'filters',
91 | 'datalog': '(not [?block :block/path-refs [:block/name "$$ARG1"]])',
92 | 'comment': 'Exclude block if it has one or more links to other pages'
93 | },
94 | 'scheduledbetween':
95 | {
96 | 'name': 'scheduledbetween',
97 | 'useincommands': ['common'],
98 | 'segment': 'inputs',
99 | 'datalog': ':inputs [$$ARG1]',
100 | 'comment': 'set the input values for a date range for example could be\n :today :365d-after'
101 | },
102 | 'journalfrom':
103 | {
104 | 'name': 'journalfrom',
105 | 'useincommands': ['common'],
106 | 'segment': 'filters',
107 | 'datalog': '[(>= ?journaldate ?startdate)]',
108 | 'comment': 'Select if journaldate greater than start date'
109 | },
110 | 'journalto':
111 | {
112 | 'name': 'journalto',
113 | 'useincommands': ['common'],
114 | 'segment': 'filters',
115 | 'datalog': '[(<= ?journaldate ?enddate)]',
116 | 'comment': 'Select if journalddate less than end date'
117 | },
118 | 'journalsbetween':
119 | {
120 | 'name': 'journalsbetween',
121 | 'useincommands': ['common'],
122 | 'segment': 'inputs',
123 | 'datalog': ':inputs [$$ARG1]',
124 | 'comment': 'set the input values for a date range for example could be\n :today :365d-after'
125 | },
126 | 'breadcrumb_show_false':
127 | {
128 | 'name': 'breadcrumb_show_false',
129 | 'useincommands': ['common'],
130 | 'segment': 'options',
131 | 'datalog': ':breadcrumb-show? false',
132 | 'comment': 'Suppress breadcrumbs view'
133 | },
134 | 'breadcrumb_show_true':
135 | {
136 | 'name': 'breadcrumb_show_true',
137 | 'useincommands': ['common'],
138 | 'segment': 'options',
139 | 'datalog': ':breadcrumb-show? true',
140 | 'comment': 'Show breadcrumbs above each block'
141 | },
142 | 'collapse_false':
143 | {
144 | 'name': 'collapse_false',
145 | 'useincommands': ['common'],
146 | 'segment': 'options',
147 | 'datalog': ':collapsed? false',
148 | 'comment': 'Toggle collapse or fold'
149 | },
150 | 'collapse_true':
151 | {
152 | 'name': 'collapse_true',
153 | 'useincommands': ['common'],
154 | 'segment': 'options',
155 | 'datalog': ':collapsed? true',
156 | 'comment': 'Toggle collapse or fold'
157 | },
158 | 'closefind':
159 | {
160 | 'name': 'closefind',
161 | 'useincommands': ['common'],
162 | 'segment': 'closefind',
163 | 'datalog': ']',
164 | 'comment': ''
165 | },
166 | 'closequery':
167 | {
168 | 'name': 'closequery',
169 | 'useincommands': ['common'],
170 | 'segment': 'closequery',
171 | 'datalog': '}',
172 | 'comment': ''
173 | },
174 | 'end':
175 | {
176 | 'name': 'end',
177 | 'useincommands': ['common'],
178 | 'segment': 'end',
179 | 'datalog': '#+END_QUERY',
180 | 'comment': ''
181 | },
182 | },
183 | 'blocks-querylines': {
184 | 'blockcontent':
185 | {
186 | 'name': 'blockcontent',
187 | 'useincommands': ['blocks'],
188 | 'segment': 'filters',
189 | 'datalog': '[?block :block/content ?blockcontent]',
190 | 'comment': 'get block content into variable ?blockcontent'
191 | },
192 | 'page':
193 | {
194 | 'name': 'page',
195 | 'useincommands': ['blocks'],
196 | 'segment': 'filters',
197 | 'datalog': '[?block :block/page ?page]',
198 | 'comment': 'get page (special type of block) into variable ?page (used later)'
199 | },
200 | 'pagename':
201 | {
202 | 'name': 'pagename',
203 | 'useincommands': ['blocks'],
204 | 'segment': 'filters',
205 | 'datalog': '[?page :block/name ?pagename]',
206 | 'comment': 'get page name (lowercase) from the page block into variable ?pagename'
207 | },
208 | 'marker':
209 | {
210 | 'name': 'marker',
211 | 'useincommands': ['blocks'],
212 | 'segment': 'filters',
213 | 'datalog': '[?block :block/marker ?marker]',
214 | 'comment': 'get block marker (TODO LATER ETC) into variable ?marker'
215 | },
216 | 'scheduled':
217 | {
218 | 'name': 'scheduled',
219 | 'useincommands': ['blocks'],
220 | 'segment': 'filters',
221 | 'datalog': '[?block :block/scheduled ?scheduleddate]',
222 | 'comment': 'get scheduled date in the block into variable ?scheduleddate'
223 | },
224 | 'scheduledfrom':
225 | {
226 | 'name': 'scheduledfrom',
227 | 'useincommands': ['blocks'],
228 | 'segment': 'filters',
229 | 'datalog': '[(>= ?scheduleddate ?startdate)]',
230 | 'comment': 'Select if scheduleddate greater than start date'
231 | },
232 | 'scheduledto':
233 | {
234 | 'name': 'scheduledto',
235 | 'useincommands': ['blocks'],
236 | 'segment': 'filters',
237 | 'datalog': '[(<= ?scheduleddate ?enddate)]',
238 | 'comment': 'Select if scheduleddate less than end date'
239 | },
240 | 'deadline':
241 | {
242 | 'name': 'deadline',
243 | 'useincommands': ['blocks'],
244 | 'segment': 'filters',
245 | 'datalog': '[?block :block/deadline ?deadlinedate]',
246 | 'comment': 'get deadline date in the block into variable ?date'
247 | },
248 | 'deadlinefrom':
249 | {
250 | 'name': 'deadlinefrom',
251 | 'useincommands': ['blocks'],
252 | 'segment': 'filters',
253 | 'datalog': '[(>= ?deadlinedate ?startdate)]',
254 | 'comment': 'Select if deadlinedate greater than start date'
255 | },
256 | 'deadlineto':
257 | {
258 | 'name': 'deadlineto',
259 | 'useincommands': ['blocks'],
260 | 'segment': 'filters',
261 | 'datalog': '[(<= ?deadlinedate ?enddate)]',
262 | 'comment': 'Select if deadlinedate less than end date'
263 | },
264 | 'pagename_is':
265 | {
266 | 'name': 'pagename_is',
267 | 'useincommands': ['blocks'],
268 | 'segment': 'filters',
269 | 'datalog': '[?block :block/name "$$ARG1"]',
270 | 'comment': 'Select specific page from the page special block\nPresence of :block/name in a blocks means \nit is a block that has the page attributes'
271 | },
272 | 'not_pagename_is':
273 | {
274 | 'name': 'not_pagename_is',
275 | 'useincommands': ['blocks'],
276 | 'segment': 'filters',
277 | 'datalog': '(not [?block :block/name "$$ARG1"])',
278 | 'comment': 'Exclude specific page from the page special block'
279 | },
280 | 'page_is_journal':
281 | {
282 | 'name': 'page_is_journal',
283 | 'useincommands': ['blocks'],
284 | 'segment': 'filters',
285 | 'datalog': '[?page :block/journal? true]',
286 | 'comment': 'Select block if its belongs to a journal page'
287 | },
288 | 'not_page_is_journal':
289 | {
290 | 'name': 'not_page_is_journal',
291 | 'useincommands': ['blocks'],
292 | 'segment': 'filters',
293 | 'datalog': '[?page :block/journal? false]',
294 | 'comment': 'Exclude block if its belongs to a journal page'
295 | },
296 | 'journal_date':
297 | {
298 | 'name': 'journal_date',
299 | 'useincommands': ['blocks'],
300 | 'segment': 'filters',
301 | 'datalog': '[?page :block/journal-day ?journaldate]',
302 | 'comment': 'get journal date into variable ?journaldate'
303 | },
304 | 'block_properties_are':
305 | {
306 | 'name': 'block_properties_are',
307 | 'useincommands': ['blocks'],
308 | 'segment': 'filters',
309 | 'datalog': '(property ?block :$$ARG1 $$ARG2)',
310 | 'comment': 'Select if block has a single property (arg1) with value arg2'
311 | },
312 | 'not_block_properties_are':
313 | {
314 | 'name': 'not_block_properties_are',
315 | 'useincommands': ['blocks'],
316 | 'segment': 'filters',
317 | 'datalog': '(not (property ?block :$$ARG1 $$ARG2))',
318 | 'comment': 'Exclude if block has a single property (arg1) with value arg2'
319 | },
320 | 'blocktags_are':
321 | {
322 | 'name': 'blocktags_are',
323 | 'useincommands': ['blocks'],
324 | 'segment': 'filters',
325 | 'datalog': '(page-ref ?block "$$ARG1")',
326 | 'comment': 'Select block if it has a specific tag or page link'
327 | },
328 | 'not_blocktags_are':
329 | {
330 | 'name': 'not_blocktags_are',
331 | 'useincommands': ['blocks'],
332 | 'segment': 'filters',
333 | 'datalog': '(not (page-ref ?block "$$ARG1"))',
334 | 'comment': 'Exclude block if it has a specific tag or page link'
335 | },
336 | 'page_properties_are':
337 | {
338 | 'name': 'page_properties_are',
339 | 'useincommands': ['blocks'],
340 | 'segment': 'filters',
341 | 'datalog': '(page-property ?page :$$ARG1 $$ARG2)',
342 | 'comment': 'Select block if the page it belongs to\nhas a page property (arg1) with value arg2'
343 | },
344 | 'not_page_properties_are':
345 | {
346 | 'name': 'not_page_properties_are',
347 | 'useincommands': ['blocks'],
348 | 'segment': 'filters',
349 | 'datalog': '(not (page-property ?page :$$ARG1 $$ARG2))',
350 | 'comment': 'Exclude block if the page it belongs to\nhas a page property (arg1) with value arg2'
351 | },
352 | 'pagetags_are':
353 | {
354 | 'name': 'pagetags_are',
355 | 'useincommands': ['blocks'],
356 | 'segment': 'filters',
357 | 'datalog': '(page-tags ?page #{"$$ARG1"})',
358 | 'comment': 'Select block if the page it belongs to\nhas a one or more page tags'
359 | },
360 | 'not_pagetags_are':
361 | {
362 | 'name': 'not_pagetags_are',
363 | 'useincommands': ['blocks'],
364 | 'segment': 'filters',
365 | 'datalog': '(not (page-tags ?page #{"$$ARG1"}))',
366 | 'comment': 'Exclude block if the page it belongs to\nhas one or more page tags'
367 | },
368 | 'namespace':
369 | {
370 | 'name': 'namespace',
371 | 'useincommands': ['blocks'],
372 | 'segment': 'filters',
373 | 'datalog': '(namespace ?page "$$ARG1")',
374 | 'comment': 'Select block if the page it belongs to is within namespace arg1'
375 | },
376 | 'not_namespace':
377 | {
378 | 'name': 'not_namespace_blocks',
379 | 'useincommands': ['blocks'],
380 | 'segment': 'filters',
381 | 'datalog': '(not (namespace ?page "$$ARG1"))',
382 | 'comment': 'Exclude block if the page it belongs to is within namespace arg1'
383 | },
384 | 'arg_blockcontent_startswith':
385 | {
386 | 'name': 'arg_blockcontent_startswith',
387 | 'useincommands': ['blocks'],
388 | 'segment': 'filters',
389 | 'datalog': '[(clojure.string/starts-with? ?blockcontent "$$ARG1")]',
390 | 'comment': 'Select if block content starts with arg1'
391 | },
392 | 'arg_blockcontent_endswith':
393 | {
394 | 'name': 'arg_blockcontent_endswith',
395 | 'useincommands': ['blocks'],
396 | 'segment': 'filters',
397 | 'datalog': '[(clojure.string/ends-with? ?blockcontent "$$ARG1")]',
398 | 'comment': 'Select if block content ends with arg1'
399 | },
400 | 'arg_blockcontent_contains':
401 | {
402 | 'name': 'arg_blockcontent_contains',
403 | 'useincommands': ['blocks'],
404 | 'segment': 'filters',
405 | 'datalog': '[(clojure.string/includes? ?blockcontent "$$ARG1")]',
406 | 'comment': 'Select if block content contains arg1'
407 | },
408 | 'not_arg_blockcontent_startswith':
409 | {
410 | 'name': 'not_arg_blockcontent_startswith',
411 | 'useincommands': ['blocks'],
412 | 'segment': 'filters',
413 | 'datalog': '(not [(clojure.string/starts-with? ?blockcontent "$$ARG1")])',
414 | 'comment': 'Exclude if block content starts with arg1'
415 | },
416 | 'not_arg_blockcontent_endswith':
417 | {
418 | 'name': 'not_arg_blockcontent_endswith',
419 | 'useincommands': ['blocks'],
420 | 'segment': 'filters',
421 | 'datalog': '(not [(clojure.string/ends-with? ?blockcontent "$$ARG1")])',
422 | 'comment': 'Exclude if block content ends with arg1'
423 | },
424 | 'not_arg_blockcontent_contains':
425 | {
426 | 'name': 'not_arg_blockcontent_contains',
427 | 'useincommands': ['blocks'],
428 | 'segment': 'filters',
429 | 'datalog': '(not [(clojure.string/includes? ?blockcontent "$$ARG1")])',
430 | 'comment': 'Exclude if block content contains arg1'
431 | },
432 | 'scheduledbetween':
433 | {
434 | 'name': 'scheduledbetween',
435 | 'useincommands': ['blocks'],
436 | 'segment': 'inputs',
437 | 'datalog': ':inputs [$$ARG1]',
438 | 'comment': 'set the input values for a date range for example could be\n :today :365d-after'
439 | },
440 | 'deadlinebetween':
441 | {
442 | 'name': 'deadlinebetween',
443 | 'useincommands': ['blocks'],
444 | 'segment': 'inputs',
445 | 'datalog': ':inputs [$$ARG1]',
446 | 'comment': 'set the input values for a date range for example could be\n :today :365d-after'
447 | },
448 | },
449 | 'pages-querylines': {
450 | 'original-pagename':
451 | {
452 | 'name': 'original-pagename',
453 | 'useincommands': ['pages'],
454 | 'segment': 'filters',
455 | 'datalog': '[?block :block/original-name ?originalpagename]',
456 | 'comment': 'get original page name (case sensitive) into variable ?originalpagename',
457 | },
458 | 'pagename':
459 | {
460 | 'name': 'pagename',
461 | 'useincommands': ['pages'],
462 | 'segment': 'filters',
463 | 'datalog': '[?block :block/name ?pagename]',
464 | 'comment': 'get page name (lowercase) from the special page block into variable ?pagename',
465 | },
466 | 'pagename_is':
467 | {
468 | 'name': 'pagename_is',
469 | 'useincommands': ['pages'],
470 | 'segment': 'filters',
471 | 'datalog': '[?block :block/name "$$ARG1"]',
472 | 'comment': 'Select specific page using the :block/name\nwhich is only present in special blocks that\nhave the page attributes'
473 | },
474 | 'not_pagename_is':
475 | {
476 | 'name': 'not_pagename_is',
477 | 'useincommands': ['pages'],
478 | 'segment': 'filters',
479 | 'datalog': '(not [?block :block/name "$$ARG1"])',
480 | 'comment': 'Exclude specific page using the :block/name\nwhich is only present in special blocks that\nhave the page attributes'
481 | },
482 | 'page_is_journal':
483 | {
484 | 'name': 'page_is_journal',
485 | 'useincommands': ['pages'],
486 | 'segment': 'filters',
487 | 'datalog': '[?block :block/journal? true]',
488 | 'comment': 'Select block if it belonhs to a a journal'
489 | },
490 | 'not_page_is_journal':
491 | {
492 | 'name': 'not_page_is_journal',
493 | 'useincommands': ['pages'],
494 | 'segment': 'filters',
495 | 'datalog': '[?block :block/journal? false]',
496 | 'comment': 'Exclude block if it belonhs to a a journal'
497 | },
498 | 'journal_date':
499 | {
500 | 'name': 'journal_date',
501 | 'useincommands': ['pages'],
502 | 'segment': 'filters',
503 | 'datalog': '[?block :block/journal-day ?journaldate]',
504 | 'comment': 'get journal date into variable ?journaldate'
505 | },
506 | 'page_properties_are':
507 | {
508 | 'name': 'page_properties_are',
509 | 'useincommands': ['pages'],
510 | 'segment': 'filters',
511 | 'datalog': '(page-property ?block :$$ARG1 $$ARG2)',
512 | 'comment': 'Select if block is a special page blockand has a single property (arg1) with value arg2'
513 | },
514 | 'not_page_properties_are':
515 | {
516 | 'name': 'not_page_properties_are',
517 | 'useincommands': ['pages'],
518 | 'segment': 'filters',
519 | 'datalog': '(not (page-property ?block :$$ARG1 $$ARG2))',
520 | 'comment': 'Exclude if block is a special page blockand has a single property (arg1) with value arg2'
521 | },
522 | 'block_properties_are':
523 | {
524 | 'name': 'block_properties_are',
525 | 'useincommands': ['pages'],
526 | 'segment': 'filters',
527 | 'datalog': '(page-property ?block :$$ARG1 $$ARG2)',
528 | 'comment': 'Select if block has a single property (arg1) with value arg2'
529 | },
530 | 'not_block_properties_are':
531 | {
532 | 'name': 'not_block_properties_are',
533 | 'useincommands': ['pages'],
534 | 'segment': 'filters',
535 | 'datalog': '(not (property ?block :$$ARG1 $$ARG2))',
536 | 'comment': 'Exclude if block has a single property (arg1) with value arg2'
537 | },
538 | 'pagetags_are':
539 | {
540 | 'name': 'pagetags_are',
541 | 'useincommands': ['pages'],
542 | 'segment': 'filters',
543 | 'datalog': '(page-tags ?block #{"$$ARG1"})',
544 | 'comment': 'Select special page block with one or more page tags'
545 | },
546 | 'not_pagetags_are':
547 | {
548 | 'name': 'not_pagetags_are',
549 | 'useincommands': ['pages'],
550 | 'segment': 'filters',
551 | 'datalog': '(not (page-tags ?block #{"$$ARG1"}))',
552 | 'comment': 'Exclude special page block with one or more page tags'
553 | },
554 | 'blocktags_are':
555 | {
556 | 'name': 'blocktags_are',
557 | 'useincommands': ['blocks'],
558 | 'segment': 'filters',
559 | 'datalog': '(page-tags ?block #{"$$ARG1"})',
560 | 'comment': 'Select block if the page it belongs to\nhas a specific page tag or page link'
561 | },
562 | 'not_blocktags_are':
563 | {
564 | 'name': 'not_blocktags_are',
565 | 'useincommands': ['blocks'],
566 | 'segment': 'filters',
567 | 'datalog': '(not (page-tags ?block #{"$$ARG1"}))',
568 | 'comment': 'Exclude block if the page it belongs to\nhas a specific page tag or page link'
569 | },
570 | 'namespace':
571 | {
572 | 'name': 'namespace_pages',
573 | 'useincommands': ['pages'],
574 | 'segment': 'filters',
575 | 'datalog': '(namespace ?block "$$ARG1")',
576 | 'comment': 'Select if special page block is within namespace arg1'
577 | },
578 | 'not_namespace':
579 | {
580 | 'name': 'not_namespace_pages',
581 | 'useincommands': ['pages'],
582 | 'segment': 'filters',
583 | 'datalog': '(not (namespace ?block "$$ARG1"))',
584 | 'comment': 'Select if special page block is within namespace arg1'
585 | },
586 | 'arg_pagename_startswith':
587 | {
588 | 'name': 'arg_pagename_startswith',
589 | 'useincommands': ['pages'],
590 | 'segment': 'filters',
591 | 'datalog': '[(clojure.string/starts-with? ?pagename "$$ARG1")]',
592 | 'comment': 'Select if page title starts with arg1'
593 | },
594 | 'arg_pagename_endswith':
595 | {
596 | 'name': 'arg_pagename_endswith',
597 | 'useincommands': ['pages'],
598 | 'segment': 'filters',
599 | 'datalog': '[(clojure.string/ends-with? ?pagename "$$ARG1")]',
600 | 'comment': 'Select if page title ends with arg1'
601 | },
602 | 'arg_pagename_contains':
603 | {
604 | 'name': 'arg_pagename_contains',
605 | 'useincommands': ['common'],
606 | 'segment': 'filters',
607 | 'datalog': '[(clojure.string/includes? ?pagename "$$ARG1")]',
608 | 'comment': 'Select if page title contains arg1'
609 | },
610 | 'not_arg_pagename_startswith':
611 | {
612 | 'name': 'not_arg_pagename_startswith',
613 | 'useincommands': ['common'],
614 | 'segment': 'filters',
615 | 'datalog': '(not [(clojure.string/starts-with? ?pagename "$$ARG1")])',
616 | 'comment': 'Exclude if page title ends with arg1'
617 | },
618 | 'not_arg_pagename_endswith':
619 | {
620 | 'name': 'not_arg_pagename_endswith',
621 | 'useincommands': ['pages'],
622 | 'segment': 'filters',
623 | 'datalog': '(not [(clojure.string/ends-with? ?pagename "$$ARG1")])',
624 | 'comment': 'Exclude if page title ends with arg1'
625 | },
626 | 'not_arg_pagename_contains':
627 | {
628 | 'name': 'not_arg_pagename_contains',
629 | 'useincommands': ['pages'],
630 | 'segment': 'filters',
631 | 'datalog': '(not [(clojure.string/includes? ?pagename "$$ARG1")])',
632 | 'comment': 'Exclude if page title contains arg1'
633 | },
634 | }
635 | }
636 |
637 | // Dictionary of query builder commands
638 | var commandsDict = {
639 | "blocks": {
640 | "querylines": [
641 | "findblocks",
642 | "where",
643 | "blockcontent",
644 | "page",
645 | "pagename",
646 | ],
647 | "description": "select logseq blocks by wildcards"
648 | },
649 | "blockproperties": {
650 | "querylines": [
651 | ],
652 | "description": "select blocks by property values"
653 | },
654 | "blocktags": {
655 | "querylines": [
656 | ],
657 | "description": "select blocks by tag"
658 | },
659 | "deadline": {
660 | "querylines": [
661 | "deadline"
662 | ],
663 | "description": "select blocks that have a deadline"
664 | },
665 | "deadlinebetween": {
666 | "querylines": [
667 | "deadline",
668 | "deadlinefrom",
669 | "deadlineto",
670 | "daterange"
671 | ],
672 | "description": "select blocks that have a deadline in a date range"
673 | },
674 | "journalsbetween": {
675 | "querylines": [
676 | "journal_date",
677 | "journalfrom",
678 | "journalto",
679 | "daterange"
680 | ],
681 | "description": "only select journal pages in a date range"
682 | },
683 | "journalonly": {
684 | "querylines": [
685 | "page_is_journal"
686 | ],
687 | "description": "only select journal pages"
688 | },
689 | "namespace": {
690 | "querylines": [
691 | ],
692 | "description": "select pages or blocks within a namespace"
693 | },
694 | "pages": {
695 | "querylines": [
696 | "findblocks",
697 | "where",
698 | "pagename",
699 | ],
700 | "description": "select pages by wildcards"
701 | },
702 | "pageproperties": {
703 | "querylines": [
704 | ],
705 | "description": "select pages by page properties"
706 | },
707 | "pagetags": {
708 | "querylines": [
709 | "not_page_is_journal"
710 | ],
711 | "description": "select pages by tag"
712 | },
713 | "pagelinks": {
714 | "querylines": [
715 | ],
716 | "description": "select any blocks that has links to pages"
717 | },
718 | "tasks": {
719 | "querylines": [
720 | 'marker',
721 | ],
722 | "description": "select blocks that have tasks present"
723 | },
724 | "scheduled": {
725 | "querylines": [
726 | "scheduled"
727 | ],
728 | "description": "select blocks that are scheduled"
729 | },
730 | "scheduledbetween": {
731 | "querylines": [
732 | "scheduled",
733 | "scheduledfrom",
734 | "scheduledto",
735 | "daterange"
736 | ],
737 | "description": "select blocks that are scheduled in a date range"
738 | },
739 | "collapse": {
740 | "querylines": [
741 | "collapse_true"
742 | ],
743 | "description": "collapse found blocks"
744 | },
745 | "expand": {
746 | "querylines": [
747 | "collapse_false"
748 | ],
749 | "description": "expand found blocks"
750 | },
751 | "showbreadcrumb": {
752 | "querylines": [
753 | "breadcrumb_show_true"
754 | ],
755 | "description": "show breadcrumb for found blocks"
756 | },
757 | "hidebreadcrumb": {
758 | "querylines": [
759 | "breadcrumb_show_false"
760 | ],
761 | "description": "hide breadcrumb for found blocks"
762 | },
763 | }
764 |
765 | // Local tests cases for automated test suite
766 | var QueryTestCases = [
767 |
768 | // test 1
769 | `title: pages command - select all pages
770 | - pages
771 | - *
772 | #+BEGIN_QUERY
773 | {
774 | :title [:b "pages command - select all pages"]
775 | :query [:find (pull ?block [*])
776 | :where
777 | [?block :block/name ?pagename]
778 | ]
779 | }
780 | #+END_QUERY
781 | `,
782 |
783 | // test 2
784 | `title: pages command - specific pages
785 | - pages
786 | - testpage001
787 | - testpage002
788 | #+BEGIN_QUERY
789 | {
790 | :title [:b "pages command - specific pages"]
791 | :query [:find (pull ?block [*])
792 | :where
793 | [?block :block/name ?pagename]
794 | ( or
795 | [?block :block/name "testpage001"]
796 | [?block :block/name "testpage002"]
797 | )
798 | ]
799 | }
800 | #+END_QUERY
801 | `,
802 |
803 | // test 3
804 | `title: pages command - pages by wildcards
805 | - pages
806 | - testpage00*
807 | #+BEGIN_QUERY
808 | {
809 | :title [:b "pages command - pages by wildcards"]
810 | :query [:find (pull ?block [*])
811 | :where
812 | [?block :block/name ?pagename]
813 | [(clojure.string/starts-with? ?pagename "testpage00")]
814 | ]
815 | }
816 | #+END_QUERY
817 | `,
818 |
819 | // test 4
820 | `title: pages command - pages by wildcards
821 | - pages
822 | - *002
823 | #+BEGIN_QUERY
824 | {
825 | :title [:b "pages command - pages by wildcards"]
826 | :query [:find (pull ?block [*])
827 | :where
828 | [?block :block/name ?pagename]
829 | [(clojure.string/ends-with? ?pagename "002")]
830 | ]
831 | }
832 | #+END_QUERY
833 | `,
834 |
835 | // test 5
836 | `title: pages command - pages by wildcards
837 | - pages
838 | - *page00*
839 | #+BEGIN_QUERY
840 | {
841 | :title [:b "pages command - pages by wildcards"]
842 | :query [:find (pull ?block [*])
843 | :where
844 | [?block :block/name ?pagename]
845 | [(clojure.string/includes? ?pagename "page00")]
846 | ]
847 | }
848 | #+END_QUERY
849 | `,
850 |
851 | // test 6
852 | `title: pages command - ignore pages (including wildcards)
853 | - pages
854 | - not testpage*
855 | - not Queries*
856 | #+BEGIN_QUERY
857 | {
858 | :title [:b "pages command - ignore pages (including wildcards)"]
859 | :query [:find (pull ?block [*])
860 | :where
861 | [?block :block/name ?pagename]
862 | (not [(clojure.string/starts-with? ?pagename "testpage")])
863 | (not [(clojure.string/starts-with? ?pagename "Queries")])
864 | ]
865 | }
866 | #+END_QUERY
867 | `,
868 |
869 | // test 7
870 | `title: blocks command - ignore blocks using wildcards
871 | - blocks
872 | - not And sir dare view*
873 | - not *here leave merit enjoy forth.
874 | - not *roof gutters*
875 | #+BEGIN_QUERY
876 | {
877 | :title [:b "blocks command - ignore blocks using wildcards"]
878 | :query [:find (pull ?block [*])
879 | :where
880 | [?block :block/content ?blockcontent]
881 | [?block :block/page ?page]
882 | [?page :block/name ?pagename]
883 | (not [(clojure.string/ends-with? ?blockcontent "And sir dare view")])
884 | (not [(clojure.string/starts-with? ?blockcontent "here leave merit enjoy forth.")])
885 | (not [(clojure.string/includes? ?blockcontent "roof gutters")])
886 | ]
887 | }
888 | #+END_QUERY
889 | `,
890 |
891 | // test 8
892 | `title: blocktags - select and exclude block level tags
893 | - blocks
894 | - *
895 | - blocktags
896 | - tagA
897 | - tagD
898 | - not tagB
899 | #+BEGIN_QUERY
900 | {
901 | :title [:b "blocktags - select and exclude block level tags"]
902 | :query [:find (pull ?block [*])
903 | :where
904 | [?block :block/content ?blockcontent]
905 | [?block :block/page ?page]
906 | [?page :block/name ?pagename]
907 | ( or
908 | (page-ref ?block "taga")
909 | (page-ref ?block "tagd")
910 | )
911 | (not (page-ref ?block "tagb"))
912 | ]
913 | }
914 | #+END_QUERY
915 | `,
916 | `title: blocktags and pages don't mix
917 | - pages
918 | - testpage00*
919 | - blocktags
920 | - tagA
921 | - not tagB
922 | #+BEGIN_QUERY
923 |
924 | ;; **ERROR: blocktags not valid with pages command use blocks command instead
925 |
926 | {
927 | :title [:b "blocktags and pages don't mix"]
928 | :query [:find (pull ?block [*])
929 | :where
930 | [?block :block/name ?pagename]
931 | [(clojure.string/starts-with? ?pagename "testpage00")]
932 | ]
933 | }
934 | #+END_QUERY
935 | `,
936 |
937 | // test 10
938 | `title: pagetags - page level tags
939 | - pages
940 | - testpage*
941 | - pagetags
942 | - classA
943 | #+BEGIN_QUERY
944 | {
945 | :title [:b "pagetags - page level tags"]
946 | :query [:find (pull ?block [*])
947 | :where
948 | [?block :block/name ?pagename]
949 | [(clojure.string/starts-with? ?pagename "testpage")]
950 | [?block :block/journal? false]
951 | (page-tags ?block #{"classa"})
952 | ]
953 | }
954 | #+END_QUERY
955 | `,
956 |
957 | // test 11
958 | `title: pagetags and pages
959 | - pages
960 | - *dynamics*
961 | - pagetags
962 | - classB
963 | #+BEGIN_QUERY
964 | {
965 | :title [:b "pagetags and pages"]
966 | :query [:find (pull ?block [*])
967 | :where
968 | [?block :block/name ?pagename]
969 | [(clojure.string/includes? ?pagename "dynamics")]
970 | [?block :block/journal? false]
971 | (page-tags ?block #{"classb"})
972 | ]
973 | }
974 | #+END_QUERY
975 | `,
976 |
977 | // test 12
978 | `title: select and exclude task types
979 | - tasks
980 | - TODO
981 | - not DOING
982 | #+BEGIN_QUERY
983 | ;; WARNING: Must have 'pages' command or 'blocks' Command
984 | ;; otherwise the query cannot get any information
985 | ;; Inserting a blocks command for you
986 |
987 | {
988 | :title [:b "select and exclude task types"]
989 | :query [:find (pull ?block [*])
990 | :where
991 | [?block :block/content ?blockcontent]
992 | [?block :block/page ?page]
993 | [?page :block/name ?pagename]
994 | [?block :block/marker ?marker]
995 | [(contains? #{"TODO"} ?marker)]
996 | (not [(contains? #{"DOING"} ?marker)])
997 | ]
998 | }
999 | #+END_QUERY
1000 | `,
1001 |
1002 | `title: select and exclude task types
1003 | - pages
1004 | - testpage00*
1005 | - tasks
1006 | - TODO
1007 | - not DOING
1008 | #+BEGIN_QUERY
1009 |
1010 | ;; **ERROR: tasks not valid with pages command use blocks command instead
1011 |
1012 | {
1013 | :title [:b "select and exclude task types"]
1014 | :query [:find (pull ?block [*])
1015 | :where
1016 | [?block :block/name ?pagename]
1017 | [(clojure.string/starts-with? ?pagename "testpage00")]
1018 | ]
1019 | }
1020 | #+END_QUERY
1021 | `,
1022 |
1023 | // test 14
1024 | `title: select and exclude pages with page properties
1025 | - pages
1026 | - *
1027 | - pageproperties
1028 | - pagetype, "p-major"
1029 | - pagetype, "p-minor"
1030 | - not pagetype, "p-advanced"
1031 | #+BEGIN_QUERY
1032 | {
1033 | :title [:b "select and exclude pages with page properties"]
1034 | :query [:find (pull ?block [*])
1035 | :where
1036 | [?block :block/name ?pagename]
1037 | ( or
1038 | (page-property ?block :pagetype "p-major")
1039 | (page-property ?block :pagetype "p-minor")
1040 | )
1041 | (not (page-property ?block :pagetype "p-advanced"))
1042 | ]
1043 | }
1044 | #+END_QUERY
1045 | `,
1046 |
1047 | // test 15
1048 | `title: select and exclude blocks with block properties
1049 | - blocks
1050 | - *
1051 | - blockproperties
1052 | - category, "b-thriller"
1053 | - category, "b-western"
1054 | - grade, "b-fiction"
1055 | #+BEGIN_QUERY
1056 | {
1057 | :title [:b "select and exclude blocks with block properties"]
1058 | :query [:find (pull ?block [*])
1059 | :where
1060 | [?block :block/content ?blockcontent]
1061 | [?block :block/page ?page]
1062 | [?page :block/name ?pagename]
1063 | ( or
1064 | (property ?block :category "b-thriller")
1065 | (property ?block :category "b-western")
1066 | (property ?block :grade "b-fiction")
1067 | )
1068 | ]
1069 | }
1070 | #+END_QUERY
1071 | `,
1072 |
1073 | // test 16
1074 | `title: only search pages in specific namespace
1075 | - pages
1076 | - *
1077 | - namespace
1078 | - physics
1079 | #+BEGIN_QUERY
1080 | {
1081 | :title [:b "only search pages in specific namespace"]
1082 | :query [:find (pull ?block [*])
1083 | :where
1084 | [?block :block/name ?pagename]
1085 | (namespace ?block "physics")
1086 | ]
1087 | }
1088 | #+END_QUERY
1089 | `,
1090 |
1091 | // test 17
1092 | `title: find block properties in a namespace
1093 | - blocks
1094 | - *
1095 | - namespace
1096 | - tech/python
1097 | - blockproperties
1098 | - grade, "b-fiction"
1099 | #+BEGIN_QUERY
1100 | {
1101 | :title [:b "find block properties in a namespace"]
1102 | :query [:find (pull ?block [*])
1103 | :where
1104 | [?block :block/content ?blockcontent]
1105 | [?block :block/page ?page]
1106 | [?page :block/name ?pagename]
1107 | (namespace ?page "tech/python")
1108 | (property ?block :grade "b-fiction")
1109 | ]
1110 | }
1111 | #+END_QUERY
1112 | `,
1113 |
1114 | // test 18
1115 | `title: find scheduled blocks in a namespace
1116 | - blocks
1117 | - *
1118 | - namespace
1119 | - physics
1120 | - scheduled
1121 | #+BEGIN_QUERY
1122 | {
1123 | :title [:b "find scheduled blocks in a namespace"]
1124 | :query [:find (pull ?block [*])
1125 | :where
1126 | [?block :block/content ?blockcontent]
1127 | [?block :block/page ?page]
1128 | [?page :block/name ?pagename]
1129 | (namespace ?page "physics")
1130 | [?block :block/scheduled ?scheduleddate]
1131 | ]
1132 | }
1133 | #+END_QUERY
1134 | `,
1135 |
1136 | // test 19
1137 | `title: scheduled - find scheduled blocks in a date range
1138 | - blocks
1139 | - *
1140 | - scheduledbetween
1141 | - :720d-before :700d-after
1142 | #+BEGIN_QUERY
1143 | {
1144 | :title [:b "scheduled - find scheduled blocks in a date range"]
1145 | :query [:find (pull ?block [*])
1146 | :in $ ?startdate ?enddate
1147 | :where
1148 | [?block :block/content ?blockcontent]
1149 | [?block :block/page ?page]
1150 | [?page :block/name ?pagename]
1151 | [?block :block/scheduled ?scheduleddate]
1152 | [(>= ?scheduleddate ?startdate)]
1153 | [(<= ?scheduleddate ?enddate)]
1154 | ]
1155 | :inputs [:720d-before :700d-after]
1156 | }
1157 | #+END_QUERY
1158 | `,
1159 |
1160 | // test 20
1161 | `title: find blocks with deadlines
1162 | - blocks
1163 | - *
1164 | - deadline
1165 | #+BEGIN_QUERY
1166 | {
1167 | :title [:b "find blocks with deadlines"]
1168 | :query [:find (pull ?block [*])
1169 | :where
1170 | [?block :block/content ?blockcontent]
1171 | [?block :block/page ?page]
1172 | [?page :block/name ?pagename]
1173 | [?block :block/deadline ?deadlinedate]
1174 | ]
1175 | }
1176 | #+END_QUERY
1177 | `,
1178 |
1179 | // test 21
1180 | `title: find blocks with deadlines in a date range
1181 | - blocks
1182 | - *
1183 | - deadlinebetween
1184 | - :120d-before :30d-after
1185 | #+BEGIN_QUERY
1186 | {
1187 | :title [:b "find blocks with deadlines in a date range"]
1188 | :query [:find (pull ?block [*])
1189 | :in $ ?startdate ?enddate
1190 | :where
1191 | [?block :block/content ?blockcontent]
1192 | [?block :block/page ?page]
1193 | [?page :block/name ?pagename]
1194 | [?block :block/deadline ?deadlinedate]
1195 | [(>= ?deadlinedate ?startdate)]
1196 | [(<= ?deadlinedate ?enddate)]
1197 | ]
1198 | :inputs [:120d-before :30d-after]
1199 | }
1200 | #+END_QUERY
1201 | `,
1202 |
1203 | // test 22
1204 | `title: find journals
1205 | - pages
1206 | - *
1207 | - journalonly
1208 | #+BEGIN_QUERY
1209 | {
1210 | :title [:b "find journals"]
1211 | :query [:find (pull ?block [*])
1212 | :where
1213 | [?block :block/name ?pagename]
1214 | [?block :block/journal? true]
1215 | ]
1216 | }
1217 | #+END_QUERY
1218 | `,
1219 |
1220 | // test 23
1221 | `title: find journal in a date range
1222 | - pages
1223 | - *
1224 | - journalsbetween
1225 | - :today :30d-after
1226 | #+BEGIN_QUERY
1227 | {
1228 | :title [:b "find journal in a date range"]
1229 | :query [:find (pull ?block [*])
1230 | :in $ ?startdate ?enddate
1231 | :where
1232 | [?block :block/name ?pagename]
1233 | [?block :block/journal-day ?journaldate]
1234 | [(>= ?journaldate ?startdate)]
1235 | [(<= ?journaldate ?enddate)]
1236 | ]
1237 | :inputs [:today :30d-after]
1238 | }
1239 | #+END_QUERY
1240 | `,
1241 |
1242 | // test 24
1243 | `title: find journals between dates
1244 | - blocks
1245 | - *
1246 | - journalsbetween
1247 | - :30d-before :today
1248 | #+BEGIN_QUERY
1249 | {
1250 | :title [:b "find journals between dates"]
1251 | :query [:find (pull ?block [*])
1252 | :in $ ?startdate ?enddate
1253 | :where
1254 | [?block :block/content ?blockcontent]
1255 | [?block :block/page ?page]
1256 | [?page :block/name ?pagename]
1257 | [?page :block/journal-day ?journaldate]
1258 | [(>= ?journaldate ?startdate)]
1259 | [(<= ?journaldate ?enddate)]
1260 | ]
1261 | :inputs [:30d-before :today]
1262 | }
1263 | #+END_QUERY
1264 | `,
1265 |
1266 | // test 25
1267 | `title: collapse results
1268 | - pages
1269 | - testpage00*
1270 | - collapse
1271 | #+BEGIN_QUERY
1272 | {
1273 | :title [:b "collapse results"]
1274 | :query [:find (pull ?block [*])
1275 | :where
1276 | [?block :block/name ?pagename]
1277 | [(clojure.string/starts-with? ?pagename "testpage00")]
1278 | ]
1279 | :collapsed? true
1280 | }
1281 | #+END_QUERY
1282 | `,
1283 |
1284 | // test 26
1285 | `title: expand results
1286 | - pages
1287 | - testpage00*
1288 | - expand
1289 | #+BEGIN_QUERY
1290 | {
1291 | :title [:b "expand results"]
1292 | :query [:find (pull ?block [*])
1293 | :where
1294 | [?block :block/name ?pagename]
1295 | [(clojure.string/starts-with? ?pagename "testpage00")]
1296 | ]
1297 | :collapsed? false
1298 | }
1299 | #+END_QUERY
1300 | `,
1301 |
1302 | // test 27
1303 | `title: show breadcrumbs
1304 | - pages
1305 | - testpage00*
1306 | - showbreadcrumb
1307 | #+BEGIN_QUERY
1308 | {
1309 | :title [:b "show breadcrumbs"]
1310 | :query [:find (pull ?block [*])
1311 | :where
1312 | [?block :block/name ?pagename]
1313 | [(clojure.string/starts-with? ?pagename "testpage00")]
1314 | ]
1315 | :breadcrumb-show? true
1316 | }
1317 | #+END_QUERY
1318 | `,
1319 |
1320 | // test 28
1321 | `title: hide breadcrumbs
1322 | - pages
1323 | - testpage00*
1324 | - hidebreadcrumb
1325 | #+BEGIN_QUERY
1326 | {
1327 | :title [:b "hide breadcrumbs"]
1328 | :query [:find (pull ?block [*])
1329 | :where
1330 | [?block :block/name ?pagename]
1331 | [(clojure.string/starts-with? ?pagename "testpage00")]
1332 | ]
1333 | :breadcrumb-show? false
1334 | }
1335 | #+END_QUERY
1336 | `,
1337 |
1338 | // test 29
1339 | `title: find journal in a date range using blocks
1340 | - blocks
1341 | - *
1342 | - journalsbetween
1343 | - :today :30d-after
1344 | #+BEGIN_QUERY
1345 | {
1346 | :title [:b "find journal in a date range using blocks"]
1347 | :query [:find (pull ?block [*])
1348 | :in $ ?startdate ?enddate
1349 | :where
1350 | [?block :block/content ?blockcontent]
1351 | [?block :block/page ?page]
1352 | [?page :block/name ?pagename]
1353 | [?page :block/journal-day ?journaldate]
1354 | [(>= ?journaldate ?startdate)]
1355 | [(<= ?journaldate ?enddate)]
1356 | ]
1357 | :inputs [:today :30d-after]
1358 | }
1359 | #+END_QUERY
1360 | `,
1361 | // test 30
1362 | `title: All blocks - test access to parent pages tags, journal
1363 | - blocks
1364 | - *
1365 | - tasks
1366 | - TODO
1367 | - pagetags
1368 | - classC
1369 | #+BEGIN_QUERY
1370 | {
1371 | :title [:b "All blocks - test access to parent pages tags, journal"]
1372 | :query [:find (pull ?block [*])
1373 | :where
1374 | [?block :block/content ?blockcontent]
1375 | [?block :block/page ?page]
1376 | [?page :block/name ?pagename]
1377 | [?block :block/marker ?marker]
1378 | [(contains? #{"TODO"} ?marker)]
1379 | [?page :block/journal? false]
1380 | (page-tags ?page #{"classc"})
1381 | ]
1382 | }
1383 | #+END_QUERY
1384 | `,
1385 | // test 31
1386 | `title: Pages only - Access page properties
1387 | - pages
1388 | - *
1389 | - pageproperties
1390 | - pagetype, "p-minor"
1391 | #+BEGIN_QUERY
1392 | {
1393 | :title [:b "Pages only - Access page properties"]
1394 | :query [:find (pull ?block [*])
1395 | :where
1396 | [?block :block/name ?pagename]
1397 | (page-property ?block :pagetype "p-minor")
1398 | ]
1399 | }
1400 | #+END_QUERY
1401 | `,
1402 | // test 32
1403 | `title: Pages only - access multiple property values
1404 | - pages
1405 | - *
1406 | - pageproperties
1407 | - pagetype, "p-minor"
1408 | - pagetype, "p-major"
1409 | #+BEGIN_QUERY
1410 | {
1411 | :title [:b "Pages only - access multiple property values"]
1412 | :query [:find (pull ?block [*])
1413 | :where
1414 | [?block :block/name ?pagename]
1415 | ( or
1416 | (page-property ?block :pagetype "p-minor")
1417 | (page-property ?block :pagetype "p-major")
1418 | )
1419 | ]
1420 | }
1421 | #+END_QUERY
1422 | `,
1423 | // test 33
1424 | `title: Page blocks only - pagetags
1425 | - pages
1426 | - *
1427 | - pagetags
1428 | - classC
1429 | #+BEGIN_QUERY
1430 | {
1431 | :title [:b "Page blocks only - pagetags"]
1432 | :query [:find (pull ?block [*])
1433 | :where
1434 | [?block :block/name ?pagename]
1435 | [?block :block/journal? false]
1436 | (page-tags ?block #{"classc"})
1437 | ]
1438 | }
1439 | #+END_QUERY
1440 | `,
1441 | // test 34
1442 | `title: Pages only - select all pages
1443 | - pages
1444 | - *
1445 | #+BEGIN_QUERY
1446 | {
1447 | :title [:b "Pages only - select all pages"]
1448 | :query [:find (pull ?block [*])
1449 | :where
1450 | [?block :block/name ?pagename]
1451 | ]
1452 | }
1453 | #+END_QUERY
1454 | `,
1455 | // test 35
1456 | `title: pages command - specific pages
1457 | - pages
1458 | - testpage001
1459 | - testpage002
1460 | #+BEGIN_QUERY
1461 | {
1462 | :title [:b "pages command - specific pages"]
1463 | :query [:find (pull ?block [*])
1464 | :where
1465 | [?block :block/name ?pagename]
1466 | ( or
1467 | [?block :block/name "testpage001"]
1468 | [?block :block/name "testpage002"]
1469 | )
1470 | ]
1471 | }
1472 | #+END_QUERY
1473 | `,
1474 | // test 36
1475 | `title: pages command - pages by wildcards
1476 | - pages
1477 | - testpage00*
1478 | #+BEGIN_QUERY
1479 | {
1480 | :title [:b "pages command - pages by wildcards"]
1481 | :query [:find (pull ?block [*])
1482 | :where
1483 | [?block :block/name ?pagename]
1484 | [(clojure.string/starts-with? ?pagename "testpage00")]
1485 | ]
1486 | }
1487 | #+END_QUERY
1488 | `,
1489 | // test 37
1490 | `title: pages command - pages by wildcards
1491 | - pages
1492 | - *002
1493 | #+BEGIN_QUERY
1494 | {
1495 | :title [:b "pages command - pages by wildcards"]
1496 | :query [:find (pull ?block [*])
1497 | :where
1498 | [?block :block/name ?pagename]
1499 | [(clojure.string/ends-with? ?pagename "002")]
1500 | ]
1501 | }
1502 | #+END_QUERY
1503 | `,
1504 | // test 38
1505 | `title: journalsbetween defaulting to blocks retrieval
1506 | - journalsbetween
1507 | - :today :30d-after
1508 | #+BEGIN_QUERY
1509 | ;; WARNING: Must have 'pages' command or 'blocks' Command
1510 | ;; otherwise the query cannot get any information
1511 | ;; Inserting a blocks command for you
1512 |
1513 | {
1514 | :title [:b "journalsbetween defaulting to blocks retrieval"]
1515 | :query [:find (pull ?block [*])
1516 | :in $ ?startdate ?enddate
1517 | :where
1518 | [?block :block/content ?blockcontent]
1519 | [?block :block/page ?page]
1520 | [?page :block/name ?pagename]
1521 | [?page :block/journal-day ?journaldate]
1522 | [(>= ?journaldate ?startdate)]
1523 | [(<= ?journaldate ?enddate)]
1524 | ]
1525 | :inputs [:today :30d-after]
1526 | }
1527 | #+END_QUERY
1528 | `,
1529 | // test 39
1530 | `title: journalsbetween using pages retrieval
1531 | - pages
1532 | - *
1533 | - journalsbetween
1534 | - :today :30d-after
1535 | #+BEGIN_QUERY
1536 | {
1537 | :title [:b "journalsbetween using pages retrieval"]
1538 | :query [:find (pull ?block [*])
1539 | :in $ ?startdate ?enddate
1540 | :where
1541 | [?block :block/name ?pagename]
1542 | [?block :block/journal-day ?journaldate]
1543 | [(>= ?journaldate ?startdate)]
1544 | [(<= ?journaldate ?enddate)]
1545 | ]
1546 | :inputs [:today :30d-after]
1547 | }
1548 | #+END_QUERY
1549 | `,
1550 | // test 40
1551 | `title: page property combinations using and and or
1552 | - pages
1553 | - *
1554 | - pageproperties
1555 | - pagecategory, "p-minor"
1556 | - or pagecategory, "p-minimum"
1557 | - and pagetype, "p-type1"
1558 | #+BEGIN_QUERY
1559 | {
1560 | :title [:b "page property combinations using and and or"]
1561 | :query [:find (pull ?block [*])
1562 | :where
1563 | [?block :block/name ?pagename]
1564 | ( or
1565 | (page-property ?block :pagecategory "p-minor")
1566 | (page-property ?block :pagecategory "p-minimum")
1567 | )
1568 | (page-property ?block :pagetype "p-type1")
1569 | ]
1570 | }
1571 | #+END_QUERY
1572 | `,
1573 | // test 41
1574 | `title: page tag combinations using and and or
1575 | - pages
1576 | - *
1577 | - pagetags
1578 | - classA
1579 | - or classB
1580 | - and classH
1581 | #+BEGIN_QUERY
1582 | {
1583 | :title [:b "page tag combinations using and and or"]
1584 | :query [:find (pull ?block [*])
1585 | :where
1586 | [?block :block/name ?pagename]
1587 | [?block :block/journal? false]
1588 | ( or
1589 | (page-tags ?block #{"classa"})
1590 | (page-tags ?block #{"classb"})
1591 | )
1592 | (page-tags ?block #{"classh"})
1593 | ]
1594 | }
1595 | #+END_QUERY
1596 | `,
1597 | // test 42
1598 | `title: block property combinations using and and or
1599 | - blocks
1600 | - *
1601 | - blockproperties
1602 | - category, "b-fiction"
1603 | - or grade, "b-western"
1604 | - and category, "b-travel"
1605 | #+BEGIN_QUERY
1606 | {
1607 | :title [:b "block property combinations using and and or"]
1608 | :query [:find (pull ?block [*])
1609 | :where
1610 | [?block :block/content ?blockcontent]
1611 | [?block :block/page ?page]
1612 | [?page :block/name ?pagename]
1613 | ( or
1614 | (property ?block :category "b-fiction")
1615 | (property ?block :grade "b-western")
1616 | )
1617 | (property ?block :category "b-travel")
1618 | ]
1619 | }
1620 | #+END_QUERY
1621 | `,
1622 | // test 43
1623 | `title: block tag combinations using and and or
1624 | - blocks
1625 | - *
1626 | - blocktags
1627 | - tagA
1628 | - or tagB
1629 | - and tagD
1630 | #+BEGIN_QUERY
1631 | {
1632 | :title [:b "block tag combinations using and and or"]
1633 | :query [:find (pull ?block [*])
1634 | :where
1635 | [?block :block/content ?blockcontent]
1636 | [?block :block/page ?page]
1637 | [?page :block/name ?pagename]
1638 | ( or
1639 | (page-ref ?block "taga")
1640 | (page-ref ?block "tagb")
1641 | )
1642 | (page-ref ?block "tagd")
1643 | ]
1644 | }
1645 | #+END_QUERY
1646 | `,
1647 | // test 44
1648 | `title: task and or combintions
1649 | - blocks
1650 | - *
1651 | - tasks
1652 | - TODO
1653 | - and WAITING
1654 | - or LATER
1655 | - not DOING
1656 | #+BEGIN_QUERY
1657 | {
1658 | :title [:b "task and or combintions"]
1659 | :query [:find (pull ?block [*])
1660 | :where
1661 | [?block :block/content ?blockcontent]
1662 | [?block :block/page ?page]
1663 | [?page :block/name ?pagename]
1664 | [?block :block/marker ?marker]
1665 | ( or
1666 | [(contains? #{"TODO"} ?marker)]
1667 | [(contains? #{"LATER"} ?marker)]
1668 | )
1669 | [(contains? #{"WAITING"} ?marker)]
1670 | (not [(contains? #{"DOING"} ?marker)])
1671 | ]
1672 | }
1673 | #+END_QUERY
1674 | `,
1675 | // test 45
1676 | `title: select blocks with links to pages
1677 | - blocks
1678 | - *
1679 | - pagelinks
1680 | - gardening
1681 | - vegetables
1682 | - not turnips
1683 | #+BEGIN_QUERY
1684 | {
1685 | :title [:b "select blocks with links to pages"]
1686 | :query [:find (pull ?block [*])
1687 | :where
1688 | [?block :block/content ?blockcontent]
1689 | [?block :block/page ?page]
1690 | [?page :block/name ?pagename]
1691 | ( or
1692 | [?block :block/path-refs [:block/name "gardening"]]
1693 | [?block :block/path-refs [:block/name "vegetables"]]
1694 | )
1695 | (not [?block :block/path-refs [:block/name "turnips"]])
1696 | ]
1697 | }
1698 | #+END_QUERY
1699 | `,
1700 | // test 46
1701 | `title: select blocks with links to journals
1702 | - blocks
1703 | - *
1704 | - pagelinks
1705 | - Dec 25th, 2022
1706 | - Jan 1st, 2019
1707 | #+BEGIN_QUERY
1708 | {
1709 | :title [:b "select blocks with links to journals"]
1710 | :query [:find (pull ?block [*])
1711 | :where
1712 | [?block :block/content ?blockcontent]
1713 | [?block :block/page ?page]
1714 | [?page :block/name ?pagename]
1715 | ( or
1716 | [?block :block/path-refs [:block/name "dec 25th, 2022"]]
1717 | [?block :block/path-refs [:block/name "jan 1st, 2019"]]
1718 | )
1719 | ]
1720 | }
1721 | #+END_QUERY
1722 | `
1723 |
1724 | ]
1725 |
1726 | function test_queryDBRead(section, key) {
1727 | try {
1728 | read1 = querylineDict[section][key]['name']
1729 | read2 = querylineDict[section][key]['segment']
1730 | read3 = querylineDict[section][key]['segment']
1731 | read4 = querylineDict[section][key]['datalog']
1732 | read5 = querylineDict[section][key]['comment']
1733 | // return read1
1734 | return read1 + '\n' + read2 + '\n' + read3 + '\n' + read4 + '\n' + read5 + '\n'
1735 |
1736 | } catch {
1737 | return "Failed"
1738 | }
1739 | }
1740 |
1741 |
1742 |
1743 |
1744 | function add(num1, num2) {
1745 | return num1 + num2
1746 | }
1747 |
1748 |
1749 | // ========= global variables
1750 |
1751 | // ---query structure
1752 | var query_template = {
1753 | "start": [],
1754 | "errors": [],
1755 | "open": [],
1756 | "title": [],
1757 | "query": [],
1758 | "in": [],
1759 | "where": [],
1760 | "filters": [],
1761 | "closefind": [],
1762 | "inputs": [],
1763 | "view": [],
1764 | "options": [],
1765 | "closequery": [],
1766 | "end": []
1767 | }
1768 |
1769 | var codeblock = false
1770 | var mode = "javascript"
1771 | query = query_template
1772 | querygroup = "pages-querylines"
1773 | querylineDBDict = {}
1774 | showcommandcomments = false
1775 |
1776 | // =========== FUNCTIONS ================
1777 |
1778 | function initialiseQuery() {
1779 | query = query_template;
1780 | for (key of Object.keys(query)) {
1781 | query[key] = []
1782 | }
1783 | return query;
1784 | }
1785 |
1786 | function initialisteQueryLineDict() {
1787 | var tempDict;
1788 | tempDict = {};
1789 | tempDict["pages-querylines"] = querylineDict["pages-querylines"];
1790 | tempDict["blocks-querylines"] = querylineDict["blocks-querylines"];
1791 |
1792 | for (const [commonqueryline, value] of Object.entries(querylineDict['common-querylines'])) {
1793 | tempDict["pages-querylines"][commonqueryline] = querylineDict["common-querylines"][commonqueryline];
1794 | tempDict["blocks-querylines"][commonqueryline] = querylineDict["common-querylines"][commonqueryline];
1795 | }
1796 | return tempDict;
1797 | }
1798 |
1799 |
1800 |
1801 | function getQueryLineSegment(querylinekey) {
1802 | var errormsg, errortext;
1803 |
1804 | try {
1805 | return ["ok", querylineDBDict[querygroup][querylinekey]["segment"]];
1806 | } catch (e) {
1807 | errortext = querylinekey + " segment value not found in QueryDB\n";
1808 | errormsg = ";; **ERROR: " + errortext + "\n";
1809 | return ["error", errormsg];
1810 | }
1811 | }
1812 |
1813 |
1814 | function getQueryLine(querylinekey, querysegment) {
1815 | var errormsg;
1816 |
1817 | try {
1818 | if (showcommandcomments === true) {
1819 | var comment = getQueryLineComment(querylinekey)
1820 | if (comment != '') {
1821 | if (!query[querysegment].includes('\n' + comment)) {
1822 | query[querysegment].push("\n" + getQueryLineComment(querylinekey));
1823 | }
1824 | }
1825 | }
1826 |
1827 | return querylineDBDict[querygroup][querylinekey]["datalog"];
1828 | } catch (e) {
1829 | errormsg = "\n---- COMMAND ERROR ----\n";
1830 | errormsg += querylinekey + " not found in QueryDB or invalid usage\n";
1831 |
1832 | if (querygroup === "pages-querylines") {
1833 | errormsg += querylinekey + " invalid within a 'pages' command query";
1834 | }
1835 |
1836 | if (querygroup === "blocks-querylines") {
1837 | errormsg += querylinekey + " invalid within a 'blocks' command query";
1838 | }
1839 |
1840 | errormsg += "\n----------------------\n";
1841 | return errormsg;
1842 | }
1843 | }
1844 |
1845 | function getQueryLineComment(querylinekey) {
1846 | var comment, separator;
1847 | separator = ''
1848 | try {
1849 | comment = querylineDBDict[querygroup][querylinekey]["comment"];
1850 | if (comment == '') {
1851 | return ''
1852 | }
1853 | return separator + ";; ---- " + comment;
1854 | } catch (e) {
1855 | return querylinekey + " not found in queryline Dictionary";
1856 | }
1857 | }
1858 |
1859 | function getCommandQueryLineKeys(command) {
1860 | var commandlist;
1861 |
1862 | if (command === null) {
1863 | return null;
1864 | }
1865 |
1866 | try {
1867 | commandlist = commandsDict[command]["querylines"];
1868 | } catch (e) {
1869 | return null;
1870 | }
1871 |
1872 | return commandlist;
1873 | }
1874 |
1875 |
1876 | function processCommand(command, commandLinesDict) {
1877 | var commandline, commandvalidity, negativecommandlines, originalcommandlines, positivecommandlines, queryline, querylinekeys, querysegment, querysegmentdata, querysegmentresponse;
1878 | commandvalidity = checkCommandValid(command);
1879 |
1880 | if (commandvalidity[0] === false) {
1881 | query["errors"].push(commandvalidity[1]);
1882 | return;
1883 | }
1884 |
1885 | querylinekeys = getCommandQueryLineKeys(command);
1886 |
1887 | if (querylinekeys === null) {
1888 | return [command + " is not a valid command"];
1889 | }
1890 |
1891 | for (value of querylinekeys) {
1892 | querysegmentresponse = getQueryLineSegment(value);
1893 |
1894 | querysegmentdata = querysegmentresponse[1];
1895 |
1896 | if (querysegmentresponse[0] === "error") {
1897 | query["errors"].push(querysegmentdata);
1898 | continue;
1899 | }
1900 |
1901 | querysegment = querysegmentdata;
1902 | queryline = getQueryLine(value, querysegment);
1903 |
1904 | if (query[querysegment].includes(queryline)) {
1905 | continue;
1906 | }
1907 |
1908 | query[querysegment].push(queryline);
1909 | }
1910 |
1911 | // sort the argument lines by positive and negative
1912 | positivecommandlines = [];
1913 | negativecommandlines = [];
1914 | originalcommandlines = commandLinesDict[command]["commandlines"].slice(1);
1915 |
1916 |
1917 | for (commandline of originalcommandlines) {
1918 | if (commandline.trim().substring(2).startsWith("not ") || commandline.trim().substring(2).startsWith("and ")) {
1919 | commandline = commandline.replace("and ", "");
1920 | negativecommandlines.push(commandline);
1921 | } else {
1922 | if (commandline.trim().substring(2).startsWith("or ")) {
1923 | commandline = commandline.replace("or ", "");
1924 | positivecommandlines.push(commandline);
1925 | } else {
1926 | positivecommandlines.push(commandline);
1927 | }
1928 | }
1929 | }
1930 |
1931 | if (positivecommandlines.length > 0) {
1932 | processCommandLines("include", command, positivecommandlines);
1933 | }
1934 |
1935 | if (negativecommandlines.length > 0) {
1936 | processCommandLines("exclude", command, negativecommandlines);
1937 | }
1938 |
1939 | return;
1940 | }
1941 |
1942 | function checkCommandValid(command) {
1943 | var commandvalidity, errormessage;
1944 | commandvalidity = true;
1945 | errormessage = "";
1946 |
1947 | if (querygroup === "pages-querylines") {
1948 | if (command === "blocktags") {
1949 | commandvalidity = false;
1950 | errormessage = "\n;; **ERROR: " + command + " not valid with pages command use blocks command instead\n";
1951 | } else {
1952 | if (command === "tasks" || command === "pagelinks") {
1953 | commandvalidity = false;
1954 | errormessage = "\n;; **ERROR: " + command + " not valid with pages command use blocks command instead\n";
1955 | }
1956 | }
1957 | } else {
1958 | if (querygroup === "blocks-querylines") {
1959 | if ([].includes(command)) {
1960 | commandvalidity = false;
1961 | }
1962 | }
1963 | }
1964 |
1965 | return [commandvalidity, errormessage];
1966 | }
1967 |
1968 | function addQueryLines(command, prefix, querylinekey, arg) {
1969 | var arg1, arg2, args, querysegment, querysegmentdata, querysegmentresponse, updatedqueryline;
1970 | querysegment = getQueryLineSegment(querylinekey);
1971 | querysegmentresponse = getQueryLineSegment(querylinekey)[0];
1972 | querysegmentdata = getQueryLineSegment(querylinekey)[1];
1973 |
1974 | if (querysegmentresponse === "error") {
1975 | query["errors"].push(querysegmentdata);
1976 | return;
1977 | }
1978 |
1979 | querysegment = querysegmentdata;
1980 | if (command == 'pagelinks') {
1981 | args = []
1982 | args.push(arg)
1983 | } else {
1984 | args = arg.split(",");
1985 | }
1986 |
1987 | if (args.length === 1) {
1988 | querylinekey = prefix + querylinekey;
1989 | updatedqueryline = getQueryLine(querylinekey, querysegment).replace("$$ARG1", arg);
1990 |
1991 | if (!query[querysegment].includes(updatedqueryline)) {
1992 | query[querysegment].push(updatedqueryline);
1993 | }
1994 | } else {
1995 | if (args.length === 2) {
1996 | arg1 = args[0].trim();
1997 | arg2 = args[1].trim();
1998 | querylinekey = prefix + querylinekey;
1999 | updatedqueryline = getQueryLine(querylinekey, querysegment).replace("$$ARG1", arg1);
2000 | updatedqueryline = updatedqueryline.replace("$$ARG2", arg2);
2001 |
2002 | if (!query[querysegment].includes(updatedqueryline)) {
2003 | query[querysegment].push(updatedqueryline);
2004 | }
2005 | } else {
2006 | query[querysegment].push(command + " => Invalid line => " + arg);
2007 | }
2008 | }
2009 | }
2010 |
2011 | function processCommandLines(action, command, commandlines) {
2012 | var arg, args, firstline, lastline, prefix;
2013 |
2014 | if (commandlines === []) {
2015 | return;
2016 | }
2017 |
2018 | firstline = "";
2019 | lastline = "";
2020 |
2021 | if (["pages", "blocks", "blocktags", "pagetags", "pagelinks", "tasks", "pageproperties", "blockproperties", "namespace"].includes(command)) {
2022 | if (commandlines.length > 1) {
2023 | if (action === "include") {
2024 | firstline = "( or ";
2025 | lastline = ")";
2026 | }
2027 | }
2028 | }
2029 |
2030 | if (firstline !== "") {
2031 | query["filters"].push(firstline);
2032 | }
2033 |
2034 | for (arg of commandlines) {
2035 | arg = arg.trim().substring(2);
2036 |
2037 | if (arg === "") {
2038 | continue;
2039 | }
2040 |
2041 | if (arg === "*") {
2042 | continue;
2043 | }
2044 |
2045 | prefix = "";
2046 |
2047 | if (arg.startsWith("not ")) {
2048 | prefix = "not_";
2049 | arg = arg.substring(prefix.length);
2050 | }
2051 |
2052 | if (command === "pages") {
2053 | if (arg[0] !== "*" && arg[arg.length - 1] === "*") {
2054 | addQueryLines(command, prefix, "arg_pagename_startswith", arg.substring(0, arg.length - 1));
2055 | continue;
2056 | }
2057 |
2058 | if (arg[0] === "*" && arg[arg.length - 1] !== "*") {
2059 | addQueryLines(command, prefix, "arg_pagename_endswith", arg.substring(1));
2060 | continue;
2061 | }
2062 |
2063 | if (arg[0] === "*" && arg[arg.length - 1] === "*") {
2064 | addQueryLines(command, prefix, "arg_pagename_contains", arg.substring(1, arg.length - 1));
2065 | continue;
2066 | }
2067 |
2068 | addQueryLines(command, prefix, "pagename_is", arg);
2069 | }
2070 |
2071 | if (command === "blocks") {
2072 | if (arg[0] !== "*" && arg[arg.length - 1] === "*") {
2073 | addQueryLines(command, prefix, "arg_blockcontent_startswith", arg.substring(0, arg.length - 1));
2074 | continue;
2075 | }
2076 |
2077 | if (arg[0] === "*" && arg[arg.length - 1] !== "*") {
2078 | addQueryLines(command, prefix, "arg_blockcontent_endswith", arg.substring(1));
2079 | continue;
2080 | }
2081 |
2082 | if (arg[0] === "*" && arg[arg.length - 1] === "*") {
2083 | addQueryLines(command, prefix, "arg_blockcontent_contains", arg.substring(1, arg.length - 1));
2084 | continue;
2085 | }
2086 | }
2087 |
2088 | if (command === "pagetags") {
2089 | args = arg.split();
2090 |
2091 | for (arg of args) {
2092 | addQueryLines(command, prefix, "pagetags_are", arg.toLowerCase());
2093 | }
2094 | }
2095 |
2096 | if (command === "blocktags") {
2097 | args = arg.split();
2098 |
2099 | for (arg of args) {
2100 | addQueryLines(command, prefix, "blocktags_are", arg.toLowerCase());
2101 | }
2102 | }
2103 |
2104 | if (command === "pageproperties") {
2105 | addQueryLines(command, prefix, "page_properties_are", arg);
2106 | }
2107 |
2108 | if (command === "blockproperties") {
2109 | addQueryLines(command, prefix, "block_properties_are", arg);
2110 | }
2111 |
2112 | if (command === "pagelinks") {
2113 | args = arg.split();
2114 |
2115 | for (arg of args) {
2116 | addQueryLines(command, prefix, "pagelinks_are", arg.toLowerCase());
2117 | }
2118 | }
2119 | if (command === "tasks") {
2120 | addQueryLines(command, prefix, "tasks_are", arg);
2121 | }
2122 |
2123 | if (command === "namespace") {
2124 | addQueryLines(command, prefix, "namespace", arg);
2125 | }
2126 |
2127 | if (command === "scheduled") {
2128 | addQueryLines(command, prefix, "scheduled", arg);
2129 | }
2130 |
2131 | if (command === "scheduledbetween") {
2132 | addQueryLines(command, prefix, "scheduledbetween", arg);
2133 | }
2134 |
2135 | if (command === "deadline") {
2136 | addQueryLines(command, prefix, "deadline", arg);
2137 | }
2138 |
2139 | if (command === "deadlinebetween") {
2140 | addQueryLines(command, prefix, "deadlinebetween", arg);
2141 | }
2142 |
2143 | if (command === "journalonly") {
2144 | addQueryLines(command, prefix, "page_is_journal", arg);
2145 | }
2146 |
2147 | if (command === "journalsbetween") {
2148 | addQueryLines(command, prefix, "journalsbetween", arg);
2149 | }
2150 |
2151 | if (command === "daterange") {
2152 | addQueryLines(command, prefix, "daterange", arg);
2153 | }
2154 |
2155 | if (command === "collapse") {
2156 | addQueryLines(command, prefix, "collapse", arg);
2157 | }
2158 |
2159 | if (command === "collapse") {
2160 | addQueryLines(command, prefix, "expand", arg);
2161 | }
2162 | }
2163 |
2164 | if (lastline !== "") {
2165 | query["filters"].push(lastline);
2166 | }
2167 |
2168 | return;
2169 | }
2170 |
2171 | function insertQueryLineIntoSegment(key) {
2172 | var querysegment, querysegmentdata, querysegmentresponse;
2173 | querysegmentresponse = getQueryLineSegment(key)[0];
2174 | querysegmentdata = getQueryLineSegment(key)[1];
2175 |
2176 | if (querysegmentresponse === "error") {
2177 | query["errors"].push(querysegmentdata);
2178 | return;
2179 | }
2180 |
2181 | querysegment = querysegmentdata;
2182 | query[key].push(getQueryLine(key, querysegment));
2183 | }
2184 |
2185 | function checkUsingPagesorBlocks(commandlines) {
2186 | var blocksfound, commandline, pagesfound
2187 | pagesfound = false;
2188 | blocksfound = false;
2189 |
2190 | for (commandline of commandlines) {
2191 |
2192 | commandline = commandline.trim();
2193 |
2194 | if (commandline.startsWith("- pages")) {
2195 | pagesfound = true;
2196 | }
2197 |
2198 | if (commandline.startsWith("- blocks")) {
2199 | blocksfound = true;
2200 | }
2201 | }
2202 |
2203 | if (pagesfound === true && blocksfound === false) {
2204 | querygroup = "pages-querylines";
2205 | return;
2206 | }
2207 |
2208 | if (blocksfound === true && pagesfound === false) {
2209 | querygroup = "blocks-querylines";
2210 | return;
2211 | }
2212 |
2213 | if (pagesfound === false && blocksfound === false) {
2214 | query["errors"].push(";; WARNING: Must have 'pages' command or 'blocks' Command\n;; otherwise the query cannot get any information\n;; Inserting a blocks command for you\n");
2215 | insertBlocksCommand(commandlines);
2216 | blocksfound = true;
2217 | querygroup = "blocks-querylines";
2218 | return;
2219 | }
2220 |
2221 | if (pagesfound && blocksfound) {
2222 | query["errors"].push(";; ERROR: Cannot have 'pages' command and 'blocks' command together in a command list\n\n");
2223 | return;
2224 | }
2225 | }
2226 |
2227 | function insertBlocksCommand(commandlines) {
2228 | if (commandlines.length > 0) {
2229 | if (commandlines[0].indexOf("title:") > -1) {
2230 | commandlines.splice(1, 0, " - *");
2231 | commandlines.splice(1, 0, "- blocks");
2232 | }
2233 | } else {
2234 | commandlines.splice(0, 0, "- blocks\n - *\n");
2235 | }
2236 | return;
2237 | }
2238 |
2239 | function validCommand(command) {
2240 | try {
2241 | if (commandsDict[command]) {
2242 | return true;
2243 | } else {
2244 | return false
2245 | }
2246 | } catch (e) {
2247 | return false;
2248 | }
2249 | }
2250 |
2251 | function processCommandList(commandlists) {
2252 | var commandLinesDict, commandlines, commandname, currentcommand, fields, query;
2253 | query = initialiseQuery();
2254 | commandlines = commandlists.split("\n");
2255 | checkUsingPagesorBlocks(commandlines);
2256 | currentcommand = "";
2257 | commandLinesDict = {};
2258 |
2259 | for (line of commandlines) {
2260 |
2261 | if (line === "" || line.startsWith(";;")) {
2262 | continue;
2263 | }
2264 |
2265 | if (line.trim().startsWith("title:")) {
2266 | query["title"].push(getQueryLine("title", "title").replace("$$ARG1", line.split(":")[1].trim()));
2267 | continue;
2268 | }
2269 |
2270 | if (line.trim().startsWith("option:")) {
2271 | var option = line.split(":")[1].trim()
2272 | if (option == "includecomments") {
2273 | setshowcommandcomments(true)
2274 | } else {
2275 | query['errors'].push(
2276 | ";; WARNING: '" + line + "' is not valid option. \n;; Valid options: includecomments")
2277 | }
2278 | continue;
2279 | }
2280 |
2281 | if (line.startsWith("- ")) {
2282 | fields = line.split(" ");
2283 | commandname = fields[1];
2284 |
2285 | if (validCommand(commandname)) {
2286 | commandLinesDict[commandname] = {};
2287 |
2288 | if (currentcommand === "" || line !== currentcommand) {
2289 | currentcommand = commandname;
2290 | commandLinesDict[commandname]["commandlines"] = [];
2291 | commandLinesDict[commandname]["commandlines"].push(line);
2292 | continue;
2293 | }
2294 | } else {
2295 | query["errors"].push(";; WARNING: '" + line + "' is not valid command.\n;; Either a mispelt command or no leading dash");
2296 | // continue;
2297 | }
2298 | } else {
2299 | if (line.startsWith(" ") && line.trim().startsWith("- ")) {
2300 | if (currentcommand === "") {
2301 | query["errors"].push(";; ERROR: '" + line + "' is a command argument but does not have a parent command\n;; Either a command is missing (or invalid) or this should be an argument line");
2302 | } else {
2303 | if (validCommand(commandname)) {
2304 | commandLinesDict[commandname]["commandlines"].push(line);
2305 | } else {
2306 | query["errors"].push(";; ERROR: '" + line + "' is a command argument but does not have a parent command\n;; Either a command is missing (or invalid) or this should be an argument line");
2307 | }
2308 | }
2309 | } else {
2310 | if (line.includes("title ")) {
2311 | query["errors"].push(";; WARNING: title line should start with title:");
2312 | } else {
2313 | if (!line.trim().startsWith("- ") && !(line.indexOf("title:") > -1)) {
2314 | query["errors"].push(";; WARNING: " + line + " has no leading hypen eg '- pages'");
2315 | }
2316 | }
2317 | }
2318 | }
2319 | }
2320 |
2321 | insertQueryLineIntoSegment("start");
2322 | insertQueryLineIntoSegment("open");
2323 | insertQueryLineIntoSegment("where");
2324 | insertQueryLineIntoSegment("closefind");
2325 | insertQueryLineIntoSegment("closequery");
2326 | insertQueryLineIntoSegment("end");
2327 |
2328 | for (command in commandLinesDict) {
2329 | processCommand(command, commandLinesDict);
2330 | }
2331 |
2332 | query["closefind"] = [getQueryLine("closefind", "closefind")];
2333 | query["closequery"] = [getQueryLine("closequery", "closequery")];
2334 | query["end"] = [getQueryLine("end", "end")];
2335 | return;
2336 | }
2337 |
2338 |
2339 | function constructQuery() {
2340 | var advancedquery;
2341 | advancedquery = "";
2342 |
2343 | for (const [key, value] of Object.entries(query)) {
2344 | for (let j = 0; j < query[key].length; j++) {
2345 | queryline = query[key][j]
2346 | advancedquery += queryline + "\n";
2347 | }
2348 | }
2349 | return advancedquery;
2350 | }
2351 |
2352 | function printGeneratedAdvancedQuery(advancedquery) {
2353 | var msg, prefix, suffix;
2354 |
2355 | if (codeblock) {
2356 | prefix = "```clojure\n";
2357 | suffix = "```";
2358 | } else {
2359 | prefix = "";
2360 | suffix = "";
2361 | }
2362 |
2363 | if (mode === "website") {
2364 | // msg = prefix + advancedquery.replace("\n", " ") + suffix;
2365 | msg = prefix + advancedquery + suffix;
2366 | websitePrintToDiv('advanced_query', msg)
2367 | } else {
2368 | console.log("----------------------------");
2369 | console.log("Logseq Advanced Query");
2370 | console.log("----------------------------");
2371 | console.log(prefix + advancedquery + suffix);
2372 | }
2373 | }
2374 |
2375 |
2376 | // global value functions
2377 | function getquerygroup() {
2378 | return querygroup
2379 | }
2380 |
2381 | function setquerygroup(value) {
2382 | querygroup = value
2383 | }
2384 |
2385 | function getshowcommandcomments() {
2386 | return showcommandcomments
2387 | }
2388 |
2389 | function setshowcommandcomments(value) {
2390 | showcommandcomments = value
2391 | }
2392 |
2393 | function getcodeblock() {
2394 | return codeblock
2395 | }
2396 |
2397 | function setcodeblock(value) {
2398 | codeblock = value
2399 | }
2400 |
2401 | function getquerylineDBDict() {
2402 | return querylineDBDict
2403 | }
2404 |
2405 | function setquerylineDBDict(value) {
2406 | querylineDBDict = value
2407 | }
2408 |
2409 | // Test queryTestDB works
2410 | function test_queryTestDBRead() {
2411 | testcases = QueryTestCases
2412 | return testcases[0];
2413 | }
2414 |
2415 | function getquerytestcases() {
2416 | return QueryTestCases
2417 | }
2418 |
2419 | function removeLastGeneratedQuery(content) {
2420 | let lines = content.split("\n")
2421 | let newcontent = ''
2422 | for (const line of lines) {
2423 | if (line.startsWith('#+BEGIN_QUERY')) {
2424 | break
2425 | }
2426 | newcontent += line + '\n'
2427 | }
2428 | return newcontent
2429 | }
2430 |
2431 | function showErrors() {
2432 | msg = 'QB: Errors Found - check built query'
2433 | if (query["errors"].length > 0) {
2434 | for (errormsg of query["errors"]) {
2435 | msg += errormsg + '\n'
2436 | }
2437 | return msg
2438 | } else {
2439 | return "QB: Query Built OK"
2440 | }
2441 | }
2442 |
2443 |
2444 | function main() {
2445 |
2446 | logseq.Editor.registerBlockContextMenuItem(
2447 | 'Advanced Query Builder',
2448 | async (e) => {
2449 | const block = await logseq.Editor.getBlock(e.uuid)
2450 | content = block.content
2451 | content = removeLastGeneratedQuery(content)
2452 | commands = content.replaceAll(/```/g, '')
2453 | showcommandcomments = false;
2454 | querygroup = "blocks-querylines";
2455 | codeblock = false;
2456 | // query = initialiseQuery();
2457 | // querylineDBDict = initialisteQueryLineDict();
2458 | // querygroup = "pages-querylines"
2459 | // logseq.App.showMsg(
2460 | // commands,
2461 | // )
2462 | setquerylineDBDict(initialisteQueryLineDict())
2463 | console.log("\ncommands\n" + commands);
2464 | console.log("\ncontent\n" + content);
2465 | initialiseQuery()
2466 | processCommandList(commands)
2467 | advancedquery = constructQuery()
2468 |
2469 | // Currently will add a child block with the generated query
2470 | // user can right click on the query and remove it or leave it there
2471 | // IDEA: Maybe always remove the last query so how do I do that
2472 | // remove any children blocks
2473 | // TODO: Returns undefined for the child uuid????? Mayne just let user insert a new child for each query execution
2474 | // if (block.children.length > 0) {
2475 | // for (let child of block.children) {
2476 | // await logseq.Editor.removeBlock(child.uuid);
2477 | // }
2478 | // }
2479 |
2480 |
2481 | // place the advanced query in a child of the current block (that has the commands in it)
2482 | await logseq.Editor.insertBlock(e.uuid, advancedquery, { sibling: false })
2483 |
2484 | logseq.App.showMsg(
2485 | showErrors()
2486 | )
2487 | })
2488 |
2489 | } // end main
2490 |
2491 | // ======== website functions
2492 |
2493 | function websiteInitialise() {
2494 |
2495 | if (mode != "website") {
2496 | return
2497 | }
2498 |
2499 | // connect the generate advanced query button
2500 | generate_query_button = document.getElementById('generate_query_button')
2501 | generate_query_button.addEventListener("click", websiteQueryBuild)
2502 |
2503 | // connect the Clear Commands button
2504 | clear_commands_button = document.getElementById('clear_commands_button')
2505 | clear_commands_button.addEventListener("click", websiteClearCommands)
2506 |
2507 | // connect the Examples button
2508 | examples_options = document.getElementById('command_examples')
2509 | examples_options.addEventListener("input", websiteChooseExample)
2510 | examples_options.value = "" // set to first option
2511 |
2512 | // connect the Command Comments Checkbox
2513 | command_comments_checkbox = document.getElementById(
2514 | 'command_comments_checkbox')
2515 | command_comments_checkbox.addEventListener("click", websiteCommandComments)
2516 | command_comments_checkbox.checked = false
2517 |
2518 | commands_input = document.getElementById('commands_input')
2519 | commands_input.value = ''
2520 |
2521 | // connect the Code Block Output Checkbox
2522 | codeblock_checkbox = document.getElementById(
2523 | 'codeblock_checkbox')
2524 | codeblock_checkbox.addEventListener("click", websiteCodeBlock)
2525 | codeblock_checkbox.checked = false
2526 |
2527 | }
2528 |
2529 | function websiteClearCommands(event) {
2530 | if (mode != "website") {
2531 | return
2532 | }
2533 |
2534 | // # hide copy to clipboard button
2535 | websitePrintToDiv('print_output', 'Clear Commands Button Pressed')
2536 | commands_input = document.getElementById('commands_input')
2537 | commands_input.value = ''
2538 | }
2539 |
2540 |
2541 | function websiteCommandComments(event) {
2542 | if (mode != "website") {
2543 | return
2544 | }
2545 | if (document.getElementById('command_comments_checkbox').checked == true) {
2546 | setshowcommandcomments(true)
2547 | } else {
2548 | setshowcommandcomments(false)
2549 | }
2550 | }
2551 |
2552 |
2553 | function websiteCodeBlock(event) {
2554 | // TODO: Check this works re global codeblock variable
2555 | if (mode != "website") {
2556 | return
2557 | }
2558 | if (document.getElementById('codeblock_checkbox').checked == true) {
2559 | codeblock = true
2560 | } else {
2561 | codeblock = false
2562 | }
2563 | }
2564 |
2565 |
2566 | function websiteChooseExample(event) {
2567 | if (mode != "website") {
2568 | return
2569 | }
2570 | // get selected Example and fill the commands Input Text Area
2571 | examples_options = document.getElementById('command_examples')
2572 | if (examples_options.value != "Choose Example..") {
2573 | advanced_query_text = document.getElementById('advanced_query')
2574 | advanced_query_text.textContent = ''
2575 | websitePrintToDiv('print_output',
2576 | "Example selected .. now press 'Generate Advanced Query' button")
2577 |
2578 | document.getElementById(
2579 | 'commands_input').value = examples_options.value
2580 | // console.log('value is ', examples_options.value)
2581 | }
2582 | }
2583 |
2584 | function websiteAdvancedQueryText(event) {
2585 | if (mode != "website") {
2586 | return
2587 | }
2588 | }
2589 |
2590 | function websitePrintToDiv(divname, text) {
2591 | if (mode != "website") {
2592 | return
2593 | }
2594 | document.getElementById(divname).innerText = text
2595 | }
2596 |
2597 |
2598 | function websiteQueryBuild(event) {
2599 | if (mode != "website") {
2600 | return
2601 | }
2602 |
2603 | // # hide copy to clipboard button
2604 | copy_button = document.getElementById('copy')
2605 | copy_button.setAttribute("hidden", "hidden")
2606 |
2607 | websitePrintToDiv('print_output', 'Processing Commands ..')
2608 |
2609 | commands_input = document.getElementById('commands_input')
2610 | if (!commands_input) {
2611 | websitePrintToDiv('print_output', 'Bug: Element is None')
2612 | return
2613 | }
2614 | processCommandList(commands_input.value)
2615 | advancedquery = constructQuery()
2616 | printGeneratedAdvancedQuery(advancedquery)
2617 |
2618 | // show copy to clipboard button
2619 | var copy_button = document.getElementById('copy')
2620 | hidden = copy_button.getAttribute("hidden")
2621 | copy_button.removeAttribute("hidden")
2622 |
2623 | websitePrintToDiv('print_output',
2624 | "Advanced Query Generated!\n- Tick 'Include Query Comments' if desired\n- Tick 'Copy as code block' if desired\nClick 'Copy Query to Clipboard")
2625 |
2626 | return
2627 | }
2628 |
2629 |
2630 |
2631 | // MAIN ENTRY POINT
2632 |
2633 | // *******************************
2634 | // LOCAL MODE TESTING WITH JEST TESTING
2635 | // (Comment out WEBSITE MODE section below and PLUGIN MODE section above)
2636 | // (Uncomment this section for local testing with JEST)
2637 | // *******************************
2638 | // // var mode = "local"
2639 | // module.exports = {
2640 | // //querygroup,
2641 | // //showcommandcomments,
2642 | // getquerygroup,
2643 | // setquerygroup,
2644 | // getshowcommandcomments,
2645 | // setshowcommandcomments,
2646 | // getcodeblock,
2647 | // setcodeblock,
2648 | // getquerylineDBDict,
2649 | // setquerylineDBDict,
2650 | // getquerytestcases,
2651 | // add,
2652 | // test_queryDBRead,
2653 | // test_queryTestDBRead,
2654 | // addQueryLines,
2655 | // checkCommandValid,
2656 | // checkUsingPagesorBlocks,
2657 | // constructQuery,
2658 | // getCommandQueryLineKeys,
2659 | // getQueryLine,
2660 | // getQueryLineComment,
2661 | // getQueryLineSegment,
2662 | // initialiseQuery,
2663 | // initialisteQueryLineDict,
2664 | // insertBlocksCommand,
2665 | // insertQueryLineIntoSegment,
2666 | // printGeneratedAdvancedQuery,
2667 | // processCommand,
2668 | // processCommandLines,
2669 | // processCommandList,
2670 | // removeLastGeneratedQuery,
2671 | // validCommand
2672 | // }
2673 | // *******************************
2674 |
2675 | // *******************************
2676 | // LOGSEQ WEBSITE MODE
2677 | // (Comment out LOCAL MODE section above and PLUGIN mode section below and uncomment this section)
2678 | // *******************************
2679 | mode = "website"
2680 | // *******************************
2681 |
2682 |
2683 | // *******************************
2684 | // LOGSEQ PLUGIN MODE
2685 | // (Comment out LOCAL MODE section above and WEBSITE section above and uncomment this section)
2686 | // *******************************
2687 | // mode = "logseq-plugin"
2688 | // *******************************
2689 |
2690 | // MAIN STARTING POINT
2691 | if (mode == "logseq-plugin") {
2692 | console.log('logseq-advanced-query-builder plugin loaded')
2693 | logseq.ready(main).catch(console.error)
2694 | }
2695 | if (mode == "local") {
2696 | console.log('logseq-advanced-query-builder code running locally')
2697 | querygroup = "";
2698 | codeblock = false;
2699 | query = initialiseQuery();
2700 | querylineDBDict = initialisteQueryLineDict();
2701 | }
2702 | if (mode == "website") {
2703 | console.log('logseq-advanced-query-builder code running in browser')
2704 | querygroup = "";
2705 | codeblock = false;
2706 | query = initialiseQuery();
2707 | querylineDBDict = initialisteQueryLineDict();
2708 | websiteInitialise()
2709 | }
2710 |
2711 |
2712 |
--------------------------------------------------------------------------------