/**
* EntryStoreUtil provides utility functionality for working with entries.
* @exports store/EntryStoreUtil
*/
export default class EntryStoreUtil {
/**
* @param {EntryStore} entrystore
*/
constructor(entrystore) {
this._entrystore = entrystore;
this._preloadIdx = new Map();
}
/**
* @returns {EntryStore}
*/
getEntryStore() {
return this._entrystore;
}
/**
* Preload entries of a specific type.
* Not strictly needed, used for optimization reasons.
* Up to a maximum of 100 entries are preloaded.
*
* @param {string} ofType
* @param {Context} context if provided limits the preload to a specific context.
* @returns {Entry}
*/
preloadEntries(ofType, context) {
let preloadForType = this._preloadIdx.get(ofType);
let promise;
if (preloadForType) {
if (context) {
promise = preloadForType[context.getEntryURI()];
if (promise) {
return promise;
}
} else if (preloadForType.noContext) {
return preloadForType.noContext;
}
} else {
preloadForType = {};
this._preloadIdx.set(ofType, preloadForType);
}
const searchObj = this._entrystore.newSolrQuery().resourceType(ofType).limit(100);
if (context) {
searchObj.context(context);
}
const list = searchObj.list();
promise = list.getEntries(0);
if (context) {
preloadForType[context.getEntryURI()] = promise;
} else {
preloadForType.noContext = promise;
}
return promise;
}
clearPreloadEntriesDuplicateCheck(ofType, inContext) {
if (ofType) {
const preloadForType = this._preloadIdx.get(ofType);
if (preloadForType && inContext) {
delete preloadForType[inContext.getEntryURI()];
} else {
this._preloadIdx.delete(ofType);
}
} else {
this._preloadIdx = new Map();
}
}
/**
* Retrieves an entry for a resource URI, note that if there are several entries that all
* have the same resource URI it is unclear which of these entries that are returned.
* Hence, only use this function if you expect there to be a single entry per resource URI.
*
* @param {string} resourceURI is the URI for the resource.
* @param {Context=} context only look for entries in this context, may be left out.
* @param {string} asyncCallType the callType used when making the search.
* @returns {Promise.<Entry>}
* @async
* @throws Error
*/
async getEntryByResourceURI(resourceURI, context, asyncCallType) {
const cache = this._entrystore.getCache();
const entriesSet = cache.getByResourceURI(resourceURI);
if (context) {
for (const entry of entriesSet) { // eslint-disable-line
if (entry.getContext().getId() === context.getId()) {
return Promise.resolve(entry);
}
}
}
const query = this._entrystore.newSolrQuery().resource(resourceURI).limit(1);
if (context) {
query.context(context);
}
const entryArr = await query.list(asyncCallType).getEntries(0);
if (entryArr.length > 0) {
return entryArr[0];
}
throw new Error(`No entries for resource with URI: ${resourceURI}`);
}
/**
* @param {string} resourceURI is the URI for the resource.
* @returns {Entry}
*/
getEntryListByResourceURI(resourceURI) {
return this._entrystore.newSolrQuery().resource(resourceURI).list();
}
/**
* Attempting to find a unique entry for a specific type,
* if multiple entries exists with the same type the returned promise fails.
* You may restrict to a specific context.
*
* @param {string} typeURI is the rdf:type URI for the entry to match.
* @param {Context} context restrict to finding the entry in this context
* @param {string} asyncCallType the callType used when making the search.
* @returns {Promise.<Entry>}
* @async
* @throws Error
*/
async getEntryByType(typeURI, context, asyncCallType) {
const query = this._entrystore.newSolrQuery().rdfType(typeURI).limit(2);
if (context) {
query.context(context);
}
const entryArr = await query.list(asyncCallType).getEntries(0);
if (entryArr.length === 1) {
return entryArr[0];
}
throw new Error('Wrong number of entries in context / repository');
}
/**
* Attempting to find one entry for a specific graph type,
* if multiple entries exists with the same type the returned promise fails.
* You may restrict to a specific context.
*
* @param {string} graphType is the graph type for the entry to match, e.g. use
* {@see types#GT_USER}.
* @param {Context} context restrict to finding the entry in this context
* @param {string} asyncCallType the callType used when making the search.
* @returns {Promise.<Entry>}
* @async
* @throws Error
*/
async getEntryByGraphType(graphType, context, asyncCallType) {
const query = this._entrystore.newSolrQuery().graphType(graphType).limit(2);
if (context) {
query.context(context);
}
const entryArr = await query.list(asyncCallType).getEntries(0);
if (entryArr.length > 0) {
return entryArr[0];
}
throw new Error(`No entries in ${context ? 'context' : 'repository'} context with graphType ${graphType}`);
}
/**
* Removes all entries matched by a search in a serial manner,
* also empties the cache from loaded entries so it should not overflow
* if the searchlist is big.
*
* The removal is accomplished by first iterating through the searchlist and collecting
* uris to all entries that should be removed. After that the entries are removed.
*
* @param {SearchList} list
* @returns {Promise}
*/
async removeAll(list) {
const uris = [];
const es = this._entrystore;
const cache = es.getCache();
const rest = es.getREST();
const deleteNext = async () => {
if (uris.length > 0) {
const uri = uris.pop();
try {
await rest.del(uri);
} catch (err) {
console.log(`Could not remove entry with uri: ${uri} continuing anyway.`);
}
deleteNext();
}
return undefined;
};
const result = await list.forEach((entry) => {
uris.push(entry.getURI());
cache.unCache(entry); // @todo @valentino perhaps they are removed from cache too early. Move to deleteNext?
});
deleteNext(result);
}
}