UNPKG

convex

Version:

Client for the Convex Cloud

349 lines (337 loc) 11.9 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var dataModel_exports = {}; __export(dataModel_exports, { dynamicDataModelDTS: () => dynamicDataModelDTS, noSchemaDataModelDTS: () => noSchemaDataModelDTS, staticDataModelDTS: () => staticDataModelDTS }); module.exports = __toCommonJS(dataModel_exports); var import_directoryStructure = require("../lib/components/definition/directoryStructure.js"); var import_common = require("./common.js"); var import_validator_helpers = require("./validator_helpers.js"); function noSchemaDataModelDTS() { return ` ${(0, import_common.header)("Generated data model types.")} import { AnyDataModel } from "convex/server"; import type { GenericId } from "convex/values"; /** * No \`schema.ts\` file found! * * This generated code has permissive types like \`Doc = any\` because * Convex doesn't know your schema. If you'd like more type safety, see * https://docs.convex.dev/using/schemas for instructions on how to add a * schema file. * * After you change a schema, rerun codegen with \`npx convex dev\`. */ /** * The names of all of your Convex tables. */ export type TableNames = string; /** * The type of a document stored in Convex. */ export type Doc = any; /** * An identifier for a document in Convex. * * Convex documents are uniquely identified by their \`Id\`, which is accessible * on the \`_id\` field. To learn more, see [Document IDs](https://docs.convex.dev/using/document-ids). * * Documents can be loaded using \`db.get(id)\` in query and mutation functions. * * IDs are just strings at runtime, but this type can be used to distinguish them from other * strings when type checking. */ export type Id<TableName extends TableNames = TableNames> = GenericId<TableName>; /** * A type describing your Convex data model. * * This type includes information about what tables you have, the type of * documents stored in those tables, and the indexes defined on them. * * This type is used to parameterize methods like \`queryGeneric\` and * \`mutationGeneric\` to make them type-safe. */ export type DataModel = AnyDataModel;`; } function dynamicDataModelDTS() { return ` ${(0, import_common.header)("Generated data model types.")} import type { DataModelFromSchemaDefinition, DocumentByName, TableNamesInDataModel, SystemTableNames } from "convex/server"; import type { GenericId } from "convex/values"; import schema from "../schema.js"; /** * The names of all of your Convex tables. */ export type TableNames = TableNamesInDataModel<DataModel>; /** * The type of a document stored in Convex. * * @typeParam TableName - A string literal type of the table name (like "users"). */ export type Doc<TableName extends TableNames> = DocumentByName<DataModel, TableName>; /** * An identifier for a document in Convex. * * Convex documents are uniquely identified by their \`Id\`, which is accessible * on the \`_id\` field. To learn more, see [Document IDs](https://docs.convex.dev/using/document-ids). * * Documents can be loaded using \`db.get(id)\` in query and mutation functions. * * IDs are just strings at runtime, but this type can be used to distinguish them from other * strings when type checking. * * @typeParam TableName - A string literal type of the table name (like "users"). */ export type Id<TableName extends TableNames | SystemTableNames> = GenericId<TableName>; /** * A type describing your Convex data model. * * This type includes information about what tables you have, the type of * documents stored in those tables, and the indexes defined on them. * * This type is used to parameterize methods like \`queryGeneric\` and * \`mutationGeneric\` to make them type-safe. */ export type DataModel = DataModelFromSchemaDefinition<typeof schema>; `; } async function staticDataModelDTS(ctx, startPush, rootComponent, componentDirectory) { const definitionPath = (0, import_directoryStructure.toComponentDefinitionPath)( rootComponent, componentDirectory ); const analysis = startPush.analysis[definitionPath]; if (!analysis) { return await ctx.crash({ exitCode: 1, errorType: "fatal", printedMessage: `No analysis found for component ${definitionPath} orig: ${definitionPath} in ${Object.keys(startPush.analysis).toString()}` }); } if (!analysis.schema) { return noSchemaDataModelDTS(); } const lines = [ (0, import_common.header)("Generated data model types."), `import type { DocumentByName, TableNamesInDataModel, SystemTableNames, AnyDataModel } from "convex/server";`, `import type { GenericId } from "convex/values";` ]; for await (const line of codegenDataModel(ctx, analysis.schema)) { lines.push(line); } lines.push(` /** * The names of all of your Convex tables. */ export type TableNames = TableNamesInDataModel<DataModel>; /** * The type of a document stored in Convex. * * @typeParam TableName - A string literal type of the table name (like "users"). */ export type Doc<TableName extends TableNames> = DocumentByName<DataModel, TableName>; /** * An identifier for a document in Convex. * * Convex documents are uniquely identified by their \`Id\`, which is accessible * on the \`_id\` field. To learn more, see [Document IDs](https://docs.convex.dev/using/document-ids). * * Documents can be loaded using \`db.get(id)\` in query and mutation functions. * * IDs are just strings at runtime, but this type can be used to distinguish them from other * strings when type checking. * * @typeParam TableName - A string literal type of the table name (like "users"). */ export type Id<TableName extends TableNames | SystemTableNames> = GenericId<TableName>; `); return lines.join("\n"); } async function* codegenDataModel(ctx, schema) { yield ` /** * A type describing your Convex data model. * * This type includes information about what tables you have, the type of * documents stored in those tables, and the indexes defined on them. * * This type is used to parameterize methods like \`queryGeneric\` and * \`mutationGeneric\` to make them type-safe. */ `; const tables = [...schema.tables]; tables.sort((a, b) => a.tableName.localeCompare(b.tableName)); yield `export type DataModel = {`; for (const table of tables) { yield ` ${table.tableName}:`; yield* codegenTable(ctx, table); yield `,`; } yield `}`; if (!schema.schemaValidation) { yield ` & AnyDataModel`; } yield `;`; } async function* codegenTable(ctx, table) { const documentType = await addSystemFields( ctx, table.tableName, table.documentType ); const indexJson = {}; for (const index of table.indexes) { indexJson[index.indexDescriptor] = index.fields; } yield `{`; yield ` document: ${(0, import_validator_helpers.validatorToType)(documentType, true)},`; const fieldPaths = /* @__PURE__ */ new Set(); for (const fieldPath of extractFieldPaths(documentType)) { fieldPaths.add(fieldPath.join(".")); } yield ` fieldPaths: ${stringLiteralUnionType(Array.from(fieldPaths).sort())},`; yield ` indexes: {`; const systemIndexes = { by_id: ["_id"], by_creation_time: ["_creationTime"] }; const indexes = {}; for (const [indexDescriptor, fields] of Object.entries(systemIndexes)) { indexes[indexDescriptor] = fields; } for (const index of table.indexes) { if (indexes[index.indexDescriptor]) { yield await ctx.crash({ exitCode: 1, errorType: "fatal", printedMessage: `Duplicate index name ${index.indexDescriptor} in table ${table.tableName}.` }); } indexes[index.indexDescriptor] = index.fields; } for (const [indexDescriptor, fields] of Object.entries(indexes)) { yield ` "${indexDescriptor}": ${JSON.stringify(fields)},`; } yield ` },`; yield ` searchIndexes: {`; for (const index of table.searchIndexes ?? []) { yield ` "${index.indexDescriptor}": {`; yield ` searchField: "${index.searchField}",`; yield ` filterFields: ${stringLiteralUnionType(index.filterFields)},`; yield ` },`; } yield ` },`; yield ` vectorIndexes: {`; for (const index of table.vectorIndexes ?? []) { yield ` "${index.indexDescriptor}": {`; yield ` vectorField: "${index.vectorField}",`; yield ` dimensions: ${index.dimensions},`; yield ` filterFields: ${stringLiteralUnionType(index.filterFields)},`; yield ` },`; } yield ` },`; yield `}`; } const SYSTEM_FIELDS = ["_id", "_creationTime"]; async function addSystemFields(ctx, tableName, validator) { if (validator.type === "object") { return addSystemFieldsToObject(ctx, tableName, validator); } else if (validator.type === "any") { return { type: "any" }; } else if (validator.type === "union") { const newSubValidators = []; for (const subValidator of validator.value) { const newSubValidator = await addSystemFieldsToObject( ctx, tableName, subValidator ); newSubValidators.push(newSubValidator); } return { type: "union", value: newSubValidators }; } else { return await ctx.crash({ exitCode: 1, errorType: "fatal", printedMessage: `Invalid top-level validator for ${tableName}.` }); } } async function addSystemFieldsToObject(ctx, tableName, validator) { if (validator.type !== "object") { return await ctx.crash({ exitCode: 1, errorType: "fatal", printedMessage: `System fields can only be added to objects.` }); } for (const systemField of SYSTEM_FIELDS) { if (Object.hasOwn(validator.value, systemField)) { return await ctx.crash({ exitCode: 1, errorType: "fatal", printedMessage: `System field ${systemField} present in table ${tableName}.` }); } } return { type: "object", value: { ...validator.value, _id: { fieldType: { type: "id", tableName }, optional: false }, _creationTime: { fieldType: { type: "number" }, optional: false } } }; } function* extractFieldPaths(validator) { if (validator.type === "object") { for (const [fieldName, fieldValidator] of Object.entries(validator.value)) { for (const subFieldPath of extractFieldPaths(fieldValidator.fieldType)) { yield [fieldName, ...subFieldPath]; } } } else if (validator.type === "union") { for (const subValidator of validator.value) { yield* extractFieldPaths(subValidator); } } else { yield []; } } function stringLiteralUnionType(fields) { if (fields.length === 0) { return "never"; } else if (fields.length === 1) { return `"${fields[0]}"`; } else { return fields.map((field) => `"${field}"`).join(" | "); } } //# sourceMappingURL=dataModel.js.map