datanotes 3.3.1 → 3.4.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 (68) hide show
  1. package/SECURITY.md +5 -3
  2. package/dist/api/extensions.cjs +141 -5
  3. package/dist/api/extensions.js +141 -5
  4. package/dist/api/index.cjs +141 -5
  5. package/dist/api/index.js +141 -5
  6. package/dist/api/mcp.cjs +141 -5
  7. package/dist/api/mcp.js +141 -5
  8. package/dist/datanotes.cjs +1672 -600
  9. package/dist/docs/administration/extensions.md +2 -2
  10. package/dist/docs/api/operations/add_column.md +1 -0
  11. package/dist/docs/api/operations/check_table.md +1 -0
  12. package/dist/docs/api/operations/create_table.md +1 -0
  13. package/dist/docs/api/operations/describe_database.md +2 -0
  14. package/dist/docs/api/operations/describe_history.md +1 -0
  15. package/dist/docs/api/operations/describe_semantic_index.md +1 -0
  16. package/dist/docs/api/operations/describe_table.md +1 -0
  17. package/dist/docs/api/operations/graph_neighbors.md +1 -0
  18. package/dist/docs/api/operations/graph_path.md +1 -0
  19. package/dist/docs/api/operations/graph_traverse.md +1 -0
  20. package/dist/docs/api/operations/infer_table.md +1 -0
  21. package/dist/docs/api/operations/list_changes.md +1 -0
  22. package/dist/docs/api/operations/list_folder.md +1 -0
  23. package/dist/docs/api/operations/list_link_targets.md +1 -0
  24. package/dist/docs/api/operations/list_migrations.md +1 -0
  25. package/dist/docs/api/operations/list_tables.md +2 -0
  26. package/dist/docs/api/operations/list_webhooks.md +1 -0
  27. package/dist/docs/api/operations/read_note.md +1 -0
  28. package/dist/docs/api/operations/search.md +39 -0
  29. package/dist/docs/api/operations/search_notes.md +1 -0
  30. package/dist/docs/api/operations/select_rows.md +1 -0
  31. package/dist/docs/api/operations/semantic_search.md +1 -0
  32. package/dist/docs/api/operations/table_changes.md +1 -0
  33. package/dist/docs/api/operations/tags/queries.md +1 -0
  34. package/dist/docs/api/operations/tags/tokens.md +1 -1
  35. package/dist/docs/api/operations/tokens_create.md +1 -0
  36. package/dist/docs/api/operations/tokens_update.md +2 -1
  37. package/dist/docs/api.md +5 -4
  38. package/dist/docs/develop/build-an-app.md +2 -1
  39. package/dist/docs/develop/change-feed-and-webhooks.md +1 -1
  40. package/dist/docs/develop/http-api.md +1 -1
  41. package/dist/docs/guides/data-quality/check-constraints.md +10 -10
  42. package/dist/docs/guides/data-quality/hand-edits.md +8 -8
  43. package/dist/docs/guides/database-objects/bases.md +11 -11
  44. package/dist/docs/guides/database-objects/catalogs-and-schemas.md +10 -10
  45. package/dist/docs/guides/database-objects/columns.md +241 -38
  46. package/dist/docs/guides/database-objects/relations.md +28 -28
  47. package/dist/docs/guides/database-objects/tables.md +26 -26
  48. package/dist/docs/guides/database-objects/views.md +19 -19
  49. package/dist/docs/guides/history/change-data-feed.md +34 -34
  50. package/dist/docs/guides/history/journal-and-undo.md +12 -12
  51. package/dist/docs/guides/history/restore.md +20 -20
  52. package/dist/docs/guides/history/table-history.md +31 -31
  53. package/dist/docs/guides/read-and-write/automatic-links.md +15 -15
  54. package/dist/docs/guides/read-and-write/import-notes.md +20 -20
  55. package/dist/docs/guides/read-and-write/write-rows.md +10 -10
  56. package/dist/docs/guides/search/hybrid.md +162 -0
  57. package/dist/docs/guides/search/text.md +1 -1
  58. package/dist/docs/guides/security/security-model.md +5 -3
  59. package/dist/docs/guides/security/tokens.md +121 -8
  60. package/dist/docs/reference/cli.md +1 -1
  61. package/dist/docs/reference/glossary.md +1 -1
  62. package/dist/docs/reference/operations/auxiliary.md +2 -2
  63. package/dist/docs/reference/operations/queries.md +16 -0
  64. package/dist/docs/reference/operations/schema.md +2 -2
  65. package/dist/docs/reference/operations.md +2 -1
  66. package/dist/docs/release-notes.md +43 -0
  67. package/dist/docs/start/connect-agents.md +10 -3
  68. package/package.json +1 -1
