sensemaking 0.13.0 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sensemaking",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.1",
|
|
4
4
|
"description": "Query and search your markdown notes with context-aware progressive disclosure: SQL over frontmatter, links, and text, plus semantic search and link-graph ranking. No server, no build step",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"markdown",
|
|
@@ -35,8 +35,8 @@ SELECT basename(f.path, '.md') AS name, f.year, f.scoreImdb, f.runtime, f.direct
|
|
|
35
35
|
FROM frontmatter f
|
|
36
36
|
WHERE EXISTS (SELECT 1 FROM json_each(f.categories) WHERE value = '[[Movies]]')
|
|
37
37
|
AND instr(basename(f.path), 'Template') = 0
|
|
38
|
-
AND (f.last IS NULL OR f.last
|
|
39
|
-
AND (f.rating IS NULL OR f.rating
|
|
38
|
+
AND (f.last IS NULL OR f.last IN ('', '[]', '[null]'))
|
|
39
|
+
AND (f.rating IS NULL OR f.rating IN ('', '[]', '[null]'))
|
|
40
40
|
ORDER BY f.scoreImdb DESC, name ASC
|
|
41
41
|
```
|
|
42
42
|
|
|
@@ -47,22 +47,27 @@ times have this shape; creation times share it.
|
|
|
47
47
|
| `==` `!=` `>` `<` `>=` `<=` | same |
|
|
48
48
|
| `&&` `\|\|` `!` | `AND` `OR` `NOT` |
|
|
49
49
|
| `and:` / `or:` / `not:` filter blocks | parenthesized `AND` / `OR` / `NOT` |
|
|
50
|
-
| `field.isEmpty()` | `(f.field IS NULL OR f.field
|
|
50
|
+
| `field.isEmpty()` | `(f.field IS NULL OR f.field IN ('', '[]', '[null]'))` |
|
|
51
51
|
| `file.hasTag("book")` | `EXISTS (SELECT 1 FROM tags WHERE tags.path = f.path AND (tag = 'book' OR tag LIKE 'book/%'))` |
|
|
52
52
|
| `file.hasLink("Note")` | `EXISTS (SELECT 1 FROM links WHERE src = f.path AND dst = 'Note.md')` |
|
|
53
53
|
| `list.contains(x)` | `EXISTS (SELECT 1 FROM json_each(f.list) WHERE value = x)` |
|
|
54
54
|
| `string.contains(x)` | `instr(f.string, x) > 0` |
|
|
55
55
|
| `list.containsAny(...)` | the `json_each` EXISTS with `value IN (...)` |
|
|
56
56
|
| `/regex/.matches(x)` | no SQLite regex; `LIKE`/`GLOB` cover anchored and wildcard shapes |
|
|
57
|
+
| `value.isType("object")` | `json_each`'s own `type` column: `... FROM json_each(f.field) j WHERE j.type = 'object'` |
|
|
57
58
|
|
|
58
59
|
A field no note in the tree declares has no column at all, so a filter naming it errors with
|
|
59
60
|
`no such column` instead of treating every row as empty. Obsidian's evaluator returns empty
|
|
60
61
|
for unknown properties; SQL does not. Dropping the clause states the same thing the error
|
|
61
62
|
did, and `SELECT name FROM pragma_table_info('frontmatter')` lists what exists.
|
|
62
63
|
|
|
63
|
-
`isEmpty()`
|
|
64
|
-
|
|
65
|
-
`isEmpty()` is true for
|
|
64
|
+
`isEmpty()` has four true cases because empty is stored three ways: NULL (key absent), `''`
|
|
65
|
+
(empty string value), `'[]'` (a list written `[]`), and `'[null]'` (a list key above a bare
|
|
66
|
+
`-`). Obsidian's `isEmpty()` is true for all of them; `IS NULL` alone finds only the first.
|
|
67
|
+
The IN list is the whole test -- `json_array_length()` is not: it reads `'[null]'` as length
|
|
68
|
+
1 and throws on plain strings. The same trap inside a list: `json_each` hands a string member
|
|
69
|
+
to `value` as plain text, so `json_type(value)` throws `malformed JSON` on it; the scan's own
|
|
70
|
+
`type` column is the discriminator.
|
|
66
71
|
|
|
67
72
|
`contains(link("Movies"))` compares against a link value. In frontmatter, a list of links
|
|
68
73
|
holds the written text, so the `json_each` comparison value is the literal `[[Movies]]`.
|
|
@@ -94,6 +99,12 @@ Formulas are SELECT expressions. The Bases functions map onto SQLite's:
|
|
|
94
99
|
Bases durations are typed; SQL date arithmetic is julianday day-fractions. A formula chaining
|
|
95
100
|
duration fields (`.days.round()`) flattens to arithmetic on the julianday difference.
|
|
96
101
|
|
|
102
|
+
A formula referencing another formula becomes a CTE layer: SQL cannot read a SELECT alias in
|
|
103
|
+
the same SELECT list, so each dependency level computes its formulas as columns and the next
|
|
104
|
+
level reads them (`WITH t AS (SELECT ..., <level-1 formulas> FROM frontmatter) SELECT ...,
|
|
105
|
+
<level-2 formulas> FROM t`). A five-formula chain is however many *levels* it has, not five
|
|
106
|
+
CTEs -- formulas that only read base columns share one layer.
|
|
107
|
+
|
|
97
108
|
## Views
|
|
98
109
|
|
|
99
110
|
- `sort:` (multi-key, each with direction) -> `ORDER BY a DESC, b ASC`. `limit:` -> `LIMIT`.
|