datanotes 2.0.1 → 3.1.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 +203 -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 +122 -0
- package/dist/api/client.d.ts +56 -34
- 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 +7470 -2771
- package/dist/api/index.d.cts +14 -0
- package/dist/api/index.d.ts +11 -7
- package/dist/api/index.js +7470 -2771
- 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 +17387 -0
- package/dist/api/mcp.d.cts +108 -0
- package/dist/api/mcp.d.ts +108 -0
- package/dist/api/mcp.js +17337 -0
- package/dist/api/otlp.d.cts +113 -0
- package/dist/api/otlp.d.ts +63 -15
- package/dist/api/redact.d.cts +42 -0
- package/dist/api/redact.d.ts +42 -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 +12 -0
- package/dist/api/tokens.d.ts +5 -0
- package/dist/api/tracing.d.cts +107 -0
- package/dist/api/tracing.d.ts +107 -0
- package/dist/datanotes.cjs +69597 -28329
- 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 +153 -0
- package/dist/docs/administration/run-the-service.md +237 -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 +34 -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 +37 -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 +188 -0
- package/dist/docs/develop/http-api.md +89 -0
- package/dist/docs/develop/telemetry.md +285 -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 +1340 -0
- package/dist/docs/guides/database-objects/views.md +1003 -0
- package/dist/docs/guides/history/back-up.md +203 -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 +26 -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 +241 -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 +44 -0
- package/dist/docs/index.md +113 -0
- package/dist/docs/llms.txt +33 -0
- package/dist/docs/reference/cli.md +143 -0
- package/dist/docs/reference/compatibility.md +83 -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 +43 -0
- package/dist/docs/release-notes.md +188 -0
- package/dist/docs/start/connect-agents.md +204 -0
- package/dist/docs/start/how-it-works.md +349 -0
- package/dist/docs/start/quick-start.md +128 -0
- package/package.json +60 -15
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
# CHECK constraints
|
|
2
|
+
|
|
3
|
+
> Write rules that every row of a table must follow, including rules that follow links into other tables.
|
|
4
|
+
|
|
5
|
+
A CHECK constraint is a rule written as a `where` filter, such as “a watched film has a rating”. Every row of the table must pass it: the engine refuses a write that breaks it, and refuses to add a constraint that rows already break. A rule can follow links into other tables.
|
|
6
|
+
|
|
7
|
+
## Enforce rules with CHECK constraints
|
|
8
|
+
|
|
9
|
+
`add_constraint` adds a CHECK constraint, a rule every row must satisfy, written as a `where` filter. The engine refuses it while existing rows break the rule and lists them; after that, it enforces the rule on every write. A condition on a column the row leaves empty passes, as in Structured Query Language (SQL). Inside `or`, `and` and `not`, the engine tests an empty value as it is, so a watched film without a `rating` breaks `rated_when_watched`.
|
|
10
|
+
|
|
11
|
+
**`add_constraint`**
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"table": "film",
|
|
16
|
+
"name": "rated_when_watched",
|
|
17
|
+
"check": { "or": [{ "status": { "ne": "watched" } }, { "rating": { "exists": true } }] }
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Answer:
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"ok": true,
|
|
26
|
+
"op": "add_constraint",
|
|
27
|
+
"planned_texts": ["datanotes/metastore.yaml"],
|
|
28
|
+
"commits": [
|
|
29
|
+
{ "table": "diary.classics.film", "version": 8, "operation": "ADD CONSTRAINT" }
|
|
30
|
+
],
|
|
31
|
+
"migration_id": "20261014T191534-add_constraint-add-constraint-rated_when_watc"
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**`add_constraint`**
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{ "table": "film", "name": "at_most_three_hours", "check": { "minutes": { "lte": 180 } } }
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**`insert_row`**
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"table": "film",
|
|
46
|
+
"values": {
|
|
47
|
+
"title": "His Girl Friday",
|
|
48
|
+
"year": 1940,
|
|
49
|
+
"minutes": 92,
|
|
50
|
+
"status": "watched"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Refused:
|
|
56
|
+
|
|
57
|
+
```text
|
|
58
|
+
insert_row refused — nothing was written:
|
|
59
|
+
invalid datanotes/diary/classics/film/His Girl Friday.md: rated_when_watched violates CHECK rated_when_watched: {"or":[{"status":{"ne":"watched"}},{"rating":{"exists":true}}]}
|
|
60
|
+
Hint: The row breaks a CHECK constraint of the table (named in the message, with its rule): change the values so the rule holds. describe_table lists the table's constraints. Then call insert_row again (dry_run: true checks without writing).
|
|
61
|
+
Docs: https://datanotes.dev/guides/data-quality/check-constraints.md#enforce-rules-with-check-constraints (offline: read_docs("guides/data-quality/check-constraints#enforce-rules-with-check-constraints"))
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**`insert_row`**
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"table": "film",
|
|
69
|
+
"values": {
|
|
70
|
+
"title": "His Girl Friday",
|
|
71
|
+
"year": 1940,
|
|
72
|
+
"minutes": 92,
|
|
73
|
+
"status": "watched",
|
|
74
|
+
"rating": 5
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Answer:
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"ok": true,
|
|
84
|
+
"op": "insert_row",
|
|
85
|
+
"files_created": 1,
|
|
86
|
+
"planned_creates": ["datanotes/diary/classics/film/His Girl Friday.md"],
|
|
87
|
+
"commits": [{ "table": "diary.classics.film", "version": 10, "operation": "WRITE" }],
|
|
88
|
+
"migration_id": "20261014T191534-insert_row-insert-into-film-2"
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`drop_constraint` removes a constraint, here the three-hour limit, which a long restoration could break:
|
|
93
|
+
|
|
94
|
+
**`drop_constraint`**
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{ "table": "film", "name": "at_most_three_hours" }
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Answer:
|
|
101
|
+
|
|
102
|
+
```json
|
|
103
|
+
{
|
|
104
|
+
"ok": true,
|
|
105
|
+
"op": "drop_constraint",
|
|
106
|
+
"planned_texts": ["datanotes/metastore.yaml"],
|
|
107
|
+
"commits": [
|
|
108
|
+
{ "table": "diary.classics.film", "version": 11, "operation": "DROP CONSTRAINT" }
|
|
109
|
+
],
|
|
110
|
+
"migration_id": "20261014T191534-drop_constraint-drop-constraint-at_most_three_"
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Write a CHECK rule that follows links
|
|
115
|
+
|
|
116
|
+
A CHECK constraint is a rule every row must satisfy, and you add one with `add_constraint`. It can follow a link the way a query does: `parent.kind` is the `kind` of the row that `parent` names. Here a genre’s parent must be an era, an era’s parent must be Cinema, and Cinema has no parent.
|
|
117
|
+
|
|
118
|
+
A rule treats links as follows:
|
|
119
|
+
|
|
120
|
+
* **Empty link**: passes at the top level of a rule and fails inside `or`, `and` and `not`; on a longer path such as `parent.parent.kind`, the rule skips only an empty first link
|
|
121
|
+
* **Link to a row that doesn’t exist**: fails, so it passes inside `not`
|
|
122
|
+
* **List of links**: every linked row must match
|
|
123
|
+
* **Resolution**: links resolve as in the vault, by path from the row’s note
|
|
124
|
+
|
|
125
|
+
**`add_constraint`**
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"table": "genre",
|
|
130
|
+
"name": "parent_by_level",
|
|
131
|
+
"check": {
|
|
132
|
+
"or": [
|
|
133
|
+
{ "kind": "cinema", "parent": { "exists": false } },
|
|
134
|
+
{ "kind": "era", "parent.kind": "cinema" },
|
|
135
|
+
{ "kind": "genre", "parent.kind": "era" }
|
|
136
|
+
]
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Answer:
|
|
142
|
+
|
|
143
|
+
```json
|
|
144
|
+
{
|
|
145
|
+
"ok": true,
|
|
146
|
+
"op": "add_constraint",
|
|
147
|
+
"planned_texts": ["datanotes/metastore.yaml"],
|
|
148
|
+
"commits": [
|
|
149
|
+
{ "table": "main.public.genre", "version": 4, "operation": "ADD CONSTRAINT" }
|
|
150
|
+
],
|
|
151
|
+
"migration_id": "20261014T191519-add_constraint-add-constraint-parent_by_level"
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The engine refuses a genre straight under Cinema:
|
|
156
|
+
|
|
157
|
+
**`insert_row`**
|
|
158
|
+
|
|
159
|
+
```json
|
|
160
|
+
{
|
|
161
|
+
"table": "genre",
|
|
162
|
+
"values": { "name": "Horror", "kind": "genre", "parent": "[[Cinema]]" }
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Refused:
|
|
167
|
+
|
|
168
|
+
```text
|
|
169
|
+
insert_row refused — nothing was written:
|
|
170
|
+
invalid datanotes/main/public/genre/Horror.md: parent_by_level violates CHECK parent_by_level: {"or":[{"kind":"cinema","parent":{"exists":false}},{"kind":"era","parent.kind":"cinema"},{"kind":"genre","parent.kind":"era"}]}
|
|
171
|
+
Hint: The row breaks a CHECK constraint of the table (named in the message, with its rule): change the values so the rule holds. describe_table lists the table's constraints. Then call insert_row again (dry_run: true checks without writing).
|
|
172
|
+
Docs: https://datanotes.dev/guides/data-quality/check-constraints.md#enforce-rules-with-check-constraints (offline: read_docs("guides/data-quality/check-constraints#enforce-rules-with-check-constraints"))
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
When a write changes a linked row, the engine checks the rows that link to it again. Sound film can’t become a top level like Cinema while a genre hangs from it, and the refusal lists Screwball comedy, naming Sound film.
|
|
176
|
+
|
|
177
|
+
**`update_row`**
|
|
178
|
+
|
|
179
|
+
```json
|
|
180
|
+
{
|
|
181
|
+
"table": "genre",
|
|
182
|
+
"path": "datanotes/main/public/genre/Sound film.md",
|
|
183
|
+
"set": { "kind": "cinema" },
|
|
184
|
+
"unset": ["parent"]
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Refused:
|
|
189
|
+
|
|
190
|
+
```text
|
|
191
|
+
update_row refused — nothing was written:
|
|
192
|
+
invalid datanotes/main/public/genre/Screwball comedy.md: parent_by_level violates CHECK parent_by_level: {"or":[{"kind":"cinema","parent":{"exists":false}},{"kind":"era","parent.kind":"cinema"},{"kind":"genre","parent.kind":"era"}]} (after this change to [[Sound film]], a row it links to)
|
|
193
|
+
Hint: The row breaks a CHECK constraint of the table (named in the message, with its rule): change the values so the rule holds. describe_table lists the table's constraints. Then call update_row again (dry_run: true checks without writing).
|
|
194
|
+
Docs: https://datanotes.dev/guides/data-quality/check-constraints.md#enforce-rules-with-check-constraints (offline: read_docs("guides/data-quality/check-constraints#enforce-rules-with-check-constraints"))
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
In a `batch`, add the era first and then its genre. The engine checks each step against the vault as the earlier steps left it, so Slapstick comedy finds its parent.
|
|
198
|
+
|
|
199
|
+
**`batch`**
|
|
200
|
+
|
|
201
|
+
```json
|
|
202
|
+
{
|
|
203
|
+
"summary": "add the silent era and slapstick comedy",
|
|
204
|
+
"operations": [
|
|
205
|
+
{
|
|
206
|
+
"op": "insert_row",
|
|
207
|
+
"table": "genre",
|
|
208
|
+
"values": { "name": "Silent cinema", "kind": "era", "parent": "[[Cinema]]" }
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"op": "insert_row",
|
|
212
|
+
"table": "genre",
|
|
213
|
+
"values": {
|
|
214
|
+
"name": "Slapstick comedy",
|
|
215
|
+
"kind": "genre",
|
|
216
|
+
"parent": "[[Silent cinema]]"
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
]
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Answer:
|
|
224
|
+
|
|
225
|
+
```json
|
|
226
|
+
{
|
|
227
|
+
"ok": true,
|
|
228
|
+
"op": "batch",
|
|
229
|
+
"dry_run": false,
|
|
230
|
+
"migration_id": "20261014T191519-batch-add-the-silent-era-and-slapsti",
|
|
231
|
+
"steps": [
|
|
232
|
+
{
|
|
233
|
+
"index": 0,
|
|
234
|
+
"op": "insert_row",
|
|
235
|
+
"ok": true,
|
|
236
|
+
"migration_id": "20261014T191519-insert_row-insert-into-genre-4",
|
|
237
|
+
"result": {
|
|
238
|
+
"ok": true,
|
|
239
|
+
"op": "insert_row",
|
|
240
|
+
"files_created": 1,
|
|
241
|
+
"planned_creates": ["datanotes/main/public/genre/Silent cinema.md"],
|
|
242
|
+
"commits": [{ "table": "main.public.genre", "version": 5, "operation": "WRITE" }],
|
|
243
|
+
"migration_id": "20261014T191519-insert_row-insert-into-genre-4"
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
"index": 1,
|
|
248
|
+
"op": "insert_row",
|
|
249
|
+
"ok": true,
|
|
250
|
+
"migration_id": "20261014T191519-insert_row-insert-into-genre-5",
|
|
251
|
+
"result": {
|
|
252
|
+
"ok": true,
|
|
253
|
+
"op": "insert_row",
|
|
254
|
+
"files_created": 1,
|
|
255
|
+
"planned_creates": ["datanotes/main/public/genre/Slapstick comedy.md"],
|
|
256
|
+
"commits": [{ "table": "main.public.genre", "version": 6, "operation": "WRITE" }],
|
|
257
|
+
"migration_id": "20261014T191519-insert_row-insert-into-genre-5"
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
]
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
**`select_rows`**
|
|
265
|
+
|
|
266
|
+
```json
|
|
267
|
+
{ "table": "genre", "columns": ["name", "kind", "parent"], "order_by": "name" }
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Answer:
|
|
271
|
+
|
|
272
|
+
```json
|
|
273
|
+
{
|
|
274
|
+
"table": "main.public.genre",
|
|
275
|
+
"total": 5,
|
|
276
|
+
"rows": [
|
|
277
|
+
{
|
|
278
|
+
"path": "datanotes/main/public/genre/Cinema.md",
|
|
279
|
+
"name": "Cinema",
|
|
280
|
+
"kind": "cinema",
|
|
281
|
+
"parent": null
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
"path": "datanotes/main/public/genre/Screwball comedy.md",
|
|
285
|
+
"name": "Screwball comedy",
|
|
286
|
+
"kind": "genre",
|
|
287
|
+
"parent": "[[Sound film]]"
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
"path": "datanotes/main/public/genre/Silent cinema.md",
|
|
291
|
+
"name": "Silent cinema",
|
|
292
|
+
"kind": "era",
|
|
293
|
+
"parent": "[[Cinema]]"
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
"path": "datanotes/main/public/genre/Slapstick comedy.md",
|
|
297
|
+
"name": "Slapstick comedy",
|
|
298
|
+
"kind": "genre",
|
|
299
|
+
"parent": "[[Silent cinema]]"
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
"path": "datanotes/main/public/genre/Sound film.md",
|
|
303
|
+
"name": "Sound film",
|
|
304
|
+
"kind": "era",
|
|
305
|
+
"parent": "[[Cinema]]"
|
|
306
|
+
}
|
|
307
|
+
]
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Renaming a row that other rows link to keeps the rule valid, because the links follow the row. Here Slapstick comedy follows the era to its new name, Silent film.
|
|
312
|
+
|
|
313
|
+
**`update_row`**
|
|
314
|
+
|
|
315
|
+
```json
|
|
316
|
+
{
|
|
317
|
+
"table": "genre",
|
|
318
|
+
"path": "datanotes/main/public/genre/Silent cinema.md",
|
|
319
|
+
"set": { "name": "Silent film" }
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Answer:
|
|
324
|
+
|
|
325
|
+
```json
|
|
326
|
+
{
|
|
327
|
+
"ok": true,
|
|
328
|
+
"op": "update_row",
|
|
329
|
+
"notes_changed": 1,
|
|
330
|
+
"files_moved": 1,
|
|
331
|
+
"planned_edits": [
|
|
332
|
+
{
|
|
333
|
+
"path": "datanotes/main/public/genre/Silent cinema.md",
|
|
334
|
+
"set": { "name": "Silent film" },
|
|
335
|
+
"remove": []
|
|
336
|
+
}
|
|
337
|
+
],
|
|
338
|
+
"planned_moves": [
|
|
339
|
+
{
|
|
340
|
+
"from": "datanotes/main/public/genre/Silent cinema.md",
|
|
341
|
+
"to": "datanotes/main/public/genre/Silent film.md"
|
|
342
|
+
}
|
|
343
|
+
],
|
|
344
|
+
"commits": [{ "table": "main.public.genre", "version": 7, "operation": "UPDATE" }],
|
|
345
|
+
"migration_id": "20261014T191519-update_row-update-genre"
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
**`select_rows`**
|
|
350
|
+
|
|
351
|
+
```json
|
|
352
|
+
{
|
|
353
|
+
"table": "genre",
|
|
354
|
+
"columns": ["name", "parent"],
|
|
355
|
+
"where": { "parent.kind": "era" },
|
|
356
|
+
"order_by": "name"
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
Answer:
|
|
361
|
+
|
|
362
|
+
```json
|
|
363
|
+
{
|
|
364
|
+
"table": "main.public.genre",
|
|
365
|
+
"total": 2,
|
|
366
|
+
"rows": [
|
|
367
|
+
{
|
|
368
|
+
"path": "datanotes/main/public/genre/Screwball comedy.md",
|
|
369
|
+
"name": "Screwball comedy",
|
|
370
|
+
"parent": "[[Sound film]]"
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
"path": "datanotes/main/public/genre/Slapstick comedy.md",
|
|
374
|
+
"name": "Slapstick comedy",
|
|
375
|
+
"parent": "[[Silent film]]"
|
|
376
|
+
}
|
|
377
|
+
]
|
|
378
|
+
}
|
|
379
|
+
```
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Find rows that break the schema
|
|
2
|
+
|
|
3
|
+
> List the rows that break their table's rules now, with check_table, for one table or the whole database.
|
|
4
|
+
|
|
5
|
+
`check_table` checks the rows a table holds now against its columns and CHECK constraints, and lists the ones that break a rule. Use it after hand edits, after a sync, or before you tighten a rule. Without `table`, it checks every table, page by page. It writes nothing.
|
|
6
|
+
|
|
7
|
+
## Find rows that break the schema
|
|
8
|
+
|
|
9
|
+
The engine can’t refuse a hand edit, so a note you edit by hand can break the schema. `check_table` validates every row against these rules:
|
|
10
|
+
|
|
11
|
+
* **Values**: types, ranges and enums
|
|
12
|
+
* **Presence**: required columns and unknown keys
|
|
13
|
+
* **Relations and rules**: links and constraints
|
|
14
|
+
|
|
15
|
+
You edit `datanotes/main/public/film/His Girl Friday.md` by hand, outside the engine. The note now reads:
|
|
16
|
+
|
|
17
|
+
```markdown
|
|
18
|
+
---
|
|
19
|
+
table: main.public.film
|
|
20
|
+
id: 01a0f000-0000-7000-8000-0000000000bb
|
|
21
|
+
title: His Girl Friday
|
|
22
|
+
year: 1940
|
|
23
|
+
status: finished
|
|
24
|
+
rating: 6
|
|
25
|
+
format: Blu-ray
|
|
26
|
+
---
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**`check_table`**
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{ "table": "film" }
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Answer:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"table": "film",
|
|
40
|
+
"rows_checked": 3,
|
|
41
|
+
"total": 1,
|
|
42
|
+
"violations": [
|
|
43
|
+
{
|
|
44
|
+
"path": "datanotes/main/public/film/His Girl Friday.md",
|
|
45
|
+
"violations": [
|
|
46
|
+
{
|
|
47
|
+
"column": "status",
|
|
48
|
+
"code": "enum",
|
|
49
|
+
"message": "must be one of: to watch; watched",
|
|
50
|
+
"value": "finished"
|
|
51
|
+
},
|
|
52
|
+
{ "column": "rating", "code": "max", "message": "must be <= 5", "value": 6 },
|
|
53
|
+
{
|
|
54
|
+
"column": "format",
|
|
55
|
+
"code": "unknown_column",
|
|
56
|
+
"message": "is not a column of table \"film\"",
|
|
57
|
+
"value": "Blu-ray"
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
```
|