@@ -35,7 +35,7 @@ Answer:
35
35
  "op": "add_column",
36
36
  "planned_texts": ["datanotes/metastore.yaml"],
37
37
  "commits": [{ "table": "main.public.film", "version": 3, "operation": "ADD COLUMNS" }],
38
- "migration_id": "20261024T053819-add_column-add-column-minutes-to-film"
38
+ "migration_id": "20261024T063903-add_column-add-column-minutes-to-film"
39
39
  }
40
40
  ```
41
41
 
@@ -118,7 +118,7 @@ Answer:
118
118
  ],
119
119
  "planned_texts": ["datanotes/metastore.yaml"],
120
120
  "commits": [{ "table": "main.public.film", "version": 5, "operation": "ADD COLUMNS" }],
121
- "migration_id": "20261024T053819-add_column-add-column-favourite-to-film"
121
+ "migration_id": "20261024T063903-add_column-add-column-favourite-to-film"
122
122
  }
123
123
  ```
124
124
 
@@ -176,7 +176,7 @@ Answer:
176
176
  "op": "add_column",
177
177
  "planned_texts": ["datanotes/metastore.yaml"],
178
178
  "commits": [{ "table": "main.public.film", "version": 6, "operation": "ADD COLUMNS" }],
179
- "migration_id": "20261024T053819-add_column-add-column-status-to-film"
179
+ "migration_id": "20261024T063903-add_column-add-column-status-to-film"
180
180
  }
181
181
  ```
182
182
 
@@ -283,7 +283,7 @@ Answer:
283
283
  ],
284
284
  "planned_texts": ["datanotes/metastore.yaml"],
285
285
  "commits": [{ "table": "main.public.film", "version": 9, "operation": "UPDATE" }],
286
- "migration_id": "20261024T053819-rename_value-rename-film-status-value-seen-"
286
+ "migration_id": "20261024T063903-rename_value-rename-film-status-value-seen-"
287
287
  }
288
288
  ```
289
289
 
@@ -338,7 +338,7 @@ Answer:
338
338
  "commits": [
339
339
  { "table": "main.public.film", "version": 10, "operation": "CHANGE COLUMN" }
340
340
  ],
341
- "migration_id": "20261024T053819-alter_column-alter-column-status-in-film"
341
+ "migration_id": "20261024T063903-alter_column-alter-column-status-in-film"
342
342
  }
343
343
  ```
344
344
 
@@ -402,7 +402,7 @@ Answer:
402
402
  "commits": [
403
403
  { "table": "main.public.film", "version": 11, "operation": "CHANGE COLUMN" }
404
404
  ],
405
- "migration_id": "20261024T053819-alter_column-alter-column-minutes-in-film"
405
+ "migration_id": "20261024T063903-alter_column-alter-column-minutes-in-film"
406
406
  }
407
407
  ```
408
408
 
@@ -424,7 +424,7 @@ Answer:
424
424
  "commits": [
425
425
  { "table": "main.public.film", "version": 12, "operation": "CHANGE COLUMN" }
426
426
  ],
427
- "migration_id": "20261024T053819-alter_column-alter-column-minutes-in-film-2"
427
+ "migration_id": "20261024T063903-alter_column-alter-column-minutes-in-film-2"
428
428
  }
429
429
  ```
430
430
 
@@ -454,7 +454,7 @@ Answer:
454
454
  "commits": [
455
455
  { "table": "main.public.film", "version": 13, "operation": "CHANGE COLUMN" }
456
456
  ],
457
- "migration_id": "20261024T053819-alter_column-alter-column-minutes-in-film-3"
457
+ "migration_id": "20261024T063903-alter_column-alter-column-minutes-in-film-3"
458
458
  }
459
459
  ```
460
460
 
