Skip to content

Commit 8d004f9

Browse files
committed
Framework: keep post.items as a map indexed by globalId
1 parent cfd1ca4 commit 8d004f9

File tree

4 files changed

+73
-73
lines changed

4 files changed

+73
-73
lines changed

client/state/posts/reducer.js

+5-8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* External dependencies
33
*/
44
import { combineReducers } from 'redux';
5+
import keyBy from 'lodash/keyBy';
56

67
/**
78
* Internal dependencies
@@ -30,18 +31,14 @@ import { DEFAULT_POST_QUERY } from './constants';
3031
* @param {Object} action Action payload
3132
* @return {Object} Updated state
3233
*/
33-
export function items( state = [], action ) {
34+
export function items( state = {}, action ) {
3435
switch ( action.type ) {
3536
case POSTS_RECEIVE:
36-
const globalIds = action.posts.map( post => post.global_ID );
37-
const withoutReceivedPosts = state.filter( ( post ) => {
38-
return globalIds.indexOf( post.global_ID ) === - 1;
39-
} );
40-
return [ ...withoutReceivedPosts, ...action.posts ];
37+
return Object.assign( {}, state, keyBy( action.posts, 'global_ID' ) );
4138
case SERIALIZE:
42-
return [];
39+
return {};
4340
case DESERIALIZE:
44-
return [];
41+
return {};
4542
}
4643
return state;
4744
}

client/state/posts/selectors.js

+10-7
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
* External dependencies
33
*/
44
import range from 'lodash/range';
5-
import keyBy from 'lodash/keyBy';
65
import { createSelector } from 'reselect';
76

87
/**
@@ -20,9 +19,9 @@ import { DEFAULT_POST_QUERY } from './constants';
2019
* @param {Object} state Global state tree
2120
* @return {Object} Posts object
2221
*/
23-
export const getPostsByGlobalId = createSelector( getPosts, ( posts ) => {
24-
return keyBy( posts, 'global_ID' );
25-
} );
22+
export function getPostsByGlobalId( state ) {
23+
return state.posts.items;
24+
};
2625

2726
/**
2827
* Returns a post object by its global ID.
@@ -41,9 +40,13 @@ export function getPost( state, globalId ) {
4140
* @param {Object} state Global state tree
4241
* @return {Array} Posts array
4342
*/
44-
export function getPosts( state ) {
45-
return state.posts.items;
46-
}
43+
export const getPosts = createSelector(
44+
getPostsByGlobalId,
45+
( postsByGlobalId = {} ) => {
46+
return Object.keys( postsByGlobalId )
47+
.map( globalId => postsByGlobalId[ globalId ] );
48+
}
49+
);
4750

4851
/**
4952
* Returns a mapping of site ID, post ID pairing to global post ID.

client/state/posts/test/reducer.js

+35-32
Original file line numberDiff line numberDiff line change
@@ -27,67 +27,70 @@ import {
2727

2828
describe( 'reducer', () => {
2929
describe( '#items()', () => {
30-
it( 'should default to an empty array', () => {
30+
it( 'should default to an empty object', () => {
3131
const state = items( undefined, {} );
3232

33-
expect( state ).to.eql( [] );
33+
expect( state ).to.eql( {} );
3434
} );
3535

36-
it( 'should add posts to array', () => {
37-
const posts = deepFreeze( [
38-
{ ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Hello World' },
39-
{ ID: 413, site_ID: 2916284, global_ID: '6c831c187ffef321eb43a67761a525a3', title: 'Ribs & Chicken' }
40-
] );
41-
const state = items( undefined, {
36+
it( 'should index posts by global ID', () => {
37+
const state = items( null, {
4238
type: POSTS_RECEIVE,
43-
posts: posts
39+
posts: [
40+
{ ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Hello World' },
41+
{ ID: 413, site_ID: 2916284, global_ID: '6c831c187ffef321eb43a67761a525a3', title: 'Ribs & Chicken' }
42+
]
4443
} );
4544

46-
expect( state ).to.eql( posts );
45+
expect( state ).to.eql( {
46+
'3d097cb7c5473c169bba0eb8e3c6cb64': { ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Hello World' },
47+
'6c831c187ffef321eb43a67761a525a3': { ID: 413, site_ID: 2916284, global_ID: '6c831c187ffef321eb43a67761a525a3', title: 'Ribs & Chicken' }
48+
} );
4749
} );
4850

4951
it( 'should accumulate posts', () => {
50-
const original = deepFreeze( [
51-
{ ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Hello World' }
52-
] );
52+
const original = deepFreeze( {
53+
'3d097cb7c5473c169bba0eb8e3c6cb64': { ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Hello World' }
54+
} );
5355
const state = items( original, {
5456
type: POSTS_RECEIVE,
5557
posts: [ { ID: 413, site_ID: 2916284, global_ID: '6c831c187ffef321eb43a67761a525a3', title: 'Ribs & Chicken' } ]
5658
} );
5759

58-
expect( state ).to.eql( [
59-
{ ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Hello World' },
60-
{ ID: 413, site_ID: 2916284, global_ID: '6c831c187ffef321eb43a67761a525a3', title: 'Ribs & Chicken' }
61-
] );
60+
expect( state ).to.eql( {
61+
'3d097cb7c5473c169bba0eb8e3c6cb64': { ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Hello World' },
62+
'6c831c187ffef321eb43a67761a525a3': { ID: 413, site_ID: 2916284, global_ID: '6c831c187ffef321eb43a67761a525a3', title: 'Ribs & Chicken' }
63+
} );
6264
} );
6365

6466
it( 'should override previous post of same ID', () => {
65-
const original = deepFreeze( [
66-
{ ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Hello World' }
67-
] );
67+
const original = deepFreeze( {
68+
'3d097cb7c5473c169bba0eb8e3c6cb64': { ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Hello World' }
69+
} );
6870
const state = items( original, {
6971
type: POSTS_RECEIVE,
70-
posts: [ { ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Donuts & Coffee' } ]
72+
posts: [ { ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Ribs & Chicken' } ]
73+
} );
74+
75+
expect( state ).to.eql( {
76+
'3d097cb7c5473c169bba0eb8e3c6cb64': { ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Ribs & Chicken' }
7177
} );
72-
expect( state ).to.eql( [
73-
{ ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Donuts & Coffee' }
74-
] );
7578
} );
7679

7780
it( 'never persists state because this is not implemented', () => {
78-
const original = deepFreeze( [
79-
{ ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Hello World' }
80-
] );
81+
const original = deepFreeze( {
82+
'3d097cb7c5473c169bba0eb8e3c6cb64': { ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Hello World' }
83+
} );
8184
const state = items( original, { type: SERIALIZE } );
82-
expect( state ).to.eql( [] );
85+
expect( state ).to.eql( {} );
8386
} );
8487

8588
it( 'never loads persisted state because this is not implemented', () => {
86-
const original = deepFreeze( [
87-
{ ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Hello World' }
88-
] );
89+
const original = deepFreeze( {
90+
'3d097cb7c5473c169bba0eb8e3c6cb64': { ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Hello World' }
91+
} );
8992
const state = items( original, { type: DESERIALIZE } );
90-
expect( state ).to.eql( [] );
93+
expect( state ).to.eql( {} );
9194
} );
9295
} );
9396

client/state/posts/test/selectors.js

+23-26
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,17 @@ import {
1616
isSitePostsLastPageForQuery,
1717
getSitePostsForQueryIgnoringPage,
1818
isRequestingSitePost,
19-
getPostsByGlobalId
19+
getPosts
2020
} from '../selectors';
2121

2222
describe( 'selectors', () => {
2323
describe( '#getPost()', () => {
2424
it( 'should return the object for the post global ID', () => {
2525
const post = getPost( {
2626
posts: {
27-
items: [
28-
{ ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Hello World' }
29-
]
27+
items: {
28+
'3d097cb7c5473c169bba0eb8e3c6cb64': { ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Hello World' }
29+
}
3030
}
3131
}, '3d097cb7c5473c169bba0eb8e3c6cb64' );
3232

@@ -38,7 +38,7 @@ describe( 'selectors', () => {
3838
it( 'should return null if the site has not received any posts', () => {
3939
const post = getSitePost( {
4040
posts: {
41-
items: []
41+
items: {}
4242
}
4343
}, 2916284, 841 );
4444

@@ -48,12 +48,9 @@ describe( 'selectors', () => {
4848
it( 'should return null if the post is not known for the site', () => {
4949
const post = getSitePost( {
5050
posts: {
51-
items: [
52-
{
53-
global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64',
54-
site_ID: 2916284
55-
}
56-
]
51+
items: {
52+
'3d097cb7c5473c169bba0eb8e3c6cb64': { site_ID: 2916284 }
53+
}
5754
}
5855
}, 2916284, 841 );
5956

@@ -63,9 +60,9 @@ describe( 'selectors', () => {
6360
it( 'should return the object for the post site ID, post ID pair', () => {
6461
const post = getSitePost( {
6562
posts: {
66-
items: [
67-
{ ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Hello World' }
68-
]
63+
items: {
64+
'3d097cb7c5473c169bba0eb8e3c6cb64': { ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Hello World' }
65+
}
6966
}
7067
}, 2916284, 841 );
7168

@@ -364,21 +361,21 @@ describe( 'selectors', () => {
364361
} );
365362
} );
366363

367-
describe( '#getPostsByGlobalId()', () => {
368-
it( 'should index by global id', () => {
369-
const postsByGlobalId = getPostsByGlobalId( {
364+
describe( '#getPosts()', () => {
365+
it( 'should return a list of posts', () => {
366+
const posts = getPosts( {
370367
posts: {
371-
items: [
372-
{ ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Hello World' },
373-
{ ID: 413, site_ID: 2916284, global_ID: '6c831c187ffef321eb43a67761a525a3', title: 'Goodbye' }
374-
]
368+
items: {
369+
'3d097cb7c5473c169bba0eb8e3c6cb64': { ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Hello World' },
370+
'6c831c187ffef321eb43a67761a525a3': { ID: 413, site_ID: 2916284, global_ID: '6c831c187ffef321eb43a67761a525a3', title: 'Goodbye' }
371+
}
375372
}
376373
} );
377-
expect( postsByGlobalId[ '3d097cb7c5473c169bba0eb8e3c6cb64' ] ).to.eql(
378-
{ ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Hello World' }
379-
);
380-
expect( postsByGlobalId['6c831c187ffef321eb43a67761a525a3'] ).to.eql(
381-
{ ID: 413, site_ID: 2916284, global_ID: '6c831c187ffef321eb43a67761a525a3', title: 'Goodbye' }
374+
expect( posts ).to.eql(
375+
[
376+
{ ID: 841, site_ID: 2916284, global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64', title: 'Hello World' },
377+
{ ID: 413, site_ID: 2916284, global_ID: '6c831c187ffef321eb43a67761a525a3', title: 'Goodbye' }
378+
]
382379
);
383380
} );
384381
} );

0 commit comments

Comments
 (0)