Schema validation on index

pull/1081/head
Zef Hemel 2024-08-24 16:14:29 +02:00
parent c416e8aeb5
commit fed9965a99
4 changed files with 37 additions and 32 deletions

View File

@ -245,8 +245,6 @@ config:
tag: tag:
type: string type: string
readOnly: true readOnly: true
enum:
- page
tags: tags:
anyOf: anyOf:
- type: array - type: array
@ -320,8 +318,6 @@ config:
tag: tag:
type: string type: string
readOnly: true readOnly: true
enum:
- aspiring-page
name: name:
type: string type: string
readOnly: true readOnly: true
@ -341,8 +337,6 @@ config:
tag: tag:
type: string type: string
readOnly: true readOnly: true
enum:
- attachment
tags: tags:
type: array type: array
readOnly: true readOnly: true
@ -386,8 +380,6 @@ config:
tag: tag:
type: string type: string
readOnly: true readOnly: true
enum:
- item
tags: tags:
type: array type: array
items: items:
@ -423,8 +415,6 @@ config:
tag: tag:
type: string type: string
readOnly: true readOnly: true
enum:
- tag
tags: tags:
type: array type: array
readOnly: true readOnly: true
@ -457,8 +447,6 @@ config:
readOnly: true readOnly: true
tag: tag:
type: string type: string
enum:
- anchor
tags: tags:
type: array type: array
items: items:
@ -483,8 +471,6 @@ config:
readOnly: true readOnly: true
tag: tag:
type: string type: string
enum:
- link
tags: tags:
type: array type: array
items: items:
@ -521,8 +507,6 @@ config:
readOnly: true readOnly: true
tag: tag:
type: string type: string
enum:
- header
tags: tags:
type: array type: array
items: items:
@ -549,8 +533,6 @@ config:
readOnly: true readOnly: true
tag: tag:
type: string type: string
enum:
- paragraph
tags: tags:
type: array type: array
items: items:
@ -575,8 +557,6 @@ config:
readOnly: true readOnly: true
tag: tag:
type: string type: string
enum:
- template
tags: tags:
anyOf: anyOf:
- type: array - type: array
@ -610,8 +590,6 @@ config:
readOnly: true readOnly: true
tag: tag:
type: string type: string
enum:
- table
tags: tags:
type: array type: array
items: items:

View File

@ -1,8 +1,10 @@
import type { IndexTreeEvent } from "@silverbulletmd/silverbullet/types"; import type { IndexTreeEvent } from "@silverbulletmd/silverbullet/types";
import { import {
editor, editor,
jsonschema,
markdown, markdown,
space, space,
system,
YAML, YAML,
} from "@silverbulletmd/silverbullet/syscalls"; } from "@silverbulletmd/silverbullet/syscalls";
@ -17,6 +19,7 @@ import {
} from "@silverbulletmd/silverbullet/lib/tree"; } from "@silverbulletmd/silverbullet/lib/tree";
import { updateITags } from "@silverbulletmd/silverbullet/lib/tags"; import { updateITags } from "@silverbulletmd/silverbullet/lib/tags";
import type { AspiringPageObject } from "./page_links.ts"; import type { AspiringPageObject } from "./page_links.ts";
import { deepObjectMerge } from "@silverbulletmd/silverbullet/lib/json";
export async function indexPage({ name, tree }: IndexTreeEvent) { export async function indexPage({ name, tree }: IndexTreeEvent) {
if (name.startsWith("_")) { if (name.startsWith("_")) {
@ -61,13 +64,38 @@ export async function indexPage({ name, tree }: IndexTreeEvent) {
updateITags(combinedPageMeta, frontmatter); updateITags(combinedPageMeta, frontmatter);
// console.log("Page object", combinedPageMeta);
await indexObjects<PageMeta>(name, [combinedPageMeta]);
// Make sure this page is no (longer) in the aspiring pages list // Make sure this page is no (longer) in the aspiring pages list
await queryDeleteObjects<AspiringPageObject>("aspiring-page", { await queryDeleteObjects<AspiringPageObject>("aspiring-page", {
filter: ["=", ["attr", "name"], ["string", name]], filter: ["=", ["attr", "name"], ["string", name]],
}); });
const tagSchema = (await system.getSpaceConfig("schema")).tag;
// Validate the page meta against schemas, and only index the tags that validate
for (const tag of combinedPageMeta.tags) {
let schema = tagSchema[tag];
if (schema) {
schema = deepObjectMerge({ type: "object" }, schema);
const validationError = await jsonschema.validateObject(
schema,
combinedPageMeta,
);
if (validationError) {
console.warn(
"Validation failed for",
combinedPageMeta,
"for tag",
tag,
". Error:",
validationError,
". Removing tag until this is resolved.",
);
combinedPageMeta.tags.splice(combinedPageMeta.tags.indexOf(tag), 1);
}
}
}
// console.log("Page object", combinedPageMeta);
await indexObjects<PageMeta>(name, [combinedPageMeta]);
} }
export async function lintFrontmatter(): Promise<LintDiagnostic[]> { export async function lintFrontmatter(): Promise<LintDiagnostic[]> {

View File

@ -53,8 +53,6 @@ config:
readOnly: true readOnly: true
tag: tag:
type: string type: string
enum:
- task
tags: tags:
type: array type: array
items: items:
@ -90,8 +88,6 @@ config:
readOnly: true readOnly: true
tag: tag:
type: string type: string
enum:
- taskstate
tags: tags:
type: array type: array
items: items:

View File

@ -82,11 +82,14 @@ schema.config.properties.myFullName.type: string
Now, if you would accidentally change `myFullName` into a number or boolean value, you would get a validation error. Now, if you would accidentally change `myFullName` into a number or boolean value, you would get a validation error.
# Validation # Validation
At the moment, validation only occurs in the editor in [[Space Config]] and [[Frontmatter]] blocks and shows any violations as highlighted errors. Validation happens during linting in the editor (visually, with squiggly lines for errors) and indexing (at the database level). Therefore, changes to your schema will only go into effect when either of those two things kick in.
Even if data does not pass validation, it is still stored in the data store so it does not (currently) _enforce_ the format. For pages, during indexing, specified [[Frontmatter]] is validated against schema specified for its tags. If validation fails for one of these tags, that _tag will be removed_ from its `tags` attribute and therefore **not** be indexed as such. This guarantees that the schema is enforced and any object follows the schema.
This may change in the future. For instance, in the example mentioned in [[#Example]], if the `lastName` of either of the two `#contact` tagged pages is removed (which would mean it no longer matches the schema constraints), this object will no longer be indexed as a `contact` and thus not appear in query results for it. However, since the page still follows the regular `page` tag schema, it will still appear in `page` query results.
> **note** Note
> If you would like to enforce a newly introduced or updated schema on your entire space, you will have to run a full {[Space: Reindex]}.
# Supported types # Supported types
All standard JSON Schema types are supported. Likely you are interested in: All standard JSON Schema types are supported. Likely you are interested in: