mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-31 02:26:50 +10:00
Add entity data denormalisation helper
This commit is contained in:
parent
36d40054a6
commit
d263202723
2 changed files with 160 additions and 1 deletions
|
|
@ -1,3 +1,5 @@
|
|||
import { reduce } from 'lodash';
|
||||
|
||||
/**
|
||||
* Combine the given relationships objects
|
||||
*
|
||||
|
|
@ -52,3 +54,49 @@ export const updatedEntities = (oldEntities, apiResponse) => {
|
|||
|
||||
return newEntities;
|
||||
};
|
||||
|
||||
/**
|
||||
* Denormalise the entities with the given IDs from the entities object
|
||||
*
|
||||
* This function calculates the dernormalised tree structure from the
|
||||
* normalised entities object with all the relationships joined in.
|
||||
*
|
||||
* @param {Object} entities entities object in the SDK Redux store
|
||||
* @param {String} type entity type of the given IDs
|
||||
* @param {Array<UUID>} ids IDs to pick from the entities
|
||||
*/
|
||||
export const denormalisedEntities = (entities, type, ids) => {
|
||||
if (!entities[type] && ids.length > 0) {
|
||||
throw new Error(`No entities of type ${type}`);
|
||||
}
|
||||
return ids.map(id => {
|
||||
const entity = entities[type][id.uuid];
|
||||
if (!entity) {
|
||||
throw new Error(`Entity ${type} with id ${id.uuid} not found`);
|
||||
}
|
||||
const { relationships, ...entityData } = entity;
|
||||
|
||||
if (relationships) {
|
||||
// Recursively join in all the relationship entities
|
||||
return reduce(
|
||||
relationships,
|
||||
(ent, relRef, relName) => {
|
||||
// A relationship reference can be either a single object or
|
||||
// an array of objects. We want to keep that form in the final
|
||||
// result.
|
||||
const hasMultipleRefs = Array.isArray(relRef);
|
||||
const refs = hasMultipleRefs ? relRef : [relRef];
|
||||
const relIds = refs.map(ref => ref.data.id);
|
||||
const relType = refs[0].data.type;
|
||||
const rels = denormalisedEntities(entities, relType, relIds);
|
||||
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
ent[relName] = hasMultipleRefs ? rels : rels[0];
|
||||
return ent;
|
||||
},
|
||||
entityData,
|
||||
);
|
||||
}
|
||||
return entityData;
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
import { types } from 'sharetribe-sdk';
|
||||
import { combinedRelationships, combinedResourceObjects, updatedEntities } from './data';
|
||||
import {
|
||||
combinedRelationships,
|
||||
combinedResourceObjects,
|
||||
updatedEntities,
|
||||
denormalisedEntities,
|
||||
} from './data';
|
||||
|
||||
const { UUID } = types;
|
||||
|
||||
|
|
@ -162,4 +167,110 @@ describe('data utils', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('denormalisedEntities()', () => {
|
||||
const createListing = id => ({
|
||||
id: new UUID(id),
|
||||
type: 'listing',
|
||||
attributes: { title: `Listing ${id} title`, description: `Listing ${id} description` },
|
||||
});
|
||||
|
||||
const createUser = id => ({
|
||||
id: new UUID(id),
|
||||
type: 'user',
|
||||
attributes: { name: `User ${id} name` },
|
||||
});
|
||||
|
||||
const createImage = id => ({
|
||||
id: new UUID(id),
|
||||
type: 'image',
|
||||
attributes: { url: `https://example.com/${id}.jpg`, width: 300, height: 200 },
|
||||
});
|
||||
|
||||
it('return no results with empty ids', () => {
|
||||
const entities = { listing: { listing1: createListing('listing1') } };
|
||||
expect(denormalisedEntities(entities, 'listing', [])).toEqual([]);
|
||||
});
|
||||
|
||||
it('return no results with empty entities and empty ids', () => {
|
||||
const entities = {};
|
||||
expect(denormalisedEntities(entities, 'listing', [])).toEqual([]);
|
||||
});
|
||||
|
||||
it('throws when selecting a nonexistent type', () => {
|
||||
const entities = { listing: { listing1: createListing('listing1') } };
|
||||
expect(() => denormalisedEntities(entities, 'user', [new UUID('user1')])).toThrow(
|
||||
'No entities of type user',
|
||||
);
|
||||
});
|
||||
|
||||
it('throws when selecting a nonexistent id', () => {
|
||||
const entities = { listing: { listing1: createListing('listing1') } };
|
||||
const ids = [new UUID('listing2')];
|
||||
expect(() => denormalisedEntities(entities, 'listing', ids)).toThrow(
|
||||
'Entity listing with id listing2 not found',
|
||||
);
|
||||
});
|
||||
|
||||
it('throws if a related entity is not found', () => {
|
||||
const listing1 = createListing('listing1');
|
||||
listing1.relationships = { author: { data: createUser('user1') } };
|
||||
const entities = { listing: { listing1 } };
|
||||
const ids = [listing1.id];
|
||||
expect(() => denormalisedEntities(entities, 'listing', ids)).toThrow(
|
||||
'No entities of type user',
|
||||
);
|
||||
});
|
||||
|
||||
it('returns the selected entities', () => {
|
||||
const listing1 = createListing('listing1');
|
||||
const listing2 = createListing('listing2');
|
||||
const listing3 = createListing('listing3');
|
||||
|
||||
const entities = { listing: { listing1, listing2, listing3 } };
|
||||
const ids = [listing1.id, listing3.id];
|
||||
expect(denormalisedEntities(entities, 'listing', ids)).toEqual([listing1, listing3]);
|
||||
});
|
||||
|
||||
it('denormalises simple relationships', () => {
|
||||
const user1 = createUser('user1');
|
||||
const listing1 = createListing('listing1');
|
||||
const listing1Relationships = { author: { data: user1 } };
|
||||
const listing1WithRelationships = { ...listing1, relationships: listing1Relationships };
|
||||
const listing2 = createListing('listing2');
|
||||
const entities = {
|
||||
listing: { listing1: listing1WithRelationships, listing2 },
|
||||
user: { user1 },
|
||||
};
|
||||
const ids = [listing1.id];
|
||||
expect(denormalisedEntities(entities, 'listing', ids)).toEqual([
|
||||
{ ...listing1, author: user1 },
|
||||
]);
|
||||
});
|
||||
|
||||
it('denormalises multiple relationships', () => {
|
||||
const user1 = createUser('user1');
|
||||
const image1 = createImage('image1');
|
||||
const image2 = createImage('image2');
|
||||
const listing1 = createListing('listing1');
|
||||
const listing1Relationships = {
|
||||
author: { data: user1 },
|
||||
images: [{ data: image1 }, { data: image2 }],
|
||||
};
|
||||
const listing1WithRelationships = { ...listing1, relationships: listing1Relationships };
|
||||
const listing2 = createListing('listing2');
|
||||
const listing3 = createListing('listing3');
|
||||
const entities = {
|
||||
listing: { listing1: listing1WithRelationships, listing2, listing3 },
|
||||
user: { user1 },
|
||||
image: { image1, image2 },
|
||||
};
|
||||
const ids = [listing1.id, listing2.id];
|
||||
|
||||
expect(denormalisedEntities(entities, 'listing', ids)).toEqual([
|
||||
{ ...listing1, author: user1, images: [image1, image2] },
|
||||
listing2,
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue