/** * MongoDB client implementation. * * Uses the native MongoDB plugin type from @superblocksteam/types. */ import type { PartialMessage } from "@bufbuild/protobuf"; import type { z } from "zod"; import type { Plugin as MongoDBPlugin } from "@superblocksteam/types/dist/src/plugins/mongodb/v1/plugin_pb"; import { RestApiValidationError } from "../../errors.js"; import { IntegrationError } from "../../runtime/errors.js"; import type { QueryExecutor, TraceMetadata } from "../registry.js"; import type { IntegrationConfig, IntegrationClientImpl } from "../types.js"; import type { MongoDBClient, MongoDBAction, MongoDBParams } from "./types.js"; /** * Internal implementation of MongoDBClient. */ export class MongoDBClientImpl implements MongoDBClient, IntegrationClientImpl { readonly config: IntegrationConfig; private readonly executeQuery: QueryExecutor; constructor(config: IntegrationConfig, executeQuery: QueryExecutor) { this.config = config; this.executeQuery = executeQuery; } get name(): string { return this.config.name; } get pluginId(): string { return this.config.pluginId; } private buildRequest( collection: string, action: MongoDBAction, params?: MongoDBParams, ): PartialMessage { const request: PartialMessage = { resource: collection, action, }; if (params) { // Query/filter if (params.query) { request.query = JSON.stringify(params.query); } if (params.filter) { request.filter = JSON.stringify(params.filter); } // Document operations if (params.document) { request.document = JSON.stringify(params.document); } if (params.update) { request.update = JSON.stringify(params.update); } // Aggregation if (params.pipeline) { request.pipeline = JSON.stringify(params.pipeline); } // Query modifiers if (params.projection) { request.projection = JSON.stringify(params.projection); } if (params.sort) { request.sortby = JSON.stringify(params.sort); } if (params.limit !== undefined) { request.limit = String(params.limit); } if (params.skip !== undefined) { request.skip = String(params.skip); } // Distinct field if (params.field) { request.field = params.field; } // Additional options if (params.options) { request.options = JSON.stringify(params.options); } } return request; } async run( collection: string, action: MongoDBAction, schema: z.ZodSchema, params?: MongoDBParams, metadata?: TraceMetadata, ): Promise { const request = this.buildRequest(collection, action, params); try { const result = await this.executeQuery( request as Record, undefined, metadata, ); // Validate result against schema const parseResult = schema.safeParse(result); if (!parseResult.success) { throw new RestApiValidationError( `Result validation failed: ${parseResult.error.message}`, { zodError: parseResult.error, data: result, }, ); } return parseResult.data; } catch (error) { if ( error instanceof RestApiValidationError || error instanceof IntegrationError ) { throw error; } throw new IntegrationError(this.config.name, "run", error); } } }