Skip to main content
Glama

Convex MCP server

Official
by get-convex
validator.test.ts6.11 kB
import { GenericId } from "../values/index.js"; import { describe, test, expect } from "vitest"; import { assert, Equals } from "../test/type_testing.js"; import { v, Infer } from "../values/validator.js"; describe("Validators", () => { test("optional types don't lose specificity", () => { const a = v.optional(v.id("a")); const b = v.optional(v.null()); const c = v.optional(v.number()); const d = v.optional(v.int64()); const e = v.optional(v.boolean()); const f = v.optional(v.string()); const g = v.optional(v.bytes()); const h = v.optional(v.literal("a")); const i = v.optional(v.array(v.string())); const j = v.optional(v.object({ a: v.string() })); const k = v.optional(v.record(v.string(), v.string())); const l = v.optional(v.union(v.string(), v.number())); // Optional makes types a union with undefined. assert<Equals<Infer<typeof a>, GenericId<"a"> | undefined>>(); assert<Equals<Infer<typeof b>, null | undefined>>(); assert<Equals<Infer<typeof c>, number | undefined>>(); assert<Equals<Infer<typeof d>, bigint | undefined>>(); assert<Equals<Infer<typeof e>, boolean | undefined>>(); assert<Equals<Infer<typeof f>, string | undefined>>(); assert<Equals<Infer<typeof g>, ArrayBuffer | undefined>>(); assert<Equals<Infer<typeof h>, "a" | undefined>>(); assert<Equals<Infer<typeof i>, string[] | undefined>>(); assert<Equals<Infer<typeof j>, { a: string } | undefined>>(); assert<Equals<Infer<typeof k>, Record<string, string> | undefined>>(); assert<Equals<Infer<typeof l>, string | number | undefined>>(); // Note: this test does not actually verify this property unless // the tsconfig.json option `"exactOptionalPropertyTypes": true` is used. const _optionals = v.object({ a, b, c, d, e, f, g, h, i, j, k, l }); assert< Equals< Infer<typeof _optionals>, { a?: GenericId<"a">; b?: null; c?: number; d?: bigint; e?: boolean; f?: string; g?: ArrayBuffer; h?: "a"; i?: string[]; j?: { a: string }; k?: Record<string, string>; l?: string | number; } > >(); }); test("Most validators don't accept optional validators as children", () => { const optional = v.optional(v.string()); const required = v.string(); v.object({ optional }); v.array(required); // @ts-expect-error This should be an error v.array(optional); v.record(required, required); const invalidRecordError = "Record validator cannot have optional "; // @ts-expect-error This should be an error expect(() => v.record(required, optional)).toThrowError( invalidRecordError + "values", ); // @ts-expect-error This should be an error expect(() => v.record(optional, required)).toThrowError( invalidRecordError + "keys", ); // @ts-expect-error This should be an error expect(() => v.record(optional, optional)).toThrowError( invalidRecordError + "keys", ); v.union(required, required); // @ts-expect-error This should be an error v.union(optional, optional); // @ts-expect-error This should be an error v.union(required, optional); // @ts-expect-error This should be an error v.union(optional, required); }); test("Record validators cannot have non-strings as arguments", () => { v.record(v.id("table1"), v.string()); v.record(v.union(v.id("table1"), v.id("table2")), v.string()); // @ts-expect-error This should be an error v.record(v.number(), v.string()); // @ts-expect-error This should be an error v.record(v.int64(), v.string()); // @ts-expect-error This should be an error v.record(v.float64(), v.string()); // @ts-expect-error This should be an error v.record(v.null(), v.string()); // @ts-expect-error This should be an error v.record(v.boolean(), v.string()); // These patterns will compile, but will be rejected by the server v.record(v.union(v.literal("abc"), v.literal("def")), v.string()); v.record(v.union(v.id("table1"), v.literal("def")), v.string()); }); test("complex types look good", () => { const _obj = v.object({ a: v.record(v.string(), v.string()), b: v.string(), c: v.union(v.string(), v.union(v.string(), v.number())), d: v.object({ foo: v.string(), bar: v.optional(v.number()) }), }); type Expected = { a: Record<string, string>; b: string; c: string | number; d: { bar?: number | undefined; foo: string; }; }; assert<Equals<Infer<typeof _obj>, Expected>>(); }); }); describe("invalid validators fail when constructed obviously wrongly", () => { describe("easy ones", () => { test("v.id", () => { expect(() => { (v as any).id(); }).toThrow(); expect(() => { v.id({} as any); }).toThrow(); expect(() => { v.id({} as any); }).toThrow(); }); // no tests for v.null, number, floag64, bigint, in64, boolean, string, or bytes test("v.literal", () => { expect(() => { (v as any).literal(); }).toThrow(); expect(() => { v.literal({} as any); }).toThrow(); }); }); test("v.object", () => { expect(() => { (v as any).object(); }).toThrow(); expect(() => { v.object({ a: {} } as any); }).toThrow(); expect(() => { v.object({}); }).not.toThrow(); expect(() => { v.object({ a: undefined as any }); }).toThrow(); }); test("v.object regression test", () => { expect(() => { // real issue from the wild v.object({ a: v.string as any }); }).toThrow(); }); test("v.record", () => { expect(() => { (v as any).record(); }).toThrow(); expect(() => { v.record({} as any, {} as any); }).toThrow(); }); test("v.union", () => { expect(() => { v.union({} as any, {} as any); }).toThrow(); }); });

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