/**
* @author Michael Hasenstein <hasenstein@yahoo.com>
* @copyright REFINIO GmbH 2017
* @license CC-BY-NC-SA-2.5; portions MIT License
* @version 0.0.1
*/
/**
* @module
*/
/**
* Options object for instance-updater, which updates the currently active instance.
* @global
* @typedef {object} InstanceUpdateOptions
* @property {Recipe[]} [recipes=[]]
* @property {Module[]} [modules=[]]
*/
export interface InstanceUpdaterOptions {
recipes?: InstanceOptions['initialRecipes'];
modules?: readonly Module[];
}
import {addRecipesToRuntimeAndStorage} from './crdt-recipes';
import {createError} from './errors';
import type {InstanceOptions} from './instance';
import {getInstanceIdHash} from './instance';
import type {Instance, Module} from './recipes';
import type {VersionedObjectResult} from './storage-versioned-objects';
import {getObjectByIdHash, storeVersionedObject} from './storage-versioned-objects';
/**
* Use this module through {@link instance.module:ts.registerRecipes|instance.registerRecipes} for
* your convenience. It provides the `name` and `owner` from the active instance
* and registers any given {@link Recipe|Recipes} with the currently running instance, which
* this function does not do since you could create or update an inactive instance.
* Note that recipes are *not* added to the runtime, since you might be updating an inactive
* Instance object.
* @static
* @async
* @param {InstanceUpdaterOptions} options
* @returns {Promise<ObjectCreation[]>} Returns the result of creating the Instance object and,
* if provided Recipe and Module objects. The Instance object creation result always is in the
* first position and always exists. The {@link Person} object creation result is in second
* place, but it only exists if the Person object had to be created. {@link Recipe} and
* {@link Module} creation results only exist if any recipes or modules were provided.
*/
export async function updateInstance({
recipes = [],
modules = []
}: InstanceUpdaterOptions): Promise<VersionedObjectResult<Instance>> {
const instanceIdHash = getInstanceIdHash();
if (instanceIdHash === undefined) {
throw createError('INU-CRO');
}
const {obj: instanceObj} = await getObjectByIdHash(instanceIdHash, 'Instance');
// Create caches used to remove duplicates, when newly added modules or recipes have already
// been registered previously
const existingRecipeObjHashes = new Set(instanceObj.recipe);
const existingModuleObjHashes = new Set(instanceObj.module);
const recipeResults = await addRecipesToRuntimeAndStorage(recipes);
const moduleCreation = await Promise.all(
modules.map(module => {
// Unlike recipes (just above) which have a lot of rules that go beyond what is checked
// by the regular ONE object to/from microdata conversion code modules are much more
// simple. It is sufficient to test the "type" For the rest the built-in checks
// using the "Module" recipe, applied when storing the object just below,are enough.
if (module.$type$ !== 'Module') {
throw createError('INU-CRO1', {modules});
}
return storeVersionedObject(module);
})
);
instanceObj.recipe.push(
...recipeResults
.filter(result => !existingRecipeObjHashes.has(result.hash))
.map(result => result.hash)
);
instanceObj.module.push(
...moduleCreation
.filter(result => !existingModuleObjHashes.has(result.hash))
.map(result => result.hash)
);
return await storeVersionedObject(instanceObj);
}