Skip to content
This repository has been archived by the owner on Dec 28, 2022. It is now read-only.

Commit

Permalink
Implement hydrator managers (aws step functions)
Browse files Browse the repository at this point in the history
Implement dynamic hydrate/extract by detect the types and related fields
Implement state hydrators
  • Loading branch information
alex20465 committed Apr 5, 2018
1 parent 6660acc commit 7883c72
Show file tree
Hide file tree
Showing 15 changed files with 621 additions and 35 deletions.
199 changes: 199 additions & 0 deletions src/hydrators/AWSStepFunctionsHydratorManager.ts
@@ -0,0 +1,199 @@
import * as hydrators from './aws';
import * as states from '../states';
import * as fields from '../fields';
import { AbstractHydratorManager } from './AbstractHydratorManager';
import { StateMachine } from '../StateMachine';
import { AbstractHydrator } from './AbstractHydrator';

interface StateHydratorRegistry {
hydrator: any;
cls: Object;
typeName: string;
}

interface FieldHydratorRegistry {
hydrator: any;
cls: Object;
}

const stateHydratorRegistery: StateHydratorRegistry[] = [
{
hydrator: hydrators.ChoiceStateHydrator,
cls: states.Choice,
typeName: 'Choice',
},
{
hydrator: hydrators.FailStateHydrator,
cls: states.Fail,
typeName: 'Fail',
},
{
hydrator: hydrators.ParallelStateHydrator,
cls: states.Parallel,
typeName: 'Parallel',
},
{
hydrator: hydrators.SucceedStateHydrator,
cls: states.Succeed,
typeName: 'Succeed',
},
{
hydrator: hydrators.TaskStateHydrator,
cls: states.Task,
typeName: 'Task',
},
{
hydrator: hydrators.WaitStateHydrator,
cls: states.Wait,
typeName: 'Wait',
},
]

const fieldHydratorRegistry: FieldHydratorRegistry[] = [
{
cls: fields.CatchField,
hydrator: hydrators.CatchFieldHydrator
},
{
cls: fields.NextField,
hydrator: hydrators.NextFieldHydrator
},
{
cls: fields.PathField,
hydrator: hydrators.PathFieldHydrator
},
{
cls: fields.ResultField,
hydrator: hydrators.ResultFieldHydrator
},
{
cls: fields.ResultPathField,
hydrator: hydrators.ResultPathFieldHydrator
},
{
cls: fields.RetryField,
hydrator: hydrators.RetryFieldHydrator
}
];

