dirsql 0.3.76 → 0.3.78

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.
@@ -112,30 +112,30 @@ through `jq` to pretty-print. Now select some columns:
112
112
  ```bash
113
113
  curl -s http://localhost:7117/query \
114
114
  -H 'content-type: application/json' \
115
- -d '{"sql":"SELECT _path, _size FROM files ORDER BY _path"}' \
115
+ -d '{"sql":"SELECT path, size FROM files ORDER BY path"}' \
116
116
  | jq
117
117
  ```
118
118
 
119
119
  ```json
120
120
  [
121
121
  {
122
- "_path": "notes/alice/ideas.md",
123
- "_size": 52
122
+ "path": "notes/alice/ideas.md",
123
+ "size": 52
124
124
  },
125
125
  {
126
- "_path": "notes/alice/welcome.md",
127
- "_size": 66
126
+ "path": "notes/alice/welcome.md",
127
+ "size": 66
128
128
  },
129
129
  {
130
- "_path": "notes/bob/reading-list.md",
131
- "_size": 41
130
+ "path": "notes/bob/reading-list.md",
131
+ "size": 41
132
132
  }
133
133
  ]
134
134
  ```
135
135
 
136
- `_path` and `_size` are two of the built-in file columns `dirsql` collects
137
- for every file — see [virtual columns](./reference/columns.md#virtual-columns)
138
- for the full list. (The `_size` values are byte counts; they match the
136
+ `path` and `size` are two of the built-in file columns `dirsql` collects
137
+ for every file — see [stat columns](./reference/columns.md#stat-columns)
138
+ for the full list. (The `size` values are byte counts; they match the
139
139
  output above because you pasted the files exactly.)
140
140
 
141
141
  You have a working SQL database over your files. Next, teach it the
@@ -152,7 +152,7 @@ In your second terminal, still inside `my-notes`, create a `.dirsql.toml`:
152
152
  ```bash
153
153
  cat > .dirsql.toml <<'EOF'
154
154
  [[table]]
155
- ddl = "CREATE TABLE notes (author TEXT, _basename TEXT, _size INTEGER)"
155
+ ddl = "CREATE TABLE notes (author TEXT, basename TEXT, size INTEGER)"
156
156
  glob = "notes/{author}/*.md"
157
157
  EOF
158
158
  ```
@@ -192,25 +192,25 @@ terminal:
192
192
  ```bash
193
193
  curl -s http://localhost:7117/query \
194
194
  -H 'content-type: application/json' \
195
- -d '{"sql":"SELECT author, _basename, _size FROM notes ORDER BY author, _basename"}' \
195
+ -d '{"sql":"SELECT author, basename, size FROM notes ORDER BY author, basename"}' \
196
196
  | jq
197
197
  ```
198
198
 
199
199
  ```json
200
200
  [
201
201
  {
202
- "_basename": "ideas.md",
203
- "_size": 52,
202
+ "basename": "ideas.md",
203
+ "size": 52,
204
204
  "author": "alice"
205
205
  },
206
206
  {
207
- "_basename": "welcome.md",
208
- "_size": 66,
207
+ "basename": "welcome.md",
208
+ "size": 66,
209
209
  "author": "alice"
210
210
  },
211
211
  {
212
- "_basename": "reading-list.md",
213
- "_size": 41,
212
+ "basename": "reading-list.md",
213
+ "size": 41,
214
214
  "author": "bob"
215
215
  }
216
216
  ]
@@ -18,7 +18,7 @@ Capture both directory levels in `.dirsql.toml`:
18
18
 
19
19
  ```toml
20
20
  [[table]]
21
- ddl = "CREATE TABLE photos (year TEXT, month TEXT, _basename TEXT)"
21
+ ddl = "CREATE TABLE photos (year TEXT, month TEXT, basename TEXT)"
22
22
  glob = "photos/{year}/{month}/*.jpg"
23
23
  ```
24
24
 
@@ -29,24 +29,18 @@ within one path segment) are in
29
29
 
30
30
  ## 2. Query the captured columns
31
31
 
32
- Start the server (`npx dirsql` / `uvx dirsql`) and query:
33
-
34
32
  ```bash
35
- curl -s http://localhost:7117/query \
36
- -H 'content-type: application/json' \
37
- -d '{"sql":"SELECT year, month, _basename FROM photos ORDER BY year, month"}'
33
+ dirsql query "SELECT year, month, basename FROM photos ORDER BY year, month"
38
34
  ```
39
35
 
40
36
  ```json
41
- [{"_basename":"beach.jpg","month":"05","year":"2024"},{"_basename":"hike.jpg","month":"11","year":"2024"},{"_basename":"snow.jpg","month":"01","year":"2025"}]
37
+ [{"basename":"beach.jpg","month":"05","year":"2024"},{"basename":"hike.jpg","month":"11","year":"2024"},{"basename":"snow.jpg","month":"01","year":"2025"}]
42
38
  ```
43
39
 
44
40
  Captures are real SQL columns, so aggregation works:
45
41
 
46
42
  ```bash
47
- curl -s http://localhost:7117/query \
48
- -H 'content-type: application/json' \
49
- -d '{"sql":"SELECT year, COUNT(*) AS photos FROM photos GROUP BY year"}'
43
+ dirsql query "SELECT year, COUNT(*) AS photos FROM photos GROUP BY year"
50
44
  ```
51
45
 
52
46
  ```json
@@ -55,8 +49,8 @@ curl -s http://localhost:7117/query \
55
49
 
56
50
  ## Going further
57
51
 
58
- - Captures combine freely with [virtual columns](../reference/columns.md#virtual-columns)
59
- (`_basename` above) — both are filesystem facts merged onto every row.
52
+ - Captures combine freely with [stat columns](../reference/columns.md#stat-columns)
53
+ (`basename` above) — both are filesystem facts merged onto every row.
60
54
  - The [tutorial](../getting-started.md) walks the same idea with an
61
55
  `{author}` capture, starting from zero.
62
56
  - When the value you need lives inside the file rather than in its path,
@@ -13,41 +13,27 @@ directory you want to index, create a `.dirsql.toml` with one
13
13
 
14
14
  ```toml
15
15
  [[table]]
16
- ddl = "CREATE TABLE posts (_path TEXT, _size INTEGER, _mtime INTEGER)"
16
+ ddl = "CREATE TABLE posts (path TEXT, size INTEGER, mtime INTEGER)"
17
17
  glob = "posts/**/*.md"
18
18
  ```
19
19
 
20
20
  - `glob` selects the files: every `.md` under `posts/`, at any depth,
21
21
  relative to the directory containing the config.
22
22
  - `ddl` is a plain SQLite `CREATE TABLE` naming the columns you want. Here
23
- all three are [virtual columns](../reference/columns.md#virtual-columns) —
23
+ all three are [stat columns](../reference/columns.md#stat-columns) —
24
24
  filesystem facts `dirsql` computes for every file. Facts are opt-in by
25
25
  DDL: only the ones you declare become columns.
26
26
 
27
- ## 2. Start the server and query
28
-
29
- ::: code-group
30
-
31
- ```bash [npm]
32
- npx dirsql
33
- ```
34
-
35
- ```bash [PyPI]
36
- uvx dirsql
37
- ```
38
-
39
- :::
27
+ ## 2. Query the table
40
28
 
41
29
  Each matched file is one row:
42
30
 
43
31
  ```bash
44
- curl -s http://localhost:7117/query \
45
- -H 'content-type: application/json' \
46
- -d '{"sql":"SELECT _path, _size FROM posts ORDER BY _path"}'
32
+ dirsql query "SELECT path, size FROM posts ORDER BY path"
47
33
  ```
48
34
 
49
35
  ```json
50
- [{"_path":"posts/2024/hello.md","_size":21},{"_path":"posts/2025/again.md","_size":55}]
36
+ [{"path":"posts/2024/hello.md","size":21},{"path":"posts/2025/again.md","size":55}]
51
37
  ```
52
38
 
53
39
  Files that don't match the glob (a `README.txt` next to `posts/`, say) are
@@ -35,7 +35,7 @@ comments/t2/c1.json # {"body": "following up", "author": "alice"}
35
35
 
36
36
  Unlike a config-file table, a programmatic table takes an `extract`
37
37
  callback — your code reads each matched file and returns its rows, with
38
- [glob captures and virtual columns](../reference/columns.md) merged on
38
+ [glob captures and stat columns](../reference/columns.md) merged on
39
39
  automatically (here, `{thread}` from the path):
40
40
 
41
41
  ::: code-group
@@ -18,7 +18,7 @@ stdout works. With [`jq`](https://jqlang.org/):
18
18
 
19
19
  ```toml
20
20
  [[table]]
21
- ddl = "CREATE TABLE books (title TEXT, author TEXT, year INTEGER, _path TEXT)"
21
+ ddl = "CREATE TABLE books (title TEXT, author TEXT, year INTEGER, path TEXT)"
22
22
  glob = "books/*.json"
23
23
  on-file = "jq -c '[{title, author, year}]' {path}"
24
24
  ```
@@ -31,19 +31,15 @@ by every hook.
31
31
 
32
32
  ## 2. Query the extracted columns
33
33
 
34
- Start the server (`npx dirsql` / `uvx dirsql`) and query:
35
-
36
34
  ```bash
37
- curl -s http://localhost:7117/query \
38
- -H 'content-type: application/json' \
39
- -d '{"sql":"SELECT title, author, year, _path FROM books ORDER BY year"}'
35
+ dirsql query "SELECT title, author, year, path FROM books ORDER BY year"
40
36
  ```
41
37
 
42
38
  ```json
43
- [{"_path":"books/bleak-house.json","author":"Charles Dickens","title":"Bleak House","year":1852},{"_path":"books/middlemarch.json","author":"George Eliot","title":"Middlemarch","year":1871}]
39
+ [{"path":"books/bleak-house.json","author":"Charles Dickens","title":"Bleak House","year":1852},{"path":"books/middlemarch.json","author":"George Eliot","title":"Middlemarch","year":1871}]
44
40
  ```
45
41
 
46
- Filesystem facts are still merged onto every row — `_path` above comes from
42
+ Filesystem facts are still merged onto every row — `path` above comes from
47
43
  `dirsql`, not from `jq`. When the command emits a key that collides with a
48
44
  fact, the command wins
49
45
  ([precedence](../reference/columns.md#precedence)).
@@ -55,15 +51,13 @@ row per line, slurp it:
55
51
 
56
52
  ```toml
57
53
  [[table]]
58
- ddl = "CREATE TABLE events (event TEXT, user TEXT, _path TEXT)"
54
+ ddl = "CREATE TABLE events (event TEXT, user TEXT, path TEXT)"
59
55
  glob = "logs/*.jsonl"
60
56
  on-file = "jq -c -s '.' {path}"
61
57
  ```
62
58
 
63
59
  ```bash
64
- curl -s http://localhost:7117/query \
65
- -H 'content-type: application/json' \
66
- -d '{"sql":"SELECT event, user FROM events"}'
60
+ dirsql query "SELECT event, user FROM events"
67
61
  ```
68
62
 
69
63
  ```json
@@ -23,13 +23,10 @@ overrides the init symbol when it doesn't match the filename-derived
23
23
  default — `sqlite-vec` is exactly such a case
24
24
  ([reference](../reference/config.md#dirsql-extension)).
25
25
 
26
- Start the server (`npx dirsql` / `uvx dirsql`) and the extension's
27
- functions are callable:
26
+ The extension's functions are callable:
28
27
 
29
28
  ```bash
30
- curl -s http://localhost:7117/query \
31
- -H 'content-type: application/json' \
32
- -d '{"sql":"SELECT vec_version() AS vec_version"}'
29
+ dirsql query "SELECT vec_version() AS vec_version"
33
30
  ```
34
31
 
35
32
  ```json
@@ -33,7 +33,7 @@ The stream delivers the resulting row change:
33
33
 
34
34
  ```
35
35
  event: row
36
- data: {"action":"insert","file_path":"inbox/two.txt","old_row":null,"row":{"_basename":"two.txt","_ctime":1783170226,"_dir":"inbox","_ext":"txt","_mtime":1783170226,"_path":"inbox/two.txt","_size":7},"table":"files"}
36
+ data: {"action":"insert","file_path":"inbox/two.txt","old_row":null,"row":{"basename":"two.txt","ctime":1783170226,"dir":"inbox","ext":"txt","mtime":1783170226,"path":"inbox/two.txt","size":7},"table":"files"}
37
37
  ```
38
38
 
39
39
  Edits arrive as `update` events carrying both the old and new row;
@@ -66,7 +66,7 @@ model = StaticModel.from_pretrained("minishlab/potion-base-8M")
66
66
  vector = model.encode([body["q"]])[0]
67
67
  needle = json.dumps([round(float(x), 6) for x in vector])
68
68
  print(
69
- "SELECT _path, ROUND(vec_distance_cosine(embedding, '%s'), 3) AS distance "
69
+ "SELECT path, ROUND(vec_distance_cosine(embedding, '%s'), 3) AS distance "
70
70
  "FROM notes ORDER BY distance LIMIT 3" % needle
71
71
  )
72
72
  ```
@@ -89,7 +89,7 @@ path = "sqlite_vec" # Python module name; see note below
89
89
  entrypoint = "sqlite3_vec_init"
90
90
 
91
91
  [[table]]
92
- ddl = "CREATE TABLE notes (_path TEXT, text TEXT, embedding TEXT)"
92
+ ddl = "CREATE TABLE notes (path TEXT, text TEXT, embedding TEXT)"
93
93
  glob = "notes/*.md"
94
94
  on-file = "uv run --with model2vec python embed.py {path}"
95
95
  ```
@@ -99,43 +99,35 @@ installed `sqlite_vec` module to its bundled loadable. Naming rules per
99
99
  runtime — and the literal-path alternative that works everywhere — are in
100
100
  [Load a SQLite extension](./load-extension.md).
101
101
 
102
- ## 3. Start the server and ask questions
102
+ ## 3. Ask questions
103
103
 
104
- Launch with `sqlite-vec` available to the launcher's environment:
104
+ Run with `sqlite-vec` available to the launcher's environment. The initial
105
+ scan runs `embed.py` once per note, then the query argument goes straight to
106
+ `pre-query`, exactly as a `POST /query` body would:
105
107
 
106
108
  ```bash
107
- uvx --with sqlite-vec dirsql
108
- ```
109
-
110
- The initial scan runs `embed.py` once per note. Then ask:
111
-
112
- ```bash
113
- curl -s http://localhost:7117/query \
114
- -H 'content-type: application/json' \
115
- -d '{"q": "how do I cook pasta?"}'
109
+ uvx --with sqlite-vec dirsql query '{"q": "how do I cook pasta?"}'
116
110
  ```
117
111
 
118
112
  ```json
119
- [{"_path":"notes/pasta.md","distance":0.315},{"_path":"notes/tomatoes.md","distance":0.881},{"_path":"notes/branches.md","distance":0.92}]
113
+ [{"path":"notes/pasta.md","distance":0.315},{"path":"notes/tomatoes.md","distance":0.881},{"path":"notes/branches.md","distance":0.92}]
120
114
  ```
121
115
 
122
116
  ```bash
123
- curl -s http://localhost:7117/query \
124
- -H 'content-type: application/json' \
125
- -d '{"q": "reviewing code on github"}'
117
+ uvx --with sqlite-vec dirsql query '{"q": "reviewing code on github"}'
126
118
  ```
127
119
 
128
120
  ```json
129
- [{"_path":"notes/branches.md","distance":0.51},{"_path":"notes/pasta.md","distance":1.033},{"_path":"notes/tomatoes.md","distance":1.074}]
121
+ [{"path":"notes/branches.md","distance":0.51},{"path":"notes/pasta.md","distance":1.033},{"path":"notes/tomatoes.md","distance":1.074}]
130
122
  ```
131
123
 
132
124
  Neither question shares a keyword with its top note — "cook" appears
133
125
  nowhere in `pasta.md`, "github" nowhere in `branches.md`. The distance
134
126
  ranking is doing the work.
135
127
 
136
- Because `pre-query` is set, the request body is *not* the usual
137
- `{"sql": …}` — the raw body goes to your script, which decides what SQL
138
- runs ([hook interactions](../reference/http-api.md#hook-interactions)).
128
+ Because `pre-query` is set, the query argument is *not* the usual
129
+ `{"sql": …}` — it goes to your script as-is, which decides what SQL runs
130
+ ([hook interactions](../reference/http-api.md#hook-interactions)).
139
131
 
140
132
  ## Recomputing vs. caching
141
133
 
@@ -22,7 +22,7 @@ Exclude the noise in `.dirsql.toml`:
22
22
  ignore = ["notes/drafts/**", "**/*.tmp"]
23
23
 
24
24
  [[table]]
25
- ddl = "CREATE TABLE notes (_path TEXT)"
25
+ ddl = "CREATE TABLE notes (path TEXT)"
26
26
  glob = "notes/**/*"
27
27
  ```
28
28
 
@@ -31,16 +31,12 @@ ignored file never reaches any table — even one whose glob would match it.
31
31
 
32
32
  ## 2. Confirm what made it in
33
33
 
34
- Start the server (`npx dirsql` / `uvx dirsql`) and check:
35
-
36
34
  ```bash
37
- curl -s http://localhost:7117/query \
38
- -H 'content-type: application/json' \
39
- -d '{"sql":"SELECT _path FROM notes ORDER BY _path"}'
35
+ dirsql query "SELECT path FROM notes ORDER BY path"
40
36
  ```
41
37
 
42
38
  ```json
43
- [{"_path":"notes/final.md"}]
39
+ [{"path":"notes/final.md"}]
44
40
  ```
45
41
 
46
42
  ## Notes
@@ -68,12 +68,12 @@ default `./.dirsql.toml`) with a single table named `files`:
68
68
 
69
69
  - Glob: `**/*` — every file under the root, at any depth, no ignores.
70
70
  - One row per file, with all seven
71
- [virtual columns](./columns.md): `_path`, `_basename`, `_dir`, `_ext`,
72
- `_size`, `_mtime`, `_ctime`.
71
+ [stat columns](./columns.md): `path`, `basename`, `dir`, `ext`,
72
+ `size`, `mtime`, `ctime`.
73
73
 
74
74
  ```bash
75
75
  curl -s localhost:7117/query -H 'content-type: application/json' \
76
- -d '{"sql":"SELECT _basename, _size FROM files ORDER BY _size DESC LIMIT 5"}'
76
+ -d '{"sql":"SELECT basename, size FROM files ORDER BY size DESC LIMIT 5"}'
77
77
  ```
78
78
 
79
79
  A config file, when present, fully overrules this default. A *missing*
@@ -104,8 +104,8 @@ Run one SQL query from the shell — for ad-hoc inspection, scripting, and
104
104
  docs verification snippets — without booting the server and `curl`ing it:
105
105
 
106
106
  ```bash
107
- dirsql query "SELECT _basename, _size FROM files ORDER BY _size DESC LIMIT 5"
108
- # [{"_basename":"model.bin","_size":104857600}, …]
107
+ dirsql query "SELECT basename, size FROM files ORDER BY size DESC LIMIT 5"
108
+ # [{"basename":"model.bin","size":104857600}, …]
109
109
 
110
110
  dirsql query "SELECT COUNT(*) AS n FROM posts" | jq '.[0].n'
111
111
  ```
@@ -1,36 +1,48 @@
1
- # Virtual columns and glob captures
1
+ # Stat columns and glob captures
2
2
 
3
3
  Every table — config-defined or programmatic — gets filesystem facts merged
4
- onto its rows automatically: seven reserved **virtual columns** derived from
5
- the file's path and stat metadata, plus one column per **`{name}` capture**
6
- in the table's glob.
4
+ onto its rows automatically: seven **stat columns** derived from the file's
5
+ path and stat metadata, plus one column per **`{name}` capture** in the
6
+ table's glob.
7
+
8
+ These are ordinary, physically stored `TEXT`/`INTEGER` columns, computed
9
+ once per file at scan time and written like any other column value — not
10
+ SQLite's `GENERATED ... VIRTUAL` columns (computed on the fly, never stored)
11
+ and not part of a `CREATE VIRTUAL TABLE` (dirsql tables are always real
12
+ tables). "Stat" describes where the value comes from — the file's path and
13
+ `stat` metadata, as opposed to its content — not how it's stored.
7
14
 
8
15
  Facts are **opt-in by DDL**: only facts whose name appears as a column in
9
16
  the table's `CREATE TABLE` are populated; the rest are silently dropped.
10
- Declaring them requires nothing else.
17
+ Declaring them requires nothing else. The names below aren't a protected or
18
+ enforced namespace — nothing stops you from declaring a column with one of
19
+ these names for an unrelated purpose, in which case dirsql's computed value
20
+ lands there like any other fact (unless your own row source — an `on-file`
21
+ command or SDK `extract` callback — supplies its own value for that name;
22
+ see [Precedence](#precedence)).
11
23
 
12
- ## Virtual columns
24
+ ## Stat columns
13
25
 
14
26
  | Column | Type | Value |
15
27
  |---|---|---|
16
- | `_path` | TEXT | The file's path relative to the scan root (e.g. `posts/hello.md`). |
17
- | `_basename` | TEXT | The filename, including extension (`hello.md`). |
18
- | `_dir` | TEXT | The parent directory relative to the root (`posts`); the empty string for files directly under the root. |
19
- | `_ext` | TEXT | The file extension without the leading dot (`md`). Original case is preserved — `Photo.JPG` yields `JPG`; use `LOWER(_ext)` for case-insensitive matching. `NULL` when the file has no extension. |
20
- | `_size` | INTEGER | File size in bytes. |
21
- | `_mtime` | INTEGER | Last-modified time, Unix seconds. |
22
- | `_ctime` | INTEGER | Creation (birth) time, Unix seconds. `NULL` when the platform or filesystem cannot supply it. |
28
+ | `path` | TEXT | The file's path relative to the scan root (e.g. `posts/hello.md`). |
29
+ | `basename` | TEXT | The filename, including extension (`hello.md`). |
30
+ | `dir` | TEXT | The parent directory relative to the root (`posts`); the empty string for files directly under the root. |
31
+ | `ext` | TEXT | The file extension without the leading dot (`md`). Original case is preserved — `Photo.JPG` yields `JPG`; use `LOWER(ext)` for case-insensitive matching. `NULL` when the file has no extension. |
32
+ | `size` | INTEGER | File size in bytes. |
33
+ | `mtime` | INTEGER | Last-modified time, Unix seconds. |
34
+ | `ctime` | INTEGER | Creation (birth) time, Unix seconds. `NULL` when the platform or filesystem cannot supply it. |
23
35
 
24
- A fact that cannot be computed (an unreadable file's `_size`/`_mtime`/
25
- `_ctime`, a missing extension's `_ext`) is absent from the row: `NULL` in
36
+ A fact that cannot be computed (an unreadable file's `size`/`mtime`/
37
+ `ctime`, a missing extension's `ext`) is absent from the row: `NULL` in
26
38
  the default relaxed mode, a missing-column error for a
27
39
  [`strict`](./config.md#table) table that declares it.
28
40
 
29
41
  ```sql
30
- SELECT _basename, _size
42
+ SELECT basename, size
31
43
  FROM posts
32
- WHERE _mtime > strftime('%s', '2024-01-01')
33
- ORDER BY _mtime DESC;
44
+ WHERE mtime > strftime('%s', '2024-01-01')
45
+ ORDER BY mtime DESC;
34
46
  ```
35
47
 
36
48
  ## Glob captures
@@ -40,7 +52,7 @@ a TEXT column named `name`:
40
52
 
41
53
  ```toml
42
54
  [[table]]
43
- ddl = "CREATE TABLE comments (thread_id TEXT, _basename TEXT, _mtime INTEGER)"
55
+ ddl = "CREATE TABLE comments (thread_id TEXT, basename TEXT, mtime INTEGER)"
44
56
  glob = "_comments/{thread_id}/*.jsonl"
45
57
  ```
46
58
 
@@ -53,7 +65,7 @@ A file at `_comments/abc123/2024-05-05.jsonl` produces a row with
53
65
  characters, never a `/`. For matching purposes, `{name}` behaves like
54
66
  `*`.
55
67
  - A glob may contain multiple captures (`{year}/{month}/*.jpg`).
56
- - Like virtual columns, a capture populates a column only when the DDL
68
+ - Like stat columns, a capture populates a column only when the DDL
57
69
  declares a column of the same name.
58
70
 
59
71
  ## Precedence
@@ -61,8 +73,8 @@ A file at `_comments/abc123/2024-05-05.jsonl` produces a row with
61
73
  Values produced by a table's own row source — an `on-file` command's JSON
62
74
  output or an SDK `extract` callback's return value — **win** over
63
75
  auto-injected facts of the same name. An extract that explicitly emits
64
- `_path` is honored.
76
+ `path` is honored.
65
77
 
66
- Injection order per row: virtual columns first, then glob captures, then
78
+ Injection order per row: stat columns first, then glob captures, then
67
79
  the row source's own values, each layer overwriting the previous, all
68
80
  filtered to the DDL's declared columns.
@@ -97,7 +97,7 @@ per-file command.
97
97
  |---|---|---|
98
98
  | `ddl` | yes | A SQLite `CREATE TABLE` statement. The table name is parsed from it. Only columns declared here are populated; auto-injected facts not in the DDL are dropped. |
99
99
  | `glob` | yes | Glob pattern matched against root-relative paths. May contain `{name}` [capture segments](./columns.md#glob-captures). First matching table wins when a file matches several globs. |
100
- | `strict` | no (default `false`) | When `true`, rows whose keys do not exactly match the declared columns are rejected with an error: extra keys error, and every declared column must be supplied (by the command/extract output, a glob capture, or a virtual column). When `false`, extra keys are dropped and missing columns become `NULL`. |
100
+ | `strict` | no (default `false`) | When `true`, rows whose keys do not exactly match the declared columns are rejected with an error: extra keys error, and every declared column must be supplied (by the command/extract output, a glob capture, or a stat column). When `false`, extra keys are dropped and missing columns become `NULL`. |
101
101
  | `on-file` | no | A command run once per matched file; its stdout (a JSON array of row objects) becomes the file's rows. Must be non-empty. See [Command hooks](./hooks.md#on-file). |
102
102
 
103
103
  Without `on-file`, a table produces exactly one row per matched file, built
@@ -108,7 +108,7 @@ callback.
108
108
 
109
109
  ```toml
110
110
  [[table]]
111
- ddl = "CREATE TABLE comments (thread_id TEXT, _basename TEXT, _mtime INTEGER)"
111
+ ddl = "CREATE TABLE comments (thread_id TEXT, basename TEXT, mtime INTEGER)"
112
112
  glob = "_comments/{thread_id}/*.jsonl"
113
113
 
114
114
  [[table]]
@@ -157,10 +157,10 @@ path = "sqlite_vec" # Python module name; on Node use the
157
157
  entrypoint = "sqlite3_vec_init"
158
158
 
159
159
  [[table]]
160
- ddl = "CREATE TABLE comments (thread_id TEXT, _basename TEXT, _mtime INTEGER)"
160
+ ddl = "CREATE TABLE comments (thread_id TEXT, basename TEXT, mtime INTEGER)"
161
161
  glob = "_comments/{thread_id}/*.jsonl"
162
162
 
163
163
  [[table]]
164
- ddl = "CREATE TABLE documents (_path TEXT, _basename TEXT, _size INTEGER)"
164
+ ddl = "CREATE TABLE documents (path TEXT, basename TEXT, size INTEGER)"
165
165
  glob = "**/index.md"
166
166
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dirsql",
3
- "version": "0.3.76",
3
+ "version": "0.3.78",
4
4
  "description": "Ephemeral SQL index over a local directory",
5
5
  "license": "MIT",
6
6
  "repository": "https://github.com/thekevinscott/dirsql",
@@ -230,15 +230,15 @@
230
230
  ]
231
231
  },
232
232
  "optionalDependencies": {
233
- "@dirsql/lib-linux-x64-gnu": "0.3.76",
234
- "@dirsql/lib-linux-arm64-gnu": "0.3.76",
235
- "@dirsql/lib-darwin-x64": "0.3.76",
236
- "@dirsql/lib-darwin-arm64": "0.3.76",
237
- "@dirsql/lib-win32-x64-msvc": "0.3.76",
238
- "@dirsql/cli-linux-x64-gnu": "0.3.76",
239
- "@dirsql/cli-linux-arm64-gnu": "0.3.76",
240
- "@dirsql/cli-darwin-x64": "0.3.76",
241
- "@dirsql/cli-darwin-arm64": "0.3.76",
242
- "@dirsql/cli-win32-x64-msvc": "0.3.76"
233
+ "@dirsql/lib-linux-x64-gnu": "0.3.78",
234
+ "@dirsql/lib-linux-arm64-gnu": "0.3.78",
235
+ "@dirsql/lib-darwin-x64": "0.3.78",
236
+ "@dirsql/lib-darwin-arm64": "0.3.78",
237
+ "@dirsql/lib-win32-x64-msvc": "0.3.78",
238
+ "@dirsql/cli-linux-x64-gnu": "0.3.78",
239
+ "@dirsql/cli-linux-arm64-gnu": "0.3.78",
240
+ "@dirsql/cli-darwin-x64": "0.3.78",
241
+ "@dirsql/cli-darwin-arm64": "0.3.78",
242
+ "@dirsql/cli-win32-x64-msvc": "0.3.78"
243
243
  }
244
244
  }