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.
Files changed (181) hide show
  1. package/NOTICE +9 -0
  2. package/README.md +207 -28
  3. package/SECURITY.md +92 -45
  4. package/dist/THIRD-PARTY-NOTICES.txt +682 -0
  5. package/dist/api/catalog.d.cts +69 -0
  6. package/dist/api/catalog.d.ts +50 -2
  7. package/dist/api/cli-options.d.cts +39 -0
  8. package/dist/api/cli-options.d.ts +39 -0
  9. package/dist/api/client.d.cts +89 -0
  10. package/dist/api/client.d.ts +19 -30
  11. package/dist/api/docs.d.cts +211 -0
  12. package/dist/api/docs.d.ts +211 -0
  13. package/dist/api/guidance.d.cts +81 -0
  14. package/dist/api/guidance.d.ts +81 -0
  15. package/dist/api/index.cjs +6610 -2247
  16. package/dist/api/index.d.cts +13 -0
  17. package/dist/api/index.d.ts +10 -7
  18. package/dist/api/index.js +6610 -2247
  19. package/dist/api/local.cjs +118 -6
  20. package/dist/api/local.d.cts +95 -0
  21. package/dist/api/local.d.ts +70 -6
  22. package/dist/api/local.js +104 -6
  23. package/dist/api/mcp.cjs +17384 -0
  24. package/dist/api/mcp.d.cts +108 -0
  25. package/dist/api/mcp.d.ts +108 -0
  26. package/dist/api/mcp.js +17334 -0
  27. package/dist/api/otlp.d.cts +65 -0
  28. package/dist/api/redact.d.cts +17 -0
  29. package/dist/api/redact.d.ts +17 -0
  30. package/dist/api/requests.d.cts +26 -0
  31. package/dist/api/requests.d.ts +14 -16
  32. package/dist/api/results.d.cts +16 -0
  33. package/dist/api/results.d.ts +2 -1
  34. package/dist/api/tokens.d.cts +7 -0
  35. package/dist/datanotes.cjs +62911 -28409
  36. package/dist/docs/administration/configuration.md +59 -0
  37. package/dist/docs/administration/docker.md +80 -0
  38. package/dist/docs/administration/git-sync.md +71 -0
  39. package/dist/docs/administration/limits.md +69 -0
  40. package/dist/docs/administration/run-the-service.md +219 -0
  41. package/dist/docs/administration/status.md +61 -0
  42. package/dist/docs/administration/use-with-obsidian.md +75 -0
  43. package/dist/docs/api/operations/add_column.md +49 -0
  44. package/dist/docs/api/operations/add_constraint.md +55 -0
  45. package/dist/docs/api/operations/adopt_rows.md +50 -0
  46. package/dist/docs/api/operations/align_relations.md +41 -0
  47. package/dist/docs/api/operations/alter_column.md +46 -0
  48. package/dist/docs/api/operations/alter_table.md +67 -0
  49. package/dist/docs/api/operations/batch.md +48 -0
  50. package/dist/docs/api/operations/changes_stream.md +28 -0
  51. package/dist/docs/api/operations/check_table.md +29 -0
  52. package/dist/docs/api/operations/clone_table.md +48 -0
  53. package/dist/docs/api/operations/comment_on.md +42 -0
  54. package/dist/docs/api/operations/configure_database.md +52 -0
  55. package/dist/docs/api/operations/create_table.md +78 -0
  56. package/dist/docs/api/operations/create_view.md +54 -0
  57. package/dist/docs/api/operations/create_webhook.md +37 -0
  58. package/dist/docs/api/operations/define_base.md +52 -0
  59. package/dist/docs/api/operations/delete_rows.md +43 -0
  60. package/dist/docs/api/operations/delete_webhook.md +31 -0
  61. package/dist/docs/api/operations/describe_database.md +30 -0
  62. package/dist/docs/api/operations/describe_history.md +40 -0
  63. package/dist/docs/api/operations/describe_semantic_index.md +24 -0
  64. package/dist/docs/api/operations/describe_table.md +38 -0
  65. package/dist/docs/api/operations/docs.md +13 -0
  66. package/dist/docs/api/operations/drop_column.md +41 -0
  67. package/dist/docs/api/operations/drop_constraint.md +39 -0
  68. package/dist/docs/api/operations/drop_table.md +43 -0
  69. package/dist/docs/api/operations/drop_view.md +38 -0
  70. package/dist/docs/api/operations/engine_status.md +23 -0
  71. package/dist/docs/api/operations/graph_neighbors.md +32 -0
  72. package/dist/docs/api/operations/graph_path.md +32 -0
  73. package/dist/docs/api/operations/graph_traverse.md +43 -0
  74. package/dist/docs/api/operations/identify_session.md +24 -0
  75. package/dist/docs/api/operations/infer_table.md +43 -0
  76. package/dist/docs/api/operations/insert_row.md +48 -0
  77. package/dist/docs/api/operations/list_changes.md +35 -0
  78. package/dist/docs/api/operations/list_folder.md +28 -0
  79. package/dist/docs/api/operations/list_link_targets.md +44 -0
  80. package/dist/docs/api/operations/list_migrations.md +35 -0
  81. package/dist/docs/api/operations/list_tables.md +32 -0
  82. package/dist/docs/api/operations/list_webhooks.md +23 -0
  83. package/dist/docs/api/operations/manual_index.md +14 -0
  84. package/dist/docs/api/operations/manual_page.md +22 -0
  85. package/dist/docs/api/operations/merge_rows.md +44 -0
  86. package/dist/docs/api/operations/move_rows.md +52 -0
  87. package/dist/docs/api/operations/openapi.md +13 -0
  88. package/dist/docs/api/operations/openapi_post.md +20 -0
  89. package/dist/docs/api/operations/read_note.md +29 -0
  90. package/dist/docs/api/operations/recompute_columns.md +44 -0
  91. package/dist/docs/api/operations/record_tool_call.md +36 -0
  92. package/dist/docs/api/operations/rename_column.md +44 -0
  93. package/dist/docs/api/operations/rename_value.md +45 -0
  94. package/dist/docs/api/operations/restore_database.md +51 -0
  95. package/dist/docs/api/operations/restore_table.md +46 -0
  96. package/dist/docs/api/operations/search_notes.md +28 -0
  97. package/dist/docs/api/operations/select_rows.md +61 -0
  98. package/dist/docs/api/operations/semantic_search.md +34 -0
  99. package/dist/docs/api/operations/semantic_search_docs.md +26 -0
  100. package/dist/docs/api/operations/set_table_bases.md +44 -0
  101. package/dist/docs/api/operations/status.md +13 -0
  102. package/dist/docs/api/operations/stop_engine.md +23 -0
  103. package/dist/docs/api/operations/sync_semantic_index.md +33 -0
  104. package/dist/docs/api/operations/table_changes.md +31 -0
  105. package/dist/docs/api/operations/tags/auxiliary.md +14 -0
  106. package/dist/docs/api/operations/tags/change-feed.md +8 -0
  107. package/dist/docs/api/operations/tags/history.md +17 -0
  108. package/dist/docs/api/operations/tags/queries.md +15 -0
  109. package/dist/docs/api/operations/tags/rows-dml.md +16 -0
  110. package/dist/docs/api/operations/tags/schema-ddl.md +22 -0
  111. package/dist/docs/api/operations/tags/service.md +15 -0
  112. package/dist/docs/api/operations/tags/tokens.md +13 -0
  113. package/dist/docs/api/operations/tokens_create.md +34 -0
  114. package/dist/docs/api/operations/tokens_delete.md +29 -0
  115. package/dist/docs/api/operations/tokens_list.md +21 -0
  116. package/dist/docs/api/operations/tokens_me.md +20 -0
  117. package/dist/docs/api/operations/tokens_rotate.md +29 -0
  118. package/dist/docs/api/operations/tokens_update.md +34 -0
  119. package/dist/docs/api/operations/undo_migration.md +46 -0
  120. package/dist/docs/api/operations/update_row.md +60 -0
  121. package/dist/docs/api/operations/update_rows.md +46 -0
  122. package/dist/docs/api/operations/vacuum_table.md +37 -0
  123. package/dist/docs/api.md +135 -0
  124. package/dist/docs/develop/build-an-app.md +320 -0
  125. package/dist/docs/develop/build-on-datanotes.md +138 -0
  126. package/dist/docs/develop/change-feed-and-webhooks.md +70 -0
  127. package/dist/docs/develop/client.md +116 -0
  128. package/dist/docs/develop/concurrency.md +153 -0
  129. package/dist/docs/develop/http-api.md +79 -0
  130. package/dist/docs/develop/telemetry.md +86 -0
  131. package/dist/docs/guides/agents/docs-offline.md +99 -0
  132. package/dist/docs/guides/agents/how-agents-use-datanotes.md +124 -0
  133. package/dist/docs/guides/agents/prompts.md +495 -0
  134. package/dist/docs/guides/agents/reading-errors.md +112 -0
  135. package/dist/docs/guides/data-quality/check-constraints.md +379 -0
  136. package/dist/docs/guides/data-quality/check-table.md +63 -0
  137. package/dist/docs/guides/data-quality/hand-edits.md +507 -0
  138. package/dist/docs/guides/data-quality/sync-between-devices.md +51 -0
  139. package/dist/docs/guides/data-quality/validation.md +90 -0
  140. package/dist/docs/guides/database-objects/bases.md +480 -0
  141. package/dist/docs/guides/database-objects/catalogs-and-schemas.md +897 -0
  142. package/dist/docs/guides/database-objects/columns.md +1332 -0
  143. package/dist/docs/guides/database-objects/relations.md +1454 -0
  144. package/dist/docs/guides/database-objects/tables.md +1404 -0
  145. package/dist/docs/guides/database-objects/views.md +1003 -0
  146. package/dist/docs/guides/history/back-up.md +195 -0
  147. package/dist/docs/guides/history/change-data-feed.md +247 -0
  148. package/dist/docs/guides/history/journal-and-undo.md +262 -0
  149. package/dist/docs/guides/history/restore.md +341 -0
  150. package/dist/docs/guides/history/table-history.md +657 -0
  151. package/dist/docs/guides/history/vacuum.md +35 -0
  152. package/dist/docs/guides/read-and-write/automatic-links.md +768 -0
  153. package/dist/docs/guides/read-and-write/batch.md +139 -0
  154. package/dist/docs/guides/read-and-write/import-notes.md +896 -0
  155. package/dist/docs/guides/read-and-write/joins-and-aggregates.md +251 -0
  156. package/dist/docs/guides/read-and-write/read-and-filter.md +536 -0
  157. package/dist/docs/guides/read-and-write/write-rows.md +573 -0
  158. package/dist/docs/guides/search/link-graph.md +146 -0
  159. package/dist/docs/guides/search/semantic.md +133 -0
  160. package/dist/docs/guides/search/text.md +142 -0
  161. package/dist/docs/guides/security/security-model.md +110 -0
  162. package/dist/docs/guides/security/tokens.md +60 -0
  163. package/dist/docs/guides/security/who-did-what.md +42 -0
  164. package/dist/docs/index.md +113 -0
  165. package/dist/docs/llms.txt +33 -0
  166. package/dist/docs/reference/cli.md +136 -0
  167. package/dist/docs/reference/compatibility.md +63 -0
  168. package/dist/docs/reference/errors.md +72 -0
  169. package/dist/docs/reference/glossary.md +161 -0
  170. package/dist/docs/reference/operations/auxiliary.md +116 -0
  171. package/dist/docs/reference/operations/history.md +168 -0
  172. package/dist/docs/reference/operations/queries.md +169 -0
  173. package/dist/docs/reference/operations/rows.md +185 -0
  174. package/dist/docs/reference/operations/schema.md +316 -0
  175. package/dist/docs/reference/operations.md +96 -0
  176. package/dist/docs/reference/settings.md +31 -0
  177. package/dist/docs/release-notes.md +67 -0
  178. package/dist/docs/start/connect-agents.md +204 -0
  179. package/dist/docs/start/how-it-works.md +317 -0
  180. package/dist/docs/start/quick-start.md +126 -0
  181. package/package.json +59 -14
