2025-04-16 16:55:38 -07:00
|
|
|
import { toLowerCaseEntityType, toTitleCase } from '@graphql-mock/helper';
|
|
|
|
import { EntityBrowseFn, EntityBrowsePath, GetBrowseResults, StringNumber } from '@graphql-mock/types';
|
|
|
|
import { BrowseInput, BrowseResultGroup, BrowseResults, Entity, EntityType, SearchResult } from '@types';
|
2021-07-17 04:56:50 +10:00
|
|
|
|
|
|
|
type ToFlatPathsArg = {
|
|
|
|
flatPaths: StringNumber[][];
|
|
|
|
paths: EntityBrowsePath[];
|
|
|
|
parentPaths: string[];
|
|
|
|
};
|
|
|
|
|
|
|
|
export const toFlatPaths = ({ flatPaths, paths, parentPaths }: ToFlatPathsArg) => {
|
|
|
|
paths.forEach(({ name, paths: childPaths, count = 0 }) => {
|
|
|
|
if (childPaths.length) {
|
|
|
|
parentPaths.push(name);
|
|
|
|
toFlatPaths({ flatPaths, parentPaths, paths: childPaths });
|
|
|
|
} else {
|
|
|
|
flatPaths.push([...parentPaths, name, count]);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
parentPaths.pop();
|
|
|
|
};
|
|
|
|
|
|
|
|
type FilterEntityByPathArg = {
|
|
|
|
term: string;
|
|
|
|
searchResults: SearchResult[];
|
|
|
|
};
|
|
|
|
|
|
|
|
export const filterEntityByPath = ({ term, searchResults }: FilterEntityByPathArg): Entity[] => {
|
|
|
|
return searchResults
|
|
|
|
.filter((r) => {
|
|
|
|
const regex = new RegExp(term);
|
|
|
|
return regex.test(r.entity.urn);
|
|
|
|
})
|
|
|
|
.map((r) => r.entity);
|
|
|
|
};
|
|
|
|
|
|
|
|
export class BrowsePathResolver {
|
|
|
|
private readonly browse: Record<string, EntityBrowseFn>;
|
|
|
|
|
|
|
|
private readonly paths: EntityBrowsePath[];
|
|
|
|
|
|
|
|
private readonly filterEntityHandler: (path: string[]) => Entity[];
|
|
|
|
|
|
|
|
private readonly baseBrowseResult: GetBrowseResults = {
|
|
|
|
data: {
|
|
|
|
browse: {
|
|
|
|
entities: [],
|
2021-07-30 10:48:32 -07:00
|
|
|
groups: [],
|
2021-07-17 04:56:50 +10:00
|
|
|
start: 0,
|
|
|
|
count: 0,
|
|
|
|
total: 0,
|
|
|
|
metadata: {
|
|
|
|
path: [],
|
|
|
|
totalNumEntities: 0,
|
|
|
|
__typename: 'BrowseResultMetadata',
|
|
|
|
},
|
|
|
|
__typename: 'BrowseResults',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
constructor({
|
|
|
|
entityType,
|
|
|
|
paths,
|
|
|
|
filterEntityHandler,
|
|
|
|
}: {
|
|
|
|
entityType: EntityType;
|
|
|
|
paths: EntityBrowsePath[];
|
|
|
|
filterEntityHandler(path: string[]): Entity[];
|
|
|
|
}) {
|
|
|
|
this.browse = {};
|
|
|
|
this.paths = paths;
|
|
|
|
this.filterEntityHandler = filterEntityHandler;
|
|
|
|
const browsePathKey = `${toLowerCaseEntityType(entityType)}Browse`;
|
|
|
|
const groups = this.paths.map<BrowseResultGroup>(({ name, paths: rootPaths, count = 0 }) => ({
|
|
|
|
name,
|
|
|
|
count: rootPaths.length ? rootPaths.reduce(this.sumTotalEntityByPaths, 0) : count,
|
|
|
|
__typename: 'BrowseResultGroup',
|
|
|
|
}));
|
|
|
|
this.initBrowsePathResolver({ browsePathKey, groups });
|
|
|
|
this.initBrowsePathResolverForPaths({ prefixPathKey: browsePathKey, paths });
|
|
|
|
}
|
|
|
|
|
|
|
|
public getBrowse() {
|
|
|
|
return this.browse;
|
|
|
|
}
|
|
|
|
|
|
|
|
private initBrowsePathResolver({ browsePathKey, groups }: { browsePathKey: string; groups: BrowseResultGroup[] }) {
|
|
|
|
if (!this.browse.hasOwnProperty(browsePathKey)) {
|
|
|
|
const dataBrowse: BrowseResults = JSON.parse(JSON.stringify(this.baseBrowseResult.data.browse));
|
|
|
|
|
|
|
|
Object.assign(this.browse, {
|
|
|
|
[browsePathKey]: ({ start, count, path }: BrowseInput): GetBrowseResults => {
|
|
|
|
const startValue = start as number;
|
|
|
|
const countValue = count as number;
|
|
|
|
const paths = path as string[];
|
|
|
|
const entities = groups.length ? [] : this.filterEntityHandler(paths);
|
|
|
|
const chunkEntities = entities.slice(startValue, startValue + countValue);
|
|
|
|
|
|
|
|
return {
|
|
|
|
data: {
|
|
|
|
browse: {
|
|
|
|
...dataBrowse,
|
|
|
|
entities: chunkEntities,
|
2021-07-30 10:48:32 -07:00
|
|
|
groups,
|
2021-07-17 04:56:50 +10:00
|
|
|
start: startValue,
|
|
|
|
count: chunkEntities.length,
|
|
|
|
total: entities.length,
|
|
|
|
metadata: {
|
|
|
|
...dataBrowse.metadata,
|
|
|
|
path: paths,
|
|
|
|
totalNumEntities: groups.reduce(this.sumTotalEntityByGroups, 0),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private initBrowsePathResolverForPaths({
|
|
|
|
prefixPathKey,
|
|
|
|
paths,
|
|
|
|
}: {
|
|
|
|
prefixPathKey: string;
|
|
|
|
paths: EntityBrowsePath[];
|
|
|
|
}) {
|
|
|
|
paths.forEach(({ name, paths: childPaths }) => {
|
|
|
|
const browsePathKey = `${prefixPathKey}${toTitleCase(name)}`;
|
|
|
|
|
|
|
|
if (childPaths.length) {
|
|
|
|
const groups = childPaths.map<BrowseResultGroup>(
|
|
|
|
({ name: childName, paths: child2Paths, count = 0 }) => ({
|
|
|
|
name: childName,
|
|
|
|
count: child2Paths.length ? child2Paths.reduce(this.sumTotalEntityByPaths, 0) : count,
|
|
|
|
__typename: 'BrowseResultGroup',
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
|
|
|
|
this.initBrowsePathResolver({ browsePathKey, groups });
|
|
|
|
this.initBrowsePathResolverForPaths({ prefixPathKey: browsePathKey, paths: childPaths });
|
|
|
|
} else {
|
|
|
|
this.initBrowsePathResolver({ browsePathKey, groups: [] });
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
private sumTotalEntityByGroups = (out: number, { count = 0 }: BrowseResultGroup): number => {
|
|
|
|
return out + count;
|
|
|
|
};
|
|
|
|
|
|
|
|
private sumTotalEntityByPaths = (out: number, { paths, count = 0 }: EntityBrowsePath): number => {
|
|
|
|
if (paths.length) {
|
|
|
|
return paths.reduce(this.sumTotalEntityByPaths, out);
|
|
|
|
}
|
|
|
|
return out + count;
|
|
|
|
};
|
|
|
|
}
|