@@ -463,7 +463,7 @@ Answer:
463
463
  ```markdown
464
464
  ---
465
465
  table: main.public.film
466
- id: 01a16c6a-c855-700d-a1ce-24a15e0b4225
466
+ id: 01a16ca2-622e-77f6-96b8-9b911fafe9fb
467
467
  title: Nosferatu
468
468
  year: 1922
469
469
  favourite: false
@@ -490,7 +490,7 @@ Answer:
490
490
  "commits": [
491
491
  { "table": "main.public.film", "version": 14, "operation": "CHANGE COLUMN" }
492
492
  ],
493
- "migration_id": "20261024T053819-alter_column-alter-column-minutes-in-film-4"
493
+ "migration_id": "20261024T063903-alter_column-alter-column-minutes-in-film-4"
494
494
  }
495
495
  ```
496
496
 
@@ -499,7 +499,7 @@ Answer:
499
499
  ```markdown
500
500
  ---
501
501
  table: main.public.film
502
- id: 01a16c6a-c855-700d-a1ce-24a15e0b4225
502
+ id: 01a16ca2-622e-77f6-96b8-9b911fafe9fb
503
503
  title: Nosferatu
504
504
  year: 1922
505
505
  favourite: false
@@ -541,7 +541,7 @@ Answer:
541
541
  "commits": [
542
542
  { "table": "main.public.film", "version": 15, "operation": "RENAME COLUMN" }
543
543
  ],
544
- "migration_id": "20261024T053819-rename_column-rename-column-favourite-to-lov"
544
+ "migration_id": "20261024T063903-rename_column-rename-column-favourite-to-lov"
545
545
  }
546
546
  ```
547
547
 
@@ -603,14 +603,14 @@ Answer:
603
603
  ],
604
604
  "planned_texts": ["datanotes/metastore.yaml"],
605
605
  "commits": [{ "table": "main.public.film", "version": 16, "operation": "DROP COLUMNS" }],
606
- "migration_id": "20261024T053819-drop_column-drop-column-loved_it-from-film"
606
+ "migration_id": "20261024T063903-drop_column-drop-column-loved_it-from-film"
607
607
  }
608
608
  ```
609
609
 
610
610
  **`undo_migration`**
611
611
 
612
612
  ```json
613
- { "migration_id": "20261024T053819-drop_column-drop-column-loved_it-from-film" }
613
+ { "migration_id": "20261024T063903-drop_column-drop-column-loved_it-from-film" }
614
614
  ```
615
615
 
616
616
  Answer:
@@ -619,8 +619,8 @@ Answer:
619
619
  {
620
620
  "ok": true,
621
621
  "op": "undo_migration",
622
- "undoes": "20261024T053819-drop_column-drop-column-loved_it-from-film",
623
- "migration_id": "20261024T053819-undo_migration-undo-20261024t053819-drop_colu",
622
+ "undoes": "20261024T063903-drop_column-drop-column-loved_it-from-film",
623
+ "migration_id": "20261024T063903-undo_migration-undo-20261024t063903-drop_colu",
624
624
  "conflicts": [],
625
625
  "failed": []
626
626
  }
@@ -681,7 +681,7 @@ Answer:
681
681
  "op": "add_column",
682
682
  "planned_texts": ["datanotes/metastore.yaml"],
683
683
  "commits": [{ "table": "main.public.film", "version": 18, "operation": "ADD COLUMNS" }],
684
- "migration_id": "20261024T053820-add_column-add-column-added-to-film"
684
+ "migration_id": "20261024T063903-add_column-add-column-added-to-film"
685
685
  }
686
686
  ```
687
687
 
@@ -714,7 +714,7 @@ Answer:
714
714
  "files_created": 1,
715
715
  "planned_creates": ["datanotes/main/public/film/Sherlock Jr..md"],
716
716
  "commits": [{ "table": "main.public.film", "version": 20, "operation": "WRITE" }],
717
- "migration_id": "20261024T053820-insert_row-insert-into-film"
717
+ "migration_id": "20261024T063903-insert_row-insert-into-film-3"
718
718
  }
719
719
  ```
720
720
 
@@ -723,12 +723,12 @@ Answer:
723
723
  ```markdown
724
724
  ---
725
725
  table: main.public.film
