From 1711ac3fa207805e0e7f96d1c5702135685d3409 Mon Sep 17 00:00:00 2001 From: Sean Warren Date: Thu, 14 Sep 2023 17:43:01 -0700 Subject: [PATCH] feat: preliminary types added to units and unit config builders --- src/units/{assertion.js => assertion.ts} | 8 +- src/units/{assignment.js => assignment.ts} | 8 +- src/units/{base.js => base.ts} | 21 ++- ...ilder.js => AssertionUnitConfigBuilder.ts} | 19 ++- .../builders/AssignmentUnitConfigBuilder.js | 36 ----- .../builders/AssignmentUnitConfigBuilder.ts | 44 ++++++ ...ilder.js => ExecutionUnitConfigBuilder.ts} | 33 +++-- ...onfigBuilder.js => IOUnitConfigBuilder.ts} | 28 ++-- src/units/builders/UnitConfigBuilder.js | 83 ----------- src/units/builders/UnitConfigBuilder.ts | 49 ++++++ src/units/builders/{index.js => index.ts} | 0 src/units/{condition.js => condition.ts} | 14 +- src/units/{execution.js => execution.ts} | 49 ++++-- src/units/factory.js | 35 ----- src/units/factory.ts | 45 ++++++ src/units/{io.js => io.ts} | 50 ++++--- src/units/{map.js => map.ts} | 7 +- src/units/{processing.js => processing.ts} | 11 +- src/units/reduce.js | 17 --- src/units/reduce.ts | 18 +++ src/units/{subworkflow.js => subworkflow.ts} | 5 +- src/units/types.ts | 140 ++++++++++++++++++ 22 files changed, 452 insertions(+), 268 deletions(-) rename src/units/{assertion.js => assertion.ts} (71%) rename src/units/{assignment.js => assignment.ts} (72%) rename src/units/{base.js => base.ts} (77%) rename src/units/builders/{AssertionUnitConfigBuilder.js => AssertionUnitConfigBuilder.ts} (54%) delete mode 100644 src/units/builders/AssignmentUnitConfigBuilder.js create mode 100644 src/units/builders/AssignmentUnitConfigBuilder.ts rename src/units/builders/{ExecutionUnitConfigBuilder.js => ExecutionUnitConfigBuilder.ts} (52%) rename src/units/builders/{IOUnitConfigBuilder.js => IOUnitConfigBuilder.ts} (59%) delete mode 100644 src/units/builders/UnitConfigBuilder.js create mode 100644 src/units/builders/UnitConfigBuilder.ts rename src/units/builders/{index.js => index.ts} (100%) rename src/units/{condition.js => condition.ts} (77%) rename src/units/{execution.js => execution.ts} (73%) delete mode 100644 src/units/factory.js create mode 100644 src/units/factory.ts rename src/units/{io.js => io.ts} (79%) rename src/units/{map.js => map.ts} (76%) rename src/units/{processing.js => processing.ts} (70%) delete mode 100644 src/units/reduce.js create mode 100644 src/units/reduce.ts rename src/units/{subworkflow.js => subworkflow.ts} (64%) create mode 100644 src/units/types.ts diff --git a/src/units/assertion.js b/src/units/assertion.ts similarity index 71% rename from src/units/assertion.js rename to src/units/assertion.ts index 13dc728..27da939 100644 --- a/src/units/assertion.js +++ b/src/units/assertion.ts @@ -1,8 +1,8 @@ -import { UNIT_TYPES } from "../enums"; import { BaseUnit } from "./base"; +import { AssertionUnitConfig, UNIT_TYPES } from "./types"; -export class AssertionUnit extends BaseUnit { - constructor(config) { +export class AssertionUnit extends BaseUnit { + constructor(config: AssertionUnitConfig) { super({ ...AssertionUnit.getAssertionConfig(), ...config }); } @@ -23,7 +23,7 @@ export class AssertionUnit extends BaseUnit { return this.prop("errorMessage"); } - getHashObject() { + getHashObject(): Partial { return { statement: this.statement, errorMessage: this.errorMessage }; } } diff --git a/src/units/assignment.js b/src/units/assignment.ts similarity index 72% rename from src/units/assignment.js rename to src/units/assignment.ts index ed74bd8..3f6e063 100644 --- a/src/units/assignment.js +++ b/src/units/assignment.ts @@ -1,8 +1,8 @@ -import { UNIT_TYPES } from "../enums"; import { BaseUnit } from "./base"; +import { AssignmentUnitConfig, UNIT_TYPES } from "./types"; -export class AssignmentUnit extends BaseUnit { - constructor(config) { +export class AssignmentUnit extends BaseUnit { + constructor(config: AssignmentUnitConfig) { super({ ...AssignmentUnit.getAssignmentConfig(), ...config }); } @@ -28,7 +28,7 @@ export class AssignmentUnit extends BaseUnit { return this.prop("input"); } - getHashObject() { + getHashObject(): Partial { return { input: this.input, operand: this.operand, value: this.value }; } } diff --git a/src/units/base.js b/src/units/base.ts similarity index 77% rename from src/units/base.js rename to src/units/base.ts index e2b30ad..ee17792 100644 --- a/src/units/base.js +++ b/src/units/base.ts @@ -6,13 +6,19 @@ import { getUUID } from "@exabyte-io/code.js/dist/utils"; import lodash from "lodash"; import { mix } from "mixwith"; -import { UNIT_STATUSES } from "../enums"; +import { UNIT_STATUSES, UnitConfig } from "./types"; // eslint-disable-next-line max-len -export class BaseUnit extends mix( +export class BaseUnit extends mix( NamedDefaultableRepetitionRuntimeItemsImportantSettingsContextAndRenderHashedInMemoryEntity, ).with(TaggableMixin) { - constructor(config) { + // TODO investigate why this is needed here instead of inherited from the mixin + public prop: (key: K, defaultValue?: T[K]) => T[K]; + public setProp: (key: K, value: T[K]) => void; + private repetition: number; + private hashObjectFromRuntimeItems: Partial; + + constructor(config: UnitConfig) { super({ ...config, status: config.status || UNIT_STATUSES.idle, @@ -22,7 +28,7 @@ export class BaseUnit extends mix( }); } - static generateFlowChartId() { + static generateFlowChartId(): string { return getUUID(); } @@ -54,11 +60,11 @@ export class BaseUnit extends mix( this.setProp("status", s); } - get lastStatusUpdate() { + get lastStatusUpdate(): UnitConfig["statusTrack"][0] { const statusTrack = this.prop("statusTrack", []).filter( (s) => (s.repetition || 0) === this.repetition, ); - const sortedStatusTrack = lodash.sortBy(statusTrack || [], (x) => x.trackedAt); + const sortedStatusTrack = lodash.sortBy(statusTrack || [], (x) => x.trackedAt); // TODO: check if this is the right way to sort with TS return sortedStatusTrack[sortedStatusTrack.length - 1]; } @@ -70,7 +76,7 @@ export class BaseUnit extends mix( return this.prop("isDraft", false); } - getHashObject() { + getHashObject(): Partial { return { ...this.hashObjectFromRuntimeItems, type: this.type }; } @@ -91,4 +97,5 @@ export class BaseUnit extends mix( }; return super.clone(flowchartIDOverrideConfigAsExtraContext); } + } diff --git a/src/units/builders/AssertionUnitConfigBuilder.js b/src/units/builders/AssertionUnitConfigBuilder.ts similarity index 54% rename from src/units/builders/AssertionUnitConfigBuilder.js rename to src/units/builders/AssertionUnitConfigBuilder.ts index bb0e6f4..1e192ee 100644 --- a/src/units/builders/AssertionUnitConfigBuilder.js +++ b/src/units/builders/AssertionUnitConfigBuilder.ts @@ -1,24 +1,31 @@ -import { UNIT_TYPES } from "../../enums"; +import { AssertionUnitConfig, UNIT_TYPES } from "../types"; import { UnitConfigBuilder } from "./UnitConfigBuilder"; -export class AssertionUnitConfigBuilder extends UnitConfigBuilder { - constructor(name, statement, errorMessage) { +export class AssertionUnitConfigBuilder extends UnitConfigBuilder { + private _statement: string; + private _errorMessage: string; + + constructor( + name: AssertionUnitConfig["name"], + statement: AssertionUnitConfig["statement"], + errorMessage: AssertionUnitConfig["errorMessage"] + ){ super({ name, type: UNIT_TYPES.assertion }); this._statement = statement; this._errorMessage = errorMessage; } - statement(str) { + statement(str: string): this { this._statement = str; return this; } - errorMessage(str) { + errorMessage(str: string): this { this._errorMessage = str; return this; } - build() { + build(): AssertionUnitConfig { return { ...super.build(), statement: this._statement, diff --git a/src/units/builders/AssignmentUnitConfigBuilder.js b/src/units/builders/AssignmentUnitConfigBuilder.js deleted file mode 100644 index c4f5646..0000000 --- a/src/units/builders/AssignmentUnitConfigBuilder.js +++ /dev/null @@ -1,36 +0,0 @@ -import { UNIT_TYPES } from "../../enums"; -import { UnitConfigBuilder } from "./UnitConfigBuilder"; - -export class AssignmentUnitConfigBuilder extends UnitConfigBuilder { - constructor(name, variableName, variableValue, input = [], results = []) { - super({ name, type: UNIT_TYPES.assignment }); - this._variableName = variableName; - this._variableValue = variableValue; - this._input = input; - this._results = results; - } - - input(arr) { - this._input = arr; - return this; - } - - variableName(str) { - this._variableName = str; - return this; - } - - variableValue(str) { - this._variableValue = str; - return this; - } - - build() { - return { - ...super.build(), - input: this._input, - operand: this._variableName, - value: this._variableValue, - }; - } -} diff --git a/src/units/builders/AssignmentUnitConfigBuilder.ts b/src/units/builders/AssignmentUnitConfigBuilder.ts new file mode 100644 index 0000000..fd5fd47 --- /dev/null +++ b/src/units/builders/AssignmentUnitConfigBuilder.ts @@ -0,0 +1,44 @@ +import { AssignmentUnitConfig, UNIT_TYPES, UnitInput } from "../types"; +import { UnitConfigBuilder } from "./UnitConfigBuilder"; + +export class AssignmentUnitConfigBuilder extends UnitConfigBuilder { + private _operand: string; + private _value: string; + private _input: UnitInput; + + constructor( + name: AssignmentUnitConfig["name"], + operand: AssignmentUnitConfig["operand"], + value: AssignmentUnitConfig["value"], + input: AssignmentUnitConfig["input"] = [] + ) { + super({ name, type: UNIT_TYPES.assignment }); + this._operand = operand; + this._value = value; + this._input = input; + } + + input(arr: UnitInput): this { + this._input = arr; + return this; + } + + variableName(str: string): this { + this._operand = str; + return this; + } + + variableValue(str: string): this { + this._value = str; + return this; + } + + build() { + return { + ...super.build(), + input: this._input, + operand: this._operand, + value: this._value, + }; + } +} diff --git a/src/units/builders/ExecutionUnitConfigBuilder.js b/src/units/builders/ExecutionUnitConfigBuilder.ts similarity index 52% rename from src/units/builders/ExecutionUnitConfigBuilder.js rename to src/units/builders/ExecutionUnitConfigBuilder.ts index dfb1e04..8bfd935 100644 --- a/src/units/builders/ExecutionUnitConfigBuilder.js +++ b/src/units/builders/ExecutionUnitConfigBuilder.ts @@ -1,16 +1,28 @@ import { Application, Executable, Flavor } from "@exabyte-io/ade.js"; - -import { UNIT_TYPES } from "../../enums"; import { UnitConfigBuilder } from "./UnitConfigBuilder"; +import { ExecutionUnitConfig, UNIT_TYPES } from "../types"; -export class ExecutionUnitConfigBuilder extends UnitConfigBuilder { - static Application = Application; +export class ExecutionUnitConfigBuilder extends UnitConfigBuilder { - static Executable = Executable; + private flavor: ExecutionUnitConfig["flavor"]; + private executable: ExecutionUnitConfig["executable"]; + private application: ExecutionUnitConfig["application"]; + private _results: ExecutionUnitConfig["flavor"]["results"]; + private _monitors: ExecutionUnitConfig["flavor"]["monitors"]; + private _preProcessors: ExecutionUnitConfig["flavor"]["preProcessors"]; + private _postProcessors: ExecutionUnitConfig["flavor"]["postProcessors"]; + static Application = Application; + static Executable = Executable; static Flavor = Flavor; - constructor(name, application, execName, flavorName, flowchartId) { + constructor( + name : ExecutionUnitConfig["name"], + application: ExecutionUnitConfig["application"], + execName: ExecutionUnitConfig["executable"]["name"], + flavorName: ExecutionUnitConfig["flavor"]["name"], + flowchartId: ExecutionUnitConfig["flowchartId"] + ) { super({ name, type: UNIT_TYPES.execution, flowchartId }); try { @@ -27,13 +39,16 @@ export class ExecutionUnitConfigBuilder extends UnitConfigBuilder { this._postProcessors = this.flavor.postProcessors; } - initialize(application, execName, flavorName) { + initialize( + application: ExecutionUnitConfig["application"], + execName: ExecutionUnitConfig["executable"]["name"], + flavorName: ExecutionUnitConfig["flavor"]["name"]) { this.application = application; - this.executable = this.constructor.Executable.create({ + this.executable = ExecutionUnitConfigBuilder.Executable.create({ name: execName, application: this.application, }); - this.flavor = this.constructor.Flavor.create({ + this.flavor = ExecutionUnitConfigBuilder.Flavor.create({ name: flavorName, executable: this.executable, }); diff --git a/src/units/builders/IOUnitConfigBuilder.js b/src/units/builders/IOUnitConfigBuilder.ts similarity index 59% rename from src/units/builders/IOUnitConfigBuilder.js rename to src/units/builders/IOUnitConfigBuilder.ts index 4a5fc3e..4d25787 100644 --- a/src/units/builders/IOUnitConfigBuilder.js +++ b/src/units/builders/IOUnitConfigBuilder.ts @@ -1,8 +1,18 @@ -import { UNIT_TYPES } from "../../enums"; +import { IOUnitConfig, IOUnitSubTypes, UNIT_TYPES } from "../types"; import { UnitConfigBuilder } from "./UnitConfigBuilder"; -export class IOUnitConfigBuilder extends UnitConfigBuilder { - constructor(name, endpointName, endpointOptions) { +export class IOUnitConfigBuilder extends UnitConfigBuilder { + private _endpointName: string; + private _endpointOptions: string; + private _variableName: string; + private _subtype: IOUnitSubTypes; + private _source: string; + + constructor( + name: IOUnitConfig["name"], + endpointName: string, + endpointOptions: string, + ) { super({ name, type: UNIT_TYPES.io }); this._endpointName = endpointName; this._endpointOptions = endpointOptions; @@ -11,32 +21,32 @@ export class IOUnitConfigBuilder extends UnitConfigBuilder { this._source = "api"; } - endpointName(str) { + endpointName(str: string): this { this._endpointName = str; return this; } - endpointOptions(options) { + endpointOptions(options: string): this { this._endpointOptions = options; return this; } - variableName(str) { + variableName(str: string): this { this._variableName = str; return this; } - subtype(str) { + subtype(str: IOUnitSubTypes): this { this._subtype = str; return this; } - source(str) { + source(str: string): this { this._source = str; return this; } - build() { + build(): IOUnitConfig { return { ...super.build(), subtype: this._subtype, diff --git a/src/units/builders/UnitConfigBuilder.js b/src/units/builders/UnitConfigBuilder.js deleted file mode 100644 index adedc29..0000000 --- a/src/units/builders/UnitConfigBuilder.js +++ /dev/null @@ -1,83 +0,0 @@ -import { getUUID } from "@exabyte-io/code.js/dist/utils"; -import _ from "underscore"; - -export class UnitConfigBuilder { - constructor({ name, type, flowchartId }) { - this.type = type; - this._name = name; - this._head = false; - this._results = []; - this._monitors = []; - this._preProcessors = []; - this._postProcessors = []; - this._flowchartId = flowchartId || this.constructor.generateFlowChartId(); - } - - name(str) { - this._name = str; - return this; - } - - head(bool) { - this._head = bool; - return this; - } - - static generateFlowChartId() { - return getUUID(); - } - - flowchartId(flowchartId) { - this._flowchartId = flowchartId; - return this; - } - - static _stringArrayToNamedObject(array) { - return array.map((name) => (_.isString(name) ? { name } : name)); - } - - addPreProcessors(preProcessorNames) { - this._preProcessors = _.union( - this.constructor._stringArrayToNamedObject(preProcessorNames), - this._preProcessors, - ); - return this; - } - - addPostProcessors(postProcessorNames) { - this._postProcessors = _.union( - this.constructor._stringArrayToNamedObject(postProcessorNames), - this._postProcessors, - ); - return this; - } - - addResults(resultNames) { - this._results = _.union( - this.constructor._stringArrayToNamedObject(resultNames), - this._results, - ); - return this; - } - - addMonitors(monitorNames) { - this._monitors = _.union( - this.constructor._stringArrayToNamedObject(monitorNames), - this._monitors, - ); - return this; - } - - build() { - return { - type: this.type, - name: this._name, - head: this._head, - results: this._results, - monitors: this._monitors, - flowchartId: this._flowchartId, - preProcessors: this._preProcessors, - postProcessors: this._postProcessors, - }; - } -} diff --git a/src/units/builders/UnitConfigBuilder.ts b/src/units/builders/UnitConfigBuilder.ts new file mode 100644 index 0000000..d184344 --- /dev/null +++ b/src/units/builders/UnitConfigBuilder.ts @@ -0,0 +1,49 @@ +import { getUUID } from "@exabyte-io/code.js/dist/utils"; +import _ from "underscore"; +import { NamedEntity, UNIT_TYPES, UnitConfig } from "../types"; + +export class UnitConfigBuilder { + private _name: string; + private _flowchartId: string; + private _type: UNIT_TYPES; + private _head: boolean; + + constructor({ name, type, flowchartId }: Pick & Partial>) { + this._type = type; + this._name = name; + this._head = false; + this._flowchartId = flowchartId || UnitConfigBuilder.generateFlowChartId(); + } + + static generateFlowChartId(): string { + return getUUID(); + } + + static _stringArrayToNamedObject(array: string[]): NamedEntity[] { + return array.map((name) => ({ name })); + } + + name(str: string): this { + this._name = str; + return this; + } + + head(bool: boolean): this { + this._head = bool; + return this; + } + + flowchartId(flowchartId: string): this { + this._flowchartId = flowchartId; + return this; + } + + build(): T { + return { + type: this._type, + name: this._name, + head: this._head, + flowchartId: this._flowchartId, + } as T; + } +} diff --git a/src/units/builders/index.js b/src/units/builders/index.ts similarity index 100% rename from src/units/builders/index.js rename to src/units/builders/index.ts diff --git a/src/units/condition.js b/src/units/condition.ts similarity index 77% rename from src/units/condition.js rename to src/units/condition.ts index c4254ad..45390f5 100644 --- a/src/units/condition.js +++ b/src/units/condition.ts @@ -1,8 +1,8 @@ -import { UNIT_TYPES } from "../enums"; import { BaseUnit } from "./base"; +import { ConditionUnitConfig, UNIT_TYPES } from "./types"; -export class ConditionUnit extends BaseUnit { - constructor(config) { +export class ConditionUnit extends BaseUnit { + constructor(config: ConditionUnitConfig) { super({ ...ConditionUnit.getConditionConfig(), ...config }); } @@ -21,15 +21,11 @@ export class ConditionUnit extends BaseUnit { }; } - get input() { - return this.prop("input"); - } - get then() { return this.prop("then"); } - get else() { + get else(){ return this.prop("else"); } @@ -41,7 +37,7 @@ export class ConditionUnit extends BaseUnit { return this.prop("maxOccurrences"); } - getHashObject() { + getHashObject(): Partial { return { statement: this.statement, maxOccurrences: this.maxOccurrences }; } } diff --git a/src/units/execution.js b/src/units/execution.ts similarity index 73% rename from src/units/execution.js rename to src/units/execution.ts index 91398e2..f10595a 100644 --- a/src/units/execution.js +++ b/src/units/execution.ts @@ -5,12 +5,27 @@ import { mix } from "mixwith"; import _ from "underscore"; import { BaseUnit } from "./base"; +import { ApplicationType, ExecutableType, ExecutionUnitConfig, FlavorType, TemplateType } from "./types"; + +export class ExecutionUnit extends mix(BaseUnit).with(HashedInputArrayMixin) { + + public prop: (key: K, defaultValue?: ExecutionUnitConfig[K]) => ExecutionUnitConfig[K]; // TODO: should be coming from mixins + public setProp: (key: K, value: ExecutionUnitConfig[K]) => void; // TODO: should be coming from mixins + private _application: ApplicationType; + private _executable: ExecutableType; + private _flavor: FlavorType; + private _templates: TemplateType[]; + private context: any; //TODO: should be coming from mixins + private setRuntimeItemsToDefaultValues: () => void; // TODO: should be coming from mixins + private getCombinedContext: () => any; // TODO: should be coming from mixins + private updateContext: (context: any) => void; // TODO: should be coming from mixins + private _renderingContext: any; // TODO: should be coming from mixins + private updatePersistentContext: (context: any) => void; // TODO: should be coming from mixins + private hashFromArrayInputContent: string; // TODO: should be coming from mixins + private clean: (obj: T) => T; // TODO: should be coming from mixins -export class ExecutionUnit extends mix(BaseUnit).with(HashedInputArrayMixin) { static Application = Application; - static Template = Template; - // keys to be omitted during toJSON static omitKeys = [ "job", @@ -23,7 +38,7 @@ export class ExecutionUnit extends mix(BaseUnit).with(HashedInputArrayMixin) { ]; _initApplication(config) { - this._application = this.constructor.Application.create(config.application); + this._application = ExecutionUnit.Application.create(config.application); this._executable = this._application.getExecutableByConfig(config.executable); this._flavor = this._executable.getFlavorByConfig(config.flavor); this._templates = this._flavor ? this._flavor.inputAsTemplates : []; @@ -55,10 +70,10 @@ export class ExecutionUnit extends mix(BaseUnit).with(HashedInputArrayMixin) { } get templatesFromInput() { - return this.input.map((i) => new this.constructor.Template(i)); + return this.input.map((i) => new ExecutionUnit.Template(i)); } - setApplication(application, omitSettingExecutable = false) { + setApplication(application: Application, omitSettingExecutable = false): void { this._application = application; this.setProp("application", application.toJSON()); if (!omitSettingExecutable) { @@ -66,25 +81,27 @@ export class ExecutionUnit extends mix(BaseUnit).with(HashedInputArrayMixin) { } } - setExecutable(executable) { + // TODO: use isolated Executable type + setExecutable(executable: ExecutableType): void { this._executable = executable; this.setProp("executable", executable.toJSON()); this.setFlavor(this.executable.defaultFlavor); } - setFlavor(flavor) { + // TODO: use isolated Flavor type + setFlavor(flavor: FlavorType): void { this._flavor = flavor; this.setRuntimeItemsToDefaultValues(); this.setProp("flavor", flavor.toJSON()); this.setTemplates(this.flavor.inputAsTemplates); } - setTemplates(templates) { + setTemplates(templates: Template[]): void { this._templates = templates; this.render(this.context, true); } - setInput(input) { + setInput(input: ExecutionUnitConfig["input"]): void { this.setProp("input", input); } @@ -113,7 +130,7 @@ export class ExecutionUnit extends mix(BaseUnit).with(HashedInputArrayMixin) { } get allContextProviders() { - const list = []; + const list: any = []; // pass context below to keep UI changes this.templates.forEach((i) => list.push(...i.getContextProvidersAsClassInstances(this.getCombinedContext())), @@ -143,12 +160,12 @@ export class ExecutionUnit extends mix(BaseUnit).with(HashedInputArrayMixin) { // context to persist in toJSON get storedContext() { - return _.omit(this.context, ...this.constructor.omitKeys); + return _.omit(this.context, ...ExecutionUnit.omitKeys); } // context to show to users with some extra keys omitted get visibleRenderingContext() { - return _.omit(this.renderingContext, ...this.constructor.omitKeys); + return _.omit(this.renderingContext, ...ExecutionUnit.omitKeys); } static getSubworkflowContext(context) { @@ -162,7 +179,7 @@ export class ExecutionUnit extends mix(BaseUnit).with(HashedInputArrayMixin) { * @param fromTemplates */ render(context, fromTemplates = false) { - const newInput = []; + const newInput: any = []; const newPersistentContext = {}; const newRenderingContext = {}; const renderingContext = { ...this.context, ...context }; @@ -189,7 +206,7 @@ export class ExecutionUnit extends mix(BaseUnit).with(HashedInputArrayMixin) { * @summary Calculates hash on unit-specific fields. * The meaningful fields of processing unit are operation, flavor and input at the moment. */ - getHashObject() { + getHashObject(): Partial { return { ...super.getHashObject(), application: removeTimestampableKeysFromConfig(this.application.toJSON()), @@ -199,7 +216,7 @@ export class ExecutionUnit extends mix(BaseUnit).with(HashedInputArrayMixin) { }; } - toJSON() { + toJSON(): ExecutionUnitConfig { return this.clean({ ...super.toJSON(), executable: this.executable.toJSON(), diff --git a/src/units/factory.js b/src/units/factory.js deleted file mode 100644 index 04abb7f..0000000 --- a/src/units/factory.js +++ /dev/null @@ -1,35 +0,0 @@ -import { UNIT_TYPES } from "../enums"; -import { AssertionUnit } from "./assertion"; -import { AssignmentUnit } from "./assignment"; -import { BaseUnit } from "./base"; -import { ConditionUnit } from "./condition"; -import { ExecutionUnit } from "./execution"; -import { IOUnit } from "./io"; -import { MapUnit } from "./map"; -import { ProcessingUnit } from "./processing"; -import { SubworkflowUnit } from "./subworkflow"; - -export class UnitFactory { - static create(config) { - switch (config.type) { - case UNIT_TYPES.execution: - return new ExecutionUnit(config); - case UNIT_TYPES.assignment: - return new AssignmentUnit(config); - case UNIT_TYPES.condition: - return new ConditionUnit(config); - case UNIT_TYPES.io: - return new IOUnit(config); - case UNIT_TYPES.processing: - return new ProcessingUnit(config); - case UNIT_TYPES.map: - return new MapUnit(config); - case UNIT_TYPES.subworkflow: - return new SubworkflowUnit(config); - case UNIT_TYPES.assertion: - return new AssertionUnit(config); - default: - return new BaseUnit(config); - } - } -} diff --git a/src/units/factory.ts b/src/units/factory.ts new file mode 100644 index 0000000..c923759 --- /dev/null +++ b/src/units/factory.ts @@ -0,0 +1,45 @@ +import { AssertionUnit } from "./assertion"; +import { AssignmentUnit } from "./assignment"; +import { BaseUnit } from "./base"; +import { ConditionUnit } from "./condition"; +import { ExecutionUnit } from "./execution"; +import { IOUnit } from "./io"; +import { MapUnit } from "./map"; +import { ProcessingUnit } from "./processing"; +import { SubworkflowUnit } from "./subworkflow"; +import { + AssertionUnitConfig, + AssignmentUnitConfig, + ConditionUnitConfig, + IOUnitConfig, + MapUnitConfig, + ProcessingUnitConfig, + SubworkflowUnitConfig, + UNIT_TYPES, + UnitConfig +} from "./types"; + +export class UnitFactory { + static create(config: UnitConfig) { + switch (config.type) { + case UNIT_TYPES.execution: + return new ExecutionUnit(); + case UNIT_TYPES.assignment: + return new AssignmentUnit(config as AssignmentUnitConfig); + case UNIT_TYPES.condition: + return new ConditionUnit(config as ConditionUnitConfig); + case UNIT_TYPES.io: + return new IOUnit(config as IOUnitConfig); + case UNIT_TYPES.processing: + return new ProcessingUnit(config as ProcessingUnitConfig); + case UNIT_TYPES.map: + return new MapUnit(config as MapUnitConfig); + case UNIT_TYPES.subworkflow: + return new SubworkflowUnit(config as SubworkflowUnitConfig); + case UNIT_TYPES.assertion: + return new AssertionUnit(config as AssertionUnitConfig); + default: + return new BaseUnit(config as UnitConfig); + } + } +} diff --git a/src/units/io.js b/src/units/io.ts similarity index 79% rename from src/units/io.js rename to src/units/io.ts index e6de1eb..e71732d 100644 --- a/src/units/io.js +++ b/src/units/io.ts @@ -2,18 +2,21 @@ import lodash from "lodash"; import { IO_ID_COLUMN, UNIT_TYPES } from "../enums"; import { BaseUnit } from "./base"; +import { IOUnitConfig } from "./types"; -export class IOUnit extends BaseUnit { - /** - * IO Unit Builder for Object Storage sources. - * - * @param {Object} config - config object with other parameters: - * @param {String} config.name - the name of the unit this builder is creating - * @param {String} config.subtype - "input", "output", or "dataframe" - * @param {Object} config.input - input containing information on the file to download - * @param {Boolean} config.enableRender - Whether to use Jinja templating at runtime - */ - constructor(config) { +export class IOUnit extends BaseUnit { + private _materials: any[]; // TODO: define Material type + private _defaultTargets: string[]; + private _features: string[]; + private _targets: string[]; + private _ids: string[]; + private _jobId: string | null; + public dataGridValues: any[]; + private clean: (obj: T) => T; // TODO: should be coming from mixins + // public toJSON: () => T; + + + constructor(config: IOUnitConfig) { super({ ...IOUnit.getIOConfig(), ...config }); this.initialize(config); } @@ -26,7 +29,7 @@ export class IOUnit extends BaseUnit { }; } - initialize(config) { + initialize(config: IOUnitConfig) { this._materials = []; this._defaultTargets = ["band_gaps:direct", "band_gaps:indirect"]; this._features = lodash.get(config, "input.0.endpoint_options.data.features", []); @@ -39,7 +42,7 @@ export class IOUnit extends BaseUnit { this._jobId = null; } - get materials() { + get materials() { // TODO: define Material type return this._materials || []; } @@ -55,7 +58,8 @@ export class IOUnit extends BaseUnit { return this.features.filter((x) => x !== IO_ID_COLUMN); } - get availableFeatures() { + // TODO: refactor to not use lodash + get availableFeatures(): any[] { const { materials } = this; return lodash.uniq( lodash @@ -76,7 +80,7 @@ export class IOUnit extends BaseUnit { * @summary Checks whether selected features contain only IO_ID_COLUMN ('exabyteId'). * Used to identify that no features are selected yet (features set always contains ID_COLUMN) */ - get onlyIdFeatureSelected() { + get onlyIdFeatureSelected(): boolean { return lodash.isEmpty(lodash.without(this.features, IO_ID_COLUMN)); } @@ -120,43 +124,43 @@ export class IOUnit extends BaseUnit { return this.prop("subtype") === "dataFrame"; } - setMaterials(materials) { + setMaterials(materials: any[]) { //TODO: define Material type this._materials = materials; this._ids = materials.map((m) => m.exabyteId); } - addFeature(feature) { + addFeature(feature: string) { // only add if not already present if (this._features.indexOf(feature) === -1) this._features.push(feature); } - removeFeature(feature) { + removeFeature(feature: string) { if (this.featuresWithoutId.length === 1) { throw new Error("At least one feature is required"); } this._features = this._features.filter((x) => feature !== x && x !== IO_ID_COLUMN); } - addTarget(target) { + addTarget(target: string) { if (this._targets.indexOf(target) === -1) this._targets.push(target); } - removeTarget(target) { + removeTarget(target: string) { if (this._targets.length === 1) { throw new Error("At least one target is required"); } this._targets = this._targets.filter((x) => target !== x); } - hasFeature(feature) { + hasFeature(feature: string) { return this._features.indexOf(feature) > -1; } - hasTarget(target) { + hasTarget(target: string) { return this._targets.indexOf(target) > -1; } - toJSON() { + toJSON(): IOUnitConfig { const config = this.isDataFrame ? this.dataFrameConfig : {}; return this.clean({ ...super.toJSON(), ...config }); } diff --git a/src/units/map.js b/src/units/map.ts similarity index 76% rename from src/units/map.js rename to src/units/map.ts index 29a6e21..2b78cdf 100644 --- a/src/units/map.js +++ b/src/units/map.ts @@ -1,5 +1,6 @@ import { UNIT_TYPES } from "../enums"; import { BaseUnit } from "./base"; +import { MapUnitConfig } from "./types"; export const defaultMapConfig = { name: UNIT_TYPES.map, @@ -14,8 +15,8 @@ export const defaultMapConfig = { }, }; -export class MapUnit extends BaseUnit { - constructor(config) { +export class MapUnit extends BaseUnit { + constructor(config: MapUnitConfig) { super({ ...defaultMapConfig, ...config }); } @@ -27,7 +28,7 @@ export class MapUnit extends BaseUnit { return this.prop("workflowId"); } - setWorkflowId(id) { + setWorkflowId(id: string) { this.setProp("workflowId", id); } } diff --git a/src/units/processing.js b/src/units/processing.ts similarity index 70% rename from src/units/processing.js rename to src/units/processing.ts index 93f0c39..55eb1b4 100644 --- a/src/units/processing.js +++ b/src/units/processing.ts @@ -1,8 +1,9 @@ import { UNIT_TYPES } from "../enums"; import { BaseUnit } from "./base"; +import { ProcessingUnitConfig, UnitInput } from "./types"; -export class ProcessingUnit extends BaseUnit { - constructor(config) { +export class ProcessingUnit extends BaseUnit { + constructor(config: ProcessingUnitConfig) { super({ ...ProcessingUnit.getProcessingConfig(), ...config }); } @@ -13,15 +14,15 @@ export class ProcessingUnit extends BaseUnit { }; } - setOperation(op) { + setOperation(op: string) { this.setProp("operation", op); } - setOperationType(type) { + setOperationType(type: string) { this.setProp("operationType", type); } - setInput(input) { + setInput(input: UnitInput) { this.setProp("input", input); } diff --git a/src/units/reduce.js b/src/units/reduce.js deleted file mode 100644 index 152b2a0..0000000 --- a/src/units/reduce.js +++ /dev/null @@ -1,17 +0,0 @@ -import { UNIT_TYPES } from "../enums"; -import { BaseUnit } from "./base"; - -export class ReduceUnit extends BaseUnit { - constructor(unitName, mapUnit, input) { - super({ ...ReduceUnit.getReduceConfig(unitName, mapUnit, input) }); - } - - static getReduceConfig(unitName, mapUnit, input) { - return { - type: UNIT_TYPES.reduce, - name: unitName, - mapFlowchartId: mapUnit, - input, - }; - } -} diff --git a/src/units/reduce.ts b/src/units/reduce.ts new file mode 100644 index 0000000..d436ef2 --- /dev/null +++ b/src/units/reduce.ts @@ -0,0 +1,18 @@ +import { UNIT_TYPES } from "../enums"; +import { BaseUnit } from "./base"; +import { ReduceUnitConfig } from "./types"; + +export class ReduceUnit extends BaseUnit { + constructor({name, mapFlowchartId, input, ...config}: ReduceUnitConfig) { + super({...ReduceUnit.getReduceConfig(name, mapFlowchartId, input), ...config }); + } + + static getReduceConfig(name, mapFlowchartId, input) { + return { + type: UNIT_TYPES.reduce, + name: name, + mapFlowchartId: mapFlowchartId, + input, + }; + } +} diff --git a/src/units/subworkflow.js b/src/units/subworkflow.ts similarity index 64% rename from src/units/subworkflow.js rename to src/units/subworkflow.ts index dea55ec..6a8ce9c 100644 --- a/src/units/subworkflow.js +++ b/src/units/subworkflow.ts @@ -1,8 +1,9 @@ import { UNIT_TYPES } from "../enums"; import { BaseUnit } from "./base"; +import { SubworkflowUnitConfig } from "./types"; -export class SubworkflowUnit extends BaseUnit { - constructor(config) { +export class SubworkflowUnit extends BaseUnit { + constructor(config: SubworkflowUnitConfig) { super({ ...SubworkflowUnit.getSubworkflowConfig(), ...config }); } diff --git a/src/units/types.ts b/src/units/types.ts new file mode 100644 index 0000000..366cd35 --- /dev/null +++ b/src/units/types.ts @@ -0,0 +1,140 @@ +export enum UNIT_TYPES { + execution = "execution", + map = "map", + reduce = "reduce", + assignment = "assignment", + condition = "condition", + subworkflow = "subworkflow", + processing = "processing", + io = "io", + assertion = "assertion", +}; + +export enum UNIT_STATUSES { + idle = "idle", + active = "active", + finished = "finished", + error = "error", + warning = "warning", +}; + +export type UnitInput = object[]; + +export interface NamedEntity { + name: string; +} + +export interface TaggableEntity { + tags: string[]; +} + +export interface StatusTrack { + repetition: number; + trackedAt: string; // ISO date string +} + +export interface StatusTrackingEntity { + status: string; + statusTrack: StatusTrack[]; +} + +export interface UnitConfig extends NamedEntity, TaggableEntity, StatusTrackingEntity { + flowchartId: string; + type: UNIT_TYPES; + head: boolean; // true if the unit is the head of the flowchart + next: string; + isDraft: boolean; // TODO: figure out where this is used +} + +export interface AssertionUnitConfig extends UnitConfig { + type: UNIT_TYPES.assertion; + statement: string; + errorMessage: string; +} + +export interface AssignmentUnitConfig extends UnitConfig { + type: UNIT_TYPES.assignment; + input: UnitInput; + operand: string; + value: string; +} + +export interface ConditionUnitConfig extends UnitConfig { + type: UNIT_TYPES.condition; + statement: string; + maxOccurrences: number; + then: string; + else: string; +} + +// TODO: define Executable and Flavor types +export interface ApplicationType extends NamedEntity { + defaultExecutable: ExecutableType; + getExecutableByConfig: (config: ExecutableConfig) => ExecutableType; + toJSON: () => this +}; + +export interface ExecutableConfig {any}; +export interface ExecutableType extends NamedEntity { + defaultFlavor: FlavorType; + results: string[]; // array of result names + monitors: string[]; // array of monitor names + preProcessors: string[]; // array of preprocessor names + postProcessors: string[] // array of postprocessor names + getFlavorByConfig: (config: FlavorConfig) => FlavorType; + toJSON: () => this +}; + +export interface TemplateType { + getContextProvidersAsClassInstances: (contextProviders: any[]) => any[]; +}; +export interface FlavorConfig {any}; +export interface FlavorType extends NamedEntity { + inputAsTemplates: TemplateType[]; + results: string[]; // array of result names + monitors: string[]; // array of monitor names + preProcessors: string[]; // array of preprocessor names + postProcessors: string[] // array of postprocessor names + getInputAsRenderedTemplates: (context: any) => TemplateType[]; + toJSON: () => this +}; + +export interface ExecutionUnitConfig extends UnitConfig { + type: UNIT_TYPES.execution; + application: ApplicationType; + executable: ExecutableType; + flavor: FlavorType; + input: UnitInput; +} + +export type IOUnitSubTypes = 'input' | 'output' | 'dataFrame'; +export interface IOUnitConfig extends UnitConfig { + type: UNIT_TYPES.io; + subtype: IOUnitSubTypes; + source: string; + input: UnitInput; + enableRender: boolean; // whether template should be rendered with jinja templates at runtime +} + +export interface MapUnitConfig extends UnitConfig { + type: UNIT_TYPES.map; + input: UnitInput; + workflowId: string; +} + +export interface ProcessingUnitConfig extends UnitConfig { + type: UNIT_TYPES.processing; + operation: string; + operationType: string; + input: UnitInput; +} + +export interface ReduceUnitConfig extends UnitConfig { + type: UNIT_TYPES.reduce; + mapFlowchartId: string; + input: UnitInput; +} + +export interface SubworkflowUnitConfig extends UnitConfig { + type: UNIT_TYPES.subworkflow; +}