Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ describe('CreateIndexForm Component', function () {
let wildcardProjectionChangedSpy;
let createNewIndexFieldSpy;
let toggleUseIndexNameSpy;
let toggleIsSparseSpy;

const spyComponentProps = () => {
updateFiedTypeSpy = sinon.spy();
Expand All @@ -49,6 +50,7 @@ describe('CreateIndexForm Component', function () {
wildcardProjectionChangedSpy = sinon.spy();
createNewIndexFieldSpy = sinon.spy();
toggleUseIndexNameSpy = sinon.spy();
toggleIsSparseSpy = sinon.spy();
};

const resetSpyComponentProps = () => {
Expand All @@ -71,6 +73,7 @@ describe('CreateIndexForm Component', function () {
wildcardProjectionChangedSpy = null;
createNewIndexFieldSpy = null;
toggleUseIndexNameSpy = null;
toggleIsSparseSpy = null;
};

before(function () {
Expand All @@ -88,6 +91,7 @@ describe('CreateIndexForm Component', function () {
schemaFields={[]}
fields={[{ name: '', type: '' }]}
isUnique={false}
isSparse={false}
useTtl={false}
ttl=""
usePartialFilterExpression={false}
Expand Down Expand Up @@ -122,6 +126,7 @@ describe('CreateIndexForm Component', function () {
wildcardProjectionChanged={wildcardProjectionChangedSpy}
createNewIndexField={createNewIndexFieldSpy}
toggleUseIndexName={toggleUseIndexNameSpy}
toggleIsSparse={toggleIsSparseSpy}
/>
);
});
Expand Down Expand Up @@ -162,6 +167,17 @@ describe('CreateIndexForm Component', function () {
});
});

context('sparse', function () {
it('calls the toggleIsSparse function', function () {
const checkbox = screen.getByTestId(
'create-index-modal-is-sparse-checkbox'
);
expect(toggleIsSparseSpy.callCount).to.equal(0);
fireEvent.click(checkbox);
expect(toggleIsSparseSpy).to.have.been.calledWith(true);
});
});

context('index name', function () {
it('calls the toggleUseIndexName functions', function () {
const checkbox = screen.getByTestId(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import CustomCollationCollapsibleFieldSet from './custom-collation';
import WildcardProjectionCollapsibleFieldSet from './wildcard-projection';
import ColumnstoreProjectionCollapsibleFieldSet from './columnstore-projection';
import IndexNameCollapsibleFieldSet from './index-name';
import SparseIndexCheckbox from './sparse-index';

const createIndexModalFieldsStyles = css({
margin: `${spacing[4]}px 0 ${spacing[5]}px 0`,
Expand All @@ -34,6 +35,7 @@ export type CreateIndexProps = {
schemaFields: string[];

isUnique: boolean;
isSparse: boolean;

useIndexName: boolean;
useTtl: boolean;
Expand All @@ -52,6 +54,7 @@ export type CreateIndexProps = {
serverVersion: string;

toggleIsUnique: (isUnique: boolean) => void;
toggleIsSparse: (isSparse: boolean) => void;

toggleUseIndexName: (useIndexName: boolean) => void;
toggleUseTtl: (useTtl: boolean) => void;
Expand Down Expand Up @@ -172,6 +175,10 @@ class CreateIndexForm extends Component<CreateIndexProps> {
}
/>
)}
<SparseIndexCheckbox
isSparse={this.props.isSparse}
toggleIsSparse={this.props.toggleIsSparse}
/>
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';
import {
Checkbox,
Label,
Description,
css,
spacing,
} from '@mongodb-js/compass-components';

type SparseIndex = {
isSparse: boolean;
toggleIsSparse: (isSparse: boolean) => void;
};

const sparseIndexStyles = css({
margin: `${spacing[3]}px 0`,
fieldset: {
paddingLeft: `${spacing[4]}px`,
},
});

const SparseIndexCheckbox = ({ isSparse, toggleIsSparse }: SparseIndex) => {
const labelId = 'create-index-modal-is-sparse-checkbox';
return (
<fieldset className={sparseIndexStyles}>
<Checkbox
data-testid="create-index-modal-is-sparse-checkbox"
onChange={(event) => {
toggleIsSparse(event.target.checked);
}}
label={<Label htmlFor={labelId}>Create sparse index</Label>}
// LG Checkbox expects a string description, but we use Description component
// to alight with styles from CollapsibleFieldSet that are used on the same form.
description={
(
<Description>
Sparse indexes only contain entries for documents that have the
indexed field, even if the index field contains a null value. The
index skips over any document that is missing the indexed field.
</Description>
) as any
}
checked={isSparse}
id={labelId}
/>
</fieldset>
);
};

export default SparseIndexCheckbox;
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import { resetForm } from '../../modules/reset-form';
import CreateIndexForm from '../create-index-form';
import { toggleUseIndexName } from '../../modules/create-index/use-index-name';
import type { RootState } from '../../modules/create-index';
import { toggleIsSparse } from '../../modules/create-index/is-sparse';

const { track } = createLoggerAndTelemetry('COMPASS-IMPORT-EXPORT-UI');

Expand Down Expand Up @@ -229,6 +230,7 @@ const mapState = ({
namespace,
serverVersion,
newIndexField,
isSparse,
}: RootState) => ({
fields,
inProgress,
Expand All @@ -251,6 +253,7 @@ const mapState = ({
namespace,
serverVersion,
newIndexField,
isSparse,
});

const mapDispatch = {
Expand Down Expand Up @@ -281,5 +284,6 @@ const mapDispatch = {
removeField,
updateFieldName,
updateFieldType,
toggleIsSparse,
};
export default connect(mapState, mapDispatch)(CreateIndexModal);
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ describe('create index module', function () {
usePartialFilterExpression: true,
partialFilterExpression: '{"a": 1}',
isUnique: true,
isSparse: true,
name: 'test name',
useCustomCollation: true,
collationString: "{locale: 'en'}",
Expand All @@ -130,6 +131,7 @@ describe('create index module', function () {
name: 'test name',
partialFilterExpression: { a: 1 },
unique: true,
sparse: true,
});
cb(null);
},
Expand Down Expand Up @@ -177,6 +179,7 @@ describe('create index module', function () {
usePartialFilterExpression: true,
partialFilterExpression: '{"a": 1}',
isUnique: true,
isSparse: false,
name: '',
useCustomCollation: true,
collationString: "{locale: 'en'}",
Expand All @@ -197,6 +200,7 @@ describe('create index module', function () {
expireAfterSeconds: 100,
partialFilterExpression: { a: 1 },
unique: true,
sparse: false,
});
cb(null);
},
Expand Down Expand Up @@ -240,6 +244,7 @@ describe('create index module', function () {
usePartialFilterExpression: false,
useTtl: false,
isUnique: false,
isSparse: false,
name: 'test name',
namespace: 'db.coll',
appRegistry: {},
Expand All @@ -250,6 +255,7 @@ describe('create index module', function () {
expect(options).to.deep.equal({
name: 'test name',
unique: false,
sparse: false,
});
cb({ message: 'test err' });
},
Expand Down
6 changes: 6 additions & 0 deletions packages/compass-indexes/src/modules/create-index/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ import name, {
} from '../create-index/name';
import namespace from '../namespace';
import serverVersion from '../server-version';
import isSparse, {
INITIAL_STATE as IS_SPARSE_INITIAL_STATE,
} from './is-sparse';

import schemaFields from '../create-index/schema-fields';
import newIndexField from '../create-index/new-index-field';
Expand Down Expand Up @@ -105,6 +108,7 @@ const reducer = combineReducers({
name,
namespace,
serverVersion,
isSparse,
});

export type RootState = ReturnType<typeof reducer>;
Expand Down Expand Up @@ -138,6 +142,7 @@ const rootReducer = (state: RootState, action: AnyAction): RootState => {
wildcardProjection: WILDCARD_PROJECTION_INITIAL_STATE,
partialFilterExpression: PARTIAL_FILTER_EXPRESSION_INITIAL_STATE,
name: NAME_INITIAL_STATE,
isSparse: IS_SPARSE_INITIAL_STATE,
};
}
return reducer(state, action);
Expand Down Expand Up @@ -182,6 +187,7 @@ export const createIndex = () => {

const options: CreateIndexesOptions = {};
options.unique = state.isUnique;
options.sparse = state.isSparse;
// The server will generate a name when we don't provide one.
if (state.name !== '') {
options.name = state.name;
Expand Down
27 changes: 27 additions & 0 deletions packages/compass-indexes/src/modules/create-index/is-sparse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
enum ActionTypes {
ToggleIsSparse = 'indexes/create-indexes/is-sparse/ToggleIsSparse',
}

type ToggleIsSparseAction = {
type: ActionTypes.ToggleIsSparse;
isSparse: boolean;
};

type State = boolean;

export const INITIAL_STATE: State = false;

export default function reducer(
state: State = INITIAL_STATE,
action: ToggleIsSparseAction
) {
if (action.type === ActionTypes.ToggleIsSparse) {
return action.isSparse;
}
return state;
}

export const toggleIsSparse = (isSparse: boolean): ToggleIsSparseAction => ({
type: ActionTypes.ToggleIsSparse,
isSparse,
});