726
- id: 01a16c6a-c8f6-7574-84e1-70fd6a9c3d59
726
+ id: 01a16ca2-62f5-7e75-b2e7-e4aab44a8a93
727
727
  loved_it: false
728
728
  title: Sherlock Jr.
729
729
  year: 1924
730
730
  added: 2026-10-24
731
- added_at: 2026-10-24T05:38:20Z
731
+ added_at: 2026-10-24T06:39:03Z
732
732
  ---
733
733
  ```
734
734
 
@@ -759,7 +759,7 @@ Answer:
759
759
  "op": "add_column",
760
760
  "planned_texts": ["datanotes/metastore.yaml"],
761
761
  "commits": [{ "table": "main.public.film", "version": 21, "operation": "ADD COLUMNS" }],
762
- "migration_id": "20261024T053820-add_column-add-column-seen_at-to-film"
762
+ "migration_id": "20261024T063903-add_column-add-column-seen_at-to-film"
763
763
  }
764
764
  ```
765
765
 
@@ -784,7 +784,7 @@ Answer:
784
784
  "op": "add_column",
785
785
  "planned_texts": ["datanotes/metastore.yaml"],
786
786
  "commits": [{ "table": "main.public.film", "version": 22, "operation": "ADD COLUMNS" }],
787
- "migration_id": "20261024T053820-add_column-add-column-viewings-to-film"
787
+ "migration_id": "20261024T063903-add_column-add-column-viewings-to-film"
788
788
  }
789
789
  ```
790
790
 
@@ -833,7 +833,7 @@ Answer:
833
833
  }
834
834
  ],
835
835
  "commits": [{ "table": "main.public.film", "version": 23, "operation": "UPDATE" }],
836
- "migration_id": "20261024T053820-update_row-update-film"
836
+ "migration_id": "20261024T063903-update_row-update-film-4"
837
837
  }
838
838
  ```
839
839
 
@@ -842,7 +842,7 @@ Answer:
842
842
  ```markdown
843
843
  ---
844
844
  table: main.public.film
845
- id: 01a16c6a-c855-700d-a1ce-24a15e0b4225
845
+ id: 01a16ca2-622e-77f6-96b8-9b911fafe9fb
846
846
  title: Nosferatu
847
847
  year: 1922
848
848
  loved_it: false
@@ -884,13 +884,14 @@ Docs: https://datanotes.dev/guides/database-objects/columns.md#describe-what-eac
884
884
 
885
885
  ## Compute a column from other columns
886
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:
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 four forms:
888
888
 
889
889
  * **A column name**: the value of that column
890
890
  * **`date(col)`**: the date of `col`, with an optional day shift
891
891
  * **A template**: text with `{col}` and `{col:FORMAT}` placeholders
892
+ * **An aggregate**: a count or a total of the items of a `json` list, shown in the next section
892
893
 
893
- `min(…)`, `max(…)` and `coalesce(…)` pick among several columns.
894
+ In a template, `min(…)`, `max(…)` and `coalesce(…)` pick among several columns.
894
895
 
895
896
  **`create_table`**
896
897
 
@@ -942,7 +943,7 @@ Answer:
942
943
  "op": "create_table",
943
944
  "planned_texts": ["datanotes/metastore.yaml"],
944
945
  "commits": [{ "table": "main.public.watch", "version": 0, "operation": "CREATE TABLE" }],
945
- "migration_id": "20261024T053820-create_table-create-table-main-public-watch"
946
+ "migration_id": "20261024T063903-create_table-create-table-main-public-watch"
946
947
  }
947
948
  ```
948
949
 
@@ -968,7 +969,7 @@ Answer:
968
969
  "files_created": 1,
969
970
  "planned_creates": ["datanotes/main/public/watch/2026-10-03T2130.md"],
970
971
  "commits": [{ "table": "main.public.watch", "version": 1, "operation": "WRITE" }],
971
- "migration_id": "20261024T053820-insert_row-insert-into-watch"
972
+ "migration_id": "20261024T063903-insert_row-insert-into-watch"
972
973
  }
973
974
  ```
974
975
 
@@ -977,7 +978,7 @@ Answer:
977
978
  ```markdown
978
979
  ---
979
980
  table: main.public.watch
