@@ -10,20 +10,24 @@ import {
1010 defineRouteContract ,
1111} from '@/lib/api/contracts/types'
1212
13- const mongoConnectionBodySchema = z
14- . object ( {
15- host : z . string ( ) . min ( 1 , 'Host is required' ) ,
16- port : z . coerce . number ( ) . int ( ) . positive ( 'Port must be a positive integer' ) ,
17- database : z . string ( ) . min ( 1 , 'Database name is required' ) ,
18- username : z . string ( ) . min ( 1 , 'Username is required' ) . optional ( ) ,
19- password : z . string ( ) . min ( 1 , 'Password is required' ) . optional ( ) ,
20- authSource : z . string ( ) . optional ( ) ,
21- ssl : sslModeSchema ,
22- } )
23- . refine ( ( data ) => Boolean ( data . username ) === Boolean ( data . password ) , {
24- message : 'Username and password must be provided together' ,
25- path : [ 'password' ] ,
26- } )
13+ // Un-refined base so the downstream operation schemas can .extend it; each
14+ // reattaches mongoUsernamePasswordPaired after its own .extend.
15+ const mongoConnectionBaseSchema = z . object ( {
16+ host : z . string ( ) . min ( 1 , 'Host is required' ) ,
17+ port : z . coerce . number ( ) . int ( ) . positive ( 'Port must be a positive integer' ) ,
18+ database : z . string ( ) . min ( 1 , 'Database name is required' ) ,
19+ username : z . string ( ) . min ( 1 , 'Username is required' ) . optional ( ) ,
20+ password : z . string ( ) . min ( 1 , 'Password is required' ) . optional ( ) ,
21+ authSource : z . string ( ) . optional ( ) ,
22+ ssl : sslModeSchema ,
23+ } )
24+
25+ const mongoUsernamePasswordPaired = ( data : { username ?: string ; password ?: string } ) =>
26+ Boolean ( data . username ) === Boolean ( data . password )
27+ const mongoUsernamePasswordPairedError = {
28+ message : 'Username and password must be provided together' ,
29+ path : [ 'password' as const ] ,
30+ }
2731
2832const mongoJsonStringOrObjectSchema = ( message : string ) =>
2933 z
@@ -45,92 +49,102 @@ const booleanStringSchema = z
4549 return false
4650 } )
4751
48- export const mongodbQueryBodySchema = mongoConnectionBodySchema . extend ( {
49- collection : z . string ( ) . min ( 1 , 'Collection name is required' ) ,
50- query : z
51- . union ( [ z . string ( ) , z . object ( { } ) . passthrough ( ) ] )
52- . optional ( )
53- . default ( '{}' )
54- . transform ( ( val ) => {
55- if ( typeof val === 'object' && val !== null ) {
56- return JSON . stringify ( val )
57- }
58- return val || '{}'
59- } ) ,
60- limit : z
61- . union ( [ z . coerce . number ( ) . int ( ) . positive ( ) , z . literal ( '' ) , z . undefined ( ) ] )
62- . optional ( )
63- . transform ( ( val ) => {
64- if ( val === '' || val === undefined || val === null ) {
65- return 100
66- }
67- return val
68- } ) ,
69- sort : z
70- . union ( [ z . string ( ) , z . object ( { } ) . passthrough ( ) , z . null ( ) ] )
71- . optional ( )
72- . transform ( ( val ) => {
73- if ( typeof val === 'object' && val !== null ) {
74- return JSON . stringify ( val )
75- }
76- return val
77- } ) ,
78- } )
79-
80- export const mongodbExecuteBodySchema = mongoConnectionBodySchema . extend ( {
81- collection : z . string ( ) . min ( 1 , 'Collection name is required' ) ,
82- pipeline : z
83- . union ( [ z . string ( ) , z . array ( z . object ( { } ) . passthrough ( ) ) ] )
84- . transform ( ( val ) => {
85- if ( Array . isArray ( val ) ) {
86- return JSON . stringify ( val )
87- }
88- return val
89- } )
90- . refine ( ( val ) => val && val . trim ( ) !== '' , {
91- message : 'Pipeline is required' ,
92- } ) ,
93- } )
94-
95- export const mongodbInsertBodySchema = mongoConnectionBodySchema . extend ( {
96- collection : z . string ( ) . min ( 1 , 'Collection name is required' ) ,
97- documents : z
98- . union ( [ z . array ( z . record ( z . string ( ) , z . unknown ( ) ) ) , z . string ( ) ] )
99- . transform ( ( val ) => {
100- if ( typeof val === 'string' ) {
101- try {
102- const parsed = JSON . parse ( val )
103- return Array . isArray ( parsed ) ? parsed : [ parsed ]
104- } catch {
105- throw new Error ( 'Invalid JSON in documents field' )
52+ export const mongodbQueryBodySchema = mongoConnectionBaseSchema
53+ . extend ( {
54+ collection : z . string ( ) . min ( 1 , 'Collection name is required' ) ,
55+ query : z
56+ . union ( [ z . string ( ) , z . object ( { } ) . passthrough ( ) ] )
57+ . optional ( )
58+ . default ( '{}' )
59+ . transform ( ( val ) => {
60+ if ( typeof val === 'object' && val !== null ) {
61+ return JSON . stringify ( val )
10662 }
107- }
108- return val
109- } )
110- . refine ( ( val ) => Array . isArray ( val ) && val . length > 0 , {
111- message : 'At least one document is required' ,
112- } ) ,
113- } )
114-
115- export const mongodbUpdateBodySchema = mongoConnectionBodySchema . extend ( {
116- collection : z . string ( ) . min ( 1 , 'Collection name is required' ) ,
117- filter : mongoJsonStringOrObjectSchema ( 'Filter is required for MongoDB Update' ) . refine (
118- ( val ) => val !== '{}' ,
119- { message : 'Filter is required for MongoDB Update' }
120- ) ,
121- update : mongoJsonStringOrObjectSchema ( 'Update is required' ) ,
122- upsert : booleanStringSchema ,
123- multi : booleanStringSchema ,
124- } )
125-
126- export const mongodbDeleteBodySchema = mongoConnectionBodySchema . extend ( {
127- collection : z . string ( ) . min ( 1 , 'Collection name is required' ) ,
128- filter : mongoJsonStringOrObjectSchema ( 'Filter is required for MongoDB Delete' ) . refine (
129- ( val ) => val !== '{}' ,
130- { message : 'Filter is required for MongoDB Delete' }
131- ) ,
132- multi : booleanStringSchema ,
133- } )
63+ return val || '{}'
64+ } ) ,
65+ limit : z
66+ . union ( [ z . coerce . number ( ) . int ( ) . positive ( ) , z . literal ( '' ) , z . undefined ( ) ] )
67+ . optional ( )
68+ . transform ( ( val ) => {
69+ if ( val === '' || val === undefined || val === null ) {
70+ return 100
71+ }
72+ return val
73+ } ) ,
74+ sort : z
75+ . union ( [ z . string ( ) , z . object ( { } ) . passthrough ( ) , z . null ( ) ] )
76+ . optional ( )
77+ . transform ( ( val ) => {
78+ if ( typeof val === 'object' && val !== null ) {
79+ return JSON . stringify ( val )
80+ }
81+ return val
82+ } ) ,
83+ } )
84+ . refine ( mongoUsernamePasswordPaired , mongoUsernamePasswordPairedError )
85+
86+ export const mongodbExecuteBodySchema = mongoConnectionBaseSchema
87+ . extend ( {
88+ collection : z . string ( ) . min ( 1 , 'Collection name is required' ) ,
89+ pipeline : z
90+ . union ( [ z . string ( ) , z . array ( z . object ( { } ) . passthrough ( ) ) ] )
91+ . transform ( ( val ) => {
92+ if ( Array . isArray ( val ) ) {
93+ return JSON . stringify ( val )
94+ }
95+ return val
96+ } )
97+ . refine ( ( val ) => val && val . trim ( ) !== '' , {
98+ message : 'Pipeline is required' ,
99+ } ) ,
100+ } )
101+ . refine ( mongoUsernamePasswordPaired , mongoUsernamePasswordPairedError )
102+
103+ export const mongodbInsertBodySchema = mongoConnectionBaseSchema
104+ . extend ( {
105+ collection : z . string ( ) . min ( 1 , 'Collection name is required' ) ,
106+ documents : z
107+ . union ( [ z . array ( z . record ( z . string ( ) , z . unknown ( ) ) ) , z . string ( ) ] )
108+ . transform ( ( val ) => {
109+ if ( typeof val === 'string' ) {
110+ try {
111+ const parsed = JSON . parse ( val )
112+ return Array . isArray ( parsed ) ? parsed : [ parsed ]
113+ } catch {
114+ throw new Error ( 'Invalid JSON in documents field' )
115+ }
116+ }
117+ return val
118+ } )
119+ . refine ( ( val ) => Array . isArray ( val ) && val . length > 0 , {
120+ message : 'At least one document is required' ,
121+ } ) ,
122+ } )
123+ . refine ( mongoUsernamePasswordPaired , mongoUsernamePasswordPairedError )
124+
125+ export const mongodbUpdateBodySchema = mongoConnectionBaseSchema
126+ . extend ( {
127+ collection : z . string ( ) . min ( 1 , 'Collection name is required' ) ,
128+ filter : mongoJsonStringOrObjectSchema ( 'Filter is required for MongoDB Update' ) . refine (
129+ ( val ) => val !== '{}' ,
130+ { message : 'Filter is required for MongoDB Update' }
131+ ) ,
132+ update : mongoJsonStringOrObjectSchema ( 'Update is required' ) ,
133+ upsert : booleanStringSchema ,
134+ multi : booleanStringSchema ,
135+ } )
136+ . refine ( mongoUsernamePasswordPaired , mongoUsernamePasswordPairedError )
137+
138+ export const mongodbDeleteBodySchema = mongoConnectionBaseSchema
139+ . extend ( {
140+ collection : z . string ( ) . min ( 1 , 'Collection name is required' ) ,
141+ filter : mongoJsonStringOrObjectSchema ( 'Filter is required for MongoDB Delete' ) . refine (
142+ ( val ) => val !== '{}' ,
143+ { message : 'Filter is required for MongoDB Delete' }
144+ ) ,
145+ multi : booleanStringSchema ,
146+ } )
147+ . refine ( mongoUsernamePasswordPaired , mongoUsernamePasswordPairedError )
134148
135149export const mongodbIntrospectBodySchema = z
136150 . object ( {
0 commit comments