Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "stated-js",
"version": "0.1.54",
"version": "0.1.55",
"license": "Apache-2.0",
"description": "JSONata embedded in JSON",
"main": "./dist/src/index.js",
Expand Down
11 changes: 11 additions & 0 deletions src/ParallelExecutionPlanDefault.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ export class ParallelExecutionPlanDefault implements ParallelExecutionPlan {
didUpdate: boolean = false;
restore?: boolean = false;
circular?:boolean;
tp:TemplateProcessor

constructor(tp: TemplateProcessor, parallelSteps: ParallelExecutionPlan[] = [], vals?: Partial<ParallelExecutionPlan> | null) {
this.tp = tp;
this.output = tp.output;
this.parallel = parallelSteps;
// Copy properties from `vals` into `this`, while preserving existing defaults
Expand Down Expand Up @@ -91,6 +93,15 @@ export class ParallelExecutionPlanDefault implements ParallelExecutionPlan {
return Array.from(nodeSet);
}

reinitialize(): void {
const walkTree = (node: ParallelExecutionPlan) => {
node.completed = false;
node.output = this.tp.output;
node.parallel.forEach(child => walkTree(child));
};
walkTree(this);
}

/**
* make a shell of an ExecutionPlan that exist just to carry the jsonPtr, with op set to "noop"
*/
Expand Down
11 changes: 10 additions & 1 deletion src/ParallelPlanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,16 @@ export class ParallelPlanner implements Planner{

//remember, initialization plan is not always for "/" because we can be initializing an imported template
getInitializationPlan(jsonPtr:JsonPointerString): ExecutionPlan {
return this.makeInitializationPlan({jsonPtr});
const cached = this.planCache.get(jsonPtr);
let initPlan: ExecutionPlan;
if(cached) {
[initPlan] = cached;
(initPlan as ParallelExecutionPlanDefault).reinitialize(); //allow this plan to be re-run
} else {
initPlan = this.makeInitializationPlan({jsonPtr});
this.planCache.set("/", [initPlan, ['/']]);
}
return initPlan;
}


Expand Down
14 changes: 14 additions & 0 deletions src/TemplateProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ export default class TemplateProcessor {
public static NOOP = Symbol('NOOP');

private isExecutingPlan: boolean = false;
private providedContext: any; //the context provided by the owner of the template before we merge it into internal context

/**
* Loads a template and initializes a new template processor instance.
Expand Down Expand Up @@ -410,6 +411,7 @@ export default class TemplateProcessor {
}

constructor(template={}, context = {}, options={}) {
this.providedContext = context;
this.timerManager = new TimerManager(this); //prevent leaks from $setTimeout and $setInterval
this.generatorManager = new GeneratorManager(this);
this.uniqueId = crypto.randomUUID();
Expand Down Expand Up @@ -472,6 +474,18 @@ export default class TemplateProcessor {
}


public async reInitializeContext(userProvidedContext:object){
this.output = JSON.parse(JSON.stringify(this.input)); //initial output is input template
for(const key in this.providedContext){ //at this point, providedContext is the OLD previously provided context
delete this.context[key]; //remove the previous user-provided context to clear out 'old' state
}
Object.assign(this.context, userProvidedContext); //spread the *new* context onto the existing context object
this.providedContext = userProvidedContext; //update providedContext
const plan:ExecutionPlan = this.planner.getInitializationPlan("/"); //will get cached initialization plan
this.executionQueue.push(plan);
await this.drainExecutionQueue(false);
}

/**
* Template processor initialize can be called from 2 major use cases
* 1. initialize a new importedSubtemplate processor importedSubtemplate
Expand Down
38 changes: 36 additions & 2 deletions src/test/TemplateProcessor.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3442,7 +3442,7 @@ test("forked homeworlds", async () => {
// Ensure the array is exactly the same length as the expected array
expect(homeworlds).toHaveLength(expectedHomeworlds.length);
expect(savedForkIds.size).toEqual(6); //5 names + 1 initialization of null name
},5000);
},10000);


test("performance test with 100 data injections", async () => {
Expand Down Expand Up @@ -3699,7 +3699,7 @@ test("repetitive snapshots stopped in random execution time", async () => {
expect(savedState.plans.length).toBeLessThanOrEqual(5);

}
}, 60000);
}, 120000);

test("output-only snapshot example", async () => {
const __filename = fileURLToPath(import.meta.url);
Expand Down Expand Up @@ -5780,6 +5780,40 @@ test("change with defaultVal", async () => {
}
});

test("reInitialize", async () => {
let template = {
a: 42,
b: "${a}",
c: "${$contextMsg & $string(b)}"
};
let tp = new TemplateProcessor(template, {contextMsg: "the answer is: ", random: "foo"});
try {
const initStart = process.hrtime.bigint();
await tp.initialize();
const initEnd = process.hrtime.bigint();
const initElapsedNs = initEnd - initStart;
console.log(`initialize took ${initElapsedNs} nanoseconds (${Number(initElapsedNs) / 1_000_000} ms)`);
expect(tp.output.c).toBe("the answer is: 42");
let totalNs = 0n;
const iterations = 100;
for (let i = 0; i < iterations; i++) {
const start = process.hrtime.bigint();
await tp.reInitializeContext( {contextMsg: "the answer is STILL: ", nonRandom: "bar"});
const end = process.hrtime.bigint();
totalNs += (end - start);
}
const avgNs = totalNs / BigInt(iterations);
console.log(`reInitializeContext avg over ${iterations} iterations: ${avgNs} nanoseconds (${Number(avgNs) / 1_000_000} ms)`);
expect(tp.output).toStrictEqual({
"a": 42,
"b": 42,
"c": "the answer is STILL: 42"
});
}finally{
await tp.close();
}
});




Expand Down