Skip to content

Commit

Permalink
fix(entity-store): split into asset and entry map to prevent id colli…
Browse files Browse the repository at this point in the history
…sion []
  • Loading branch information
chrishelgert committed Nov 7, 2023
1 parent 34f699e commit a7bc176
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 33 deletions.
38 changes: 22 additions & 16 deletions packages/visual-sdk/src/store/EditorEntityStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,27 +67,33 @@ export class EditorEntityStore extends EntityStore {
return id.length === 1 ? id[0] : id.join(this.cacheIdSeperator);
}

private findMissingEntites(ids: string[]) {
const missing = [];
// TODO: we have this bascially already covered in the EntityStore (except: it throws an error instead of returning both)
private findMissingEntites(type: 'Asset', ids: string[]): { missingIds: string[], resolvedEntities: Array<Asset> }
private findMissingEntites(type: 'Entry', ids: string[]): { missingIds: string[], resolvedEntities: Array<Entry> }
private findMissingEntites(type: 'Asset' | 'Entry', ids: string[]) {
const resolvedEntities = [];
const missingIds = [];

for (const id of ids) {
const entry = this.entitiesMap.get(id);
if (!entry) {
missing.push(id);
const entity = this.getEntity(type, id);
if (entity) {
resolvedEntities.push(entity)
} else {
missingIds.push(id);
}
}

return missing;
return {missingIds, resolvedEntities};
}

private async fetchEntity(ids: string[]): Promise<Array<Entry>>;
private async fetchEntity(ids: string[], isAsset: true): Promise<Array<Asset>>;
private async fetchEntity(ids: string[], isAsset?: boolean): Promise<Array<Entry | Asset>> {
const missingIds = this.findMissingEntites(ids);
private async fetchEntity(type: 'Asset', ids: string[]): Promise<Array<Asset>>;
private async fetchEntity(type: 'Entry', ids: string[]): Promise<Array<Entry>>;
private async fetchEntity(type: 'Asset' | 'Entry', ids: string[]): Promise<Array<Entry> | Array<Asset>> {
const {missingIds, resolvedEntities} = this.findMissingEntites(type, ids);

if (missingIds.length === 0) {
// everything is already in cache
return ids.map((id) => this.entitiesMap.get(id)) as Array<Entry | Asset>;
return resolvedEntities;
}

const cacheId = this.getCacheId(missingIds);
Expand Down Expand Up @@ -120,7 +126,7 @@ export class EditorEntityStore extends EntityStore {

this.sendMessage(PostMessageMethods.REQUEST_ENTITIES, {
entityIds: missingIds,
entityType: isAsset ? 'Asset' : 'Entry',
entityType: type,
locale: this.locale,
});
});
Expand All @@ -133,10 +139,10 @@ export class EditorEntityStore extends EntityStore {
const result = (await newPromise) as Array<Entry | Asset>;

result.forEach((value) => {
this.entitiesMap.set(value.sys.id, value);
this.addEntity(value)
});

return ids.map((id) => this.entitiesMap.get(id)) as Array<Entry | Asset>;
return ids.map((id) => this.getEntity(type, id));
}

public async fetchAsset(id: string): Promise<Asset | undefined> {
Expand All @@ -150,7 +156,7 @@ export class EditorEntityStore extends EntityStore {
}

public fetchAssets(ids: string[]): Promise<Asset[]> {
return this.fetchEntity(ids, true);
return this.fetchEntity('Asset', ids);
}

public async fetchEntry(id: string): Promise<Entry | undefined> {
Expand All @@ -164,6 +170,6 @@ export class EditorEntityStore extends EntityStore {
}

public fetchEntries(ids: string[]): Promise<Entry[]> {
return this.fetchEntity(ids);
return this.fetchEntity('Entry', ids);
}
}
60 changes: 43 additions & 17 deletions packages/visual-sdk/src/store/EntityStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,33 @@ import { get } from './utils';
*/
export class EntityStore {
protected locale: string;
protected entitiesMap: Map<string, Entry | Asset>;
protected entryMap = new Map<string, Entry>();
protected assetMap = new Map<string, Asset>();

constructor({ entities, locale }: { entities: Array<Entry | Asset>; locale: string }) {
this.entitiesMap = new Map(entities.map((entity) => [entity.sys.id, entity]));
this.locale = locale;

for (const entity of entities) {
this.addEntity(entity)
}
}

public get entities() {
return [...this.entitiesMap.values()];
return [...this.entryMap.values(), ...this.assetMap.values()];
}

public updateEntity(entity: Entry | Asset) {
this.entitiesMap.set(entity.sys.id, entity);
this.addEntity(entity);
}

public getValue(
entityLink: UnresolvedLink<'Entry' | 'Asset'>,
path: string[]
): string | undefined {
const entity = this.entitiesMap.get(entityLink.sys.id);
entityLink.sys.type
const entity = this.getEntity(entityLink.sys.linkType, entityLink.sys.id);

if (!entity || entity.sys.type !== entityLink.sys.linkType) {
if (!entity) {
// TODO: move to `debug` utils once it is extracted
console.warn(`Unresolved entity reference: ${entityLink}`);
return;
Expand All @@ -38,42 +43,44 @@ export class EntityStore {
return get<string>(entity, path);
}

private getEntitiesFromMap(ids: string[]) {
const entity = [];
private getEntitiesFromMap(type: 'Entry', ids: string[]): Array<Entry>
private getEntitiesFromMap(type: 'Asset', ids: string[]): Array<Asset>
private getEntitiesFromMap(type: 'Entry' | 'Asset', ids: string[]) {
const entityList = [];
const missingEntityIds = [];

for (const id of ids) {
const entry = this.entitiesMap.get(id);
if (entry) {
entity.push(entry);
const entity = this.getEntity(type, id);
if (entity) {
entityList.push(entity);
} else {
missingEntityIds.push(id);
}
}

if (missingEntityIds.length) {
throw new Error(`Missing entity in the store (${missingEntityIds.join(',')})`);
throw new Error(`Missing ${type} in the store (${missingEntityIds.join(',')})`);
}

return entity as Array<Asset | Entry>;
return entityList;
}

public async fetchAsset(id: string): Promise<Asset | undefined> {
try {
return this.getEntitiesFromMap([id])[0] as Asset;
return this.getEntitiesFromMap('Asset', [id])[0];
} catch (err) {
// TODO: move to `debug` utils once it is extracted
console.warn(`Asset "${id}" is not in the store`);
return undefined;
}
}
public async fetchAssets(ids: string[]): Promise<Asset[]> {
return this.getEntitiesFromMap(ids) as Asset[];
return this.getEntitiesFromMap('Asset', ids);
}

public async fetchEntry(id: string): Promise<Entry | undefined> {
try {
return this.getEntitiesFromMap([id])[0] as Entry;
return this.getEntitiesFromMap('Entry', [id])[0];
} catch (err) {
// TODO: move to `debug` utils once it is extracted
console.warn(`Entry "${id}" is not in the store`);
Expand All @@ -82,6 +89,25 @@ export class EntityStore {
}

public async fetchEntries(ids: string[]): Promise<Entry[]> {
return this.getEntitiesFromMap(ids) as Entry[];
return this.getEntitiesFromMap('Entry', ids);
}

private isAsset(entity: Entry | Asset): entity is Asset {
return entity.sys.type === 'Asset'
}

protected addEntity(entity: Entry | Asset): void {
if (this.isAsset(entity)) {
this.assetMap.set(entity.sys.id, entity)
} else {
this.entryMap.set(entity.sys.id, entity)
}
}

protected getEntity(type: 'Entry' | 'Asset', id: string): Asset | Entry | undefined {
if (type === 'Asset') {
return this.assetMap.get(id)
}
return this.entryMap.get(id)
}
}

0 comments on commit a7bc176

Please sign in to comment.