semantic-network
Version:
A utility library for manipulating a list of links that form a semantic interface to a network of resources.
352 lines • 18 kB
JavaScript
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.syncResource = void 0;
var semantic_link_1 = require("semantic-link");
var namedRepresentationFactory_1 = require("../representation/namedRepresentationFactory");
var instanceOfSingleton_1 = require("../utils/instanceOf/instanceOfSingleton");
var apiUtil_1 = require("../apiUtil");
var linkRelation_1 = require("../linkRelation");
var syncUtil_1 = require("./syncUtil");
var instanceOfCollection_1 = require("../utils/instanceOf/instanceOfCollection");
var instanceOfDocumentCollection_1 = require("../utils/instanceOf/instanceOfDocumentCollection");
var instanceOfDocumentSingleton_1 = require("../utils/instanceOf/instanceOfDocumentSingleton");
var representationUtil_1 = require("../utils/representationUtil");
var anylogger_1 = __importDefault(require("anylogger"));
var log = (0, anylogger_1.default)('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
*/
function syncResource(resource, document, strategies, options) {
if (strategies === void 0) { strategies = []; }
return __awaiter(this, void 0, void 0, function () {
var _a, _b, rel, _c, relOnDocument, _d, name, _e, nameOnDocument, result, update, info, result, syncInfo, result, namedResource, syncInfo, namedResource, namedDocument, updated;
return __generator(this, function (_f) {
switch (_f.label) {
case 0:
_a = __assign({}, options), _b = _a.rel, rel = _b === void 0 ? undefined : _b, _c = _a.relOnDocument, relOnDocument = _c === void 0 ? undefined : _c, _d = _a.name, name = _d === void 0 ? namedRepresentationFactory_1.NamedRepresentationFactory.defaultNameStrategy(rel, resource) : _d, _e = _a.nameOnDocument, nameOnDocument = _e === void 0 ? namedRepresentationFactory_1.NamedRepresentationFactory.defaultNameStrategy(relOnDocument, document) : _e;
// do not pass down
options = __assign(__assign({}, options), { rel: undefined, name: undefined, relOnDocument: undefined, nameOnDocument: undefined });
if (!(!rel && !relOnDocument && (0, instanceOfSingleton_1.instanceOfSingleton)(resource) && (0, instanceOfSingleton_1.instanceOfSingleton)(document))) return [3 /*break*/, 6];
return [4 /*yield*/, apiUtil_1.ApiUtil.get(resource, options)];
case 1:
result = _f.sent();
if (!result) return [3 /*break*/, 5];
log.debug('sync singleton on rel \'%s\' %s', rel, semantic_link_1.LinkUtil.getUri(resource, linkRelation_1.LinkRelation.Self));
return [4 /*yield*/, apiUtil_1.ApiUtil.update(resource, document, options)];
case 2:
update = _f.sent();
if (!update) return [3 /*break*/, 5];
return [4 /*yield*/, syncUtil_1.SyncUtil.syncResources(resource, document, strategies, options)];
case 3: return [4 /*yield*/, (_f.sent())()];
case 4:
_f.sent();
_f.label = 5;
case 5: return [3 /*break*/, 35];
case 6:
if (!(!rel && !relOnDocument && (0, instanceOfCollection_1.instanceOfCollection)(resource) && (0, instanceOfDocumentCollection_1.instanceOfDocumentCollection)(document))) return [3 /*break*/, 11];
log.debug('sync collection items %s', semantic_link_1.LinkUtil.getUri(resource, linkRelation_1.LinkRelation.Self));
return [4 /*yield*/, syncUtil_1.SyncUtil.synchroniseCollection(resource, document, options)];
case 7:
info = (_f.sent()).info;
if (!info) return [3 /*break*/, 10];
// 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
return [4 /*yield*/, apiUtil_1.ApiUtil.get(resource, __assign(__assign({}, options), { includeItems: true }))];
case 8:
// 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
_f.sent();
return [4 /*yield*/, syncUtil_1.SyncUtil.tailRecursionThroughStrategies(strategies, info, options)];
case 9:
_f.sent();
_f.label = 10;
case 10: return [3 /*break*/, 35];
case 11:
if (!(!rel && !relOnDocument && (0, instanceOfCollection_1.instanceOfCollection)(resource) && (0, instanceOfDocumentSingleton_1.instanceOfDocumentSingleton)(document))) return [3 /*break*/, 18];
log.debug('sync collection %s', semantic_link_1.LinkUtil.getUri(resource, linkRelation_1.LinkRelation.Self));
return [4 /*yield*/, apiUtil_1.ApiUtil.get(resource, options)];
case 12:
result = _f.sent();
if (!(0, instanceOfCollection_1.instanceOfCollection)(result)) return [3 /*break*/, 16];
return [4 /*yield*/, syncUtil_1.SyncUtil.syncResourceInCollection(result, document, options)];
case 13:
syncInfo = _f.sent();
if (!syncInfo) return [3 /*break*/, 15];
return [4 /*yield*/, syncUtil_1.SyncUtil.syncInfos(strategies, options)(syncInfo)];
case 14: return [2 /*return*/, _f.sent()];
case 15: return [3 /*break*/, 17];
case 16:
log.error('result is not a collection');
_f.label = 17;
case 17: return [2 /*return*/, result];
case 18:
if (!(rel && !relOnDocument && (0, instanceOfDocumentCollection_1.instanceOfDocumentCollection)(document))) return [3 /*break*/, 23];
log.debug('collection (in named collection) \'%s\' on %s', name, semantic_link_1.LinkUtil.getUri(resource, linkRelation_1.LinkRelation.Self));
return [4 /*yield*/, apiUtil_1.ApiUtil.get(resource, __assign(__assign({}, options), { rel: rel }))];
case 19:
result = _f.sent();
if (!(0, instanceOfCollection_1.instanceOfCollection)(result)) return [3 /*break*/, 21];
// in the context of the collection, synchronise the collection part of the document
return [4 /*yield*/, syncResource(result, document, strategies, options)];
case 20:
// in the context of the collection, synchronise the collection part of the document
_f.sent();
return [3 /*break*/, 22];
case 21:
log.info('No \'%s\' on resource %s', name, semantic_link_1.LinkUtil.getUri(resource, linkRelation_1.LinkRelation.Self));
_f.label = 22;
case 22: return [3 /*break*/, 35];
case 23:
if (!(rel && !relOnDocument && (0, instanceOfDocumentSingleton_1.instanceOfDocumentSingleton)(document))) return [3 /*break*/, 28];
log.debug('sync resource (named collection) \'%s\' on %s', name, semantic_link_1.LinkUtil.getUri(resource, linkRelation_1.LinkRelation.Self));
return [4 /*yield*/, apiUtil_1.ApiUtil.get(resource, __assign(__assign({}, options), { rel: rel }))];
case 24:
namedResource = _f.sent();
if (!(0, instanceOfCollection_1.instanceOfCollection)(namedResource)) return [3 /*break*/, 27];
return [4 /*yield*/, syncUtil_1.SyncUtil.syncResourceInCollection(namedResource, document, options)];
case 25:
syncInfo = _f.sent();
if (!syncInfo) return [3 /*break*/, 27];
return [4 /*yield*/, syncUtil_1.SyncUtil.syncInfos(strategies, options)(syncInfo)];
case 26: return [2 /*return*/, _f.sent()];
case 27: return [2 /*return*/, namedResource];
case 28:
if (!(rel && relOnDocument)) return [3 /*break*/, 35];
return [4 /*yield*/, apiUtil_1.ApiUtil.get(resource, __assign(__assign({}, options), { rel: rel }))];
case 29:
namedResource = _f.sent();
if (!namedResource) return [3 /*break*/, 34];
log.debug('sync resource (named singleton) \'%s\' on %s', name, semantic_link_1.LinkUtil.getUri(resource, linkRelation_1.LinkRelation.Self));
namedDocument = representationUtil_1.RepresentationUtil.getProperty(document, nameOnDocument);
return [4 /*yield*/, apiUtil_1.ApiUtil.update(namedResource, namedDocument, options)];
case 30:
updated = _f.sent();
if (!updated) return [3 /*break*/, 33];
return [4 /*yield*/, syncUtil_1.SyncUtil.syncResources(updated, namedDocument, strategies, options)];
case 31: return [4 /*yield*/, (_f.sent())()];
case 32:
_f.sent();
_f.label = 33;
case 33: return [3 /*break*/, 35];
case 34:
log.debug('no update: singleton \'%s\' not found on %s', name, semantic_link_1.LinkUtil.getUri(resource, linkRelation_1.LinkRelation.Self));
_f.label = 35;
case 35: return [2 /*return*/, resource];
}
});
});
}
exports.syncResource = syncResource;
//# sourceMappingURL=syncResource.js.map