980
- id: 01a16c6a-c91c-75d4-af58-f40270afa72e
981
+ id: 01a16ca2-6327-778b-85f9-d586c0c733a8
981
982
  film: His Girl Friday
982
983
  occurred_at: 2026-10-03T21:30
983
984
  where: home
@@ -1011,6 +1012,168 @@ Docs: https://datanotes.dev/guides/database-objects/columns.md#compute-a-column-
1011
1012
 
1012
1013
  `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
 
1015
+ ## Count and total the items of a json list
1016
+
1017
+ A `generated` column can count the items of a `json` list of objects. It can also total one field of them. The engine recomputes it on every write of the row, so a total never falls behind its list. These functions read the list:
1018
+
1019
+ * **`count(films)`**: the number of items
1020
+ * **`count(films.minutes)`**: the items that have a `minutes` value
1021
+ * **`sum(films.minutes)`**: the total of the field
1022
+ * **`avg(…)`, `min(…)`, `max(…)`**: the average, the smallest and the largest value
1023
+
1024
+ A filter after a comma keeps only some items: `count(films, rewatch = true)`. It compares one field with `"text"`, a number, `true` or `false`. It uses `=`, `!=`, `<`, `<=`, `>` or `>=`, and the four orderings compare numbers. `!=` keeps every item that `=` leaves out, items without the field included.
1025
+
1026
+ **`create_table`**
1027
+
1028
+ ```json
1029
+ {
1030
+ "name": "marathon",
1031
+ "description": "Nights when I watch several films in a row",
1032
+ "columns": [
1033
+ {
1034
+ "name": "night",
1035
+ "type": "date",
1036
+ "required": true,
1037
+ "description": "The night of the marathon"
1038
+ },
1039
+ {
1040
+ "name": "films",
1041
+ "type": "json",
1042
+ "description": "The films of the night: title, minutes and rewatch"
1043
+ },
1044
+ {
1045
+ "name": "film_count",
1046
+ "type": "integer",
1047
+ "generated": "count(films)",
1048
+ "description": "How many films I watched"
1049
+ },
1050
+ {
1051
+ "name": "rewatches",
1052
+ "type": "integer",
1053
+ "generated": "count(films, rewatch = true)",
1054
+ "description": "Films I had seen before"
1055
+ },
1056
+ {
1057
+ "name": "total_min",
1058
+ "type": "integer",
1059
+ "generated": "sum(films.minutes)",
1060
+ "description": "Minutes of film in the night"
1061
+ },
1062
+ {
1063
+ "name": "longest_min",
1064
+ "type": "integer",
1065
+ "generated": "max(films.minutes)",
1066
+ "description": "Running time of the longest film"
1067
+ },
1068
+ {
1069
+ "name": "avg_min",
1070
+ "type": "number",
1071
+ "generated": "avg(films.minutes, rewatch != true)",
1072
+ "description": "Average running time of the new films"
1073
+ }
1074
+ ],
1075
+ "filename": "{night}"
1076
+ }
1077
+ ```
1078
+
1079
+ Answer:
1080
+
1081
+ ```json
1082
+ {
1083
+ "ok": true,
1084
+ "op": "create_table",
1085
+ "planned_texts": ["datanotes/metastore.yaml"],
1086
+ "commits": [
1087
+ { "table": "main.public.marathon", "version": 0, "operation": "CREATE TABLE" }
1088
+ ],
1089
+ "migration_id": "20261024T063903-create_table-create-table-main-public-marat"
1090
+ }
1091
+ ```
1092
+
1093
+ **`insert_row`**
1094
+
1095
+ ```json
1096
+ {
1097
+ "table": "marathon",
1098
+ "values": {
1099
+ "night": "2026-10-31",
1100
+ "films": [
1101
+ { "title": "Nosferatu", "minutes": 94, "rewatch": true },
1102
+ { "title": "Vampyr", "minutes": 73 },
1103
+ { "title": "Frankenstein", "minutes": 70 }
1104
+ ]
1105
+ }
1106
+ }
1107
+ ```
1108
+
1109
+ Answer:
1110
+
1111
+ ```json
1112
+ {
1113
+ "ok": true,
1114
+ "op": "insert_row",
1115
+ "files_created": 1,
1116
+ "planned_creates": ["datanotes/main/public/marathon/2026-10-31.md"],
1117
+ "commits": [{ "table": "main.public.marathon", "version": 1, "operation": "WRITE" }],
1118
+ "migration_id": "20261024T063903-insert_row-insert-into-marathon"
1119
+ }
1120
+ ```
1121
+
1122
+ `datanotes/main/public/marathon/2026-10-31.md` now reads:
1123
+
1124
+ ```markdown
1125
+ ---
1126
+ table: main.public.marathon
1127
+ id: 01a16ca2-633b-782d-afde-11976841ccee
1128
+ night: 2026-10-31
1129
+ films:
1130
+ - title: Nosferatu
1131
+ minutes: 94
1132
+ rewatch: true
1133
+ - title: Vampyr
1134
+ minutes: 73
1135
+ - title: Frankenstein
1136
+ minutes: 70
1137
+ film_count: 3
1138
+ rewatches: 1
1139
+ total_min: 237
1140
+ longest_min: 94
1141
+ avg_min: 71.5
1142
+ ---
1143
+ ```
1144
+
1145
+ The type of the column must fit the result. `count` makes a whole number, and `avg` needs a `number` column. An aggregate of a column that isn’t `json` is refused too:
1146
+
1147
+ **`add_column`**
1148
+
1149
+ ```json
1150
+ {
1151
+ "table": "marathon",
1152
+ "column": {
1153
+ "name": "nights",
1154
+ "type": "integer",
1155
+ "generated": "count(night)",
1156
+ "description": "Not a list"
1157
+ }
1158
+ }
1159
+ ```
1160
+
1161
+ Refused:
1162
+
1163
+ ```text
1164
+ columns[8]: "generated" aggregates "night", which is not a json column
1165
+ Hint: count() reads a json column (type json, or a list of json) holding a list of objects, such as [{side: left, min: 12}]; "night" has type date. describe_table shows the type of each column.
1166
+ Docs: https://datanotes.dev/guides/database-objects/columns.md#count-and-total-the-items-of-a-json-list (offline: read_docs("guides/database-objects/columns#count-and-total-the-items-of-a-json-list"))
1167
+ ```
1168
+
1169
+ Values the engine can’t total leave the column empty instead of storing a wrong number:
1170
+
1171
+ * **No list, or an empty one**: `count` and `sum` are 0, and `avg`, `min` and `max` are empty
1172
+ * **An item without the field**: the engine leaves it out
1173
+ * **A field that isn’t a number**: the total is empty, as when the column isn’t a list
1174
+
1175
+ An `integer` column refuses a write whose total isn’t whole. After a hand edit of the list, `check_table` reports the stale totals and `recompute_columns` fixes them.
1176
+
1014
1177
  ## Let the engine fill identity columns
1015
1178
 
1016
1179
  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.
@@ -1037,7 +1200,7 @@ Answer:
1037
1200
  "op": "add_column",
1038
1201
  "planned_texts": ["datanotes/metastore.yaml"],
1039
1202
  "commits": [{ "table": "main.public.film", "version": 24, "operation": "ADD COLUMNS" }],
1040
- "migration_id": "20261024T053820-add_column-add-column-note_name-to-film"
1203
+ "migration_id": "20261024T063904-add_column-add-column-note_name-to-film"
1041
1204
  }
1042
1205
  ```
