+
+
- Sample documents
+ Preview sample documents
-
-
- {/* Documents that match the validation */}
-
+
+
+ This section displays one document that passed validation and one that
+ failed validation.
+
+
+
+ );
+};
+
+function SampleDocuments({
+ validDocument,
+ invalidDocument,
+ isInitialState,
+ fetchSampleDocuments,
+}: {
+ validDocument?: Record
;
+ invalidDocument?: Record;
+ isInitialState: boolean;
+ fetchSampleDocuments: () => void;
+}) {
+ const darkMode = useDarkMode();
+
+ return (
+
+ {isInitialState ? (
+
+ ) : (
+
+ {/* Documents that match the validation */}
-
- Passed validation
+
+
+
+ Passed validation
+
+
+
-
-
- {/* Documents that do not match the validation */}
-
+ {/* Documents that do not match the validation */}
-
- Failed validation
+
+
+
+ Failed validation
+
+
+
-
-
+ )}
);
}
+
+const ConnectedSampleDocuments = connect(
+ (state: RootState) => ({
+ validDocument: state.sampleDocuments.validDocument,
+ invalidDocument: state.sampleDocuments.invalidDocument,
+ isInitialState: state.sampleDocuments.validDocumentState === 'initial',
+ }),
+ {
+ fetchSampleDocuments,
+ }
+)(SampleDocuments);
+
+export { ConnectedSampleDocuments as SampleDocuments };
diff --git a/packages/compass-schema-validation/src/modules/sample-documents.spec.ts b/packages/compass-schema-validation/src/modules/sample-documents.spec.ts
index ddfdd1e2d29..01b3eae8e45 100644
--- a/packages/compass-schema-validation/src/modules/sample-documents.spec.ts
+++ b/packages/compass-schema-validation/src/modules/sample-documents.spec.ts
@@ -4,18 +4,17 @@ import reducer, {
INITIAL_STATE,
CLEAR_SAMPLE_DOCUMENTS,
clearSampleDocuments,
- fetchingValidDocument,
- FETCHING_VALID_DOCUMENT,
fetchedValidDocument,
FETCHED_VALID_DOCUMENT,
- fetchingInvalidDocument,
- FETCHING_INVALID_DOCUMENT,
fetchedInvalidDocument,
FETCHED_INVALID_DOCUMENT,
fetchingValidDocumentFailed,
FETCHING_INVALID_DOCUMENT_FAILED,
fetchingInvalidDocumentFailed,
FETCHING_VALID_DOCUMENT_FAILED,
+ fetchingSampleDocuments,
+ FETCHING_SAMPLE_DOCUMENTS,
+ type SampleDocumentState,
} from './sample-documents';
const SAMPLE_DOCUMENT = {
@@ -31,14 +30,8 @@ describe('sample-documents module', function () {
});
it('returns the FETCHING_VALID_DOCUMENT action', function () {
- expect(fetchingValidDocument()).to.deep.equal({
- type: FETCHING_VALID_DOCUMENT,
- });
- });
-
- it('returns the FETCHING_INVALID_DOCUMENT action', function () {
- expect(fetchingInvalidDocument()).to.deep.equal({
- type: FETCHING_INVALID_DOCUMENT,
+ expect(fetchingSampleDocuments()).to.deep.equal({
+ type: FETCHING_SAMPLE_DOCUMENTS,
});
});
@@ -93,66 +86,74 @@ describe('sample-documents module', function () {
});
});
- context('when the action is FETCHING_VALID_DOCUMENT', function () {
+ context('when the action is FETCHING_SAMPLE_DOCUMENTS', function () {
it('returns a loading state', function () {
- const sampleDocuments = reducer(undefined, fetchingValidDocument());
+ const sampleDocuments = reducer(undefined, fetchingSampleDocuments());
expect(sampleDocuments.validDocumentState).to.equal('loading');
- });
- });
-
- context('when the action is FETCHING_INVALID_DOCUMENT', function () {
- it('returns a loading state', function () {
- const sampleDocuments = reducer(undefined, fetchingInvalidDocument());
expect(sampleDocuments.invalidDocumentState).to.equal('loading');
});
});
- context('when the action is FETCHED_VALID_DOCUMENT', function () {
- it('updates the state with the document', function () {
- for (const document of [null, undefined, SAMPLE_DOCUMENT] as any[]) {
- const sampleDocuments = reducer(
- undefined,
- fetchedValidDocument(document)
- );
- expect(sampleDocuments.validDocumentState).to.equal('success');
- expect(sampleDocuments.validDocument).to.deep.equal(document);
- }
+ context('fetch results', function () {
+ let loadingState: SampleDocumentState;
+ beforeEach(function () {
+ loadingState = reducer(undefined, fetchingSampleDocuments());
});
- });
- context('when the action is FETCHED_INVALID_DOCUMENT', function () {
- it('updates the state with the document', function () {
- for (const document of [null, undefined, SAMPLE_DOCUMENT] as any[]) {
- const sampleDocuments = reducer(
- undefined,
- fetchedInvalidDocument(document)
- );
- expect(sampleDocuments.invalidDocumentState).to.equal('success');
- expect(sampleDocuments.invalidDocument).to.deep.equal(document);
- }
+ context('when the action is FETCHED_VALID_DOCUMENT', function () {
+ it('updates the state with the document', function () {
+ for (const document of [null, undefined, SAMPLE_DOCUMENT] as any[]) {
+ const sampleDocuments = reducer(
+ loadingState,
+ fetchedValidDocument(document)
+ );
+ expect(sampleDocuments.validDocumentState).to.equal('success');
+ expect(sampleDocuments.validDocument).to.deep.equal(document);
+ expect(sampleDocuments.invalidDocumentState).to.equal('loading');
+ }
+ });
});
- });
- context('when the action is FETCHING_VALID_DOCUMENT_FAILED', function () {
- it('updates an error state', function () {
- const sampleDocuments = reducer(
- undefined,
- fetchingValidDocumentFailed()
- );
- expect(sampleDocuments.validDocumentState).to.equal('error');
- expect(sampleDocuments.validDocument).to.equal(undefined);
+ context('when the action is FETCHED_INVALID_DOCUMENT', function () {
+ it('updates the invalid document state', function () {
+ for (const document of [null, undefined, SAMPLE_DOCUMENT] as any[]) {
+ const sampleDocuments = reducer(
+ loadingState,
+ fetchedInvalidDocument(document)
+ );
+ expect(sampleDocuments.invalidDocumentState).to.equal('success');
+ expect(sampleDocuments.invalidDocument).to.deep.equal(document);
+ expect(sampleDocuments.validDocumentState).to.equal('loading');
+ }
+ });
});
- });
- context('when the action is FETCHING_INVALID_DOCUMENT_FAILED', function () {
- it('updates an error state', function () {
- const sampleDocuments = reducer(
- undefined,
- fetchingInvalidDocumentFailed()
- );
- expect(sampleDocuments.invalidDocumentState).to.equal('error');
- expect(sampleDocuments.invalidDocument).to.deep.equal(undefined);
+ context('when the action is FETCHING_VALID_DOCUMENT_FAILED', function () {
+ it('updates an error state', function () {
+ const sampleDocuments = reducer(
+ loadingState,
+ fetchingValidDocumentFailed()
+ );
+ expect(sampleDocuments.validDocumentState).to.equal('error');
+ expect(sampleDocuments.validDocument).to.equal(undefined);
+ expect(sampleDocuments.invalidDocumentState).to.equal('loading');
+ });
});
+
+ context(
+ 'when the action is FETCHING_INVALID_DOCUMENT_FAILED',
+ function () {
+ it('updates an error state', function () {
+ const sampleDocuments = reducer(
+ loadingState,
+ fetchingInvalidDocumentFailed()
+ );
+ expect(sampleDocuments.invalidDocumentState).to.equal('error');
+ expect(sampleDocuments.invalidDocument).to.deep.equal(undefined);
+ expect(sampleDocuments.validDocumentState).to.equal('loading');
+ });
+ }
+ );
});
});
});
diff --git a/packages/compass-schema-validation/src/modules/sample-documents.ts b/packages/compass-schema-validation/src/modules/sample-documents.ts
index 5dbaab7ea8d..b018d7ba651 100644
--- a/packages/compass-schema-validation/src/modules/sample-documents.ts
+++ b/packages/compass-schema-validation/src/modules/sample-documents.ts
@@ -8,19 +8,22 @@ export const SAMPLE_SIZE = 10000;
/**
* Initial state
*/
-export type DOCUMENT_LOADING_STATES =
- | 'initial'
- | 'loading'
- | 'success'
- | 'error';
+export type DOCUMENT_LOADING_STATES = 'loading' | 'success' | 'error';
-export interface SampleDocumentState {
- validDocumentState: DOCUMENT_LOADING_STATES;
- validDocument: undefined | Record
;
+type InitialState = {
+ validDocumentState: 'initial';
+ invalidDocumentState: 'initial';
+};
+type LoadingState = {
+ validDocumentState: DOCUMENT_LOADING_STATES;
invalidDocumentState: DOCUMENT_LOADING_STATES;
+};
+
+export type SampleDocumentState = {
+ validDocument: undefined | Record;
invalidDocument: undefined | Record;
-}
+} & (InitialState | LoadingState);
export const INITIAL_STATE: SampleDocumentState = {
validDocumentState: 'initial',
@@ -39,10 +42,10 @@ interface ClearSampleDocumentsAction {
type: typeof CLEAR_SAMPLE_DOCUMENTS;
}
-export const FETCHING_VALID_DOCUMENT =
- 'validation/namespace/FETCHING_VALID_DOCUMENT' as const;
-interface FetchingValidDocumentAction {
- type: typeof FETCHING_VALID_DOCUMENT;
+export const FETCHING_SAMPLE_DOCUMENTS =
+ 'validation/namespace/FETCHING_SAMPLE_DOCUMENTS' as const;
+interface FetchingSampleDocumentsAction {
+ type: typeof FETCHING_SAMPLE_DOCUMENTS;
}
export const FETCHED_VALID_DOCUMENT =
@@ -58,12 +61,6 @@ interface FetchingValidDocumentFailedAction {
type: typeof FETCHING_VALID_DOCUMENT_FAILED;
}
-export const FETCHING_INVALID_DOCUMENT =
- 'validation/namespace/FETCHING_INVALID_DOCUMENT' as const;
-interface FetchingInvalidDocumentAction {
- type: typeof FETCHING_INVALID_DOCUMENT;
-}
-
export const FETCHED_INVALID_DOCUMENT =
'validation/namespace/FETCHED_INVALID_DOCUMENT' as const;
interface FetchedInvalidDocumentAction {
@@ -77,16 +74,17 @@ interface FetchingInvalidDocumentFailedAction {
type: typeof FETCHING_INVALID_DOCUMENT_FAILED;
}
-export type SampleDocumentAction =
+type SampleDocumentNonInitialAction =
| ClearSampleDocumentsAction
- | FetchingValidDocumentAction
| FetchedValidDocumentAction
- | FetchingValidDocumentAction
- | FetchingInvalidDocumentAction
| FetchedInvalidDocumentAction
| FetchingInvalidDocumentFailedAction
| FetchingValidDocumentFailedAction;
+export type SampleDocumentAction =
+ | SampleDocumentNonInitialAction
+ | FetchingSampleDocumentsAction;
+
/**
* Action creators
*/
@@ -95,12 +93,8 @@ export const clearSampleDocuments = (): ClearSampleDocumentsAction => ({
type: CLEAR_SAMPLE_DOCUMENTS,
});
-export const fetchingValidDocument = (): FetchingValidDocumentAction => ({
- type: FETCHING_VALID_DOCUMENT,
-});
-
-export const fetchingInvalidDocument = (): FetchingInvalidDocumentAction => ({
- type: FETCHING_INVALID_DOCUMENT,
+export const fetchingSampleDocuments = (): FetchingSampleDocumentsAction => ({
+ type: FETCHING_SAMPLE_DOCUMENTS,
});
export const fetchedValidDocument = (
@@ -133,22 +127,16 @@ export const fetchingInvalidDocumentFailed =
export const clearingSampleDocuments = (): SampleDocumentState => INITIAL_STATE;
-export const startFetchingValidDocument = (
+export const startFetchingSampleDocuments = (
state: SampleDocumentState
): SampleDocumentState => ({
...state,
validDocumentState: 'loading',
-});
-
-export const startFetchingInvalidDocument = (
- state: SampleDocumentState
-): SampleDocumentState => ({
- ...state,
invalidDocumentState: 'loading',
});
export const updateStateWithFetchedValidDocument = (
- state: SampleDocumentState,
+ state: SampleDocumentState & LoadingState,
action: FetchedValidDocumentAction
): SampleDocumentState => ({
...state,
@@ -157,7 +145,7 @@ export const updateStateWithFetchedValidDocument = (
});
export const updateStateWithFetchedInvalidDocument = (
- state: SampleDocumentState,
+ state: SampleDocumentState & LoadingState,
action: FetchedInvalidDocumentAction
): SampleDocumentState => ({
...state,
@@ -166,7 +154,7 @@ export const updateStateWithFetchedInvalidDocument = (
});
export const validDocumentFetchErrored = (
- state: SampleDocumentState
+ state: SampleDocumentState & LoadingState
): SampleDocumentState => ({
...state,
validDocumentState: 'error',
@@ -174,24 +162,22 @@ export const validDocumentFetchErrored = (
});
export const invalidDocumentFetchErrored = (
- state: SampleDocumentState
+ state: SampleDocumentState & LoadingState
): SampleDocumentState => ({
...state,
invalidDocumentState: 'error',
invalidDocument: undefined,
});
-const ACTION_TO_REDUCER_MAPPINGS: {
- [Type in SampleDocumentAction['type']]: (
- state: SampleDocumentState,
- action: SampleDocumentAction & { type: Type }
+const LOADING_ACTION_TO_REDUCER_MAPPINGS: {
+ [Type in SampleDocumentNonInitialAction['type']]: (
+ state: SampleDocumentState & LoadingState,
+ action: SampleDocumentNonInitialAction & { type: Type }
) => SampleDocumentState;
} = {
[CLEAR_SAMPLE_DOCUMENTS]: clearingSampleDocuments,
- [FETCHING_VALID_DOCUMENT]: startFetchingValidDocument,
[FETCHED_VALID_DOCUMENT]: updateStateWithFetchedValidDocument,
[FETCHING_VALID_DOCUMENT_FAILED]: validDocumentFetchErrored,
- [FETCHING_INVALID_DOCUMENT]: startFetchingInvalidDocument,
[FETCHED_INVALID_DOCUMENT]: updateStateWithFetchedInvalidDocument,
[FETCHING_INVALID_DOCUMENT_FAILED]: invalidDocumentFetchErrored,
};
@@ -200,8 +186,14 @@ export default function (
state: SampleDocumentState = INITIAL_STATE,
action: RootAction
): SampleDocumentState {
- const fn =
- ACTION_TO_REDUCER_MAPPINGS[action.type as SampleDocumentAction['type']];
+ let fn;
+ if (state.validDocumentState !== 'initial') {
+ fn =
+ LOADING_ACTION_TO_REDUCER_MAPPINGS[
+ action.type as SampleDocumentNonInitialAction['type']
+ ];
+ } else if (action.type === FETCHING_SAMPLE_DOCUMENTS)
+ fn = startFetchingSampleDocuments;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore-error TS does not understand that action can be passed to fn
@@ -232,11 +224,12 @@ const getSampleDocuments = async ({
return await dataService.aggregate(namespace, pipeline, aggOptions);
};
-export const fetchValidDocument = (): SchemaValidationThunkAction<
- Promise
+export const fetchSampleDocuments = (): SchemaValidationThunkAction<
+ void,
+ FetchingSampleDocumentsAction
> => {
- return async (dispatch, getState, { preferences, dataService }) => {
- dispatch(fetchingValidDocument());
+ return (dispatch, getState) => {
+ dispatch(fetchingSampleDocuments());
const state = getState();
const namespace = state.namespace.ns;
@@ -247,6 +240,22 @@ export const fetchValidDocument = (): SchemaValidationThunkAction<
checkedValidator.validator as string
).validator;
+ void dispatch(fetchValidDocument({ namespace, query }));
+ void dispatch(fetchInvalidDocument({ namespace, query }));
+ };
+};
+
+const fetchValidDocument = ({
+ namespace,
+ query,
+}: {
+ namespace: string;
+ query: string | Record;
+}): SchemaValidationThunkAction<
+ Promise,
+ FetchedValidDocumentAction | FetchingValidDocumentFailedAction
+> => {
+ return async (dispatch, getState, { preferences, dataService }) => {
try {
const valid = (
await getSampleDocuments({
@@ -264,22 +273,17 @@ export const fetchValidDocument = (): SchemaValidationThunkAction<
};
};
-export const fetchInvalidDocument = (): SchemaValidationThunkAction<
- Promise
+const fetchInvalidDocument = ({
+ namespace,
+ query,
+}: {
+ namespace: string;
+ query: string | Record;
+}): SchemaValidationThunkAction<
+ Promise,
+ FetchedInvalidDocumentAction | FetchingInvalidDocumentFailedAction
> => {
return async (dispatch, getState, { preferences, dataService }) => {
- dispatch(fetchingInvalidDocument());
-
- const state = getState();
- const namespace = state.namespace.ns;
- const validator = state.validation.validator;
-
- // Calling checkValidator twice here seems wrong
- const checkedValidator = checkValidator(validator);
- const query = checkValidator(
- checkedValidator.validator as string
- ).validator;
-
try {
const invalid = (
await getSampleDocuments({
diff --git a/packages/compass-schema-validation/src/stores/store.spec.ts b/packages/compass-schema-validation/src/stores/store.spec.ts
index 598b1f1ba48..3c9154385cb 100644
--- a/packages/compass-schema-validation/src/stores/store.spec.ts
+++ b/packages/compass-schema-validation/src/stores/store.spec.ts
@@ -9,10 +9,7 @@ import {
validationActionChanged,
validationLevelChanged,
} from '../modules/validation';
-import {
- fetchValidDocument,
- fetchInvalidDocument,
-} from '../modules/sample-documents';
+import { fetchSampleDocuments } from '../modules/sample-documents';
import { stringify as javascriptStringify } from 'javascript-stringify';
import type { Store } from 'redux';
import type { RootAction, RootState } from '../modules';
@@ -157,7 +154,7 @@ describe('Schema Validation Store', function () {
});
});
- context('when the action is fetch valid sample documents', function () {
+ context('when the action is fetch sample documents', function () {
it('updates the sample document loading in state', function (done) {
expect(store.getState().sampleDocuments.validDocumentState).to.equal(
'initial'
@@ -167,25 +164,12 @@ describe('Schema Validation Store', function () {
expect(store.getState().sampleDocuments.validDocumentState).to.equal(
'loading'
);
- done();
- });
- store.dispatch(fetchValidDocument() as any);
- });
- });
-
- context('when the action is fetch invalid sample documents', function () {
- it('updates the sample document loading in state', function (done) {
- expect(store.getState().sampleDocuments.invalidDocumentState).to.equal(
- 'initial'
- );
- const unsubscribe = store.subscribe(() => {
- unsubscribe();
expect(
store.getState().sampleDocuments.invalidDocumentState
).to.equal('loading');
done();
});
- store.dispatch(fetchInvalidDocument() as any);
+ store.dispatch(fetchSampleDocuments() as any);
});
});