export class AWSStepFunctionsHydratorManager extends AbstractHydratorManager {
extractState(state: states.State): any {
const hydrator = this.getStateHydrator(state);
const data: any = hydrator.extract(state);

Object.assign(data, this.extractRelatedFields(state), {
Type: state.constructor.name,
});

if (state.getComment()) {
data['Comment'] = state.getComment();
}

return data;
}
extractField(field: fields.Field<any>): any {
const hydrator = this.getFieldHydrator(field);
return hydrator.extract(field);
}
extractStateMachine(stateMachine: StateMachine): any {
return null;
}

extractRelatedFields(target: any) {
let data = {};
const relatedFields = this.getRelatedConfiguredFields(target);
return relatedFields.reduce((data, field) => {
return Object.assign(data, this.extractField(field));
}, data);
}
hydrateRelatedFields(target: any, data: any): any {
const relatedFields = this.getRelatedConfiguredFields(target, false);
relatedFields.forEach((field) => {
this.hydrateField(field, data);
});
}

hydrateState(name: string, data: any): states.State {
const registry = this.getStateRegistryByTypeName(data['Type']);
const state: states.State = new (<any>registry.cls)(name);
const hydrator: AbstractHydrator<any, this> = new (<any>registry.hydrator)(this);
return hydrator.hydrate(state, data);
}

hydrateField(field: fields.Field<any>, data: any): fields.Field<any> {
const hydrator = this.getFieldHydrator(field);
hydrator.hydrate(field, data);
return field;
}
hydrateStateMachine(data: any): StateMachine {
return null;
}

getRelatedConfiguredFields(target: any, onlyConfigured: boolean = true): fields.Field<any>[] {
const properies = Object.keys(target);

return properies.filter((name: string) => {
const property = target[name];
if (property instanceof fields.Field && (onlyConfigured === false || property.isConfigured())) {
return true;
} else {
return false;
}
})
.map((name) => target[name]);
}

private getFieldHydrator(field: fields.Field<any>): AbstractHydrator<any, any> {
let hydrator: AbstractHydrator<fields.Field<any>, any> | null = null;

fieldHydratorRegistry.every((registry: FieldHydratorRegistry) => {
if (field instanceof (<any>registry.cls)) {
hydrator = new (<any>registry.hydrator)(this);
return false;
} else {
return true;
}
});
if (!hydrator) {
throw new Error(`State hydrator for ${field} not found`);
} else {
return hydrator;
}
}

private getStateHydrator<T>(state: states.State): AbstractHydrator<T, any> {
let hydrator: AbstractHydrator<states.State, any> | null = null;
stateHydratorRegistery.every((registry: StateHydratorRegistry) => {
if (state instanceof (<any>registry.cls)) {
hydrator = new (<any>registry.hydrator)(this);
return false;
} else {
return true;
}
});

if (!hydrator) {
throw new Error(`State hydrator for ${state} not found`);
} else {
return hydrator;
}
}

private getStateRegistryByTypeName(typeName: string): StateHydratorRegistry {
let registry: StateHydratorRegistry | null = null;
stateHydratorRegistery.every((reg: StateHydratorRegistry) => {
if (reg.typeName === typeName) {
registry = reg;
return false;
} else {
return true;
}
});

if (!registry) {
throw new Error(`No state-registry with type ${typeName} found`);
} else {
return registry;
}
}
}
11 changes: 8 additions & 3 deletions src/hydrators/AbstractHydrator.ts
@@ -1,5 +1,10 @@
import { AbstractHydratorManager } from "./AbstractHydratorManager";