1043
1206
 
@@ -1058,7 +1221,7 @@ Answer:
1058
1221
  "op": "add_column",
1059
1222
  "planned_texts": ["datanotes/metastore.yaml"],
1060
1223
  "commits": [{ "table": "main.public.film", "version": 25, "operation": "ADD COLUMNS" }],
1061
- "migration_id": "20261024T053820-add_column-add-column-created-to-film"
1224
+ "migration_id": "20261024T063904-add_column-add-column-created-to-film"
1062
1225
  }
1063
1226
  ```
1064
1227
 
@@ -1077,7 +1240,7 @@ Answer:
1077
1240
  "files_created": 1,
1078
1241
  "planned_creates": ["datanotes/main/public/film/Charade.md"],
1079
1242
  "commits": [{ "table": "main.public.film", "version": 26, "operation": "WRITE" }],
1080
- "migration_id": "20261024T053820-insert_row-insert-into-film-2"
1243
+ "migration_id": "20261024T063904-insert_row-insert-into-film"
1081
1244
  }
1082
1245
  ```
1083
1246
 
@@ -1086,14 +1249,14 @@ Answer:
1086
1249
  ```markdown
1087
1250
  ---
1088
1251
  table: main.public.film
1089
- id: 01a16c6a-c932-724c-b71e-793d0c0744ff
1252
+ id: 01a16ca2-636a-7001-a23b-b75df0897156
1090
1253
  loved_it: false
1091
1254
  title: Charade
1092
1255
  year: 1963
1093
1256
  added: 2026-10-24
1094
- added_at: 2026-10-24T05:38:20Z
1257
+ added_at: 2026-10-24T06:39:04Z
1095
1258
  note_name: Charade
1096
- created: 2026-10-24T05:38:20Z
1259
+ created: 2026-10-24T06:39:04Z
1097
1260
  ---
1098
1261
  ```
