From 4116122dcf4bf075b3100ce356af852e0dde25f8 Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Wed, 22 Feb 2023 14:36:51 +0200 Subject: [PATCH 1/2] Lodash: Remove remaining _.get() from core-data --- packages/core-data/src/entities.js | 3 +- .../core-data/src/queried-data/selectors.js | 7 +- packages/core-data/src/reducer.js | 8 +- packages/core-data/src/selectors.ts | 160 +++++++----------- 4 files changed, 66 insertions(+), 112 deletions(-) diff --git a/packages/core-data/src/entities.js b/packages/core-data/src/entities.js index ed0ddefad0da07..3b8a443bcf1e39 100644 --- a/packages/core-data/src/entities.js +++ b/packages/core-data/src/entities.js @@ -2,7 +2,6 @@ * External dependencies */ import { capitalCase, pascalCase } from 'change-case'; -import { get } from 'lodash'; /** * WordPress dependencies @@ -45,7 +44,7 @@ export const rootEntitiesConfig = [ kind: 'root', baseURL: '/wp/v2/settings', getTitle: ( record ) => { - return get( record, [ 'title' ], __( 'Site Title' ) ); + return record?.title ?? __( 'Site Title' ); }, }, { diff --git a/packages/core-data/src/queried-data/selectors.js b/packages/core-data/src/queried-data/selectors.js index e52dab36e61889..723e1baf223c88 100644 --- a/packages/core-data/src/queried-data/selectors.js +++ b/packages/core-data/src/queried-data/selectors.js @@ -3,7 +3,7 @@ */ import createSelector from 'rememo'; import EquivalentKeyMap from 'equivalent-key-map'; -import { get, set } from 'lodash'; +import { set } from 'lodash'; /** * Internal dependencies @@ -66,7 +66,10 @@ function getQueriedItemsUncached( state, query ) { for ( let f = 0; f < fields.length; f++ ) { const field = fields[ f ].split( '.' ); - const value = get( item, field ); + let value = { ...item }; + field.forEach( ( fieldName ) => { + value = value[ fieldName ]; + } ); set( filteredItem, field, value ); } } else { diff --git a/packages/core-data/src/reducer.js b/packages/core-data/src/reducer.js index 0e12cfc97e8149..7ab77293568886 100644 --- a/packages/core-data/src/reducer.js +++ b/packages/core-data/src/reducer.js @@ -2,7 +2,7 @@ * External dependencies */ import fastDeepEqual from 'fast-deep-equal/es6'; -import { groupBy, get } from 'lodash'; +import { groupBy } from 'lodash'; /** * WordPress dependencies @@ -245,11 +245,7 @@ function entity( entityConfig ) { // comparison. ! fastDeepEqual( edits[ key ], - get( - record[ key ], - 'raw', - record[ key ] - ) + record[ key ]?.raw ?? record[ key ] ) && // Sometimes the server alters the sent value which means // we need to also remove the edits before the api request. diff --git a/packages/core-data/src/selectors.ts b/packages/core-data/src/selectors.ts index 8e2278f5c1ebdc..1a0c736599a217 100644 --- a/packages/core-data/src/selectors.ts +++ b/packages/core-data/src/selectors.ts @@ -2,7 +2,7 @@ * External dependencies */ import createSelector from 'rememo'; -import { set, get } from 'lodash'; +import { set } from 'lodash'; /** * WordPress dependencies @@ -36,6 +36,7 @@ export interface State { themeBaseGlobalStyles: Record< string, Object >; themeGlobalStyleVariations: Record< string, string >; undo: UndoState; + userPermissions: Record< string, boolean >; users: UserState; } @@ -46,9 +47,20 @@ interface EntitiesState { records: Record< string, Record< string, EntityState< ET.EntityRecord > > >; } +interface QueriedData { + items: Record< ET.Context, Record< number, ET.EntityRecord > >; + itemIsComplete: Record< ET.Context, Record< number, boolean > >; + queries: Record< ET.Context, Record< string, Array< number > > >; +} + interface EntityState< EntityRecord extends ET.EntityRecord > { edits: Record< string, Partial< EntityRecord > >; - saving: Record< string, { pending: boolean } >; + saving: Record< + string, + Partial< { pending: boolean; isAutosave: boolean; error: Error } > + >; + deleting: Record< string, Partial< { pending: boolean; error: Error } > >; + queriedData: QueriedData; } interface EntityConfig { @@ -298,11 +310,8 @@ export const getEntityRecord = createSelector( key: EntityRecordKey, query?: GetRecordsHttpQuery ): EntityRecord | undefined => { - const queriedState = get( state.entities.records, [ - kind, - name, - 'queriedData', - ] ); + const queriedState = + state.entities.records?.[ kind ]?.[ name ]?.queriedData; if ( ! queriedState ) { return undefined; } @@ -323,7 +332,10 @@ export const getEntityRecord = createSelector( const fields = getNormalizedCommaSeparable( query._fields ) ?? []; for ( let f = 0; f < fields.length; f++ ) { const field = fields[ f ].split( '.' ); - const value = get( item, field ); + let value = { ...item }; + field.forEach( ( fieldName ) => { + value = value[ fieldName ]; + } ); set( filteredItem, field, value ); } return filteredItem as EntityRecord; @@ -334,22 +346,11 @@ export const getEntityRecord = createSelector( ( state: State, kind, name, recordId, query ) => { const context = query?.context ?? 'default'; return [ - get( state.entities.records, [ - kind, - name, - 'queriedData', - 'items', - context, - recordId, - ] ), - get( state.entities.records, [ - kind, - name, - 'queriedData', - 'itemIsComplete', - context, - recordId, - ] ), + state.entities.records?.[ kind ]?.[ name ]?.queriedData?.items[ + context + ]?.[ recordId ], + state.entities.records?.[ kind ]?.[ name ]?.queriedData + ?.itemIsComplete[ context ]?.[ recordId ], ]; } ) as GetEntityRecord; @@ -403,11 +404,7 @@ export const getRawEntityRecord = createSelector( // Because edits are the "raw" attribute values, // we return those from record selectors to make rendering, // comparisons, and joins with edits easier. - accumulator[ _key ] = get( - record[ _key ], - 'raw', - record[ _key ] - ); + accumulator[ _key ] = record[ _key ]?.raw ?? record[ _key ]; } else { accumulator[ _key ] = record[ _key ]; } @@ -425,22 +422,11 @@ export const getRawEntityRecord = createSelector( const context = query?.context ?? 'default'; return [ state.entities.config, - get( state.entities.records, [ - kind, - name, - 'queriedData', - 'items', - context, - recordId, - ] ), - get( state.entities.records, [ - kind, - name, - 'queriedData', - 'itemIsComplete', - context, - recordId, - ] ), + state.entities.records?.[ kind ]?.[ name ]?.queriedData?.items[ + context + ]?.[ recordId ], + state.entities.records?.[ kind ]?.[ name ]?.queriedData + ?.itemIsComplete[ context ]?.[ recordId ], ]; } ); @@ -519,11 +505,8 @@ export const getEntityRecords = ( < ): EntityRecord[] | null => { // Queried data state is prepopulated for all known entities. If this is not // assigned for the given parameters, then it is known to not exist. - const queriedState = get( state.entities.records, [ - kind, - name, - 'queriedData', - ] ); + const queriedState = + state.entities.records?.[ kind ]?.[ name ]?.queriedData; if ( ! queriedState ) { return null; } @@ -661,12 +644,9 @@ export function getEntityRecordEdits( name: string, recordId: EntityRecordKey ): Optional< any > { - return get( state.entities.records, [ - kind, - name, - 'edits', - recordId as string | number, - ] ); + return state.entities.records?.[ kind ]?.[ name ]?.edits?.[ + recordId as string | number + ]; } /** @@ -704,7 +684,7 @@ export const getEntityRecordNonTransientEdits = createSelector( }, ( state: State, kind: string, name: string, recordId: EntityRecordKey ) => [ state.entities.config, - get( state.entities.records, [ kind, name, 'edits', recordId ] ), + state.entities.records?.[ kind ]?.[ name ]?.edits?.[ recordId ], ] ); @@ -763,23 +743,12 @@ export const getEditedEntityRecord = createSelector( const context = query?.context ?? 'default'; return [ state.entities.config, - get( state.entities.records, [ - kind, - name, - 'queriedData', - 'items', - context, - recordId, - ] ), - get( state.entities.records, [ - kind, - name, - 'queriedData', - 'itemIsComplete', - context, - recordId, - ] ), - get( state.entities.records, [ kind, name, 'edits', recordId ] ), + state.entities.records?.[ kind ]?.[ name ]?.queriedData.items[ + context + ]?.[ recordId ], + state.entities.records?.[ kind ]?.[ name ]?.queriedData + .itemIsComplete[ context ]?.[ recordId ], + state.entities.records?.[ kind ]?.[ name ]?.edits?.[ recordId ], ]; } ); @@ -800,11 +769,8 @@ export function isAutosavingEntityRecord( name: string, recordId: EntityRecordKey ): boolean { - const { pending, isAutosave } = get( - state.entities.records, - [ kind, name, 'saving', recordId ], - {} - ); + const { pending, isAutosave } = + state.entities.records?.[ kind ]?.[ name ]?.saving?.[ recordId ] ?? {}; return Boolean( pending && isAutosave ); } @@ -824,10 +790,10 @@ export function isSavingEntityRecord( name: string, recordId: EntityRecordKey ): boolean { - return get( - state.entities.records, - [ kind, name, 'saving', recordId as EntityRecordKey, 'pending' ], - false + return ( + state.entities.records?.[ kind ]?.[ name ]?.saving?.[ + recordId as EntityRecordKey + ]?.pending ?? false ); } @@ -847,10 +813,10 @@ export function isDeletingEntityRecord( name: string, recordId: EntityRecordKey ): boolean { - return get( - state.entities.records, - [ kind, name, 'deleting', recordId, 'pending' ], - false + return ( + state.entities.records?.[ kind ]?.[ name ]?.deleting?.[ + recordId as EntityRecordKey + ]?.pending ?? false ); } @@ -870,13 +836,8 @@ export function getLastEntitySaveError( name: string, recordId: EntityRecordKey ): any { - return get( state.entities.records, [ - kind, - name, - 'saving', - recordId, - 'error', - ] ); + return state.entities.records?.[ kind ]?.[ name ]?.saving?.[ recordId ] + ?.error; } /** @@ -895,13 +856,8 @@ export function getLastEntityDeleteError( name: string, recordId: EntityRecordKey ): any { - return get( state.entities.records, [ - kind, - name, - 'deleting', - recordId, - 'error', - ] ); + return state.entities.records?.[ kind ]?.[ name ]?.deleting?.[ recordId ] + ?.error; } /** @@ -1057,7 +1013,7 @@ export function canUser( id?: EntityRecordKey ): boolean | undefined { const key = [ action, resource, id ].filter( Boolean ).join( '/' ); - return get( state, [ 'userPermissions', key ] ); + return state.userPermissions[ key ]; } /** From f00713e60d9a563b8b8349f81e394a33b0832c70 Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Wed, 22 Feb 2023 15:27:05 +0200 Subject: [PATCH 2/2] Remove unnecessary cloning --- packages/core-data/src/queried-data/selectors.js | 2 +- packages/core-data/src/selectors.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core-data/src/queried-data/selectors.js b/packages/core-data/src/queried-data/selectors.js index 723e1baf223c88..17372f390d3ce5 100644 --- a/packages/core-data/src/queried-data/selectors.js +++ b/packages/core-data/src/queried-data/selectors.js @@ -66,7 +66,7 @@ function getQueriedItemsUncached( state, query ) { for ( let f = 0; f < fields.length; f++ ) { const field = fields[ f ].split( '.' ); - let value = { ...item }; + let value = item; field.forEach( ( fieldName ) => { value = value[ fieldName ]; } ); diff --git a/packages/core-data/src/selectors.ts b/packages/core-data/src/selectors.ts index 1a0c736599a217..fd91452d6549b7 100644 --- a/packages/core-data/src/selectors.ts +++ b/packages/core-data/src/selectors.ts @@ -332,7 +332,7 @@ export const getEntityRecord = createSelector( const fields = getNormalizedCommaSeparable( query._fields ) ?? []; for ( let f = 0; f < fields.length; f++ ) { const field = fields[ f ].split( '.' ); - let value = { ...item }; + let value = item; field.forEach( ( fieldName ) => { value = value[ fieldName ]; } );