@@ -27,9 +27,19 @@ import type { RootState } from '../stores/query-bar-store';
2727import { useAutocompleteFields } from '@mongodb-js/compass-field-store' ;
2828import { applyFromHistory } from '../stores/query-bar-reducer' ;
2929import { getQueryAttributes } from '../utils' ;
30- import type { BaseQuery , QueryFormFields } from '../constants/query-properties' ;
30+ import type {
31+ BaseQuery ,
32+ QueryFormFields ,
33+ QueryProperty ,
34+ } from '../constants/query-properties' ;
35+ import { QUERY_PROPERTIES } from '../constants/query-properties' ;
3136import { mapQueryToFormFields } from '../utils/query' ;
3237import { DEFAULT_FIELD_VALUES } from '../constants/query-bar-store' ;
38+ import type {
39+ FavoriteQuery ,
40+ RecentQuery ,
41+ } from '@mongodb-js/my-queries-storage' ;
42+ import _ from 'lodash' ;
3343
3444const editorContainerStyles = css ( {
3545 position : 'relative' ,
@@ -87,8 +97,9 @@ const insightsBadgeStyles = css({
8797 flex : 'none' ,
8898} ) ;
8999
100+ type OptionEditorName = Exclude < QueryProperty , 'maxTimeMS' | 'limit' | 'skip' > ;
90101type OptionEditorProps = {
91- optionName : string ;
102+ optionName : OptionEditorName ;
92103 namespace : string ;
93104 id ?: string ;
94105 hasError ?: boolean ;
@@ -107,7 +118,7 @@ type OptionEditorProps = {
107118 insights ?: Signal | Signal [ ] ;
108119 disabled ?: boolean ;
109120 savedQueries : SavedQuery [ ] ;
110- onApplyQuery : ( query : BaseQuery ) => void ;
121+ onApplyQuery : ( query : BaseQuery , fieldsToPreserve : QueryProperty [ ] ) => void ;
111122} ;
112123
113124export const OptionEditor : React . FunctionComponent < OptionEditorProps > = ( {
@@ -166,27 +177,19 @@ export const OptionEditor: React.FunctionComponent<OptionEditorProps> = ({
166177 return isQueryHistoryAutocompleteEnabled
167178 ? createQueryWithHistoryAutocompleter ( {
168179 queryProperty : optionName ,
169- savedQueries : savedQueries
170- . filter ( ( query ) => {
171- const isOptionNameInQuery =
172- optionName === 'filter' || optionName in query . queryProperties ;
173- const isUpdateNotInQuery = ! ( 'update' in query . queryProperties ) ;
174- return isOptionNameInQuery && isUpdateNotInQuery ;
175- } )
176- . map ( ( query ) => ( {
177- type : query . type ,
178- lastExecuted : query . lastExecuted ,
179- queryProperties : query . queryProperties ,
180- } ) )
181- . sort (
182- ( a , b ) => a . lastExecuted . getTime ( ) - b . lastExecuted . getTime ( )
183- ) ,
180+ savedQueries,
184181 options : {
185182 fields : schemaFields ,
186183 serverVersion,
187184 } ,
188185 onApply : ( query : SavedQuery [ 'queryProperties' ] ) => {
189- onApplyQuery ( query ) ;
186+ // When we are applying a query from `filter` field, we want to apply the whole query,
187+ // otherwise we want to preserve the other fields that are already in the current query.
188+ const fieldsToPreserve =
189+ optionName === 'filter'
190+ ? [ ]
191+ : QUERY_PROPERTIES . filter ( ( x ) => x !== optionName ) ;
192+ onApplyQuery ( query , fieldsToPreserve ) ;
190193 if ( ! query [ optionName ] ) {
191194 return ;
192195 }
@@ -295,25 +298,66 @@ export const OptionEditor: React.FunctionComponent<OptionEditorProps> = ({
295298 ) ;
296299} ;
297300
298- const ConnectedOptionEditor = ( state : RootState ) => ( {
301+ export function getOptionBasedQueries (
302+ optionName : OptionEditorName ,
303+ type : 'recent' | 'favorite' ,
304+ queries : ( RecentQuery | FavoriteQuery ) [ ]
305+ ) {
306+ return (
307+ queries
308+ . map ( ( query ) => ( {
309+ type,
310+ lastExecuted : query . _lastExecuted ,
311+ // For query that's being autocompeted from the main `filter`, we want to
312+ // show whole query to the user, so that when its applied, it will replace
313+ // the whole query (filter, project, sort etc).
314+ // For other options, we only want to show the query for that specific option.
315+ queryProperties : getQueryAttributes (
316+ optionName !== 'filter' ? { [ optionName ] : query [ optionName ] } : query
317+ ) ,
318+ } ) )
319+ // Filter the query if:
320+ // - its empty
321+ // - its an `update` query
322+ // - its a duplicate
323+ . filter ( ( query , i , arr ) => {
324+ const queryIsUpdate = _ . has ( query . queryProperties , 'update' ) ;
325+ const queryIsEmpty = _ . isEmpty ( query . queryProperties ) ;
326+ if ( queryIsEmpty || queryIsUpdate ) {
327+ return false ;
328+ }
329+ return (
330+ i ===
331+ arr . findIndex (
332+ ( t ) =>
333+ JSON . stringify ( t . queryProperties ) ===
334+ JSON . stringify ( query . queryProperties )
335+ )
336+ ) ;
337+ } )
338+ . sort ( ( a , b ) => a . lastExecuted . getTime ( ) - b . lastExecuted . getTime ( ) )
339+ ) ;
340+ }
341+
342+ const mapStateToProps = ( state : RootState , ownProps : OptionEditorProps ) => ( {
299343 namespace : state . queryBar . namespace ,
300344 serverVersion : state . queryBar . serverVersion ,
301345 savedQueries : [
302- ...state . queryBar . recentQueries . map ( ( query ) => ( {
303- type : 'recent' ,
304- lastExecuted : query . _lastExecuted ,
305- queryProperties : getQueryAttributes ( query ) ,
306- } ) ) ,
307- ...state . queryBar . favoriteQueries . map ( ( query ) => ( {
308- type : 'favorite' ,
309- lastExecuted : query . _lastExecuted ,
310- queryProperties : getQueryAttributes ( query ) ,
311- } ) ) ,
346+ ...getOptionBasedQueries (
347+ ownProps . optionName ,
348+ 'recent' ,
349+ state . queryBar . recentQueries
350+ ) ,
351+ ...getOptionBasedQueries (
352+ ownProps . optionName ,
353+ 'favorite' ,
354+ state . queryBar . favoriteQueries
355+ ) ,
312356 ] ,
313357} ) ;
314358
315359const mapDispatchToProps = {
316360 onApplyQuery : applyFromHistory ,
317361} ;
318362
319- export default connect ( ConnectedOptionEditor , mapDispatchToProps ) ( OptionEditor ) ;
363+ export default connect ( mapStateToProps , mapDispatchToProps ) ( OptionEditor ) ;
0 commit comments