export abstract class AbstractHydrator<T, D> {
abstract hydrate(target: T, data: D): T;
abstract extract(target: T): D;
export abstract class AbstractHydrator<T, M> {
protected manager: M;
constructor(manager: M) {
this.manager = manager;
}
abstract hydrate(target: T, data: object): T;
abstract extract(target: T): object;
}
17 changes: 17 additions & 0 deletions src/hydrators/AbstractHydratorManager.ts
@@ -0,0 +1,17 @@
import { State } from "../states/State";
import { Field } from "../fields/Field";
import { StateMachine } from "../StateMachine";



export abstract class AbstractHydratorManager {

abstract extractState(state: State): any;
abstract extractField(field: Field<any>): any;
abstract extractStateMachine(stateMachine: StateMachine): any;

abstract hydrateState(name: string, data: any): State;
abstract hydrateField(field: Field<any>, data: any): Field<any>;
abstract hydrateStateMachine(data: any): StateMachine;

}
10 changes: 0 additions & 10 deletions src/hydrators/HydratorInterface.ts

This file was deleted.

20 changes: 7 additions & 13 deletions src/hydrators/aws/CatchFieldHydrator.ts
Expand Up @@ -3,34 +3,28 @@ import { AbstractHydrator } from '../AbstractHydrator';
import { CatchField } from '../../fields/CatchField';
import { NextFieldHydrator } from './NextFieldHydrator';
import { ResultPathFieldHydrator } from './ResultPathFieldHydrator';
import { AbstractHydratorManager } from '../AbstractHydratorManager';
import { AWSStepFunctionsHydratorManager } from '..';


export class CatchFieldHydrator extends AbstractHydrator<CatchField<any>, Object> {
export class CatchFieldHydrator extends AbstractHydrator<CatchField<any>, AWSStepFunctionsHydratorManager> {
extract(instance: CatchField<any>) {
const nextHydrator = new NextFieldHydrator();
const resultPathHydrator = new ResultPathFieldHydrator();
return {
Catch: instance.getCatchers().map((cacher) => {
Catch: instance.getCatchers().map((catcher) => {
let data = {
ErrorEquals: cacher.getErrors()
ErrorEquals: catcher.getErrors()
};
Object.assign(data, nextHydrator.extract(cacher.next));
if (cacher.resultPath.isConfigured()) {
Object.assign(data, resultPathHydrator.extract(cacher.resultPath));
}
Object.assign(data, this.manager.extractRelatedFields(catcher));
return data;
})
}
}

hydrate(instance: CatchField<any>, data: any) {
const nextHydrator = new NextFieldHydrator();
const resultPathHydrator = new ResultPathFieldHydrator();

data.Catch.forEach((catcherData: any) => {
const catcher = instance.errors(catcherData.ErrorEquals);
nextHydrator.hydrate(catcher.next, catcherData);
resultPathHydrator.hydrate(catcher.resultPath, catcherData);
this.manager.hydrateRelatedFields(catcher, catcherData);
});

return instance;
Expand Down
15 changes: 15 additions & 0 deletions src/hydrators/aws/ChoiceStateHydrator.ts
@@ -0,0 +1,15 @@

import { AbstractHydrator } from '../AbstractHydrator';
import { Choice } from '../../states/Choice';


export class ChoiceStateHydrator extends AbstractHydrator<Choice, Object> {
extract(instance: Choice) {
let data: any = {};
return data;
}

hydrate(instance: Choice, data: any) {
return instance;
}
}
15 changes: 15 additions & 0 deletions src/hydrators/aws/FailStateHydrator.ts
@@ -0,0 +1,15 @@

import { AbstractHydrator } from '../AbstractHydrator';
import { Fail } from '../../states/Fail';


export class FailStateHydrator extends AbstractHydrator<Fail, Object> {
extract(instance: Fail) {
let data: any = { };

return data;
}
hydrate(instance: Fail, data: any) {
return instance;
}
}
35 changes: 35 additions & 0 deletions src/hydrators/aws/ParallelStateHydrator.ts
@@ -0,0 +1,35 @@

import { AbstractHydrator } from '../AbstractHydrator';
import { Parallel } from '../../states/Parallel';
import { State } from '../..';
import { AWSStepFunctionsHydratorManager } from '..';


export class ParallelStateHydrator extends AbstractHydrator<Parallel, AWSStepFunctionsHydratorManager> {
extract(instance: Parallel) {
let data: any = { };
data['Branches'] = instance.getBranches().map((branch) => {
return {
StartAt: branch.getStartAt().getName(),
States: branch.getStates().reduce((data: any, state: State) => {
data[state.getName()] = this.manager.extractState(state);
return data;
}, {})
}
});
return data;
}
hydrate(instance: Parallel, data: any) {

data['Branches'].map((branchData: any) => {
const branch = instance.addBranch();
Object.keys(branchData.States).forEach((stateName) => {
const stateData = branchData.States[stateName];
const state = this.manager.hydrateState(stateName, stateData);
branch.addState(state);
});
});

return instance;
}
}
14 changes: 14 additions & 0 deletions src/hydrators/aws/SucceedStateHydrator.ts
@@ -0,0 +1,14 @@

import { AbstractHydrator } from '../AbstractHydrator';
import { Succeed } from '../../states/Succeed';


export class SucceedStateHydrator extends AbstractHydrator<Succeed, Object> {
extract(instance: Succeed) {
let data: any = {};
return data;
}
hydrate(instance: Succeed, data: any) {
return instance;
}
}

0 comments on commit 7883c72

Please sign in to comment.