datanotes 2.0.0 → 3.0.0
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/NOTICE +9 -0
- package/README.md +207 -28
- package/SECURITY.md +92 -45
- package/dist/THIRD-PARTY-NOTICES.txt +682 -0
- package/dist/api/catalog.d.cts +69 -0
- package/dist/api/catalog.d.ts +50 -2
- package/dist/api/cli-options.d.cts +39 -0
- package/dist/api/cli-options.d.ts +39 -0
- package/dist/api/client.d.cts +89 -0
- package/dist/api/client.d.ts +19 -30
- package/dist/api/docs.d.cts +211 -0
- package/dist/api/docs.d.ts +211 -0
- package/dist/api/guidance.d.cts +81 -0
- package/dist/api/guidance.d.ts +81 -0
- package/dist/api/index.cjs +6610 -2247
- package/dist/api/index.d.cts +13 -0
- package/dist/api/index.d.ts +10 -7
- package/dist/api/index.js +6610 -2247
- package/dist/api/local.cjs +118 -6
- package/dist/api/local.d.cts +95 -0
- package/dist/api/local.d.ts +70 -6
- package/dist/api/local.js +104 -6
- package/dist/api/mcp.cjs +17384 -0
- package/dist/api/mcp.d.cts +108 -0
- package/dist/api/mcp.d.ts +108 -0
- package/dist/api/mcp.js +17334 -0
- package/dist/api/otlp.d.cts +65 -0
- package/dist/api/redact.d.cts +17 -0
- package/dist/api/redact.d.ts +17 -0
- package/dist/api/requests.d.cts +26 -0
- package/dist/api/requests.d.ts +14 -16
- package/dist/api/results.d.cts +16 -0
- package/dist/api/results.d.ts +2 -1
- package/dist/api/tokens.d.cts +7 -0
- package/dist/datanotes.cjs +62911 -28409
- package/dist/docs/administration/configuration.md +59 -0
- package/dist/docs/administration/docker.md +80 -0
- package/dist/docs/administration/git-sync.md +71 -0
- package/dist/docs/administration/limits.md +69 -0
- package/dist/docs/administration/run-the-service.md +219 -0
- package/dist/docs/administration/status.md +61 -0
- package/dist/docs/administration/use-with-obsidian.md +75 -0
- package/dist/docs/api/operations/add_column.md +49 -0
- package/dist/docs/api/operations/add_constraint.md +55 -0
- package/dist/docs/api/operations/adopt_rows.md +50 -0
- package/dist/docs/api/operations/align_relations.md +41 -0
- package/dist/docs/api/operations/alter_column.md +46 -0
- package/dist/docs/api/operations/alter_table.md +67 -0
- package/dist/docs/api/operations/batch.md +48 -0
- package/dist/docs/api/operations/changes_stream.md +28 -0
- package/dist/docs/api/operations/check_table.md +29 -0
- package/dist/docs/api/operations/clone_table.md +48 -0
- package/dist/docs/api/operations/comment_on.md +42 -0
- package/dist/docs/api/operations/configure_database.md +52 -0
- package/dist/docs/api/operations/create_table.md +78 -0
- package/dist/docs/api/operations/create_view.md +54 -0
- package/dist/docs/api/operations/create_webhook.md +37 -0
- package/dist/docs/api/operations/define_base.md +52 -0
- package/dist/docs/api/operations/delete_rows.md +43 -0
- package/dist/docs/api/operations/delete_webhook.md +31 -0
- package/dist/docs/api/operations/describe_database.md +30 -0
- package/dist/docs/api/operations/describe_history.md +40 -0
- package/dist/docs/api/operations/describe_semantic_index.md +24 -0
- package/dist/docs/api/operations/describe_table.md +38 -0
- package/dist/docs/api/operations/docs.md +13 -0
- package/dist/docs/api/operations/drop_column.md +41 -0
- package/dist/docs/api/operations/drop_constraint.md +39 -0
- package/dist/docs/api/operations/drop_table.md +43 -0
- package/dist/docs/api/operations/drop_view.md +38 -0
- package/dist/docs/api/operations/engine_status.md +23 -0
- package/dist/docs/api/operations/graph_neighbors.md +32 -0
- package/dist/docs/api/operations/graph_path.md +32 -0
- package/dist/docs/api/operations/graph_traverse.md +43 -0
- package/dist/docs/api/operations/identify_session.md +24 -0
- package/dist/docs/api/operations/infer_table.md +43 -0
- package/dist/docs/api/operations/insert_row.md +48 -0
- package/dist/docs/api/operations/list_changes.md +35 -0
- package/dist/docs/api/operations/list_folder.md +28 -0
- package/dist/docs/api/operations/list_link_targets.md +44 -0
- package/dist/docs/api/operations/list_migrations.md +35 -0
- package/dist/docs/api/operations/list_tables.md +32 -0
- package/dist/docs/api/operations/list_webhooks.md +23 -0
- package/dist/docs/api/operations/manual_index.md +14 -0
- package/dist/docs/api/operations/manual_page.md +22 -0
- package/dist/docs/api/operations/merge_rows.md +44 -0
- package/dist/docs/api/operations/move_rows.md +52 -0
- package/dist/docs/api/operations/openapi.md +13 -0
- package/dist/docs/api/operations/openapi_post.md +20 -0
- package/dist/docs/api/operations/read_note.md +29 -0
- package/dist/docs/api/operations/recompute_columns.md +44 -0
- package/dist/docs/api/operations/record_tool_call.md +36 -0
- package/dist/docs/api/operations/rename_column.md +44 -0
- package/dist/docs/api/operations/rename_value.md +45 -0
- package/dist/docs/api/operations/restore_database.md +51 -0
- package/dist/docs/api/operations/restore_table.md +46 -0
- package/dist/docs/api/operations/search_notes.md +28 -0
- package/dist/docs/api/operations/select_rows.md +61 -0
- package/dist/docs/api/operations/semantic_search.md +34 -0
- package/dist/docs/api/operations/semantic_search_docs.md +26 -0
- package/dist/docs/api/operations/set_table_bases.md +44 -0
- package/dist/docs/api/operations/status.md +13 -0
- package/dist/docs/api/operations/stop_engine.md +23 -0
- package/dist/docs/api/operations/sync_semantic_index.md +33 -0
- package/dist/docs/api/operations/table_changes.md +31 -0
- package/dist/docs/api/operations/tags/auxiliary.md +14 -0
- package/dist/docs/api/operations/tags/change-feed.md +8 -0
- package/dist/docs/api/operations/tags/history.md +17 -0
- package/dist/docs/api/operations/tags/queries.md +15 -0
- package/dist/docs/api/operations/tags/rows-dml.md +16 -0
- package/dist/docs/api/operations/tags/schema-ddl.md +22 -0
- package/dist/docs/api/operations/tags/service.md +15 -0
- package/dist/docs/api/operations/tags/tokens.md +13 -0
- package/dist/docs/api/operations/tokens_create.md +34 -0
- package/dist/docs/api/operations/tokens_delete.md +29 -0
- package/dist/docs/api/operations/tokens_list.md +21 -0
- package/dist/docs/api/operations/tokens_me.md +20 -0
- package/dist/docs/api/operations/tokens_rotate.md +29 -0
- package/dist/docs/api/operations/tokens_update.md +34 -0
- package/dist/docs/api/operations/undo_migration.md +46 -0
- package/dist/docs/api/operations/update_row.md +60 -0
- package/dist/docs/api/operations/update_rows.md +46 -0
- package/dist/docs/api/operations/vacuum_table.md +37 -0
- package/dist/docs/api.md +135 -0
- package/dist/docs/develop/build-an-app.md +320 -0
- package/dist/docs/develop/build-on-datanotes.md +138 -0
- package/dist/docs/develop/change-feed-and-webhooks.md +70 -0
- package/dist/docs/develop/client.md +116 -0
- package/dist/docs/develop/concurrency.md +153 -0
- package/dist/docs/develop/http-api.md +79 -0
- package/dist/docs/develop/telemetry.md +86 -0
- package/dist/docs/guides/agents/docs-offline.md +99 -0
- package/dist/docs/guides/agents/how-agents-use-datanotes.md +124 -0
- package/dist/docs/guides/agents/prompts.md +495 -0
- package/dist/docs/guides/agents/reading-errors.md +112 -0
- package/dist/docs/guides/data-quality/check-constraints.md +379 -0
- package/dist/docs/guides/data-quality/check-table.md +63 -0
- package/dist/docs/guides/data-quality/hand-edits.md +507 -0
- package/dist/docs/guides/data-quality/sync-between-devices.md +51 -0
- package/dist/docs/guides/data-quality/validation.md +90 -0
- package/dist/docs/guides/database-objects/bases.md +480 -0
- package/dist/docs/guides/database-objects/catalogs-and-schemas.md +897 -0
- package/dist/docs/guides/database-objects/columns.md +1332 -0
- package/dist/docs/guides/database-objects/relations.md +1454 -0
- package/dist/docs/guides/database-objects/tables.md +1404 -0
- package/dist/docs/guides/database-objects/views.md +1003 -0
- package/dist/docs/guides/history/back-up.md +195 -0
- package/dist/docs/guides/history/change-data-feed.md +247 -0
- package/dist/docs/guides/history/journal-and-undo.md +262 -0
- package/dist/docs/guides/history/restore.md +341 -0
- package/dist/docs/guides/history/table-history.md +657 -0
- package/dist/docs/guides/history/vacuum.md +35 -0
- package/dist/docs/guides/read-and-write/automatic-links.md +768 -0
- package/dist/docs/guides/read-and-write/batch.md +139 -0
- package/dist/docs/guides/read-and-write/import-notes.md +896 -0
- package/dist/docs/guides/read-and-write/joins-and-aggregates.md +251 -0
- package/dist/docs/guides/read-and-write/read-and-filter.md +536 -0
- package/dist/docs/guides/read-and-write/write-rows.md +573 -0
- package/dist/docs/guides/search/link-graph.md +146 -0
- package/dist/docs/guides/search/semantic.md +133 -0
- package/dist/docs/guides/search/text.md +142 -0
- package/dist/docs/guides/security/security-model.md +110 -0
- package/dist/docs/guides/security/tokens.md +60 -0
- package/dist/docs/guides/security/who-did-what.md +42 -0
- package/dist/docs/index.md +113 -0
- package/dist/docs/llms.txt +33 -0
- package/dist/docs/reference/cli.md +136 -0
- package/dist/docs/reference/compatibility.md +63 -0
- package/dist/docs/reference/errors.md +72 -0
- package/dist/docs/reference/glossary.md +161 -0
- package/dist/docs/reference/operations/auxiliary.md +116 -0
- package/dist/docs/reference/operations/history.md +168 -0
- package/dist/docs/reference/operations/queries.md +169 -0
- package/dist/docs/reference/operations/rows.md +185 -0
- package/dist/docs/reference/operations/schema.md +316 -0
- package/dist/docs/reference/operations.md +96 -0
- package/dist/docs/reference/settings.md +31 -0
- package/dist/docs/release-notes.md +67 -0
- package/dist/docs/start/connect-agents.md +204 -0
- package/dist/docs/start/how-it-works.md +317 -0
- package/dist/docs/start/quick-start.md +126 -0
- package/package.json +59 -14
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
# Write and move rows
|
|
2
|
+
|
|
3
|
+
> Insert a row, update one row or many, edit a note’s text, upsert, guard against concurrent edits, delete and move rows.
|
|
4
|
+
|
|
5
|
+
The engine checks every write before it changes anything, records it in the journal, and lets you undo it with `undo_migration`. A write answers with the notes it created, changed, moved or deleted.
|
|
6
|
+
|
|
7
|
+
The first example adds a row to the film diary of [Tables](https://datanotes.dev/guides/database-objects/tables/); the others work on a small diary of five classic films.
|
|
8
|
+
|
|
9
|
+
When several clients write at once, the engine checks each write on the latest data. [Concurrent writes](https://datanotes.dev/develop/concurrency/) explains the rules and when to retry.
|
|
10
|
+
|
|
11
|
+
## Insert a row
|
|
12
|
+
|
|
13
|
+
`insert_row` writes a new note. The engine fills in the default (`status`) and an `id`, and names the note from `filename`. `body` sets the note’s text.
|
|
14
|
+
|
|
15
|
+
**`insert_row`**
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"table": "film",
|
|
20
|
+
"values": { "title": "Metropolis", "year": 1927, "minutes": 153 },
|
|
21
|
+
"body": "Next on my list. Two and a half hours of silent film need a quiet evening.\n"
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Answer:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"ok": true,
|
|
30
|
+
"op": "insert_row",
|
|
31
|
+
"files_created": 1,
|
|
32
|
+
"planned_creates": ["datanotes/main/public/film/Metropolis.md"],
|
|
33
|
+
"commits": [{ "table": "main.public.film", "version": 1, "operation": "WRITE" }],
|
|
34
|
+
"migration_id": "20261012T071946-insert_row-insert-into-film"
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`datanotes/main/public/film/Metropolis.md` now reads:
|
|
39
|
+
|
|
40
|
+
```markdown
|
|
41
|
+
---
|
|
42
|
+
table: main.public.film
|
|
43
|
+
id: 01a12efb-5925-7551-9fc3-ca301818d73d
|
|
44
|
+
title: Metropolis
|
|
45
|
+
year: 1927
|
|
46
|
+
minutes: 153
|
|
47
|
+
status: to watch
|
|
48
|
+
---
|
|
49
|
+
Next on my list. Two and a half hours of silent film need a quiet evening.
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Pick a free file name for a new row
|
|
53
|
+
|
|
54
|
+
Without `path`, the table’s filename pattern names the new note. When another note has that name, the engine adds `-2`, `-3` and so on.
|
|
55
|
+
|
|
56
|
+
A `path` you pass must be free. Windows and macOS see `Nosferatu.md` and `nosferatu.md` as one file. So on every system, the engine refuses a name that another note has in another case, and names that note:
|
|
57
|
+
|
|
58
|
+
**`insert_row`**
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"table": "film",
|
|
63
|
+
"values": { "title": "The Kid", "year": 1921 },
|
|
64
|
+
"path": "datanotes/main/public/film/nosferatu.md"
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Refused:
|
|
69
|
+
|
|
70
|
+
```text
|
|
71
|
+
insert_row refused — nothing was written:
|
|
72
|
+
conflict datanotes/main/public/film/nosferatu.md: note already exists in another case: "datanotes/main/public/film/Nosferatu.md" (one file on Windows and macOS)
|
|
73
|
+
Hint: Another note has this file name, maybe in another case (Windows and macOS see one file): pass another "path", give the row values its table's filename pattern turns into a free name, or update that note with update_row. Then call insert_row again.
|
|
74
|
+
Docs: https://datanotes.dev/guides/read-and-write/write-rows.md#pick-a-free-file-name-for-a-new-row (offline: read_docs("guides/read-and-write/write-rows#pick-a-free-file-name-for-a-new-row"))
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Update one row
|
|
78
|
+
|
|
79
|
+
`update_row` changes exactly one row, which you address by `path` or by its `id`. `set` sets columns and `unset` removes them. The engine checks the whole row before it writes anything.
|
|
80
|
+
|
|
81
|
+
**`update_row`**
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"table": "film",
|
|
86
|
+
"path": "datanotes/main/public/film/His Girl Friday.md",
|
|
87
|
+
"set": { "status": "watched", "rating": 5, "tags": ["screwball"] }
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Answer:
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"ok": true,
|
|
96
|
+
"op": "update_row",
|
|
97
|
+
"notes_changed": 1,
|
|
98
|
+
"planned_edits": [
|
|
99
|
+
{
|
|
100
|
+
"path": "datanotes/main/public/film/His Girl Friday.md",
|
|
101
|
+
"set": { "status": "watched", "rating": 5, "tags": ["screwball"] },
|
|
102
|
+
"remove": []
|
|
103
|
+
}
|
|
104
|
+
],
|
|
105
|
+
"commits": [{ "table": "main.public.film", "version": 6, "operation": "UPDATE" }],
|
|
106
|
+
"migration_id": "20261012T071951-update_row-update-film"
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**`update_row`**
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"table": "film",
|
|
115
|
+
"path": "datanotes/main/public/film/His Girl Friday.md",
|
|
116
|
+
"unset": ["tags"]
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
The engine refuses a path that isn’t a row, and creates nothing:
|
|
121
|
+
|
|
122
|
+
**`update_row`**
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"table": "film",
|
|
127
|
+
"path": "datanotes/main/public/film/Night of the Living Dead.md",
|
|
128
|
+
"set": { "rating": 4 }
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Refused:
|
|
133
|
+
|
|
134
|
+
```text
|
|
135
|
+
film has no row at datanotes/main/public/film/Night of the Living Dead.md
|
|
136
|
+
Hint: Name the row by its "path" (the vault path of its note, e.g. "Films/Metropolis.md") or its "id": select_rows with columns ["path", "id"] and a "where" finds them.
|
|
137
|
+
Docs: https://datanotes.dev/guides/read-and-write/write-rows.md#update-one-row (offline: read_docs("guides/read-and-write/write-rows#update-one-row"))
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Edit a note’s text
|
|
141
|
+
|
|
142
|
+
`update_row` edits the note’s text with these arguments:
|
|
143
|
+
|
|
144
|
+
* **`body_sections`**: replaces the text under one heading and leaves the rest of the note alone; the engine adds a missing heading at the end
|
|
145
|
+
* **`body_append`** and **`body_prepend`**: add text after or before the existing text
|
|
146
|
+
* **`body`**: replaces all of the text
|
|
147
|
+
|
|
148
|
+
**`update_row`**
|
|
149
|
+
|
|
150
|
+
```json
|
|
151
|
+
{
|
|
152
|
+
"table": "film",
|
|
153
|
+
"path": "datanotes/main/public/film/Nosferatu.md",
|
|
154
|
+
"body_sections": {
|
|
155
|
+
"Rewatch": "Watched it again in October. The shadow on the stairs still works a century later."
|
|
156
|
+
},
|
|
157
|
+
"body_append": "Next: Metropolis, for more German Expressionism.\n"
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Answer:
|
|
162
|
+
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
"ok": true,
|
|
166
|
+
"op": "update_row",
|
|
167
|
+
"notes_changed": 1,
|
|
168
|
+
"planned_edits": [
|
|
169
|
+
{
|
|
170
|
+
"path": "datanotes/main/public/film/Nosferatu.md",
|
|
171
|
+
"set": {},
|
|
172
|
+
"remove": [],
|
|
173
|
+
"body": true
|
|
174
|
+
}
|
|
175
|
+
],
|
|
176
|
+
"commits": [{ "table": "main.public.film", "version": 8, "operation": "UPDATE" }],
|
|
177
|
+
"migration_id": "20261012T071951-update_row-update-film-3",
|
|
178
|
+
"ambiguous_mentions": [
|
|
179
|
+
{
|
|
180
|
+
"path": "datanotes/main/public/film/Nosferatu.md",
|
|
181
|
+
"text": "Metropolis",
|
|
182
|
+
"reason": "sentence_start",
|
|
183
|
+
"candidates": ["datanotes/main/public/film/Metropolis.md"],
|
|
184
|
+
"context": "Next: Metropolis, for more German Expressionism.",
|
|
185
|
+
"hint": "\"Metropolis\" starts a sentence, a line or a label, so its capital does not make it a name: read the note and the text around it, then write the link with update_row and autolink: false, or leave the text as it is."
|
|
186
|
+
}
|
|
187
|
+
]
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
`datanotes/main/public/film/Nosferatu.md` now reads:
|
|
192
|
+
|
|
193
|
+
```markdown
|
|
194
|
+
---
|
|
195
|
+
table: main.public.film
|
|
196
|
+
id: 01a12efb-6c2e-7852-8b4b-ed121d84aec5
|
|
197
|
+
title: Nosferatu
|
|
198
|
+
year: 1922
|
|
199
|
+
status: watched
|
|
200
|
+
rating: 5
|
|
201
|
+
---
|
|
202
|
+
## Notes
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
Max Schreck doesn’t need a single word.
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
## Rewatch
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
Watched it again in October. The shadow on the stairs still works a century later.
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
Next: Metropolis, for more German Expressionism.
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
The engine links Metropolis, the note of another film, and lists the link in `links_added`. [Automatic links](https://datanotes.dev/guides/read-and-write/automatic-links/) shows which names it links.
|
|
218
|
+
|
|
219
|
+
## Guard a write against concurrent edits with `expect`
|
|
220
|
+
|
|
221
|
+
A person may edit a note between an agent’s read and its write. `expect` makes the write a compare-and-set: it goes through only if the row still has those values.
|
|
222
|
+
|
|
223
|
+
**`update_row`**
|
|
224
|
+
|
|
225
|
+
```json
|
|
226
|
+
{
|
|
227
|
+
"table": "film",
|
|
228
|
+
"path": "datanotes/main/public/film/Sherlock Jr..md",
|
|
229
|
+
"expect": { "status": "to watch" },
|
|
230
|
+
"set": { "status": "watched" }
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Answer:
|
|
235
|
+
|
|
236
|
+
```json
|
|
237
|
+
{
|
|
238
|
+
"ok": true,
|
|
239
|
+
"op": "update_row",
|
|
240
|
+
"notes_changed": 1,
|
|
241
|
+
"planned_edits": [
|
|
242
|
+
{
|
|
243
|
+
"path": "datanotes/main/public/film/Sherlock Jr..md",
|
|
244
|
+
"set": { "status": "watched" },
|
|
245
|
+
"remove": []
|
|
246
|
+
}
|
|
247
|
+
],
|
|
248
|
+
"commits": [{ "table": "main.public.film", "version": 9, "operation": "UPDATE" }],
|
|
249
|
+
"migration_id": "20261012T071951-update_row-update-film-4"
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Run the same call again. `status` is no longer `to watch`, so the engine writes nothing.
|
|
254
|
+
|
|
255
|
+
**`update_row`**
|
|
256
|
+
|
|
257
|
+
```json
|
|
258
|
+
{
|
|
259
|
+
"table": "film",
|
|
260
|
+
"path": "datanotes/main/public/film/Sherlock Jr..md",
|
|
261
|
+
"expect": { "status": "to watch" },
|
|
262
|
+
"set": { "status": "watched" }
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Refused:
|
|
267
|
+
|
|
268
|
+
```text
|
|
269
|
+
update_row refused — nothing was written:
|
|
270
|
+
conflict datanotes/main/public/film/Sherlock Jr..md: row changed: expected status = "to watch", found "watched" — read it again
|
|
271
|
+
Hint: The row changed since you read it: read it again (select_rows), then retry update_row with "expect" set to what you read.
|
|
272
|
+
Docs: https://datanotes.dev/guides/read-and-write/write-rows.md#guard-a-write-against-concurrent-edits-with-expect (offline: read_docs("guides/read-and-write/write-rows#guard-a-write-against-concurrent-edits-with-expect"))
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Update many rows
|
|
276
|
+
|
|
277
|
+
`update_rows` changes every row matching `where`. `expect_count` guards the write: the engine refuses it unless exactly that many rows match, so a filter that’s too broad changes nothing.
|
|
278
|
+
|
|
279
|
+
**`update_rows`**
|
|
280
|
+
|
|
281
|
+
```json
|
|
282
|
+
{
|
|
283
|
+
"table": "film",
|
|
284
|
+
"where": { "status": "watched" },
|
|
285
|
+
"set": { "tags": ["seen-2026"] },
|
|
286
|
+
"expect_count": 2
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Refused:
|
|
291
|
+
|
|
292
|
+
```text
|
|
293
|
+
update_rows refused — nothing was written:
|
|
294
|
+
conflict datanotes/main/public/film: "where" matched 3 rows, expected 2: nothing was written
|
|
295
|
+
Hint: Check the rows with select_rows and the same "where", then narrow it or change expect_count.
|
|
296
|
+
Docs: https://datanotes.dev/guides/read-and-write/write-rows.md#update-many-rows (offline: read_docs("guides/read-and-write/write-rows#update-many-rows"))
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**`update_rows`**
|
|
300
|
+
|
|
301
|
+
```json
|
|
302
|
+
{
|
|
303
|
+
"table": "film",
|
|
304
|
+
"where": { "status": "watched" },
|
|
305
|
+
"set": { "tags": ["seen-2026"] },
|
|
306
|
+
"expect_count": 3
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
Answer:
|
|
311
|
+
|
|
312
|
+
```json
|
|
313
|
+
{
|
|
314
|
+
"ok": true,
|
|
315
|
+
"op": "update_rows",
|
|
316
|
+
"notes_changed": 3,
|
|
317
|
+
"planned_edits": [
|
|
318
|
+
{
|
|
319
|
+
"path": "datanotes/main/public/film/His Girl Friday.md",
|
|
320
|
+
"set": { "tags": ["seen-2026"] },
|
|
321
|
+
"remove": []
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
"path": "datanotes/main/public/film/Nosferatu.md",
|
|
325
|
+
"set": { "tags": ["seen-2026"] },
|
|
326
|
+
"remove": []
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
"path": "datanotes/main/public/film/Sherlock Jr..md",
|
|
330
|
+
"set": { "tags": ["seen-2026"] },
|
|
331
|
+
"remove": []
|
|
332
|
+
}
|
|
333
|
+
],
|
|
334
|
+
"commits": [{ "table": "main.public.film", "version": 10, "operation": "UPDATE" }],
|
|
335
|
+
"migration_id": "20261012T071951-update_rows-update-film"
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
## Insert or update rows with `merge_rows`
|
|
340
|
+
|
|
341
|
+
`merge_rows` is an upsert: it inserts rows or updates existing ones. A row whose `on` columns match an existing row updates that row, and the engine inserts the others. The whole merge is one operation with one undo.
|
|
342
|
+
|
|
343
|
+
**`merge_rows`**
|
|
344
|
+
|
|
345
|
+
```json
|
|
346
|
+
{
|
|
347
|
+
"table": "film",
|
|
348
|
+
"on": ["title"],
|
|
349
|
+
"rows": [
|
|
350
|
+
{ "title": "Sherlock Jr.", "rating": 4 },
|
|
351
|
+
{ "title": "Battleship Potemkin", "year": 1925 }
|
|
352
|
+
]
|
|
353
|
+
}
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
Answer:
|
|
357
|
+
|
|
358
|
+
```json
|
|
359
|
+
{
|
|
360
|
+
"ok": true,
|
|
361
|
+
"op": "merge_rows",
|
|
362
|
+
"notes_changed": 1,
|
|
363
|
+
"files_created": 1,
|
|
364
|
+
"planned_edits": [
|
|
365
|
+
{
|
|
366
|
+
"path": "datanotes/main/public/film/Sherlock Jr..md",
|
|
367
|
+
"set": { "rating": 4 },
|
|
368
|
+
"remove": []
|
|
369
|
+
}
|
|
370
|
+
],
|
|
371
|
+
"planned_creates": ["datanotes/main/public/film/Battleship Potemkin.md"],
|
|
372
|
+
"commits": [{ "table": "main.public.film", "version": 11, "operation": "MERGE" }],
|
|
373
|
+
"migration_id": "20261012T071951-merge_rows-merge-2-rows-into-film"
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
**`select_rows`**
|
|
378
|
+
|
|
379
|
+
```json
|
|
380
|
+
{
|
|
381
|
+
"table": "film",
|
|
382
|
+
"columns": ["title", "rating", "status"],
|
|
383
|
+
"where": { "title": { "in": ["Sherlock Jr.", "Battleship Potemkin"] } }
|
|
384
|
+
}
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
Answer:
|
|
388
|
+
|
|
389
|
+
```json
|
|
390
|
+
{
|
|
391
|
+
"table": "main.public.film",
|
|
392
|
+
"total": 2,
|
|
393
|
+
"rows": [
|
|
394
|
+
{
|
|
395
|
+
"path": "datanotes/main/public/film/Battleship Potemkin.md",
|
|
396
|
+
"title": "Battleship Potemkin",
|
|
397
|
+
"rating": null,
|
|
398
|
+
"status": "to watch"
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
"path": "datanotes/main/public/film/Sherlock Jr..md",
|
|
402
|
+
"title": "Sherlock Jr.",
|
|
403
|
+
"rating": 4,
|
|
404
|
+
"status": "watched"
|
|
405
|
+
}
|
|
406
|
+
]
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
## Delete rows into the archive
|
|
411
|
+
|
|
412
|
+
By default, `delete_rows` moves the matching rows to the table’s archive folder, so you lose nothing. `mode: "delete"` moves them to the trash instead, and the journal keeps their content for undo. Always pass `where`: without it, every row matches.
|
|
413
|
+
|
|
414
|
+
**`delete_rows`**
|
|
415
|
+
|
|
416
|
+
```json
|
|
417
|
+
{ "table": "film", "where": { "title": "Battleship Potemkin" } }
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
Answer:
|
|
421
|
+
|
|
422
|
+
```json
|
|
423
|
+
{
|
|
424
|
+
"ok": true,
|
|
425
|
+
"op": "delete_rows",
|
|
426
|
+
"files_moved": 1,
|
|
427
|
+
"planned_moves": [
|
|
428
|
+
{
|
|
429
|
+
"from": "datanotes/main/public/film/Battleship Potemkin.md",
|
|
430
|
+
"to": "datanotes/main/public/film/_archive/Battleship Potemkin.md"
|
|
431
|
+
}
|
|
432
|
+
],
|
|
433
|
+
"commits": [{ "table": "main.public.film", "version": 12, "operation": "DELETE" }],
|
|
434
|
+
"migration_id": "20261012T071951-delete_rows-archive-1-rows-of-film"
|
|
435
|
+
}
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
**`list_folder`**
|
|
439
|
+
|
|
440
|
+
```json
|
|
441
|
+
{ "folder": "datanotes/main/public/film/_archive" }
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
Answer:
|
|
445
|
+
|
|
446
|
+
```json
|
|
447
|
+
{
|
|
448
|
+
"folder": "datanotes/main/public/film/_archive",
|
|
449
|
+
"folders": [],
|
|
450
|
+
"files": ["datanotes/main/public/film/_archive/Battleship Potemkin.md"]
|
|
451
|
+
}
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
## Move rows to another table
|
|
455
|
+
|
|
456
|
+
`move_rows` moves rows to another table. During the move, it can `rename` keys, `set` values and `drop` keys, and it checks every row against the destination first. The engine reports keys the destination doesn’t know and never drops them silently. `relocate: true` also moves the notes to the destination’s folder.
|
|
457
|
+
|
|
458
|
+
**`create_table`**
|
|
459
|
+
|
|
460
|
+
```json
|
|
461
|
+
{
|
|
462
|
+
"name": "watchlist",
|
|
463
|
+
"description": "Films I plan to watch soon",
|
|
464
|
+
"columns": [
|
|
465
|
+
{
|
|
466
|
+
"name": "title",
|
|
467
|
+
"type": "string",
|
|
468
|
+
"required": true,
|
|
469
|
+
"description": "The film's title"
|
|
470
|
+
},
|
|
471
|
+
{ "name": "released", "type": "integer", "description": "Year the film came out" }
|
|
472
|
+
],
|
|
473
|
+
"filename": "{title}"
|
|
474
|
+
}
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
**`move_rows`**
|
|
478
|
+
|
|
479
|
+
```json
|
|
480
|
+
{
|
|
481
|
+
"table": "film",
|
|
482
|
+
"to_table": "watchlist",
|
|
483
|
+
"where": { "status": "to watch" },
|
|
484
|
+
"relocate": true
|
|
485
|
+
}
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
Refused:
|
|
489
|
+
|
|
490
|
+
```text
|
|
491
|
+
move_rows refused — nothing was written:
|
|
492
|
+
invalid datanotes/main/public/film/Battleship Potemkin.md: year is not a column of table "watchlist"
|
|
493
|
+
invalid datanotes/main/public/film/Battleship Potemkin.md: status is not a column of table "watchlist"
|
|
494
|
+
invalid datanotes/main/public/film/Charade.md: year is not a column of table "watchlist"
|
|
495
|
+
invalid datanotes/main/public/film/Charade.md: status is not a column of table "watchlist"
|
|
496
|
+
invalid datanotes/main/public/film/Metropolis.md: year is not a column of table "watchlist"
|
|
497
|
+
invalid datanotes/main/public/film/Metropolis.md: status is not a column of table "watchlist"
|
|
498
|
+
invalid datanotes/main/public/film/The General.md: year is not a column of table "watchlist"
|
|
499
|
+
invalid datanotes/main/public/film/The General.md: status is not a column of table "watchlist"
|
|
500
|
+
Hint: Write only the table's columns: describe_table lists them. To keep a new front matter key, add_column first. Then call move_rows again (dry_run: true checks without writing).
|
|
501
|
+
Docs: https://datanotes.dev/guides/database-objects/tables.md#describe-a-table-before-writing-to-it (offline: read_docs("guides/database-objects/tables#describe-a-table-before-writing-to-it"))
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
The watchlist has no `status`, `tags` or `rating` column, so the call drops them, and `year` becomes `released`:
|
|
505
|
+
|
|
506
|
+
**`move_rows`**
|
|
507
|
+
|
|
508
|
+
```json
|
|
509
|
+
{
|
|
510
|
+
"table": "film",
|
|
511
|
+
"to_table": "watchlist",
|
|
512
|
+
"where": { "status": "to watch" },
|
|
513
|
+
"rename": { "year": "released" },
|
|
514
|
+
"drop": ["status", "tags", "rating"],
|
|
515
|
+
"relocate": true
|
|
516
|
+
}
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
Answer (51 lines)
|
|
520
|
+
|
|
521
|
+
```json
|
|
522
|
+
{
|
|
523
|
+
"ok": true,
|
|
524
|
+
"op": "move_rows",
|
|
525
|
+
"notes_changed": 4,
|
|
526
|
+
"files_moved": 4,
|
|
527
|
+
"planned_edits": [
|
|
528
|
+
{
|
|
529
|
+
"path": "datanotes/main/public/film/Battleship Potemkin.md",
|
|
530
|
+
"set": { "table": "main.public.watchlist", "released": 1925 },
|
|
531
|
+
"remove": ["year", "status"]
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
"path": "datanotes/main/public/film/Charade.md",
|
|
535
|
+
"set": { "table": "main.public.watchlist", "released": 1963 },
|
|
536
|
+
"remove": ["year", "status"]
|
|
537
|
+
},
|
|
538
|
+
{
|
|
539
|
+
"path": "datanotes/main/public/film/Metropolis.md",
|
|
540
|
+
"set": { "table": "main.public.watchlist", "released": 1927 },
|
|
541
|
+
"remove": ["year", "status"]
|
|
542
|
+
},
|
|
543
|
+
{
|
|
544
|
+
"path": "datanotes/main/public/film/The General.md",
|
|
545
|
+
"set": { "table": "main.public.watchlist", "released": 1926 },
|
|
546
|
+
"remove": ["year", "status"]
|
|
547
|
+
}
|
|
548
|
+
],
|
|
549
|
+
"planned_moves": [
|
|
550
|
+
{
|
|
551
|
+
"from": "datanotes/main/public/film/Battleship Potemkin.md",
|
|
552
|
+
"to": "datanotes/main/public/watchlist/Battleship Potemkin.md"
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
"from": "datanotes/main/public/film/Charade.md",
|
|
556
|
+
"to": "datanotes/main/public/watchlist/Charade.md"
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
"from": "datanotes/main/public/film/Metropolis.md",
|
|
560
|
+
"to": "datanotes/main/public/watchlist/Metropolis.md"
|
|
561
|
+
},
|
|
562
|
+
{
|
|
563
|
+
"from": "datanotes/main/public/film/The General.md",
|
|
564
|
+
"to": "datanotes/main/public/watchlist/The General.md"
|
|
565
|
+
}
|
|
566
|
+
],
|
|
567
|
+
"commits": [
|
|
568
|
+
{ "table": "main.public.film", "version": 22, "operation": "MOVE ROWS" },
|
|
569
|
+
{ "table": "main.public.watchlist", "version": 1, "operation": "MOVE ROWS" }
|
|
570
|
+
],
|
|
571
|
+
"migration_id": "20261012T071951-move_rows-move-4-rows-from-film-to-watch"
|
|
572
|
+
}
|
|
573
|
+
```
|