From a8069510b450854f65d3601b652edc826c090aa4 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Fri, 25 Jun 2021 11:41:58 +0100 Subject: [PATCH] Allow making context specific requests using the data module (#32961) Co-authored-by: Nik Tsekouras --- .../src/queried-data/get-query-parts.js | 5 + .../core-data/src/queried-data/reducer.js | 116 +++++++----- .../core-data/src/queried-data/selectors.js | 22 ++- .../src/queried-data/test/get-query-parts.js | 20 +++ .../src/queried-data/test/reducer.js | 61 ++++--- .../src/queried-data/test/selectors.js | 168 +++++++++++------- packages/core-data/src/resolvers.js | 4 +- packages/core-data/src/selectors.js | 7 +- packages/core-data/src/test/reducer.js | 32 ++-- packages/core-data/src/test/resolvers.js | 14 +- packages/core-data/src/test/selectors.js | 99 +++++++---- 11 files changed, 360 insertions(+), 188 deletions(-) diff --git a/packages/core-data/src/queried-data/get-query-parts.js b/packages/core-data/src/queried-data/get-query-parts.js index 9b54bd4c7cfa20..1cd96314955053 100644 --- a/packages/core-data/src/queried-data/get-query-parts.js +++ b/packages/core-data/src/queried-data/get-query-parts.js @@ -41,6 +41,7 @@ export function getQueryParts( query ) { perPage: 10, fields: null, include: null, + context: 'default', }; // Ensure stable key by sorting keys. Also more efficient for iterating. @@ -65,6 +66,10 @@ export function getQueryParts( query ) { ); break; + case 'context': + parts.context = value; + break; + default: // While in theory, we could exclude "_fields" from the stableKey // because two request with different fields have the same results diff --git a/packages/core-data/src/queried-data/reducer.js b/packages/core-data/src/queried-data/reducer.js index 9198b9f16fa12a..12ad7d69fac5f7 100644 --- a/packages/core-data/src/queried-data/reducer.js +++ b/packages/core-data/src/queried-data/reducer.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { map, flowRight, omit, forEach, filter } from 'lodash'; +import { map, flowRight, omit, filter, mapValues } from 'lodash'; /** * WordPress dependencies @@ -20,6 +20,16 @@ import { import { DEFAULT_ENTITY_KEY } from '../entities'; import getQueryParts from './get-query-parts'; +function getContextFromAction( action ) { + const { query } = action; + if ( ! query ) { + return 'default'; + } + + const queryParts = getQueryParts( query ); + return queryParts.context; +} + /** * Returns a merged array of item IDs, given details of the received paginated * items. The array is sparse-like with `undefined` entries where holes exist. @@ -71,24 +81,30 @@ export function getMergedItemIds( itemIds, nextItemIds, page, perPage ) { * * @return {Object} Next state. */ -function items( state = {}, action ) { +export function items( state = {}, action ) { switch ( action.type ) { - case 'RECEIVE_ITEMS': + case 'RECEIVE_ITEMS': { + const context = getContextFromAction( action ); const key = action.key || DEFAULT_ENTITY_KEY; return { ...state, - ...action.items.reduce( ( accumulator, value ) => { - const itemId = value[ key ]; - accumulator[ itemId ] = conservativeMapItem( - state[ itemId ], - value - ); - return accumulator; - }, {} ), + [ context ]: { + ...state[ context ], + ...action.items.reduce( ( accumulator, value ) => { + const itemId = value[ key ]; + accumulator[ itemId ] = conservativeMapItem( + state?.[ context ]?.[ itemId ], + value + ); + return accumulator; + }, {} ), + }, }; + } case 'REMOVE_ITEMS': - const newState = omit( state, action.itemIds ); - return newState; + return mapValues( state, ( contextState ) => + omit( contextState, action.itemIds ) + ); } return state; } @@ -106,32 +122,45 @@ function items( state = {}, action ) { * @return {Object} Next state. */ export function itemIsComplete( state = {}, action ) { - const { type, query, key = DEFAULT_ENTITY_KEY } = action; - if ( type !== 'RECEIVE_ITEMS' ) { - return state; + switch ( action.type ) { + case 'RECEIVE_ITEMS': { + const context = getContextFromAction( action ); + const { query, key = DEFAULT_ENTITY_KEY } = action; + + // An item is considered complete if it is received without an associated + // fields query. Ideally, this would be implemented in such a way where the + // complete aggregate of all fields would satisfy completeness. Since the + // fields are not consistent across all entity types, this would require + // introspection on the REST schema for each entity to know which fields + // compose a complete item for that entity. + const queryParts = query ? getQueryParts( query ) : {}; + const isCompleteQuery = + ! query || ! Array.isArray( queryParts.fields ); + + return { + ...state, + [ context ]: { + ...state[ context ], + ...action.items.reduce( ( result, item ) => { + const itemId = item[ key ]; + + // Defer to completeness if already assigned. Technically the + // data may be outdated if receiving items for a field subset. + result[ itemId ] = + state?.[ context ]?.[ itemId ] || isCompleteQuery; + + return result; + }, {} ), + }, + }; + } + case 'REMOVE_ITEMS': + return mapValues( state, ( contextState ) => + omit( contextState, action.itemIds ) + ); } - // An item is considered complete if it is received without an associated - // fields query. Ideally, this would be implemented in such a way where the - // complete aggregate of all fields would satisfy completeness. Since the - // fields are not consistent across all entity types, this would require - // introspection on the REST schema for each entity to know which fields - // compose a complete item for that entity. - const isCompleteQuery = - ! query || ! Array.isArray( getQueryParts( query ).fields ); - - return { - ...state, - ...action.items.reduce( ( result, item ) => { - const itemId = item[ key ]; - - // Defer to completeness if already assigned. Technically the - // data may be outdated if receiving items for a field subset. - result[ itemId ] = state[ itemId ] || isCompleteQuery; - - return result; - }, {} ), - }; + return state; } /** @@ -163,6 +192,8 @@ const receiveQueries = flowRight( [ return action; } ), + onSubKey( 'context' ), + // Queries shape is shared, but keyed by query `stableKey` part. Original // reducer tracks only a single query object. onSubKey( 'stableKey' ), @@ -194,17 +225,18 @@ const queries = ( state = {}, action ) => { case 'RECEIVE_ITEMS': return receiveQueries( state, action ); case 'REMOVE_ITEMS': - const newState = { ...state }; const removedItems = action.itemIds.reduce( ( result, itemId ) => { result[ itemId ] = true; return result; }, {} ); - forEach( newState, ( queryItems, key ) => { - newState[ key ] = filter( queryItems, ( queryId ) => { - return ! removedItems[ queryId ]; + + return mapValues( state, ( contextQueries ) => { + return mapValues( contextQueries, ( queryItems ) => { + return filter( queryItems, ( queryId ) => { + return ! removedItems[ queryId ]; + } ); } ); } ); - return newState; default: return state; } diff --git a/packages/core-data/src/queried-data/selectors.js b/packages/core-data/src/queried-data/selectors.js index 63468bc65491bb..2e9ee2538160a2 100644 --- a/packages/core-data/src/queried-data/selectors.js +++ b/packages/core-data/src/queried-data/selectors.js @@ -28,10 +28,16 @@ const queriedItemsCacheByState = new WeakMap(); * @return {?Array} Query items. */ function getQueriedItemsUncached( state, query ) { - const { stableKey, page, perPage, include, fields } = getQueryParts( - query - ); + const { + stableKey, + page, + perPage, + include, + fields, + context, + } = getQueryParts( query ); let itemIds; + if ( Array.isArray( include ) && ! stableKey ) { // If the parsed query yields a set of IDs, but otherwise no filtering, // it's safe to consider targeted item IDs as the include set. This @@ -40,8 +46,8 @@ function getQueriedItemsUncached( state, query ) { itemIds = include; // TODO: Avoid storing the empty stable string in reducer, since it // can be computed dynamically here always. - } else if ( state.queries[ stableKey ] ) { - itemIds = state.queries[ stableKey ]; + } else if ( state.queries?.[ context ]?.[ stableKey ] ) { + itemIds = state.queries[ context ][ stableKey ]; } if ( ! itemIds ) { @@ -61,11 +67,11 @@ function getQueriedItemsUncached( state, query ) { continue; } - if ( ! state.items.hasOwnProperty( itemId ) ) { + if ( ! state.items[ context ]?.hasOwnProperty( itemId ) ) { return null; } - const item = state.items[ itemId ]; + const item = state.items[ context ][ itemId ]; let filteredItem; if ( Array.isArray( fields ) ) { @@ -79,7 +85,7 @@ function getQueriedItemsUncached( state, query ) { } else { // If expecting a complete item, validate that completeness, or // otherwise abort. - if ( ! state.itemIsComplete[ itemId ] ) { + if ( ! state.itemIsComplete[ context ]?.[ itemId ] ) { return null; } diff --git a/packages/core-data/src/queried-data/test/get-query-parts.js b/packages/core-data/src/queried-data/test/get-query-parts.js index 156e18c995cc4c..0de6036d696b30 100644 --- a/packages/core-data/src/queried-data/test/get-query-parts.js +++ b/packages/core-data/src/queried-data/test/get-query-parts.js @@ -8,6 +8,7 @@ describe( 'getQueryParts', () => { const parts = getQueryParts( { page: 2, per_page: 2 } ); expect( parts ).toEqual( { + context: 'default', page: 2, perPage: 2, stableKey: '', @@ -20,6 +21,7 @@ describe( 'getQueryParts', () => { const parts = getQueryParts( { include: [ 1 ] } ); expect( parts ).toEqual( { + context: 'default', page: 1, perPage: 10, stableKey: '', @@ -34,6 +36,7 @@ describe( 'getQueryParts', () => { expect( first ).toEqual( second ); expect( first ).toEqual( { + context: 'default', page: 1, perPage: 10, stableKey: '%3F=%26&b=2', @@ -46,6 +49,7 @@ describe( 'getQueryParts', () => { const parts = getQueryParts( { a: [ 1, 2 ] } ); expect( parts ).toEqual( { + context: 'default', page: 1, perPage: 10, stableKey: 'a%5B0%5D=1&a%5B1%5D=2', @@ -60,6 +64,7 @@ describe( 'getQueryParts', () => { expect( first ).toEqual( second ); expect( first ).toEqual( { + context: 'default', page: 1, perPage: 10, stableKey: 'b=2', @@ -72,6 +77,7 @@ describe( 'getQueryParts', () => { const parts = getQueryParts( { b: 2, page: 1, per_page: -1 } ); expect( parts ).toEqual( { + context: 'default', page: 1, perPage: -1, stableKey: 'b=2', @@ -84,6 +90,7 @@ describe( 'getQueryParts', () => { const parts = getQueryParts( { _fields: [ 'id', 'title' ] } ); expect( parts ).toEqual( { + context: 'default', page: 1, perPage: 10, stableKey: '_fields=id%2Ctitle', @@ -91,4 +98,17 @@ describe( 'getQueryParts', () => { include: null, } ); } ); + + it( 'returns the context as a dedicated query part', () => { + const parts = getQueryParts( { context: 'view' } ); + + expect( parts ).toEqual( { + page: 1, + perPage: 10, + stableKey: '', + include: null, + fields: null, + context: 'view', + } ); + } ); } ); diff --git a/packages/core-data/src/queried-data/test/reducer.js b/packages/core-data/src/queried-data/test/reducer.js index 71f5a205e39953..63a4f4bd259ceb 100644 --- a/packages/core-data/src/queried-data/test/reducer.js +++ b/packages/core-data/src/queried-data/test/reducer.js @@ -75,7 +75,7 @@ describe( 'itemIsComplete', () => { } ); expect( state ).toEqual( { - 1: true, + default: { 1: true }, } ); } ); @@ -85,12 +85,13 @@ describe( 'itemIsComplete', () => { type: 'RECEIVE_ITEMS', query: { per_page: 5, + context: 'edit', }, items: [ { id: 1, content: 'chicken', author: 'bob' } ], } ); expect( state ).toEqual( { - 1: true, + edit: { 1: true }, } ); } ); @@ -105,13 +106,13 @@ describe( 'itemIsComplete', () => { } ); expect( state ).toEqual( { - 1: false, + default: { 1: false }, } ); } ); it( 'should defer to existing completeness when receiving filtered query', () => { const original = deepFreeze( { - 1: true, + default: { 1: true }, } ); const state = itemIsComplete( original, { type: 'RECEIVE_ITEMS', @@ -122,7 +123,7 @@ describe( 'itemIsComplete', () => { } ); expect( state ).toEqual( { - 1: true, + default: { 1: true }, } ); } ); } ); @@ -133,16 +134,16 @@ describe( 'reducer', () => { expect( state ).toEqual( { items: {}, - itemIsComplete: {}, queries: {}, + itemIsComplete: {}, } ); } ); it( 'receives a page of queried data', () => { const original = deepFreeze( { - items: {}, + items: { default: {} }, queries: {}, - itemIsComplete: {}, + itemIsComplete: { default: {} }, } ); const state = reducer( original, { type: 'RECEIVE_ITEMS', @@ -152,22 +153,22 @@ describe( 'reducer', () => { expect( state ).toEqual( { items: { - 1: { id: 1, name: 'abc' }, + default: { 1: { id: 1, name: 'abc' } }, }, itemIsComplete: { - 1: true, + default: { 1: true }, }, queries: { - 's=a': [ 1 ], + default: { 's=a': [ 1 ] }, }, } ); } ); it( 'receives an unqueried page of items', () => { const original = deepFreeze( { - items: {}, + items: { default: {} }, queries: {}, - itemIsComplete: {}, + itemIsComplete: { default: {} }, } ); const state = reducer( original, { type: 'RECEIVE_ITEMS', @@ -176,10 +177,10 @@ describe( 'reducer', () => { expect( state ).toEqual( { items: { - 1: { id: 1, name: 'abc' }, + default: { 1: { id: 1, name: 'abc' } }, }, itemIsComplete: { - 1: true, + default: { 1: true }, }, queries: {}, } ); @@ -190,14 +191,18 @@ describe( 'reducer', () => { const name = 'menu'; const original = deepFreeze( { items: { - 1: { id: 1, name: 'abc' }, - 2: { id: 2, name: 'def' }, - 3: { id: 3, name: 'ghi' }, - 4: { id: 4, name: 'klm' }, + default: { + 1: { id: 1, name: 'abc' }, + 2: { id: 2, name: 'def' }, + 3: { id: 3, name: 'ghi' }, + 4: { id: 4, name: 'klm' }, + }, }, queries: { - '': [ 1, 2, 3, 4 ], - 's=a': [ 1, 3 ], + default: { + '': [ 1, 2, 3, 4 ], + 's=a': [ 1, 3 ], + }, }, } ); const state = reducer( original, removeItems( kind, name, 3 ) ); @@ -205,13 +210,17 @@ describe( 'reducer', () => { expect( state ).toEqual( { itemIsComplete: {}, items: { - 1: { id: 1, name: 'abc' }, - 2: { id: 2, name: 'def' }, - 4: { id: 4, name: 'klm' }, + default: { + 1: { id: 1, name: 'abc' }, + 2: { id: 2, name: 'def' }, + 4: { id: 4, name: 'klm' }, + }, }, queries: { - '': [ 1, 2, 4 ], - 's=a': [ 1 ], + default: { + '': [ 1, 2, 4 ], + 's=a': [ 1 ], + }, }, } ); } ); diff --git a/packages/core-data/src/queried-data/test/selectors.js b/packages/core-data/src/queried-data/test/selectors.js index 76dec520a73589..39b46a97a9395e 100644 --- a/packages/core-data/src/queried-data/test/selectors.js +++ b/packages/core-data/src/queried-data/test/selectors.js @@ -19,15 +19,21 @@ describe( 'getQueriedItems', () => { it( 'should return an array of items', () => { const state = { items: { - 1: { id: 1 }, - 2: { id: 2 }, + default: { + 1: { id: 1 }, + 2: { id: 2 }, + }, }, itemIsComplete: { - 1: true, - 2: true, + default: { + 1: true, + 2: true, + }, }, queries: { - '': [ 1, 2 ], + default: { + '': [ 1, 2 ], + }, }, }; @@ -39,12 +45,16 @@ describe( 'getQueriedItems', () => { it( 'should cache on query by state', () => { const state = { items: { - 1: { id: 1 }, - 2: { id: 2 }, + default: { + 1: { id: 1 }, + 2: { id: 2 }, + }, }, itemIsComplete: { - 1: true, - 2: true, + default: { + 1: true, + 2: true, + }, }, queries: [ 1, 2 ], }; @@ -58,15 +68,21 @@ describe( 'getQueriedItems', () => { it( 'should return items queried by include', () => { const state = { items: { - 1: { id: 1 }, - 2: { id: 2 }, + default: { + 1: { id: 1 }, + 2: { id: 2 }, + }, }, itemIsComplete: { - 1: true, - 2: true, + default: { + 1: true, + 2: true, + }, }, queries: { - '': [ 1, 2 ], + default: { + '': [ 1, 2 ], + }, }, }; @@ -78,23 +94,29 @@ describe( 'getQueriedItems', () => { it( 'should dynamically construct fields-filtered item from available data', () => { const state = { items: { - 1: { - id: 1, - content: 'chicken', - author: 'bob', - }, - 2: { - id: 2, - content: 'ribs', - author: 'sally', + default: { + 1: { + id: 1, + content: 'chicken', + author: 'bob', + }, + 2: { + id: 2, + content: 'ribs', + author: 'sally', + }, }, }, itemIsComplete: { - 1: true, - 2: true, + default: { + 1: true, + 2: true, + }, }, queries: { - '_fields=content': [ 1, 2 ], + default: { + '_fields=content': [ 1, 2 ], + }, }, }; @@ -109,31 +131,37 @@ describe( 'getQueriedItems', () => { it( 'should dynamically construct fields-filtered item from available data with nested fields', () => { const state = { items: { - 1: { - id: 1, - content: 'chicken', - author: 'bob', - meta: { - template: 'single', - _private: 'unused', + default: { + 1: { + id: 1, + content: 'chicken', + author: 'bob', + meta: { + template: 'single', + _private: 'unused', + }, }, - }, - 2: { - id: 2, - content: 'ribs', - author: 'sally', - meta: { - template: 'single', - _private: 'unused', + 2: { + id: 2, + content: 'ribs', + author: 'sally', + meta: { + template: 'single', + _private: 'unused', + }, }, }, }, itemIsComplete: { - 1: true, - 2: true, + default: { + 1: true, + 2: true, + }, }, queries: { - '_fields=content%2Cmeta.template': [ 1, 2 ], + default: { + '_fields=content%2Cmeta.template': [ 1, 2 ], + }, }, }; @@ -150,21 +178,27 @@ describe( 'getQueriedItems', () => { it( 'should return null if attempting to filter by yet-unknown fields', () => { const state = { items: { - 1: { - id: 1, - author: 'bob', - }, - 2: { - id: 2, - author: 'sally', + default: { + 1: { + id: 1, + author: 'bob', + }, + 2: { + id: 2, + author: 'sally', + }, }, }, itemIsComplete: { - 1: false, - 2: false, + default: { + 1: false, + 2: false, + }, }, queries: { - '': [ 1, 2 ], + default: { + '': [ 1, 2 ], + }, }, }; @@ -176,21 +210,27 @@ describe( 'getQueriedItems', () => { it( 'should return null if querying non-filtered data for incomplete item', () => { const state = { items: { - 1: { - id: 1, - author: 'bob', - }, - 2: { - id: 2, - author: 'sally', + default: { + 1: { + id: 1, + author: 'bob', + }, + 2: { + id: 2, + author: 'sally', + }, }, }, itemIsComplete: { - 1: false, - 2: false, + default: { + 1: false, + 2: false, + }, }, queries: { - '': [ 1, 2 ], + default: { + '': [ 1, 2 ], + }, }, }; diff --git a/packages/core-data/src/resolvers.js b/packages/core-data/src/resolvers.js index 877f94e0a5ebc9..8ed8d1474e864b 100644 --- a/packages/core-data/src/resolvers.js +++ b/packages/core-data/src/resolvers.js @@ -193,8 +193,8 @@ export function* getEntityRecords( kind, name, query = {} ) { } const path = addQueryArgs( entity.baseURL, { + ...entity.baseURLParams, ...query, - context: 'edit', } ); let records = Object.values( yield apiFetch( { path } ) ); @@ -217,7 +217,7 @@ export function* getEntityRecords( kind, name, query = {} ) { // When requesting all fields, the list of results can be used to // resolve the `getEntityRecord` selector in addition to `getEntityRecords`. // See https://github.com/WordPress/gutenberg/pull/26575 - if ( ! query?._fields ) { + if ( ! query?._fields && ! query.context ) { const key = entity.key || DEFAULT_ENTITY_KEY; const resolutionsArgs = records .filter( ( record ) => record[ key ] ) diff --git a/packages/core-data/src/selectors.js b/packages/core-data/src/selectors.js index 4dd61d85265397..3208ea79882168 100644 --- a/packages/core-data/src/selectors.js +++ b/packages/core-data/src/selectors.js @@ -151,17 +151,18 @@ export function getEntityRecord( state, kind, name, key, query ) { if ( ! queriedState ) { return undefined; } + const context = query?.context ?? 'default'; if ( query === undefined ) { // If expecting a complete item, validate that completeness. - if ( ! queriedState.itemIsComplete[ key ] ) { + if ( ! queriedState.itemIsComplete[ context ]?.[ key ] ) { return undefined; } - return queriedState.items[ key ]; + return queriedState.items[ context ][ key ]; } - const item = queriedState.items[ key ]; + const item = queriedState.items[ context ]?.[ key ]; if ( item && query._fields ) { const filteredItem = {}; const fields = getNormalizedCommaSeparable( query._fields ); diff --git a/packages/core-data/src/test/reducer.js b/packages/core-data/src/test/reducer.js index c8cd519e16bcd7..e3665d619d668f 100644 --- a/packages/core-data/src/test/reducer.js +++ b/packages/core-data/src/test/reducer.js @@ -67,12 +67,16 @@ describe( 'entities', () => { expect( state.data.root.postType.queriedData ).toEqual( { items: { - b: { slug: 'b', title: 'beach' }, - s: { slug: 's', title: 'sun' }, + default: { + b: { slug: 'b', title: 'beach' }, + s: { slug: 's', title: 'sun' }, + }, }, itemIsComplete: { - b: true, - s: true, + default: { + b: true, + s: true, + }, }, queries: {}, } ); @@ -85,10 +89,14 @@ describe( 'entities', () => { postType: { queriedData: { items: { - w: { slug: 'w', title: 'water' }, + default: { + w: { slug: 'w', title: 'water' }, + }, }, itemIsComplete: { - w: true, + default: { + w: true, + }, }, queries: {}, }, @@ -105,12 +113,16 @@ describe( 'entities', () => { expect( state.data.root.postType.queriedData ).toEqual( { items: { - w: { slug: 'w', title: 'water' }, - b: { slug: 'b', title: 'beach' }, + default: { + w: { slug: 'w', title: 'water' }, + b: { slug: 'b', title: 'beach' }, + }, }, itemIsComplete: { - w: true, - b: true, + default: { + w: true, + b: true, + }, }, queries: {}, } ); diff --git a/packages/core-data/src/test/resolvers.js b/packages/core-data/src/test/resolvers.js index e22958c387f83a..0cb095dc5fb874 100644 --- a/packages/core-data/src/test/resolvers.js +++ b/packages/core-data/src/test/resolvers.js @@ -120,8 +120,18 @@ describe( 'getEntityRecords', () => { page: { slug: 'page', id: 2 }, }; const ENTITIES = [ - { name: 'postType', kind: 'root', baseURL: '/wp/v2/types' }, - { name: 'postType', kind: 'root', baseURL: '/wp/v2/types' }, + { + name: 'postType', + kind: 'root', + baseURL: '/wp/v2/types', + baseURLParams: { context: 'edit' }, + }, + { + name: 'postType', + kind: 'root', + baseURL: '/wp/v2/types', + baseURLParams: { context: 'edit' }, + }, ]; it( 'yields with requested post type', async () => { diff --git a/packages/core-data/src/test/selectors.js b/packages/core-data/src/test/selectors.js index cce4293885f32d..68878692351a07 100644 --- a/packages/core-data/src/test/selectors.js +++ b/packages/core-data/src/test/selectors.js @@ -74,10 +74,14 @@ describe.each( [ postType: { queriedData: { items: { - post: { slug: 'post' }, + default: { + post: { slug: 'post' }, + }, }, itemIsComplete: { - post: true, + default: { + post: true, + }, }, queries: {}, }, @@ -105,14 +109,18 @@ describe.each( [ post: { queriedData: { items: { - 1: { - id: 1, - content: 'chicken', - author: 'bob', + default: { + 1: { + id: 1, + content: 'chicken', + author: 'bob', + }, }, }, itemIsComplete: { - 1: true, + default: { + 1: true, + }, }, queries: {}, }, @@ -168,15 +176,21 @@ describe( 'hasEntityRecords', () => { postType: { queriedData: { items: { - post: { slug: 'post' }, - page: { slug: 'page' }, + default: { + post: { slug: 'post' }, + page: { slug: 'page' }, + }, }, itemIsComplete: { - post: true, - page: true, + default: { + post: true, + page: true, + }, }, queries: { - '': [ 'post', 'page' ], + default: { + '': [ 'post', 'page' ], + }, }, }, }, @@ -227,15 +241,21 @@ describe( 'getEntityRecords', () => { postType: { queriedData: { items: { - post: { slug: 'post' }, - page: { slug: 'page' }, + default: { + post: { slug: 'post' }, + page: { slug: 'page' }, + }, }, itemIsComplete: { - post: true, - page: true, + default: { + post: true, + page: true, + }, }, queries: { - '': [ 'post', 'page' ], + default: { + '': [ 'post', 'page' ], + }, }, }, }, @@ -257,17 +277,23 @@ describe( 'getEntityRecords', () => { post: { queriedData: { items: { - 1: { - id: 1, - content: 'chicken', - author: 'bob', + default: { + 1: { + id: 1, + content: 'chicken', + author: 'bob', + }, }, }, itemIsComplete: { - 1: true, + default: { + 1: true, + }, }, queries: { - '_fields=id%2Ccontent': [ 1 ], + default: { + '_fields=id%2Ccontent': [ 1 ], + }, }, }, }, @@ -335,16 +361,20 @@ describe( '__experimentalGetDirtyEntityRecords', () => { someName: { queriedData: { items: { - someKey: { - someProperty: 'somePersistedValue', - someRawProperty: { - raw: 'somePersistedRawValue', + default: { + someKey: { + someProperty: 'somePersistedValue', + someRawProperty: { + raw: 'somePersistedRawValue', + }, + id: 'someKey', }, - id: 'someKey', }, }, itemIsComplete: { - someKey: true, + default: { + someKey: true, + }, }, }, edits: { @@ -475,10 +505,17 @@ describe( 'canUserEditEntityRecord', () => { postType: { queriedData: { items: { - post: { slug: 'post', __unstable: 'posts' }, + default: { + post: { + slug: 'post', + __unstable: 'posts', + }, + }, }, itemIsComplete: { - post: true, + default: { + post: true, + }, }, queries: {}, },