diff --git a/spec/value_ref/value_ref_partial_session.spec.ts b/spec/value_ref/value_ref_partial_session.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..c974bb714f2b91b04d6501bd07d467a34063bad9 --- /dev/null +++ b/spec/value_ref/value_ref_partial_session.spec.ts @@ -0,0 +1,110 @@ +import { ExtensionStrategy, ParamValueMode } from "../../src/index"; +import { Nub } from "../../src/nub"; +import { PabChute, PabChuteParams } from "../../src/pab/pab_chute"; +import { PabNombre, PabNombreParams } from "../../src/pab/pab_nombre"; +import { Session } from "../../src/session"; + +function saveAndReload(nubToSave: Nub): Nub { + // partial saving + const options: any = {}; + options[nubToSave.uid] = true; // save only this Nub + const json = Session.getInstance().serialise(options); + // reloading + Session.getInstance().clear(); + Session.getInstance().unserialise(json); + const reloadedNub = Session.getInstance().findNubByUid(nubToSave.uid); + return reloadedNub; +} + +describe("partial session saving/reloading : ", () => { + + it("link to single param", () => { + // init scenario + Session.getInstance().clear(); + const pabChute = new PabChute(new PabChuteParams(3, 0.7, 2.3)); + Session.getInstance().registerNub(pabChute); + const pabNombre = new PabNombre(new PabNombreParams(7, 20, 0.35)); + Session.getInstance().registerNub(pabNombre); + pabChute.calculatedParam = pabChute.prms.Z2; + pabNombre.prms.DHT.defineReference(pabChute, "DH"); + + const loadedPabNombre = saveAndReload(pabNombre); + // check values + expect(loadedPabNombre.getParameter("DHT").valueMode).toEqual(ParamValueMode.SINGLE); + expect(loadedPabNombre.getParameter("DHT").singleValue).toEqual(2.3); + }); + + it("link to minmax param", () => { + // init scenario + Session.getInstance().clear(); + const pabChute = new PabChute(new PabChuteParams(3, 0.7, 2.3)); + Session.getInstance().registerNub(pabChute); + const pabNombre = new PabNombre(new PabNombreParams(7, 20, 0.35)); + Session.getInstance().registerNub(pabNombre); + pabChute.calculatedParam = pabChute.prms.Z2; + pabChute.prms.DH.setValues(2, 2.5, 0.1); + pabChute.prms.DH.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + pabNombre.prms.DHT.defineReference(pabChute, "DH"); + + const loadedPabNombre = saveAndReload(pabNombre); + // check values + expect(loadedPabNombre.getParameter("DHT").valueMode).toEqual(ParamValueMode.MINMAX); + expect(loadedPabNombre.getParameter("DHT").min).toEqual(2); + expect(loadedPabNombre.getParameter("DHT").max).toEqual(2.5); + expect(loadedPabNombre.getParameter("DHT").step).toEqual(0.1); + expect(loadedPabNombre.getParameter("DHT").extensionStrategy).toEqual(ExtensionStrategy.REPEAT_LAST); + }); + + it("link to list param", () => { + // init scenario + Session.getInstance().clear(); + const pabChute = new PabChute(new PabChuteParams(3, 0.7, 2.3)); + Session.getInstance().registerNub(pabChute); + const pabNombre = new PabNombre(new PabNombreParams(7, 20, 0.35)); + Session.getInstance().registerNub(pabNombre); + pabChute.calculatedParam = pabChute.prms.Z2; + pabChute.prms.DH.setValues([ 3.1, 3.2, 3.3 ]); + pabChute.prms.DH.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + pabNombre.prms.DHT.defineReference(pabChute, "DH"); + + const loadedPabNombre = saveAndReload(pabNombre); + // check values + expect(loadedPabNombre.getParameter("DHT").valueMode).toEqual(ParamValueMode.LISTE); + expect(loadedPabNombre.getParameter("DHT").valueList).toEqual([ 3.1, 3.2, 3.3 ]); + expect(loadedPabNombre.getParameter("DHT").extensionStrategy).toEqual(ExtensionStrategy.REPEAT_LAST); + }); + + it("link to calculated param", () => { + // init scenario + Session.getInstance().clear(); + const pabChute = new PabChute(new PabChuteParams(3, 0.6, 2)); + Session.getInstance().registerNub(pabChute); + const pabNombre = new PabNombre(new PabNombreParams(7, 20, 0.35)); + Session.getInstance().registerNub(pabNombre); + pabChute.calculatedParam = pabChute.prms.DH; + pabNombre.prms.DHT.defineReference(pabChute, "DH"); + + const loadedPabNombre = saveAndReload(pabNombre); + // check values + expect(loadedPabNombre.getParameter("DHT").valueMode).toEqual(ParamValueMode.SINGLE); + expect(loadedPabNombre.getParameter("DHT").singleValue).toEqual(2.4); // 3 - 0.6 + }); + + it("link to calculated variated param", () => { + // init scenario + Session.getInstance().clear(); + const pabChute = new PabChute(new PabChuteParams(3, 0.6, 2)); + Session.getInstance().registerNub(pabChute); + const pabNombre = new PabNombre(new PabNombreParams(7, 20, 0.35)); + Session.getInstance().registerNub(pabNombre); + pabChute.calculatedParam = pabChute.prms.DH; + pabChute.prms.Z1.setValues(2.9, 3.1, 0.1); + pabNombre.prms.DHT.defineReference(pabChute, "DH"); + + const loadedPabNombre = saveAndReload(pabNombre); + // check values + expect(loadedPabNombre.getParameter("DHT").valueMode).toEqual(ParamValueMode.LISTE); + expect(loadedPabNombre.getParameter("DHT").valueList).toEqual([ 2.3, 2.4, 2.5 ]); // [ 2.9, 3.0, 3.1 ] - 0.6 + }); + +}); diff --git a/src/nub.ts b/src/nub.ts index e4809e58135d1c0b994b75d0e09dc9420369bfd4..36dbbb0e637ca77a0d4b2b8b7cd31b4e4726b483 100644 --- a/src/nub.ts +++ b/src/nub.ts @@ -861,8 +861,11 @@ export abstract class Nub extends ComputeNode implements IObservable { /** * Returns an object representation of the Nub's current state * @param extra extra key-value pairs, for ex. calculator title in GUI + * @param nubUidsInSession UIDs of Nubs that will be saved in session along with this one; + * useful to determine if linked parameters must be kept as links + * or have their value copied (if target is not in UIDs list) */ - public objectRepresentation(extra?: object) { + public objectRepresentation(extra?: object, nubUidsInSession?: string[]): object { let ret: any = { uid: this.uid, props: Session.invertEnumKeysAndValuesInProperties(this.properties.props), @@ -877,13 +880,13 @@ export abstract class Nub extends ComputeNode implements IObservable { const localParametersIterator = new ParamsEquationArrayIterator([this._prms]); for (const p of localParametersIterator) { if (p.visible) { - ret.parameters.push(p.objectRepresentation()); + ret.parameters.push(p.objectRepresentation(nubUidsInSession)); } } // iterate over children Nubs for (const child of this._children) { - ret.children.push(child.objectRepresentation()); + ret.children.push(child.objectRepresentation(undefined, nubUidsInSession)); } return ret; diff --git a/src/param/param-definition.ts b/src/param/param-definition.ts index fd7362becbbeeb72e68560a5726c596a8fd8710b..53ca53572379548517c645b980e6498af6c64b0a 100644 --- a/src/param/param-definition.ts +++ b/src/param/param-definition.ts @@ -742,8 +742,11 @@ export class ParamDefinition implements INamedIterableValues, IObservable { /** * Returns an object representation of the Parameter's current state + * @param nubUidsInSession UIDs of Nubs that will be saved in session along with this one; + * useful to determine if linked parameters must be kept as links + * or have their value copied (if target is not in UIDs list) */ - public objectRepresentation(): { symbol: string, mode: string } { + public objectRepresentation(nubUidsInSession?: string[]): { symbol: string, mode: string } { // parameter representation const paramRep: any = { symbol: this.symbol, @@ -768,8 +771,31 @@ export class ParamDefinition implements INamedIterableValues, IObservable { break; case ParamValueMode.LINK: - paramRep.targetNub = this._referencedValue.nub.uid; - paramRep.targetParam = this._referencedValue.symbol; + if (nubUidsInSession !== undefined && nubUidsInSession.includes(this._referencedValue.nub.uid)) { + // target Nub is available in session, link won't get broken + paramRep.targetNub = this._referencedValue.nub.uid; + paramRep.targetParam = this._referencedValue.symbol; + } else { + // target Nub will be lost, copy value(s) to keep consistency + const targetPV = this._referencedValue.getParamValues(true); + paramRep.mode = ParamValueMode[targetPV.valueMode]; + switch (targetPV.valueMode) { + case ParamValueMode.SINGLE: + paramRep.value = targetPV.singleValue; + break; + case ParamValueMode.MINMAX: + paramRep.min = targetPV.min; + paramRep.max = targetPV.max; + paramRep.step = targetPV.step; + paramRep.extensionStrategy = targetPV.extensionStrategy; + break; + case ParamValueMode.LISTE: + paramRep.values = targetPV.valueList; + paramRep.extensionStrategy = targetPV.extensionStrategy; + break; + // should never be in LINK or CALC mode (see LinkedValue methods) + } + } break; } return paramRep; diff --git a/src/session.ts b/src/session.ts index 745bc6c54e7e9a1808d361baa1df2c1be5eb1570..f340f7433a394b694ede5a63758bb90926a30fc4 100644 --- a/src/session.ts +++ b/src/session.ts @@ -155,9 +155,9 @@ export class Session { } for (const n of this._nubs) { if (ids.length === 0) { - sess.push(n.objectRepresentation()); + sess.push(n.objectRepresentation(undefined, ids)); } else if (ids.includes(n.uid)) { - sess.push(n.objectRepresentation(options[n.uid])); + sess.push(n.objectRepresentation(options[n.uid], ids)); } } return JSON.stringify({