semantic-network
Version:
A utility library for manipulating a list of links that form a semantic interface to a network of resources.
256 lines • 10.7 kB
JavaScript
import { __awaiter } from "tslib";
import { LinkUtil } from 'semantic-link';
import { NamedRepresentationFactory } from '../representation/namedRepresentationFactory';
import { instanceOfSingleton } from '../utils/instanceOf/instanceOfSingleton';
import { ApiUtil } from '../apiUtil';
import { LinkRelation } from '../linkRelation';
import { SyncUtil } from './syncUtil';
import { instanceOfCollection } from '../utils/instanceOf/instanceOfCollection';
import { instanceOfDocumentCollection } from '../utils/instanceOf/instanceOfDocumentCollection';
import { instanceOfDocumentSingleton } from '../utils/instanceOf/instanceOfDocumentSingleton';
import { RepresentationUtil } from '../utils/representationUtil';
import anylogger from 'anylogger';
const log = anylogger('syncResource');
/**
* Sync resources between two networks of data
*
* There six scenarios:
*
* key: x - undefined
* + - specified
* [empty] - not required
*
* options resource document
* rel relOnDocument singleton collection singleton collection
* 1. x x + +
* 2. + +
* 3. x x + +
* 4. + x +
* 5. x x + +
* 6. + x +
*
*
* Strategy One
* ============
*
* Retrieves a resource and synchronises (its attributes) from the document
*
* Note: this is used for syncing two documents through their parents
*
*
* @example
*
* Resource Document
*
* sync
* +-----+ +-----+
* | | <-----------+ | |
* | | | |
* +-----+ +-----+
*
*
* Strategy Two
* ============
*
* Retrieves a singleton resource on a parent resource and updates (its
* attributes) based on a singleton of the same name in the given parent document.
*
* The parent maybe either a collection resource or a singleton resource
*
* Note: this is used for syncing two documents through their parents
*
* @example
*
*
* parent singleton singleton parent
* Resource Resource Document Document
*
* +----------+ +---------+
* | | sync | |
* | +-----+ +-----+ |
* | Named| | <-----------+ | |Named |
* | | | | | |
* | +-----+ +-----+ |
* | | | |
* | | ^ | |
* +----------+ | +---------+
* |
* +
* looks for
*
* Strategy Three
* ==============
*
*
* Retrieves a resource item from a resource collection and synchronises (its attributes) from the document.
*
* @example
*
* resource
* Collection Document
*
* +-----+
* | |
* | |
* +-----+ sync
* X +---+
* X <-----------+ | x |
* X +---+
* items
*
* Strategy Four
* =============
*
*
* Retrieves a parent resource and its named collection with items (sparsely populated), finds the item in that
* collection and then synchronises (its attributes) with the document.
*
* @example
*
* parent resource
* Resource Collection Document
*
* +----------+
* | |
* | +-----+
* | Named| |
* | | |
* | +-----+ sync
* | | X +---+
* | | X <-----------+ | x |
* +----------+ X +---+
* items
*
* Strategy Five
* =============
*
*
* Retrieves a collection resource with items (sparsely populated), then synchronises the
* collection items where each item may be updated (its attributes), a new item created or an item removed.
*
* @example
*
* resource document
* Collection Collection
*
*
* sync
* +-----+ +-----+
* | | <-----------+ | |
* | | | |
* +-----+ +-----+
* X X
* X items X items
* X X
*
*
* Strategy Six
* ============
*
* Retrieves a parent resource and its named collection with items (sparsely populated), then synchronises the
* collection items where each item may be updated (its attributes), a new item created or an item removed.
*
* This method is used when you have context of one parent and the document collection
*
* @example
*
* parent resource document
* Resource Collection Collection
*
* +----------+
* | | sync
* | +-----+ +-----+
* | Named| | <-----------+ | |
* | | | | |
* | +-----+ +-----+
* | | X X
* | | X items X items
* +----------+ X X
*
*
*
* @param resource
* @param document
* @param strategies
* @param options
*/
export function syncResource(resource, document, strategies = [], options) {
return __awaiter(this, void 0, void 0, function* () {
const { rel = undefined, relOnDocument = undefined, name = NamedRepresentationFactory.defaultNameStrategy(rel, resource), nameOnDocument = NamedRepresentationFactory.defaultNameStrategy(relOnDocument, document), } = Object.assign({}, options);
// do not pass down
options = Object.assign(Object.assign({}, options), { rel: undefined, name: undefined, relOnDocument: undefined, nameOnDocument: undefined });
if (!rel && !relOnDocument && instanceOfSingleton(resource) && instanceOfSingleton(document)) {
const result = yield ApiUtil.get(resource, options);
if (result) {
log.debug('sync singleton on rel \'%s\' %s', rel, LinkUtil.getUri(resource, LinkRelation.Self));
const update = yield ApiUtil.update(resource, document, options);
if (update) {
yield (yield SyncUtil.syncResources(resource, document, strategies, options))();
}
}
}
else if (!rel && !relOnDocument && instanceOfCollection(resource) && instanceOfDocumentCollection(document)) {
log.debug('sync collection items %s', LinkUtil.getUri(resource, LinkRelation.Self));
const { info } = yield SyncUtil.synchroniseCollection(resource, document, options);
if (info) {
// populate the potentially sparse collection - we need to ensure that
// any existing ones (old) are not stale and that any just created (sparse)
// are hydrated
yield ApiUtil.get(resource, Object.assign(Object.assign({}, options), { includeItems: true }));
yield SyncUtil.tailRecursionThroughStrategies(strategies, info, options);
}
}
else if (!rel && !relOnDocument && instanceOfCollection(resource) && instanceOfDocumentSingleton(document)) {
log.debug('sync collection %s', LinkUtil.getUri(resource, LinkRelation.Self));
const result = yield ApiUtil.get(resource, options);
if (instanceOfCollection(result)) {
const syncInfo = yield SyncUtil.syncResourceInCollection(result, document, options);
if (syncInfo) {
return yield SyncUtil.syncInfos(strategies, options)(syncInfo);
}
}
else {
log.error('result is not a collection');
}
return result;
}
else if (rel && !relOnDocument && instanceOfDocumentCollection(document)) {
log.debug('collection (in named collection) \'%s\' on %s', name, LinkUtil.getUri(resource, LinkRelation.Self));
const result = yield ApiUtil.get(resource, Object.assign(Object.assign({}, options), { rel }));
if (instanceOfCollection(result)) {
// in the context of the collection, synchronise the collection part of the document
yield syncResource(result, document, strategies, options);
}
else {
log.info('No \'%s\' on resource %s', name, LinkUtil.getUri(resource, LinkRelation.Self));
}
}
else if (rel && !relOnDocument && instanceOfDocumentSingleton(document)) {
log.debug('sync resource (named collection) \'%s\' on %s', name, LinkUtil.getUri(resource, LinkRelation.Self));
const namedResource = yield ApiUtil.get(resource, Object.assign(Object.assign({}, options), { rel }));
if (instanceOfCollection(namedResource)) {
const syncInfo = yield SyncUtil.syncResourceInCollection(namedResource, document, options);
if (syncInfo) {
return yield SyncUtil.syncInfos(strategies, options)(syncInfo);
}
}
return namedResource;
}
else if (rel && relOnDocument) {
const namedResource = yield ApiUtil.get(resource, Object.assign(Object.assign({}, options), { rel }));
if (namedResource) {
log.debug('sync resource (named singleton) \'%s\' on %s', name, LinkUtil.getUri(resource, LinkRelation.Self));
const namedDocument = RepresentationUtil.getProperty(document, nameOnDocument);
const updated = yield ApiUtil.update(namedResource, namedDocument, options);
if (updated) {
yield (yield SyncUtil.syncResources(updated, namedDocument, strategies, options))();
}
}
else {
log.debug('no update: singleton \'%s\' not found on %s', name, LinkUtil.getUri(resource, LinkRelation.Self));
}
}
return resource;
});
}
//# sourceMappingURL=syncResource.js.map