+ );
+ }
+
+ private onFileInputChanged(e: React.FormEvent): void {
+ const file: File = this.fileInput.current.files[0];
+ const filename = file.name;
+
+ this.setState({
+ type: States.Loading,
+ }, () => {
+ toB64(file)
+ .then(b64Str => {
+ const upd = InputEditorUpdate.value({
+ filename: file.name,
+ data: b64Str,
+ });
+ this.props.onJobInputUpdate(upd);
+ this.setState({
+ type: States.Showing,
+ error: null,
+ });
+ })
+ .catch(err => {
+ this.setState({
+ type: States.Showing,
+ error: err,
+ });
+ })
+ });
+ }
+}
diff --git a/jobson-ui/src/ts/components/inputeditors/InputEditor.tsx b/jobson-ui/src/ts/components/inputeditors/InputEditor.tsx
index cf69f71..9144ff9 100644
--- a/jobson-ui/src/ts/components/inputeditors/InputEditor.tsx
+++ b/jobson-ui/src/ts/components/inputeditors/InputEditor.tsx
@@ -26,6 +26,7 @@ import {UnknownInputTypeInputEditor} from "./UnknownInputTypeInputEditor";
import {IntegerInputEditor} from "./IntegerInputEditor";
import {Constants} from "../../Constants";
import {DecimalInputEditor} from "./DecimalInputEditor";
+import {FileInputEditor} from "./FileInputEditor";
import {APIExpectedInput} from "../../apitypes/APIExpectedInput";
import {InputEditorUpdate} from "./updates/InputEditorUpdate";
import {Component, ReactElement} from "react";
@@ -75,15 +76,19 @@ export class InputEditor extends Component {
max: Constants.F64_MAX,
typeName: "double"
}, props),
+ "file": props => new FileInputEditor(props),
};
+ private static unknownInputCtor = props => new UnknownInputTypeInputEditor(props);
+
public static getSupportedInputEditors(): string[] {
return Object.keys(this.expectedInputUiComponentCtors);
}
public render(): ReactElement {
- const unknownCtor = (props: InputEditorProps) => new UnknownInputTypeInputEditor(props);
- const inputEditor = InputEditor.expectedInputUiComponentCtors[this.props.expectedInput.type] || unknownCtor;
+ const inputEditor =
+ InputEditor.expectedInputUiComponentCtors[this.props.expectedInput.type] ||
+ InputEditor.unknownInputCtor;
const expectedInput = this.props.expectedInput;
const editorProps = {
diff --git a/jobson/pom.xml b/jobson/pom.xml
index a4f10af..897d38b 100644
--- a/jobson/pom.xml
+++ b/jobson/pom.xml
@@ -7,11 +7,11 @@
com.github.jobsonjobson-project
- 1.0.8
+ 1.0.9jobson
- 1.0.8
+ 1.0.9jar
diff --git a/jobson/src/main/java/com/github/jobson/jobinputs/JobExpectedInput.java b/jobson/src/main/java/com/github/jobson/jobinputs/JobExpectedInput.java
index ee5231e..4980ecf 100644
--- a/jobson/src/main/java/com/github/jobson/jobinputs/JobExpectedInput.java
+++ b/jobson/src/main/java/com/github/jobson/jobinputs/JobExpectedInput.java
@@ -25,6 +25,7 @@
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.github.jobson.jobinputs.f32.F32ExpectedInput;
import com.github.jobson.jobinputs.f64.F64ExpectedInput;
+import com.github.jobson.jobinputs.file.FileExpectedInput;
import com.github.jobson.jobinputs.i32.I32ExpectedInput;
import com.github.jobson.jobinputs.i64.I64ExpectedInput;
import com.github.jobson.jobinputs.select.SelectExpectedInput;
@@ -49,6 +50,7 @@
@JsonSubTypes.Type(value = F64ExpectedInput.class, name = "double"),
@JsonSubTypes.Type(value = I32ExpectedInput.class, name = "int"),
@JsonSubTypes.Type(value = I64ExpectedInput.class, name = "long"),
+ @JsonSubTypes.Type(value = FileExpectedInput.class, name = "file"),
})
public abstract class JobExpectedInput {
diff --git a/jobson/src/main/java/com/github/jobson/jobinputs/file/FileExpectedInput.java b/jobson/src/main/java/com/github/jobson/jobinputs/file/FileExpectedInput.java
new file mode 100644
index 0000000..86d7202
--- /dev/null
+++ b/jobson/src/main/java/com/github/jobson/jobinputs/file/FileExpectedInput.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.github.jobson.jobinputs.file;
+
+import com.github.jobson.jobinputs.JobExpectedInput;
+import com.github.jobson.utils.ValidationError;
+
+import java.util.List;
+import java.util.Optional;
+
+public final class FileExpectedInput extends JobExpectedInput {
+
+ @Override
+ public Class getExpectedInputClass() {
+ return FileInput.class;
+ }
+
+ @Override
+ public Optional> validate(FileInput input) {
+ return Optional.empty();
+ }
+
+ @Override
+ public FileInput generateExampleInput() {
+ // A file containing "Hello, world!" as a b64-encoded string
+ return new FileInput("hello-world.txt", "SGVsbG8sIHdvcmxkIQo=");
+ }
+}
diff --git a/jobson/src/main/java/com/github/jobson/jobinputs/file/FileInput.java b/jobson/src/main/java/com/github/jobson/jobinputs/file/FileInput.java
new file mode 100644
index 0000000..3ee7082
--- /dev/null
+++ b/jobson/src/main/java/com/github/jobson/jobinputs/file/FileInput.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.github.jobson.jobinputs.file;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonValue;
+import com.github.jobson.jobinputs.JobInput;
+
+import javax.validation.constraints.NotNull;
+import java.util.Arrays;
+import java.util.Base64;
+
+public final class FileInput implements JobInput {
+
+ @NotNull
+ @JsonProperty
+ private final String filename;
+
+ @NotNull
+ @JsonProperty
+ private final byte[] data;
+
+ @JsonCreator
+ public FileInput(@JsonProperty(value = "filename") String filename,
+ @JsonProperty(value = "data", required = true) String b64data) {
+ this.filename = filename != null ? filename : "unnamed";
+ this.data = Base64.getDecoder().decode(b64data);
+ }
+
+ public FileInput(String filename,
+ byte[] b64data) {
+ this.filename = filename != null ? filename : "unnamed";
+ this.data = b64data;
+ }
+
+ public byte[] getData() {
+ return this.data;
+ }
+
+ public String getFilename() {
+ return this.filename;
+ }
+}
diff --git a/jobson/src/main/java/com/github/jobson/scripting/TemplateStringEvaluator.java b/jobson/src/main/java/com/github/jobson/scripting/TemplateStringEvaluator.java
index 31b72ae..7601385 100644
--- a/jobson/src/main/java/com/github/jobson/scripting/TemplateStringEvaluator.java
+++ b/jobson/src/main/java/com/github/jobson/scripting/TemplateStringEvaluator.java
@@ -19,6 +19,7 @@
package com.github.jobson.scripting;
+import com.github.jobson.jobinputs.file.FileInput;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
@@ -46,7 +47,26 @@ public static String evaluate(String templateString, Map environ
final TemplateStringEvaluatorVisitor visitor = new TemplateStringEvaluatorVisitor(environment);
- ret.append(parser.expression().accept(visitor).toString());
+ final Object evaluationOutput = parser.expression().accept(visitor);
+
+ // The evaluation of a template string element (e.g. ${someExpr}) can either yield
+ //
+ // - A "normal" java object (e.g. String, number). Could be the result of a function (e.g. `toString`)
+ // or literal (e.g. `"str"`). Should be left untouched and dumped into the output
+ //
+ // - A `JobInput`. Probably the result of a lookup operation (e.g. `${inputs.fileInput}`). Should be
+ // coerced to its final output value.
+ //
+ // For `JobInput`s specifically, the coercions into a string are as follows:
+ //
+ // numeric (f32, f64, i32, i64) -> string (e.g. `1.34 -> "1.34")
+ // string-like (select, sql, string, stringarray) -> string (e.g. ["a", "b"] -> "a,b")
+ // file -> path to a temporary file
+ final String coercedValue = evaluationOutput instanceof FileInput ?
+ ((FreeFunction)environment.get("toFile")).call(evaluationOutput).toString() :
+ evaluationOutput.toString();
+
+ ret.append(coercedValue);
} else {
ret.append(str);
}
diff --git a/jobson/src/main/java/com/github/jobson/scripting/TemplateStringEvaluatorVisitor.java b/jobson/src/main/java/com/github/jobson/scripting/TemplateStringEvaluatorVisitor.java
index 22594f9..1a2fab5 100644
--- a/jobson/src/main/java/com/github/jobson/scripting/TemplateStringEvaluatorVisitor.java
+++ b/jobson/src/main/java/com/github/jobson/scripting/TemplateStringEvaluatorVisitor.java
@@ -122,7 +122,19 @@ private List