@@ -75,6 +75,13 @@ interface ValidationLevelChangedAction {
7575 validationLevel : ValidationLevel ;
7676}
7777
78+ export const SET_VALIDATION_TO_DEFAULT =
79+ `${ PREFIX } /SET_VALIDATION_TO_DEFAULT` as const ;
80+ export interface SetValidationToDefaultAction {
81+ type : typeof SET_VALIDATION_TO_DEFAULT ;
82+ validator : string ;
83+ }
84+
7885/**
7986 * Syntax error occurred action name.
8087 */
@@ -89,6 +96,7 @@ export type ValidationAction =
8996 | ValidationCanceledAction
9097 | ValidationSaveFailedAction
9198 | ValidationFetchedAction
99+ | SetValidationToDefaultAction
92100 | ValidationActionChangedAction
93101 | ValidationLevelChangedAction
94102 | SyntaxErrorOccurredAction ;
@@ -113,6 +121,36 @@ export interface ValidationState extends Validation {
113121 prevValidation ?: Validation ;
114122}
115123
124+ export const VALIDATION_TEMPLATE = `/**
125+ * This is a starter template for a schema validation rule for a collection.
126+ * More information on schema validation rules can be found at:
127+ * https://www.mongodb.com/docs/manual/core/schema-validation/
128+ */
129+ {
130+ $jsonSchema: {
131+ title: "Library.books",
132+ bsonType: "object",
133+ required: ["fieldname1", "fieldname2"],
134+ properties: {
135+ fieldname1: {
136+ bsonType: "string",
137+ description: "Fieldname1 must be a string",
138+ },
139+ fieldname2: {
140+ bsonType: "int",
141+ description: "Fieldname2 must be an integer",
142+ },
143+ arrayFieldName: {
144+ bsonType: "array",
145+ items: {
146+ bsonType: "string"
147+ },
148+ description: "arrayFieldName must be an array of strings"
149+ },
150+ }
151+ }
152+ }` ;
153+
116154/**
117155 * The initial state.
118156 */
@@ -276,6 +314,23 @@ const changeValidationLevel = (
276314 } ;
277315} ;
278316
317+ const changeValidationToDefault = (
318+ state : ValidationState ,
319+ action : SetValidationToDefaultAction
320+ ) : ValidationState => {
321+ return {
322+ ...state ,
323+ validationAction : INITIAL_STATE . validationAction ,
324+ validationLevel : INITIAL_STATE . validationLevel ,
325+ validator : action . validator ,
326+
327+ // Set the previous validation to undefined so that the isChanged
328+ // flag is set to true in future checks.
329+ prevValidation : undefined ,
330+ isChanged : true ,
331+ } ;
332+ } ;
333+
279334/**
280335 * To not have a huge switch statement in the reducer.
281336 */
@@ -288,6 +343,7 @@ const MAPPINGS: {
288343 [ VALIDATOR_CHANGED ] : changeValidator ,
289344 [ VALIDATION_CANCELED ] : setValidation ,
290345 [ VALIDATION_FETCHED ] : setValidation ,
346+ [ SET_VALIDATION_TO_DEFAULT ] : changeValidationToDefault ,
291347 [ VALIDATION_SAVE_FAILED ] : setError ,
292348 [ VALIDATION_ACTION_CHANGED ] : changeValidationAction ,
293349 [ VALIDATION_LEVEL_CHANGED ] : changeValidationLevel ,
@@ -348,6 +404,11 @@ export const validationFetched = (
348404 validation,
349405} ) ;
350406
407+ export const setValidationToDefault = ( validator : string ) => ( {
408+ type : SET_VALIDATION_TO_DEFAULT ,
409+ validator,
410+ } ) ;
411+
351412/**
352413 * Action creator for validation canceled events.
353414 */
@@ -385,40 +446,55 @@ export const syntaxErrorOccurred = (
385446export const fetchValidation = ( namespace : {
386447 database : string ;
387448 collection : string ;
388- } ) : SchemaValidationThunkAction < void > => {
389- return ( dispatch , _getState , { dataService } ) => {
390- dataService . collectionInfo ( namespace . database , namespace . collection ) . then (
391- ( collInfo ) => {
392- const validation = validationFromCollection ( null , collInfo ?? { } ) ;
393-
394- if ( ! validation . validator ) {
395- const newValidation = { ...validation , validator : '{}' } ;
396- dispatch ( validationFetched ( newValidation ) ) ;
397- dispatch ( isLoadedChanged ( true ) ) ;
398- return ;
399- }
400-
401- // TODO(COMPASS-4989): EJSON??
402- const newValidation = {
403- ...validation ,
404- validator : EJSON . stringify ( validation . validator , undefined , 2 ) ,
405- } ;
406-
407- dispatch ( validationFetched ( newValidation ) ) ;
408- dispatch ( zeroStateChanged ( false ) ) ;
409- dispatch ( isLoadedChanged ( true ) ) ;
410- } ,
411- ( err : Error ) => {
449+ } ) : SchemaValidationThunkAction < Promise < void > > => {
450+ return async ( dispatch , _getState , { dataService, preferences } ) => {
451+ try {
452+ const collInfo = await dataService . collectionInfo (
453+ namespace . database ,
454+ namespace . collection
455+ ) ;
456+ if ( ! collInfo ?. validation ?. validator ) {
412457 dispatch (
413- validationFetched ( {
414- ...validationFromCollection ( err ) ,
415- validator : undefined ,
416- } )
458+ setValidationToDefault (
459+ preferences . getPreferences ( ) . enableExportSchema
460+ ? VALIDATION_TEMPLATE
461+ : '{}'
462+ )
417463 ) ;
418- dispatch ( zeroStateChanged ( false ) ) ;
419464 dispatch ( isLoadedChanged ( true ) ) ;
465+ return ;
420466 }
421- ) ;
467+
468+ dispatch (
469+ validationFetched ( {
470+ validationAction :
471+ ( collInfo . validation . validationAction as ValidationServerAction ) ??
472+ INITIAL_STATE . validationAction ,
473+ validationLevel :
474+ ( collInfo . validation . validationLevel as ValidationLevel ) ??
475+ INITIAL_STATE . validationLevel ,
476+ // TODO(COMPASS-4989): EJSON??
477+ validator : EJSON . stringify (
478+ collInfo . validation . validator ,
479+ undefined ,
480+ 2
481+ ) ,
482+ } )
483+ ) ;
484+ dispatch ( zeroStateChanged ( false ) ) ;
485+ dispatch ( isLoadedChanged ( true ) ) ;
486+ } catch ( err ) {
487+ dispatch (
488+ validationFetched ( {
489+ validationAction : INITIAL_STATE . validationAction ,
490+ validationLevel : INITIAL_STATE . validationLevel ,
491+ error : err as Error ,
492+ validator : undefined ,
493+ } )
494+ ) ;
495+ dispatch ( zeroStateChanged ( false ) ) ;
496+ dispatch ( isLoadedChanged ( true ) ) ;
497+ }
422498 } ;
423499} ;
424500
@@ -489,7 +565,7 @@ export const saveValidation = (
489565 validationLevel : savedValidation . validationLevel ,
490566 }
491567 ) ;
492- dispatch ( fetchValidation ( namespace ) ) ;
568+ void dispatch ( fetchValidation ( namespace ) ) ;
493569 openToast ( toastId , {
494570 title : 'New validation rules applied' ,
495571 variant : 'success' ,
@@ -506,7 +582,7 @@ export const saveValidation = (
506582 *
507583 * @returns {Function } The function.
508584 */
509- export const cancelValidation = ( ) => {
585+ export const cancelValidation = ( ) : SchemaValidationThunkAction < void > => {
510586 return (
511587 dispatch : ThunkDispatch < RootState , unknown , RootAction > ,
512588 getState : ( ) => RootState
@@ -518,9 +594,11 @@ export const cancelValidation = () => {
518594 dispatch (
519595 validationCanceled ( {
520596 isChanged : false ,
521- validator : prevValidation ! . validator ,
522- validationAction : prevValidation ! . validationAction ,
523- validationLevel : prevValidation ! . validationLevel ,
597+ validator : prevValidation ?. validator ?? '{}' ,
598+ validationAction :
599+ prevValidation ?. validationAction ?? INITIAL_STATE . validationAction ,
600+ validationLevel :
601+ prevValidation ?. validationLevel ?? INITIAL_STATE . validationLevel ,
524602 error : null ,
525603 } )
526604 ) ;
@@ -540,6 +618,6 @@ export const activateValidation = (): SchemaValidationThunkAction<void> => {
540618 const state = getState ( ) ;
541619 const namespace = state . namespace ;
542620
543- dispatch ( fetchValidation ( namespace ) ) ;
621+ void dispatch ( fetchValidation ( namespace ) ) ;
544622 } ;
545623} ;
0 commit comments