Thin MongoDB ODM built for Standard Schema
mongodb
zod
deno
1import type { z } from "@zod/zod";
2
3// Type for Zod validation issues
4type ValidationIssue = z.ZodIssue;
5
6/**
7 * Base error class for all Nozzle errors
8 */
9export class NozzleError extends Error {
10 constructor(message: string) {
11 super(message);
12 this.name = this.constructor.name;
13 // Maintains proper stack trace for where error was thrown (only available on V8)
14 if (Error.captureStackTrace) {
15 Error.captureStackTrace(this, this.constructor);
16 }
17 }
18}
19
20/**
21 * Validation error with structured issue details
22 * Thrown when data fails schema validation
23 */
24export class ValidationError extends NozzleError {
25 public readonly issues: ValidationIssue[];
26 public readonly operation: "insert" | "update" | "replace";
27
28 constructor(
29 issues: ValidationIssue[],
30 operation: "insert" | "update" | "replace",
31 ) {
32 const message = ValidationError.formatIssues(issues);
33 super(`Validation failed on ${operation}: ${message}`);
34 this.issues = issues;
35 this.operation = operation;
36 }
37
38 private static formatIssues(issues: ValidationIssue[]): string {
39 return issues.map((issue) => {
40 const path = issue.path.join(".");
41 return `${path || "root"}: ${issue.message}`;
42 }).join("; ");
43 }
44
45 /**
46 * Get validation errors grouped by field
47 */
48 public getFieldErrors(): Record<string, string[]> {
49 const fieldErrors: Record<string, string[]> = {};
50 for (const issue of this.issues) {
51 const field = issue.path.join(".") || "root";
52 if (!fieldErrors[field]) {
53 fieldErrors[field] = [];
54 }
55 fieldErrors[field].push(issue.message);
56 }
57 return fieldErrors;
58 }
59}
60
61/**
62 * Connection error
63 * Thrown when database connection fails or is not established
64 */
65export class ConnectionError extends NozzleError {
66 public readonly uri?: string;
67
68 constructor(message: string, uri?: string) {
69 super(message);
70 this.uri = uri;
71 }
72}
73
74/**
75 * Configuration error
76 * Thrown when invalid configuration options are provided
77 */
78export class ConfigurationError extends NozzleError {
79 public readonly option?: string;
80
81 constructor(message: string, option?: string) {
82 super(message);
83 this.option = option;
84 }
85}
86
87/**
88 * Document not found error
89 * Thrown when a required document is not found
90 */
91export class DocumentNotFoundError extends NozzleError {
92 public readonly query: unknown;
93 public readonly collection: string;
94
95 constructor(collection: string, query: unknown) {
96 super(`Document not found in collection '${collection}'`);
97 this.collection = collection;
98 this.query = query;
99 }
100}
101
102/**
103 * Operation error
104 * Thrown when a database operation fails
105 */
106export class OperationError extends NozzleError {
107 public readonly operation: string;
108 public readonly collection?: string;
109 public override readonly cause?: Error;
110
111 constructor(
112 operation: string,
113 message: string,
114 collection?: string,
115 cause?: Error,
116 ) {
117 super(`${operation} operation failed: ${message}`);
118 this.operation = operation;
119 this.collection = collection;
120 this.cause = cause;
121 }
122}
123
124/**
125 * Async validation not supported error
126 * Thrown when async validation is attempted
127 */
128export class AsyncValidationError extends NozzleError {
129 constructor() {
130 super(
131 "Async validation is not currently supported. " +
132 "Please use synchronous validation schemas.",
133 );
134 }
135}