dirsql 0.4.130 → 0.4.131
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.
|
@@ -12,12 +12,16 @@ as in [Define tables for your files](./define-tables.md).
|
|
|
12
12
|
|
|
13
13
|
## Why triggers, and why only two
|
|
14
14
|
|
|
15
|
-
`dirsql` writes
|
|
16
|
-
delete and an insert in one transaction
|
|
17
|
-
|
|
15
|
+
`dirsql` writes the rows of a table with no key with plain `INSERT` and
|
|
16
|
+
`DELETE`; a changed row is a delete and an insert in one transaction. So an
|
|
17
|
+
insert trigger and a delete trigger cover every way a row can
|
|
18
18
|
change — during the initial build, on each [watcher](./react-to-changes.md)
|
|
19
19
|
event, and when a [persistent cache](./persist.md) reconciles a tree that
|
|
20
20
|
moved on. There is no third trigger to write and no maintenance command to run.
|
|
21
|
+
A table with a `PRIMARY KEY`, or a `UNIQUE` column the command fills, has its
|
|
22
|
+
changed rows `UPDATE`d in place instead
|
|
23
|
+
([hooks](../reference/hooks.md#on-file-contract)); give it an `AFTER UPDATE`
|
|
24
|
+
trigger as well.
|
|
21
25
|
|
|
22
26
|
The triggers are also the part that goes wrong, which is why the templates
|
|
23
27
|
spell them out rather than hiding them behind an abstraction.
|
package/docs/reference/config.md
CHANGED
|
@@ -236,6 +236,11 @@ rows — filtered to the DDL — are the table. For plain stat columns with no
|
|
|
236
236
|
command, query the path directly with a [path-table](./path-tables.md)
|
|
237
237
|
instead of declaring a table.
|
|
238
238
|
|
|
239
|
+
Tables' `on-file` commands run one table at a time, in declaration order:
|
|
240
|
+
a table's command finishes before the next table's starts, whatever order
|
|
241
|
+
their files sort in. That holds at startup and when a change under watch
|
|
242
|
+
re-runs several tables at once.
|
|
243
|
+
|
|
239
244
|
```toml
|
|
240
245
|
[[table]]
|
|
241
246
|
name = "comments"
|
|
@@ -302,11 +307,14 @@ dirsql query "SELECT text FROM messages_fts WHERE messages_fts MATCH 'deploy'" \
|
|
|
302
307
|
-c ./.dirsql.toml
|
|
303
308
|
```
|
|
304
309
|
|
|
305
|
-
Those two triggers are all a keyword index needs.
|
|
306
|
-
plain `INSERT` and `DELETE` —
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
[watcher](../howto/react-to-changes.md) event.
|
|
310
|
+
Those two triggers are all a keyword index needs. `messages` declares no key,
|
|
311
|
+
so dirsql writes its rows with plain `INSERT` and `DELETE` — a changed row is a
|
|
312
|
+
delete and an insert in one transaction — and triggers you declare here stay
|
|
313
|
+
current through the initial load and every
|
|
314
|
+
[watcher](../howto/react-to-changes.md) event. A table with a `PRIMARY KEY` or
|
|
315
|
+
`UNIQUE` column the command fills has its changed rows `UPDATE`d in place
|
|
316
|
+
instead (see [hooks](./hooks.md#on-file-contract)); give it an
|
|
317
|
+
`AFTER UPDATE` trigger too. The same shape with a `vec0`
|
|
310
318
|
virtual table and an [`embed()`](#dirsql-function) call in the trigger gives
|
|
311
319
|
you stored vectors.
|
|
312
320
|
|
|
@@ -337,6 +345,39 @@ Two consequences of `ddl` running **once, when the table is created**:
|
|
|
337
345
|
That is the only invalidation lane: dirsql tracks no ownership of what the
|
|
338
346
|
batch made.
|
|
339
347
|
|
|
348
|
+
### Foreign keys
|
|
349
|
+
|
|
350
|
+
SQLite enforces a `REFERENCES` clause in a table's `ddl`. Tables fill in no
|
|
351
|
+
fixed order, so `dirsql` checks foreign keys once per unit of work rather than
|
|
352
|
+
per row: every constraint is deferred to the end of the unit, as if declared
|
|
353
|
+
`DEFERRABLE INITIALLY DEFERRED`. A unit is the initial build, or one batch of
|
|
354
|
+
[watcher](../howto/react-to-changes.md) events across all tables. A child may
|
|
355
|
+
land before its parent, and a parent's file may change while its children
|
|
356
|
+
point at it.
|
|
357
|
+
|
|
358
|
+
A row that still references nothing when the unit ends fails the whole unit,
|
|
359
|
+
and the error names each offending row, the file that produced it, and the
|
|
360
|
+
values that match nothing:
|
|
361
|
+
|
|
362
|
+
```text
|
|
363
|
+
foreign key violation: `task` row from `projects/beta/tasks/t1.json` has project_id = 2, which matches no row in `project`
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
- **Build:** the build fails and nothing is written.
|
|
367
|
+
- **Watch:** the batch is rolled back and reported as one error event, against
|
|
368
|
+
the child's table and file. The database stays as it was before the batch.
|
|
369
|
+
The rejected changes are retried with each later batch, as the files stand
|
|
370
|
+
then, and land with the first batch that resolves them, such as one that
|
|
371
|
+
repoints or deletes the orphaned child. Until then each later batch is also
|
|
372
|
+
tried on its own and lands if it leaves no orphan, and the error is reported
|
|
373
|
+
again. A table's `on-file` command re-reads all of its files, so a later
|
|
374
|
+
batch that touches the same table carries the orphaning change and waits
|
|
375
|
+
too.
|
|
376
|
+
|
|
377
|
+
`ON DELETE` and `ON UPDATE` actions are not deferred. `dirsql` applies a changed
|
|
378
|
+
file as a delete and an insert, so `ON DELETE CASCADE` deletes the children of a
|
|
379
|
+
parent whose file is edited or renamed, even though their files still exist.
|
|
380
|
+
|
|
340
381
|
### `on-file` row mapping
|
|
341
382
|
|
|
342
383
|
The command prints one JSON object per line (NDJSON); each line becomes one
|
|
@@ -369,6 +410,8 @@ The configs load and merge in **argv order**:
|
|
|
369
410
|
that config file's own directory** — so a relative command like
|
|
370
411
|
`on-file = "sh ./extract.sh"` resolves against the config that declared it,
|
|
371
412
|
wherever it lives.
|
|
413
|
+
- **`on-file` commands run in argv order**: every table of the first config,
|
|
414
|
+
in declaration order, before any table of the second.
|
|
372
415
|
- Each config is **validated on its own** (the [parse errors](#parse-errors)
|
|
373
416
|
below apply per file). There is no cross-file merge validation, with two
|
|
374
417
|
structural exceptions: **two configs defining a table of the same name is
|
package/docs/reference/hooks.md
CHANGED
|
@@ -128,7 +128,22 @@ for path in sys.argv[1:]:
|
|
|
128
128
|
There is no row-to-file attribution: dirsql does not know which file a row
|
|
129
129
|
came from, and a row that needs the path carries it as a column the command
|
|
130
130
|
emitted. In watch mode a change to any file under the table's glob re-runs
|
|
131
|
-
the command over all of the table's files and
|
|
131
|
+
the command over all of the table's files and writes only the difference,
|
|
132
|
+
comparing just the columns the command emits:
|
|
133
|
+
|
|
134
|
+
- A table with a key matches old and new rows by it. The key is the
|
|
135
|
+
`PRIMARY KEY`, or else a `UNIQUE` constraint (or unique index) whose columns
|
|
136
|
+
the command fills, non-NULL, in every row. A matched row that changed is
|
|
137
|
+
`UPDATE`d in place, so its rowid and every column the command leaves out (a
|
|
138
|
+
generated `INTEGER PRIMARY KEY`, a default) keep their values, and the watch
|
|
139
|
+
stream carries an `update`. A key that disappears is deleted and a new key is
|
|
140
|
+
inserted.
|
|
141
|
+
- A table without one has no row identity: a row the command still emits
|
|
142
|
+
stays put, and every other row is deleted or inserted.
|
|
143
|
+
|
|
144
|
+
With `CREATE TABLE experiments (id INTEGER PRIMARY KEY, folder_name TEXT UNIQUE, name TEXT)`
|
|
145
|
+
and a command that emits `folder_name` and `name`, renaming an experiment keeps
|
|
146
|
+
its `id`, so a table that stores that `id` still points at it.
|
|
132
147
|
|
|
133
148
|
The same command is attachable two ways, over the same contract: the
|
|
134
149
|
`on-file` config key on a `[[table]]`, and the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dirsql",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.131",
|
|
4
4
|
"description": "Ephemeral SQL index over a local directory",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "https://github.com/thekevinscott/dirsql",
|
|
@@ -221,10 +221,10 @@
|
|
|
221
221
|
]
|
|
222
222
|
},
|
|
223
223
|
"optionalDependencies": {
|
|
224
|
-
"@dirsql/lib-linux-x64-gnu": "0.4.
|
|
225
|
-
"@dirsql/lib-linux-arm64-gnu": "0.4.
|
|
226
|
-
"@dirsql/lib-darwin-x64": "0.4.
|
|
227
|
-
"@dirsql/lib-darwin-arm64": "0.4.
|
|
228
|
-
"@dirsql/lib-win32-x64-msvc": "0.4.
|
|
224
|
+
"@dirsql/lib-linux-x64-gnu": "0.4.131",
|
|
225
|
+
"@dirsql/lib-linux-arm64-gnu": "0.4.131",
|
|
226
|
+
"@dirsql/lib-darwin-x64": "0.4.131",
|
|
227
|
+
"@dirsql/lib-darwin-arm64": "0.4.131",
|
|
228
|
+
"@dirsql/lib-win32-x64-msvc": "0.4.131"
|
|
229
229
|
}
|
|
230
230
|
}
|