1099
1262
 
@@ -1134,7 +1297,7 @@ Answer:
1134
1297
  "op": "create_table",
1135
1298
  "planned_texts": ["datanotes/metastore.yaml"],
1136
1299
  "commits": [{ "table": "main.public.actor", "version": 0, "operation": "CREATE TABLE" }],
1137
- "migration_id": "20261024T053821-create_table-create-table-main-public-actor"
1300
+ "migration_id": "20261024T063905-create_table-create-table-main-public-actor"
1138
1301
  }
1139
1302
  ```
1140
1303
 
@@ -1153,7 +1316,7 @@ Answer:
1153
1316
  "files_created": 1,
1154
1317
  "planned_creates": ["datanotes/main/public/actor/1904/Cary Grant.md"],
1155
1318
  "commits": [{ "table": "main.public.actor", "version": 1, "operation": "WRITE" }],
1156
- "migration_id": "20261024T053821-insert_row-insert-into-actor"
1319
+ "migration_id": "20261024T063905-insert_row-insert-into-actor"
1157
1320
  }
1158
1321
  ```
1159
1322
 
@@ -1190,7 +1353,7 @@ The engine wrote this file with the columns from this page, in the operations’
1190
1353
 
1191
1354
  ```yaml
1192
1355
  # Metastore (Datanotes): catalogs, schemas, tables, columns, views.
1193
- id: 01a16c6a-c84a-7a99-9e17-51884bf8c6da
1356
+ id: 01a16ca2-6220-75b7-ab5a-a37b8500206f
1194
1357
  config:
1195
1358
  history: true
1196
1359
 
@@ -1307,6 +1470,46 @@ catalogs:
1307
1470
  type: string
1308
1471
  description: A one-line summary of the viewing, for lists
1309
1472
  generated: "{film} ({occurred_at:DD/MM HH:mm}, {where})"
1473
+ marathon:
1474
+ description: Nights when I watch several films in a row
1475
+ options:
1476
+ filename: "{night}"
1477
+ archive: _archive
1478
+ columns:
1479
+ - name: id
1480
+ type: string
1481
+ required: true
1482
+ description: "Unique id of the row (UUIDv7): set when the row is created, never changes"
1483
+ unique: true
1484
+ identity: uuid
1485
+ dense: true
1486
+ - name: night
1487
+ type: date
1488
+ required: true
1489
+ description: The night of the marathon
1490
+ - name: films
1491
+ type: json
1492
+ description: "The films of the night: title, minutes and rewatch"
1493
+ - name: film_count
1494
+ type: integer
1495
+ description: How many films I watched
1496
+ generated: count(films)
1497
+ - name: rewatches
1498
+ type: integer
1499
+ description: Films I had seen before
1500
+ generated: count(films, rewatch = true)
1501
+ - name: total_min
1502
+ type: integer
1503
+ description: Minutes of film in the night
1504
+ generated: sum(films.minutes)
1505
+ - name: longest_min
1506
+ type: integer
1507
+ description: Running time of the longest film
1508
+ generated: max(films.minutes)
1509
+ - name: avg_min
1510
+ type: number
1511
+ description: Average running time of the new films
1512
+ generated: avg(films.minutes, rewatch != true)
1310
1513
  actor:
1311
1514
  description: Actors of the films I watch
1312
1515
  options: