Skip to main content
Glama

Convex MCP server

Official
by get-convex
walkPatchDocuments.ts3.71 kB
import { ValidatorJSON, Value } from "convex/values"; import isPlainObject from "lodash/isPlainObject"; import { UNDEFINED_PLACEHOLDER } from "system-udfs/convex/_system/frontend/lib/values"; import { ConvexSchemaValidationError, ConvexValidationError, isUndefined, Node, ObjectPropertyNode, } from "@common/elements/ObjectEditor/ast/types"; import { Walker } from "@common/elements/ObjectEditor/ast/ast"; // This function walks an AST when the mode is "patchDocuments". export function walkPatchDocuments(node: Node, validator?: ValidatorJSON) { // Since we're patching multiple documents, we should make sure the value is an object, // and that any undefined values in the object are removed from the nodes to walk, // but still validated. const extractResult = extractUndefinedValuesFromNode(node, validator); const { node: nodeToWalk, errors: errorsToMerge } = extractResult; let { value } = extractResult; // If the validator type is a union, we should ignore it. // We don't have a better way to handle validating patches for unions yet. const walker = new Walker({ validator: validator?.type === "union" ? undefined : validator, }); const { value: walkerValue, errors: walkErrors } = walker.walk( nodeToWalk, false, ); if (!isPlainObject(walkerValue)) { return { value: walkerValue, errors: [ new ConvexValidationError("Value must be an object.", nodeToWalk.loc), ], }; } // @ts-expect-error -- we know walkerValue is an object value = value === undefined ? walkerValue : { ...value, ...walkerValue }; // If we're patching documents, we should ignore RequiredPropertyMissing errors on any fields that were not // specified. const filteredWalkErrors = walkErrors.filter( (error: any) => !(error instanceof ConvexSchemaValidationError) || error.code !== "RequiredPropertyMissing", ); return { value: value === undefined ? walkerValue : value, errors: [...errorsToMerge, ...filteredWalkErrors], }; } const propertyKey = (property: ObjectPropertyNode) => property.key.type === "Identifier" ? property.key.name : property.key.type === "Literal" ? typeof property.key.value === "string" ? property.key.value : undefined : undefined; function extractUndefinedValuesFromNode( nodeToWalk: Node, validator?: ValidatorJSON, ) { if (nodeToWalk.type !== "ObjectExpression") { return { node: nodeToWalk, value: undefined, errors: [ new ConvexValidationError("Value must be an object.", nodeToWalk.loc), ], }; } const v: Record<string, Value> = {}; const errors: ConvexValidationError[] = []; nodeToWalk.properties.forEach((property) => { if (isUndefined(property.value)) { const key = propertyKey(property); if (typeof key !== "string") { errors.push( new ConvexValidationError( "Unsupported field name: key must be a string.", property.key.loc, ), ); return; } v[key] = UNDEFINED_PLACEHOLDER; if (validator && validator.type === "object") { const fieldValidator = validator.value[key]; if (fieldValidator && !fieldValidator.optional) { errors.push( new ConvexSchemaValidationError( "RequiredPropertyMissing", validator, key, property.value.loc, ), ); } } } }); return { node: { ...nodeToWalk, properties: nodeToWalk.properties.filter( (property) => !isUndefined(property.value), ), }, value: v, errors, }; }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/get-convex/convex-backend'

If you have feedback or need assistance with the MCP directory API, please join our Discord server