UNPKG

kitcn

Version:

kitcn - React Query integration and CLI tools for Convex

197 lines (195 loc) 8.24 kB
import { t as assert } from "./upstream-BR6sBLg3.js"; import { asObjectValidator, v } from "convex/values"; //#region src/internal/upstream/validators.ts function partial(fieldsOrObjOrUnion) { if (fieldsOrObjOrUnion.isConvexValidator) { if (fieldsOrObjOrUnion.kind === "object") return partialVObject(fieldsOrObjOrUnion); if (fieldsOrObjOrUnion.kind === "union") return partialUnion(fieldsOrObjOrUnion); throw new Error("partial only works with union or object Validators, or a Record<string, Validator> currently"); } return partialFields(fieldsOrObjOrUnion); } /** * partialFields helps you define an object of optional validators more concisely. * * e.g. `partialFields({a: v.string(), b: v.number()})` is equivalent to * `{a: v.optional(v.string()), b: v.optional(v.number())}` * * @param obj The object of validators to make optional. e.g. {a: v.string()} * @returns A new object of validators that can be the value or undefined. */ function partialFields(obj) { return Object.fromEntries(Object.entries(obj).map(([k, vv]) => [k, vv.isOptional === "optional" ? vv : v.optional(vv)])); } /** * partialObject helps you define an object of optional validators more concisely. * * e.g. `partialObject({a: v.string(), b: v.number()})` is equivalent to * `{a: v.optional(v.string()), b: v.optional(v.number())}` * * @param obj The object of validators to make optional. e.g. {a: v.string()} * @returns A new object of validators that can be the value or undefined. */ function partialVObject(obj) { const o = v.object(partialFields(obj.fields)); if (obj.isOptional === "optional") return v.optional(o); return o; } function partialUnion(union) { const u = v.union(...union.members.map((m) => { assert(m.isOptional === "required", "Union members cannot be optional"); if (m.kind === "object") return partialVObject(m); if (m.kind === "union") return partialUnion(m); throw new Error(`Invalid union member type: ${m.kind}`); })); if (union.isOptional === "optional") return v.optional(u); return u; } /** @deprecated Use `v.string()` instead. Any string value. */ const string = v.string(); /** @deprecated Use `v.float64()` instead. JavaScript number, represented as a float64 in the database. */ const number = v.float64(); /** @deprecated Use `v.float64()` instead. JavaScript number, represented as a float64 in the database. */ const float64 = v.float64(); /** @deprecated Use `v.boolean()` instead. boolean value. For typing it only as true, use `l(true)` */ const boolean = v.boolean(); /** @deprecated Use `v.int64()` instead. bigint, though stored as an int64 in the database. */ const biging = v.int64(); /** @deprecated Use `v.int64()` instead. bigint, though stored as an int64 in the database. */ const int64 = v.int64(); /** @deprecated Use `v.any()` instead. Any Convex value */ const any = v.any(); /** @deprecated Use `v.null()` instead. Null value. Underscore is so it doesn't shadow the null builtin */ const null_ = v.null(); /** @deprecated Use `v.*()` instead. */ const { id, object, array, bytes, literal, optional, union } = v; /** @deprecated Use `v.bytes()` instead. ArrayBuffer validator. */ const arrayBuffer = v.bytes(); function addFieldsToValidator(validatorOrFields, fields) { const validator = asObjectValidator(validatorOrFields); if (Object.keys(fields).length === 0) return validator; switch (validator.kind) { case "object": return v.object(intersectValidators(validator.fields, fields)); case "union": return v.union(...validator.members.map((m) => addFieldsToValidator(m, fields))); default: throw new Error("Cannot add arguments to a validator that is not an object or union."); } } function intersectValidators(fields, fields2) { const specificFields = { ...fields }; for (const [k, v] of Object.entries(fields2)) { const existing = specificFields[k]; if (existing) { if (existing.kind !== v.kind) throw new Error(`Cannot intersect validators with different kinds: ${existing.kind} and ${v.kind}`); if (existing.isOptional !== v.isOptional && existing.isOptional === "optional") specificFields[k] = v; } else specificFields[k] = v; } return specificFields; } /** Mark fields as deprecated with this permissive validator typed as null */ const deprecated = v.optional(v.any()); /** A maximally permissive validator that type checks as a given validator. * * If you want to have types that match some validator but you have invalid data * and you want to temporarily not validate schema for this field, * you can use this function to cast the permissive validator. * * Example in a schema: * ```ts * export default defineSchema({ * myTable: defineTable({ * myString: pretend(v.array(v.string())), * }), * }); * //...in some mutation * ctx.db.insert("myTable", { myString: 123 as any }); // no runtime error * ``` * Example in function argument validation: * ```ts * const myQuery = defineQuery({ * args: { myNumber: pretend(v.number()) }, * handler: async (ctx, args) => { * // args.myNumber is typed as number, but it's not validated. * const num = typeof args.myNumber === "number" ? * args.myNumber : Number(args.myNumber); * }, * }); */ const pretend = (_typeToImmitate) => v.optional(v.any()); /** A validator that validates as optional but type checks as required. * * If you want to assume a field is set for type checking, but your data may not * actually have it set for all documents (e.g. when adding a new field), * you can use this function to allow the field to be unset at runtime. * This is unsafe, but can be convenient in these situations: * * 1. You are developing locally and want to add a required field and write * code assuming it is set. Once you push the code & schema, you can update * the data to match before running your code. * 2. You are going to run a migration right after pushing code, and are ok with * and you don't want to edit your code to handle the field being unset, * your app being in an inconsistent state until the migration completes. * * This differs from {@link pretend} in that it type checks the inner validator, * if the value is provided. * * Example in a schema: * ```ts * export default defineSchema({ * myTable: defineTable({ * myString: pretendRequired(v.array(v.string())), * }), * }); * //...in some mutation * ctx.db.insert("myTable", { myString: undefined }); // no runtime error * ``` * Example in function argument validation: * ```ts * const myQuery = defineQuery({ * args: { myNumber: pretendRequired(v.number()) }, * handler: async (ctx, args) => { * // args.myNumber is typed as number, but it might be undefined * const num = args.myNumber || 0; * }, * }); */ const pretendRequired = (optionalType) => v.optional(optionalType); /** * Converts an optional validator to a required validator. * * This is the inverse of `v.optional()`. It takes a validator that may be optional * and returns the equivalent required validator. * * ```ts * const optionalString = v.optional(v.string()); * const requiredString = vRequired(optionalString); // v.string() * * // Already required validators are returned as-is * const alreadyRequired = v.string(); * const stillRequired = vRequired(alreadyRequired); // v.string() * ``` * * @param validator The validator to make required. * @returns A required version of the validator. */ function vRequired(validator) { const { kind, isOptional } = validator; if (isOptional === "required") return validator; switch (kind) { case "id": return v.id(validator.tableName); case "string": return v.string(); case "float64": return v.float64(); case "int64": return v.int64(); case "boolean": return v.boolean(); case "null": return v.null(); case "any": return v.any(); case "literal": return v.literal(validator.value); case "bytes": return v.bytes(); case "object": return v.object(validator.fields); case "array": return v.array(validator.element); case "record": return v.record(validator.key, validator.value); case "union": return v.union(...validator.members); default: throw new Error("Unknown Convex validator type: " + kind); } } //#endregion export { pretendRequired as a, pretend as i, deprecated as n, vRequired as o, partial as r, addFieldsToValidator as t };