@@ -0,0 +1,1332 @@
1
+ # Columns and types
2
+
3
+ > Choose column types and attributes, compute generated columns, name rows after a time, and change the columns of a table that already has rows.
4
+
5
+ You declare columns once, in `metastore.yaml`, and the engine checks every write against them. Changing a column changes every row that has it, in one undoable operation.
6
+
7
+ The examples on this page share one fresh vault, which starts with a `film` table holding Nosferatu and Metropolis.
8
+
9
+ ## Add a sparse column
10
+
11
+ A new column is sparse by default: the table knows it, but only the rows that get a value store it. Use sparse columns for things you record sometimes. Every column needs a `description`, and `label` and `aliases` add other words for it. They tell an agent what the column means, so it reuses the column instead of adding a second one. `note` links to a note that documents the column.
12
+
13
+ **`add_column`**
14
+
15
+ ```json
16
+ {
17
+ "table": "film",
18
+ "column": {
19
+ "name": "minutes",
20
+ "type": "integer",
21
+ "min": 1,
22
+ "label": "Runtime",
23
+ "aliases": ["runtime", "length"],
24
+ "description": "Running time in minutes",
25
+ "note": "[[How I count minutes]]"
26
+ }
27
+ }
28
+ ```
29
+
30
+ Answer:
31
+
32
+ ```json
33
+ {
34
+ "ok": true,
35
+ "op": "add_column",
36
+ "planned_texts": ["datanotes/metastore.yaml"],
37
+ "commits": [{ "table": "main.public.film", "version": 3, "operation": "ADD COLUMNS" }],
38
+ "migration_id": "20261012T071946-add_column-add-column-minutes-to-film"
39
+ }
40
+ ```
41
+
42
+ **`update_row`**
43
+
44
+ ```json
45
+ {
46
+ "table": "film",
47
+ "path": "datanotes/main/public/film/Metropolis.md",
48
+ "set": { "minutes": 153 }
49
+ }
50
+ ```
51
+
52
+ Only Metropolis has a value. The Nosferatu note has no `minutes` key, so it reads as `null`:
53
+
54
+ **`select_rows`**
55
+
56
+ ```json
57
+ { "table": "film", "columns": ["title", "minutes"] }
58
+ ```
59
+
60
+ Answer:
61
+
62
+ ```json
63
+ {
64
+ "table": "main.public.film",
65
+ "total": 2,
66
+ "rows": [
67
+ {
68
+ "path": "datanotes/main/public/film/Metropolis.md",
69
+ "title": "Metropolis",
70
+ "minutes": 153
71
+ },
72
+ {
73
+ "path": "datanotes/main/public/film/Nosferatu.md",
74
+ "title": "Nosferatu",
75
+ "minutes": null
76
+ }
77
+ ]
78
+ }
79
+ ```
80
+
81
+ ## Add a dense column to every row
82
+
83
+ `dense: true` writes the column on every row, existing rows included, with its `default`.
84
+
85
+ **`add_column`**
86
+
87
+ ```json
88
+ {
89
+ "table": "film",
90
+ "column": {
91
+ "name": "favourite",
92
+ "type": "boolean",
93
+ "default": false,
94
+ "description": "True for the films I would watch again and again",
95
+ "dense": true
96
+ }
97
+ }
98
+ ```
99
+
100
+ Answer:
101
+
102
+ ```json
103
+ {
104
+ "ok": true,
105
+ "op": "add_column",
106
+ "notes_changed": 2,
107
+ "planned_edits": [
108
+ {
109
+ "path": "datanotes/main/public/film/Metropolis.md",
110
+ "set": { "favourite": false },
111
+ "remove": []
112
+ },
113
+ {
114
+ "path": "datanotes/main/public/film/Nosferatu.md",
115
+ "set": { "favourite": false },
116
+ "remove": []
117
+ }
118
+ ],
119
+ "planned_texts": ["datanotes/metastore.yaml"],
120
+ "commits": [{ "table": "main.public.film", "version": 5, "operation": "ADD COLUMNS" }],
121
+ "migration_id": "20261012T071947-add_column-add-column-favourite-to-film"
122
+ }
123
+ ```
124
+
125
+ **`select_rows`**
126
+
127
+ ```json
128
+ { "table": "film", "columns": ["title", "favourite"] }
129
+ ```
130
+
131
+ Answer:
132
+
133
+ ```json
134
+ {
135
+ "table": "main.public.film",
136
+ "total": 2,
137
+ "rows": [
138
+ {
139
+ "path": "datanotes/main/public/film/Metropolis.md",
140
+ "title": "Metropolis",
141
+ "favourite": false
142
+ },
143
+ {
144
+ "path": "datanotes/main/public/film/Nosferatu.md",
145
+ "title": "Nosferatu",
146
+ "favourite": false
147
+ }
148
+ ]
149
+ }
150
+ ```
151
+
152
+ ## Turn an enum into an ordered scale
153
+
154
+ An `enum` accepts only its `values`. With `ordered: true`, the values form a scale: filters, sorting and averages use each value’s position (1, 2…), while the notes keep the words. Here the last value is `seen`; the next example renames it.
155
+
156
+ **`add_column`**
157
+
158
+ ```json
159
+ {
160
+ "table": "film",
161
+ "column": {
162
+ "name": "status",
163
+ "type": "enum",
164
+ "values": ["to watch", "seen"],
165
+ "ordered": true,
166
+ "description": "Where the film is on my list"
167
+ }
168
+ }
169
+ ```
170
+
171
+ Answer:
172
+
173
+ ```json
174
+ {
175
+ "ok": true,
176
+ "op": "add_column",
177
+ "planned_texts": ["datanotes/metastore.yaml"],
178
+ "commits": [{ "table": "main.public.film", "version": 6, "operation": "ADD COLUMNS" }],
179
+ "migration_id": "20261012T071947-add_column-add-column-status-to-film"
180
+ }
181
+ ```
182
+
183
+ **`update_row`**
184
+
185
+ ```json
186
+ {
187
+ "table": "film",
188
+ "path": "datanotes/main/public/film/Nosferatu.md",
189
+ "set": { "status": "seen" }
190
+ }
191
+ ```
192
+
193
+ **`update_row`**
194
+
195
+ ```json
196
+ {
197
+ "table": "film",
198
+ "path": "datanotes/main/public/film/Metropolis.md",
199
+ "set": { "status": "to watch" }
200
+ }
201
+ ```
202
+
203
+ Sorting follows the scale, furthest along first:
204
+
205
+ **`select_rows`**
206
+
207
+ ```json
208
+ { "table": "film", "columns": ["title", "status"], "order_by": "-status" }
209
+ ```
210
+
211
+ Answer:
212
+
213
+ ```json
214
+ {
215
+ "table": "main.public.film",
216
+ "total": 2,
217
+ "rows": [
218
+ {
219
+ "path": "datanotes/main/public/film/Nosferatu.md",
220
+ "title": "Nosferatu",
221
+ "status": "seen"
222
+ },
223
+ {
224
+ "path": "datanotes/main/public/film/Metropolis.md",
225
+ "title": "Metropolis",
226
+ "status": "to watch"
227
+ }
228
+ ]
229
+ }
230
+ ```
231
+
232
+ So does a filter. `gt: "to watch"` means further along than `to watch`:
233
+
234
+ **`select_rows`**
235
+
236
+ ```json
237
+ {
238
+ "table": "film",
239
+ "columns": ["title", "status"],
240
+ "where": { "status": { "gt": "to watch" } }
241
+ }
242
+ ```
243
+
244
+ Answer:
245
+
246
+ ```json
247
+ {
248
+ "table": "main.public.film",
249
+ "total": 1,
250
+ "rows": [
251
+ {
252
+ "path": "datanotes/main/public/film/Nosferatu.md",
253
+ "title": "Nosferatu",
254
+ "status": "seen"
255
+ }
256
+ ]
257
+ }
258
+ ```
259
+
260
+ ## Rename an enum value
261
+
262
+ `rename_value` renames one value in the definition and on every row. The value keeps its position on the scale. Here `seen` becomes `watched`.
263
+
264
+ **`rename_value`**
265
+
266
+ ```json
267
+ { "table": "film", "column": "status", "from_value": "seen", "to_value": "watched" }
268
+ ```
269
+
270
+ Answer:
271
+
272
+ ```json
273
+ {
274
+ "ok": true,
275
+ "op": "rename_value",
276
+ "notes_changed": 1,
277
+ "planned_edits": [
278
+ {
279
+ "path": "datanotes/main/public/film/Nosferatu.md",
280
+ "set": { "status": "watched" },
281
+ "remove": []
282
+ }
283
+ ],
284
+ "planned_texts": ["datanotes/metastore.yaml"],
285
+ "commits": [{ "table": "main.public.film", "version": 9, "operation": "UPDATE" }],
286
+ "migration_id": "20261012T071947-rename_value-rename-film-status-value-seen-"
287
+ }
288
+ ```
289
+
290
+ **`select_rows`**
291
+
292
+ ```json
293
+ { "table": "film", "columns": ["title", "status"], "where": { "title": "Nosferatu" } }
294
+ ```
295
+
296
+ Answer:
297
+
298
+ ```json
299
+ {
300
+ "table": "main.public.film",
301
+ "total": 1,
302
+ "rows": [
303
+ {
304
+ "path": "datanotes/main/public/film/Nosferatu.md",
305
+ "title": "Nosferatu",
306
+ "status": "watched"
307
+ }
308
+ ]
309
+ }
310
+ ```
311
+
312
+ ## Describe what each enum value means
313
+
314
+ `value_descriptions` says when to use each value of an enum. `describe_table` shows the descriptions, and so does the refusal of a wrong value, so an agent picks the right one.
315
+
316
+ **`alter_column`**
317
+
318
+ ```json
319
+ {
320
+ "table": "film",
321
+ "column": "status",
322
+ "changes": {
323
+ "value_descriptions": {
324
+ "to watch": "on my list, not seen yet",
325
+ "watched": "seen to the end"
326
+ }
327
+ }
328
+ }
329
+ ```
330
+
331
+ Answer:
332
+
333
+ ```json
334
+ {
335
+ "ok": true,
336
+ "op": "alter_column",
337
+ "planned_texts": ["datanotes/metastore.yaml"],
338
+ "commits": [
339
+ { "table": "main.public.film", "version": 10, "operation": "CHANGE COLUMN" }
340
+ ],
341
+ "migration_id": "20261012T071947-alter_column-alter-column-status-in-film"
342
+ }
343
+ ```
344
+
345
+ **`update_row`**
346
+
347
+ ```json
348
+ {
349
+ "table": "film",
350
+ "path": "datanotes/main/public/film/Nosferatu.md",
351
+ "set": { "status": "finished" }
352
+ }
353
+ ```
354
+
355
+ Refused:
356
+
357
+ ```text
358
+ update_row refused — nothing was written:
359
+ invalid datanotes/main/public/film/Nosferatu.md: status must be one of: to watch (on my list, not seen yet); watched (seen to the end)
360
+ Hint: Use one of the allowed values listed in the message, written exactly; describe_table shows what each one means. To add a value, alter_column the enum. Then call update_row again (dry_run: true checks without writing).
361
+ Docs: https://datanotes.dev/guides/database-objects/columns.md#describe-what-each-enum-value-means (offline: read_docs("guides/database-objects/columns#describe-what-each-enum-value-means"))
362
+ ```
363
+
364
+ ## Change a column’s attributes
365
+
366
+ `alter_column` changes a column’s attributes. If rows would break the new definition, the engine refuses the change, lists those rows and changes nothing.
367
+
368
+ **`alter_column`**
369
+
370
+ ```json
371
+ { "table": "film", "column": "minutes", "changes": { "max": 120 } }
372
+ ```
373
+
374
+ Refused:
375
+
376
+ ```text
377
+ alter_column refused — nothing was written:
378
+ invalid datanotes/main/public/film/Metropolis.md: minutes must be <= 120
379
+ Hint: Give a value inside the column's range (the message names the bound); describe_table shows its min and max. Then call alter_column again (dry_run: true checks without writing).
380
+ 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"))
381
+ ```
382
+
383
+ A change that every row satisfies goes through:
384
+
385
+ **`alter_column`**
386
+
387
+ ```json
388
+ {
389
+ "table": "film",
390
+ "column": "minutes",
391
+ "changes": { "max": 300, "description": "Running time of the commonly cited version" }
392
+ }
393
+ ```
394
+
395
+ Answer:
396
+
397
+ ```json
398
+ {
399
+ "ok": true,
400
+ "op": "alter_column",
401
+ "planned_texts": ["datanotes/metastore.yaml"],
402
+ "commits": [
403
+ { "table": "main.public.film", "version": 11, "operation": "CHANGE COLUMN" }
404
+ ],
405
+ "migration_id": "20261012T071947-alter_column-alter-column-minutes-in-film"
406
+ }
407
+ ```
408
+
409
+ `null` removes an attribute. Without `max`, any runtime is valid again.
410
+
411
+ **`alter_column`**
412
+
413
+ ```json
414
+ { "table": "film", "column": "minutes", "changes": { "max": null } }
415
+ ```
416
+
417
+ Answer:
418
+
419
+ ```json
420
+ {
421
+ "ok": true,
422
+ "op": "alter_column",
423
+ "planned_texts": ["datanotes/metastore.yaml"],
424
+ "commits": [
425
+ { "table": "main.public.film", "version": 12, "operation": "CHANGE COLUMN" }
426
+ ],
427
+ "migration_id": "20261012T071947-alter_column-alter-column-minutes-in-film-2"
428
+ }
429
+ ```
430
+
431
+ `dense: true` makes the column dense, so the engine writes it on every row, including Nosferatu, which has no value.
432
+
433
+ **`alter_column`**
434
+
435
+ ```json
436
+ { "table": "film", "column": "minutes", "changes": { "dense": true } }
437
+ ```
438
+
439
+ Answer:
440
+
441
+ ```json
442
+ {
443
+ "ok": true,
444
+ "op": "alter_column",
445
+ "notes_changed": 1,
446
+ "planned_edits": [
447
+ {
448
+ "path": "datanotes/main/public/film/Nosferatu.md",
449
+ "set": { "minutes": null },
450
+ "remove": []
451
+ }
452
+ ],
453
+ "planned_texts": ["datanotes/metastore.yaml"],
454
+ "commits": [
455
+ { "table": "main.public.film", "version": 13, "operation": "CHANGE COLUMN" }
456
+ ],
457
+ "migration_id": "20261012T071947-alter_column-alter-column-minutes-in-film-3"
458
+ }
459
+ ```
460
+
461
+ `datanotes/main/public/film/Nosferatu.md` now reads:
462
+
463
+ ```markdown
464
+ ---
465
+ table: main.public.film
466
+ id: 01a12efb-5a12-7e85-a3a1-85a2fe3425ec
467
+ title: Nosferatu
468
+ year: 1922
469
+ favourite: false
470
+ status: watched
471
+ minutes: null
472
+ ---
473
+ ```
474
+
475
+ `dense: false` makes the column sparse again. Rows written from now on store it only when it has a value, and the empty `minutes` already in Nosferatu stays:
476
+
477
+ **`alter_column`**
478
+
479
+ ```json
480
+ { "table": "film", "column": "minutes", "changes": { "dense": false } }
481
+ ```
482
+
483
+ Answer:
484
+
485
+ ```json
486
+ {
487
+ "ok": true,
488
+ "op": "alter_column",
489
+ "planned_texts": ["datanotes/metastore.yaml"],
490
+ "commits": [
491
+ { "table": "main.public.film", "version": 14, "operation": "CHANGE COLUMN" }
492
+ ],
493
+ "migration_id": "20261012T071947-alter_column-alter-column-minutes-in-film-4"
494
+ }
495
+ ```
496
+
497
+ `datanotes/main/public/film/Nosferatu.md` now reads:
498
+
499
+ ```markdown
500
+ ---
501
+ table: main.public.film
502
+ id: 01a12efb-5a12-7e85-a3a1-85a2fe3425ec
503
+ title: Nosferatu
504
+ year: 1922
505
+ favourite: false
506
+ status: watched
507
+ minutes: null
508
+ ---
509
+ ```
510
+
511
+ ## Rename a column
512
+
513
+ `rename_column` renames the key in `metastore.yaml` and on every row.
514
+
515
+ **`rename_column`**
516
+
517
+ ```json
518
+ { "table": "film", "from_column": "favourite", "to_column": "loved_it" }
519
+ ```
520
+
521
+ Answer:
522
+
523
+ ```json
524
+ {
525
+ "ok": true,
526
+ "op": "rename_column",
527
+ "notes_changed": 2,
528
+ "planned_edits": [
529
+ {
530
+ "path": "datanotes/main/public/film/Metropolis.md",
531
+ "set": { "loved_it": false },
532
+ "remove": ["favourite"]
533
+ },
534
+ {
535
+ "path": "datanotes/main/public/film/Nosferatu.md",
536
+ "set": { "loved_it": false },
537
+ "remove": ["favourite"]
538
+ }
539
+ ],
540
+ "planned_texts": ["datanotes/metastore.yaml"],
541
+ "commits": [
542
+ { "table": "main.public.film", "version": 15, "operation": "RENAME COLUMN" }
543
+ ],
544
+ "migration_id": "20261012T071947-rename_column-rename-column-favourite-to-lov"
545
+ }
546
+ ```
547
+
548
+ **`select_rows`**
549
+
550
+ ```json
551
+ { "table": "film", "columns": ["title", "loved_it"] }
552
+ ```
553
+
554
+ Answer:
555
+
556
+ ```json
557
+ {
558
+ "table": "main.public.film",
559
+ "total": 2,
560
+ "rows": [
561
+ {
562
+ "path": "datanotes/main/public/film/Metropolis.md",
563
+ "title": "Metropolis",
564
+ "loved_it": false
565
+ },
566
+ {
567
+ "path": "datanotes/main/public/film/Nosferatu.md",
568
+ "title": "Nosferatu",
569
+ "loved_it": false
570
+ }
571
+ ]
572
+ }
573
+ ```
574
+
575
+ ## Drop a column and undo the drop
576
+
577
+ `drop_column` removes the column and its values from every row. The journal keeps the values, so `undo_migration` brings them back.
578
+
579
+ **`drop_column`**
580
+
581
+ ```json
582
+ { "table": "film", "column": "loved_it" }
583
+ ```
584
+
585
+ Answer:
586
+
587
+ ```json
588
+ {
589
+ "ok": true,
590
+ "op": "drop_column",
591
+ "notes_changed": 2,
592
+ "planned_edits": [
593
+ {
594
+ "path": "datanotes/main/public/film/Metropolis.md",
595
+ "set": {},
596
+ "remove": ["loved_it"]
597
+ },
598
+ {
599
+ "path": "datanotes/main/public/film/Nosferatu.md",
600
+ "set": {},
601
+ "remove": ["loved_it"]
602
+ }
603
+ ],
604
+ "planned_texts": ["datanotes/metastore.yaml"],
605
+ "commits": [{ "table": "main.public.film", "version": 16, "operation": "DROP COLUMNS" }],
606
+ "migration_id": "20261012T071947-drop_column-drop-column-loved_it-from-film"
607
+ }
608
+ ```
609
+
610
+ **`undo_migration`**
611
+
612
+ ```json
613
+ { "migration_id": "20261012T071947-drop_column-drop-column-loved_it-from-film" }
614
+ ```
615
+
616
+ Answer:
617
+
618
+ ```json
619
+ {
620
+ "ok": true,
621
+ "op": "undo_migration",
622
+ "undoes": "20261012T071947-drop_column-drop-column-loved_it-from-film",
623
+ "migration_id": "20261012T071947-undo_migration-undo-20261012t071947-drop_colu",
624
+ "conflicts": [],
625
+ "failed": []
626
+ }
627
+ ```
628
+
629
+ The values are back:
630
+
631
+ **`select_rows`**
632
+
633
+ ```json
634
+ { "table": "film", "columns": ["title", "loved_it"] }
635
+ ```
636
+
637
+ Answer:
638
+
639
+ ```json
640
+ {
641
+ "table": "main.public.film",
642
+ "total": 2,
643
+ "rows": [
644
+ {
645
+ "path": "datanotes/main/public/film/Metropolis.md",
646
+ "title": "Metropolis",
647
+ "loved_it": false
648
+ },
649
+ {
650
+ "path": "datanotes/main/public/film/Nosferatu.md",
651
+ "title": "Nosferatu",
652
+ "loved_it": false
653
+ }
654
+ ]
655
+ }
656
+ ```
657
+
658
+ ## Default to today’s date or the current time
659
+
660
+ As a default, `"{today}"` gives a date and `"{now}"` gives a date-time. The engine evaluates them when it writes the row.
661
+
662
+ **`add_column`**
663
+
664
+ ```json
665
+ {
666
+ "table": "film",
667
+ "column": {
668
+ "name": "added",
669
+ "type": "date",
670
+ "default": "{today}",
671
+ "description": "The day I put the film on my list"
672
+ }
673
+ }
674
+ ```
675
+
676
+ Answer:
677
+
678
+ ```json
679
+ {
680
+ "ok": true,
681
+ "op": "add_column",
682
+ "planned_texts": ["datanotes/metastore.yaml"],
683
+ "commits": [{ "table": "main.public.film", "version": 18, "operation": "ADD COLUMNS" }],
684
+ "migration_id": "20261012T071947-add_column-add-column-added-to-film"
685
+ }
686
+ ```
687
+
688
+ **`add_column`**
689
+
690
+ ```json
691
+ {
692
+ "table": "film",
693
+ "column": {
694
+ "name": "added_at",
695
+ "type": "datetime",
696
+ "default": "{now}",
697
+ "description": "When I put the film on my list"
698
+ }
699
+ }
700
+ ```
701
+
702
+ **`insert_row`**
703
+
704
+ ```json
705
+ { "table": "film", "values": { "title": "Sherlock Jr.", "year": 1924 } }
706
+ ```
707
+
708
+ Answer:
709
+
710
+ ```json
711
+ {
712
+ "ok": true,
713
+ "op": "insert_row",
714
+ "files_created": 1,
715
+ "planned_creates": ["datanotes/main/public/film/Sherlock Jr..md"],
716
+ "commits": [{ "table": "main.public.film", "version": 20, "operation": "WRITE" }],
717
+ "migration_id": "20261012T071947-insert_row-insert-into-film"
718
+ }
719
+ ```
720
+
721
+ `datanotes/main/public/film/Sherlock Jr..md` now reads:
722
+
723
+ ```markdown
724
+ ---
725
+ table: main.public.film
726
+ id: 01a12efb-5b24-7686-937c-757e0d7b754a
727
+ loved_it: false
728
+ title: Sherlock Jr.
729
+ year: 1924
730
+ added: 2026-10-12
731
+ added_at: 2026-10-12T07:19:47Z
732
+ ---
733
+ ```
734
+
735
+ ## Store lists and structured values
736
+
737
+ A `list` column holds several values of its `items` type, and the engine checks each one. A `json` column stores any YAML Ain’t Markup Language (YAML) value as is, without checks, such as objects or lists of objects. Its name comes from JavaScript Object Notation (JSON).
738
+
739
+ **`add_column`**
740
+
741
+ ```json
742
+ {
743
+ "table": "film",
744
+ "column": {
745
+ "name": "seen_at",
746
+ "type": "list",
747
+ "items": "enum",
748
+ "values": ["cinema", "home", "outdoor screening"],
749
+ "description": "Every kind of place I saw the film in"
750
+ }
751
+ }
752
+ ```
753
+
754
+ Answer:
755
+
756
+ ```json
757
+ {
758
+ "ok": true,
759
+ "op": "add_column",
760
+ "planned_texts": ["datanotes/metastore.yaml"],
761
+ "commits": [{ "table": "main.public.film", "version": 21, "operation": "ADD COLUMNS" }],
762
+ "migration_id": "20261012T071947-add_column-add-column-seen_at-to-film"
763
+ }
764
+ ```
765
+
766
+ **`add_column`**
767
+
768
+ ```json
769
+ {
770
+ "table": "film",
771
+ "column": {
772
+ "name": "viewings",
773
+ "type": "json",
774
+ "description": "Each viewing: when, where, and a note on it"
775
+ }
776
+ }
777
+ ```
778
+
779
+ Answer:
780
+
781
+ ```json
782
+ {
783
+ "ok": true,
784
+ "op": "add_column",
785
+ "planned_texts": ["datanotes/metastore.yaml"],
786
+ "commits": [{ "table": "main.public.film", "version": 22, "operation": "ADD COLUMNS" }],
787
+ "migration_id": "20261012T071947-add_column-add-column-viewings-to-film"
788
+ }
789
+ ```
790
+
791
+ **`update_row`**
792
+
793
+ ```json
794
+ {
795
+ "table": "film",
796
+ "path": "datanotes/main/public/film/Nosferatu.md",
797
+ "set": {
798
+ "seen_at": ["outdoor screening", "home"],
799
+ "viewings": [
800
+ { "on": "2026-07-18", "where": "outdoor screening", "note": "live piano" },
801
+ {
802
+ "on": "2026-10-02",
803
+ "where": "home",
804
+ "note": "the shadow on the stairs still works"
805
+ }
806
+ ]
807
+ }
808
+ }
809
+ ```
810
+
811
+ Answer:
812
+
813
+ ```json
814
+ {
815
+ "ok": true,
816
+ "op": "update_row",
817
+ "notes_changed": 1,
818
+ "planned_edits": [
819
+ {
820
+ "path": "datanotes/main/public/film/Nosferatu.md",
821
+ "set": {
822
+ "seen_at": ["outdoor screening", "home"],
823
+ "viewings": [
824
+ { "on": "2026-07-18", "where": "outdoor screening", "note": "live piano" },
825
+ {
826
+ "on": "2026-10-02",
827
+ "where": "home",
828
+ "note": "the shadow on the stairs still works"
829
+ }
830
+ ]
831
+ },
832
+ "remove": []
833
+ }
834
+ ],
835
+ "commits": [{ "table": "main.public.film", "version": 23, "operation": "UPDATE" }],
836
+ "migration_id": "20261012T071947-update_row-update-film-3"
837
+ }
838
+ ```
839
+
840
+ `datanotes/main/public/film/Nosferatu.md` now reads:
841
+
842
+ ```markdown
843
+ ---
844
+ table: main.public.film
845
+ id: 01a12efb-5a12-7e85-a3a1-85a2fe3425ec
846
+ title: Nosferatu
847
+ year: 1922
848
+ loved_it: false
849
+ status: watched
850
+ minutes: null
851
+ seen_at:
852
+ - outdoor screening
853
+ - home
854
+ viewings:
855
+ - on: 2026-07-18
856
+ where: outdoor screening
857
+ note: live piano
858
+ - on: 2026-10-02
859
+ where: home
860
+ note: the shadow on the stairs still works
861
+ ---
862
+ ```
863
+
864
+ One wrong item makes the engine refuse the whole write:
865
+
866
+ **`update_row`**
867
+
868
+ ```json
869
+ {
870
+ "table": "film",
871
+ "path": "datanotes/main/public/film/Metropolis.md",
872
+ "set": { "seen_at": ["home", "festival"] }
873
+ }
874
+ ```
875
+
876
+ Refused:
877
+
878
+ ```text
879
+ update_row refused — nothing was written:
880
+ invalid datanotes/main/public/film/Metropolis.md: seen_at[1] must be one of: cinema; home; outdoor screening
881
+ Hint: Use one of the allowed values listed in the message, written exactly; describe_table shows what each one means. To add a value, alter_column the enum. Then call update_row again (dry_run: true checks without writing).
882
+ Docs: https://datanotes.dev/guides/database-objects/columns.md#describe-what-each-enum-value-means (offline: read_docs("guides/database-objects/columns#describe-what-each-enum-value-means"))
883
+ ```
884
+
885
+ ## Compute a column from other columns
886
+
887
+ The engine computes a `generated` column from other columns on every write, and you can’t set it yourself. The expression takes one of three forms:
888
+
889
+ * **A column name**: the value of that column
890
+ * **`date(col)`**: the date of `col`, with an optional day shift
891
+ * **A template**: text with `{col}` and `{col:FORMAT}` placeholders
892
+
893
+ `min(…)`, `max(…)` and `coalesce(…)` pick among several columns.
894
+
895
+ **`create_table`**
896
+
897
+ ```json
898
+ {
899
+ "name": "watch",
900
+ "columns": [
901
+ {
902
+ "name": "film",
903
+ "type": "string",
904
+ "required": true,
905
+ "description": "The film I watched"
906
+ },
907
+ {
908
+ "name": "occurred_at",
909
+ "type": "datetime",
910
+ "required": true,
911
+ "description": "When the film started"
912
+ },
913
+ {
914
+ "name": "where",
915
+ "type": "enum",
916
+ "values": ["cinema", "home", "outdoor screening"],
917
+ "description": "The kind of place I watched it in"
918
+ },
919
+ {
920
+ "name": "day",
921
+ "type": "date",
922
+ "generated": "date(occurred_at)",
923
+ "description": "The day of the viewing, for daily notes"
924
+ },
925
+ {
926
+ "name": "label",
927
+ "type": "string",
928
+ "generated": "{film} ({occurred_at:DD/MM HH:mm}, {where})",
929
+ "description": "A one-line summary of the viewing, for lists"
930
+ }
931
+ ],
932
+ "time_column": "occurred_at",
933
+ "description": "Each time I watch a film"
934
+ }
935
+ ```
936
+
937
+ Answer:
938
+
939
+ ```json
940
+ {
941
+ "ok": true,
942
+ "op": "create_table",
943
+ "planned_texts": ["datanotes/metastore.yaml"],
944
+ "commits": [{ "table": "main.public.watch", "version": 0, "operation": "CREATE TABLE" }],
945
+ "migration_id": "20261012T071947-create_table-create-table-main-public-watch"
946
+ }
947
+ ```
948
+
949
+ **`insert_row`**
950
+
951
+ ```json
952
+ {
953
+ "table": "watch",
954
+ "values": {
955
+ "film": "His Girl Friday",
956
+ "occurred_at": "2026-10-03T21:30",
957
+ "where": "home"
958
+ }
959
+ }
960
+ ```
961
+
962
+ Answer:
963
+
964
+ ```json
965
+ {
966
+ "ok": true,
967
+ "op": "insert_row",
968
+ "files_created": 1,
969
+ "planned_creates": ["datanotes/main/public/watch/2026-10-03T2130.md"],
970
+ "commits": [{ "table": "main.public.watch", "version": 1, "operation": "WRITE" }],
971
+ "migration_id": "20261012T071947-insert_row-insert-into-watch"
972
+ }
973
+ ```
974
+
975
+ `datanotes/main/public/watch/2026-10-03T2130.md` now reads:
976
+
977
+ ```markdown
978
+ ---
979
+ table: main.public.watch
980
+ id: 01a12efb-5b61-7abf-9cb9-45a1f5a8f839
981
+ film: His Girl Friday
982
+ occurred_at: 2026-10-03T21:30
983
+ where: home
984
+ day: 2026-10-03
985
+ label: His Girl Friday (03/10 21:30, home)
986
+ ---
987
+ ```
988
+
989
+ The engine refuses a value for a generated column:
990
+
991
+ **`insert_row`**
992
+
993
+ ```json
994
+ {
995
+ "table": "watch",
996
+ "values": {
997
+ "film": "His Girl Friday",
998
+ "occurred_at": "2026-10-04T21:30",
999
+ "day": "2026-10-01"
1000
+ }
1001
+ }
1002
+ ```
1003
+
1004
+ Refused:
1005
+
1006
+ ```text
1007
+ "day" is a generated column: its value is computed
1008
+ Hint: Leave generated and identity columns out of the values: the engine computes them (recompute_columns computes them again).
1009
+ Docs: https://datanotes.dev/guides/database-objects/columns.md#compute-a-column-from-other-columns (offline: read_docs("guides/database-objects/columns#compute-a-column-from-other-columns"))
1010
+ ```
1011
+
1012
+ `time_column` names each row’s file after that date-time: here, the time the viewing started. The name follows the database’s `filename` format, `YYYY-MM-DD[T]HHmm` by default.
1013
+
1014
+ ## Let the engine fill identity columns
1015
+
1016
+ The engine fills an `identity` column on its own. `filename` keeps the note’s file name, and `created` records when the engine created the row and never changes. Every table also has `id`, the identity column that holds the row’s universally unique identifier (UUID). The meaning of `id` and `created` never changes, so the engine writes their descriptions too.
1017
+
1018
+ **`add_column`**
1019
+
1020
+ ```json
1021
+ {
1022
+ "table": "film",
1023
+ "column": {
1024
+ "name": "note_name",
1025
+ "type": "string",
1026
+ "identity": "filename",
1027
+ "description": "The name of the film's note, kept as the file is renamed"
1028
+ }
1029
+ }
1030
+ ```
1031
+
1032
+ Answer:
1033
+
1034
+ ```json
1035
+ {
1036
+ "ok": true,
1037
+ "op": "add_column",
1038
+ "planned_texts": ["datanotes/metastore.yaml"],
1039
+ "commits": [{ "table": "main.public.film", "version": 24, "operation": "ADD COLUMNS" }],
1040
+ "migration_id": "20261012T071947-add_column-add-column-note_name-to-film"
1041
+ }
1042
+ ```
1043
+
1044
+ **`add_column`**
1045
+
1046
+ ```json
1047
+ {
1048
+ "table": "film",
1049
+ "column": { "name": "created", "type": "datetime", "identity": "created" }
1050
+ }
1051
+ ```
1052
+
1053
+ Answer:
1054
+
1055
+ ```json
1056
+ {
1057
+ "ok": true,
1058
+ "op": "add_column",
1059
+ "planned_texts": ["datanotes/metastore.yaml"],
1060
+ "commits": [{ "table": "main.public.film", "version": 25, "operation": "ADD COLUMNS" }],
1061
+ "migration_id": "20261012T071947-add_column-add-column-created-to-film"
1062
+ }
1063
+ ```
1064
+
1065
+ **`insert_row`**
1066
+
1067
+ ```json
1068
+ { "table": "film", "values": { "title": "Charade", "year": 1963 } }
1069
+ ```
1070
+
1071
+ Answer:
1072
+
1073
+ ```json
1074
+ {
1075
+ "ok": true,
1076
+ "op": "insert_row",
1077
+ "files_created": 1,
1078
+ "planned_creates": ["datanotes/main/public/film/Charade.md"],
1079
+ "commits": [{ "table": "main.public.film", "version": 26, "operation": "WRITE" }],
1080
+ "migration_id": "20261012T071947-insert_row-insert-into-film-2"
1081
+ }
1082
+ ```
1083
+
1084
+ `datanotes/main/public/film/Charade.md` now reads:
1085
+
1086
+ ```markdown
1087
+ ---
1088
+ table: main.public.film
1089
+ id: 01a12efb-5b90-78eb-ba11-d2990af01451
1090
+ loved_it: false
1091
+ title: Charade
1092
+ year: 1963
1093
+ added: 2026-10-12
1094
+ added_at: 2026-10-12T07:19:47Z
1095
+ note_name: Charade
1096
+ created: 2026-10-12T07:19:47Z
1097
+ ---
1098
+ ```
1099
+
1100
+ ## Partition rows into folders
1101
+
1102
+ `options.partition` puts rows in subfolders named from their values. A `{column:FORMAT}` placeholder formats a date, so here each actor goes in the folder of their birth year. A table of events could use one folder per year and month, with `{occurred_at:YYYY/MM}`.
1103
+
1104
+ **`create_table`**
1105
+
1106
+ ```json
1107
+ {
1108
+ "name": "actor",
1109
+ "description": "Actors of the films I watch",
1110
+ "columns": [
1111
+ {
1112
+ "name": "name",
1113
+ "type": "string",
1114
+ "required": true,
1115
+ "description": "The actor's name, as credited"
1116
+ },
1117
+ {
1118
+ "name": "born",
1119
+ "type": "date",
1120
+ "required": true,
1121
+ "description": "The actor's date of birth"
1122
+ }
1123
+ ],
1124
+ "filename": "{name}",
1125
+ "partition": "{born:YYYY}"
1126
+ }
1127
+ ```
1128
+
1129
+ Answer:
1130
+
1131
+ ```json
1132
+ {
1133
+ "ok": true,
1134
+ "op": "create_table",
1135
+ "planned_texts": ["datanotes/metastore.yaml"],
1136
+ "commits": [{ "table": "main.public.actor", "version": 0, "operation": "CREATE TABLE" }],
1137
+ "migration_id": "20261012T071948-create_table-create-table-main-public-actor"
1138
+ }
1139
+ ```
1140
+
1141
+ **`insert_row`**
1142
+
1143
+ ```json
1144
+ { "table": "actor", "values": { "name": "Cary Grant", "born": "1904-01-18" } }
1145
+ ```
1146
+
1147
+ Answer:
1148
+
1149
+ ```json
1150
+ {
1151
+ "ok": true,
1152
+ "op": "insert_row",
1153
+ "files_created": 1,
1154
+ "planned_creates": ["datanotes/main/public/actor/1904/Cary Grant.md"],
1155
+ "commits": [{ "table": "main.public.actor", "version": 1, "operation": "WRITE" }],
1156
+ "migration_id": "20261012T071948-insert_row-insert-into-actor"
1157
+ }
1158
+ ```
1159
+
1160
+ **`insert_row`**
1161
+
1162
+ ```json
1163
+ { "table": "actor", "values": { "name": "Audrey Hepburn", "born": "1929-05-04" } }
1164
+ ```
1165
+
1166
+ **`list_folder`**
1167
+
1168
+ ```json
1169
+ { "folder": "datanotes/main/public/actor" }
1170
+ ```
1171
+
1172
+ Answer:
1173
+
1174
+ ```json
1175
+ {
1176
+ "folder": "datanotes/main/public/actor",
1177
+ "folders": ["datanotes/main/public/actor/1904", "datanotes/main/public/actor/1929"],
1178
+ "files": []
1179
+ }
1180
+ ```
1181
+
1182
+ ## See the column definitions in `metastore.yaml`
1183
+
1184
+ The engine wrote this file with the columns from this page, in the operations’ words. Two things have a place of their own:
1185
+
1186
+ * **`time_column`**: the table’s `filename` pattern under `options`
1187
+ * **`partition`**: under `options`, next to `filename`
1188
+
1189
+ `datanotes/metastore.yaml` now reads:
1190
+
1191
+ ```yaml
1192
+ # Metastore (Datanotes): catalogs, schemas, tables, columns, views.
1193
+ id: 01a12efb-5a06-7f54-8618-acdaa56c69f9
1194
+ config:
1195
+ history: true
1196
+
1197
+
1198
+ catalogs:
1199
+ main:
1200
+ schemas:
1201
+ public:
1202
+ tables:
1203
+ film:
1204
+ description: Classic films I watched or want to watch
1205
+ options:
1206
+ filename: "{title}"
1207
+ archive: _archive
1208
+ columns:
1209
+ - name: id
1210
+ type: string
1211
+ required: true
1212
+ description: "Unique id of the row (UUIDv7): set when the row is created, never changes"
1213
+ unique: true
1214
+ identity: uuid
1215
+ dense: true
1216
+ - name: title
1217
+ type: string
1218
+ required: true
1219
+ description: The film's title, as on its poster
1220
+ - name: year
1221
+ type: integer
1222
+ description: Year the film first came out
1223
+ - name: minutes
1224
+ type: integer
1225
+ min: 1
1226
+ label: Runtime
1227
+ description: Running time of the commonly cited version
1228
+ aliases:
1229
+ - runtime
1230
+ - length
1231
+ note: "[[How I count minutes]]"
1232
+ - name: loved_it
1233
+ type: boolean
1234
+ default: false
1235
+ description: True for the films I would watch again and again
1236
+ dense: true
1237
+ - name: status
1238
+ type: enum
1239
+ values:
1240
+ - to watch
1241
+ - watched
1242
+ value_descriptions:
1243
+ to watch: on my list, not seen yet
1244
+ watched: seen to the end
1245
+ description: Where the film is on my list
1246
+ ordered: true
1247
+ - name: added
1248
+ type: date
1249
+ default: "{today}"
1250
+ description: The day I put the film on my list
1251
+ - name: added_at
1252
+ type: datetime
1253
+ default: "{now}"
1254
+ description: When I put the film on my list
1255
+ - name: seen_at
1256
+ type: list
1257
+ items: enum
1258
+ values:
1259
+ - cinema
1260
+ - home
1261
+ - outdoor screening
1262
+ description: Every kind of place I saw the film in
1263
+ - name: viewings
1264
+ type: json
1265
+ description: "Each viewing: when, where, and a note on it"
1266
+ - name: note_name
1267
+ type: string
1268
+ description: The name of the film's note, kept as the file is renamed
1269
+ identity: filename
1270
+ - name: created
1271
+ type: datetime
1272
+ description: "When the row was created: set by the engine, never changes"
1273
+ identity: created
1274
+ watch:
1275
+ description: Each time I watch a film
1276
+ options:
1277
+ filename: "{occurred_at:YYYY-MM-DD[T]HHmm}"
1278
+ archive: _archive
1279
+ columns:
1280
+ - name: id
1281
+ type: string
1282
+ required: true
1283
+ description: "Unique id of the row (UUIDv7): set when the row is created, never changes"
1284
+ unique: true
1285
+ identity: uuid
1286
+ dense: true
1287
+ - name: film
1288
+ type: string
1289
+ required: true
1290
+ description: The film I watched
1291
+ - name: occurred_at
1292
+ type: datetime
1293
+ required: true
1294
+ description: When the film started
1295
+ - name: where
1296
+ type: enum
1297
+ values:
1298
+ - cinema
1299
+ - home
1300
+ - outdoor screening
1301
+ description: The kind of place I watched it in
1302
+ - name: day
1303
+ type: date
1304
+ description: The day of the viewing, for daily notes
1305
+ generated: date(occurred_at)
1306
+ - name: label
1307
+ type: string
1308
+ description: A one-line summary of the viewing, for lists
1309
+ generated: "{film} ({occurred_at:DD/MM HH:mm}, {where})"
1310
+ actor:
1311
+ description: Actors of the films I watch
1312
+ options:
1313
+ partition: "{born:YYYY}"
1314
+ filename: "{name}"
1315
+ archive: _archive
1316
+ columns:
1317
+ - name: id
1318
+ type: string
1319
+ required: true
1320
+ description: "Unique id of the row (UUIDv7): set when the row is created, never changes"
1321
+ unique: true
1322
+ identity: uuid
1323
+ dense: true
1324
+ - name: name
1325
+ type: string
1326
+ required: true
1327
+ description: The actor's name, as credited
1328
+ - name: born
1329
+ type: date
1330
+ required: true
1331
+ description: The actor's date of birth
1332
+ ```