terriajs
Version:
Geospatial data visualization platform.
78 lines (70 loc) • 2.54 kB
text/typescript
import joinUrl from "./joinUrl";
import loadCsv from "../../Core/loadCsv";
import { IndexBase, IndexType } from "./Types";
// IDs of enum to search
type EnumSearchQuery = string[];
// An enum value definition.
export type EnumValue = {
count: number; // Number of objects this enum value has
url: string; // Url of the CSV file containing the enum index
dataRowIds?: Promise<number[]>; // Array of IDs
};
/**
* An index used for searching enums (fixed set of strings).
*
* Enum indexes contains sub-indexes, one for each enum value.
* The sub-index is simply an array of IDs that has the enum value.
* Searching for an enum value simply returns the IDs array for that value.
*/
export default class EnumIndex implements IndexBase<EnumSearchQuery> {
readonly type = IndexType.enum;
/**
* Constructs an EnumIndex.
*
* @param values An object mapping an enum value string to the value definition.
*/
constructor(readonly values: Record<string, EnumValue>) {}
/**
* Load an enum index.
*
* @param indexRootUrl The URL of the index root directory.
* @param searchHint The enum values that will be searched. We only load the sub-indexes for these values.
*/
async load(indexRootUrl: string, searchHint: EnumSearchQuery): Promise<void> {
const enumValueIds = searchHint;
const promises = enumValueIds.map(async (valueId) => {
const value = this.values[valueId];
if (value.dataRowIds) return Promise.resolve();
const promise = loadCsv(joinUrl(indexRootUrl, value.url), {
dynamicTyping: true,
header: true
}).then((rows) => rows.map(({ dataRowId }) => dataRowId));
value.dataRowIds = promise;
return promise;
});
await Promise.all(promises);
}
/**
* Search the enum index.
*
* @param enumValueIds The enum values to be searched
* @return Set of IDs for all matching enum values.
*/
async search(enumValueIds: EnumSearchQuery): Promise<Set<number>> {
const idSets = await Promise.all(
enumValueIds.map(async (valueId) => {
const value = this.values[valueId];
if (!value) throw new Error(`Not an enum value: ${valueId}`);
if (!value.dataRowIds)
throw new Error(`Index for enum value ${valueId} is not loaded`);
return await value.dataRowIds;
})
);
const ids = flatten(idSets);
return new Set(ids);
}
}
function flatten<T>(array: T[][]): T[] {
const flattened = array.reduce((acc, a) => acc.concat(a), []);
return flattened;
}