sdk-go icon indicating copy to clipboard operation
sdk-go copied to clipboard

DataInputSchema can only be a string and not an object

Open spolti opened this issue 1 year ago • 19 comments

fixes #194

Many thanks for submitting your Pull Request :heart:!

What this PR does / why we need it:

Special notes for reviewers:

Additional information (if needed):

spolti avatar Nov 29 '23 18:11 spolti

@ricardozanini PTAL.

there is one test specific that I left a comment, we would need to revisit that later.

spolti avatar Nov 29 '23 18:11 spolti

@ribeiromiranda wanna take a look?

ricardozanini avatar Dec 04 '23 14:12 ricardozanini

@spolti can you rebase and review @ribeiromiranda's comment?

ricardozanini avatar Dec 18 '23 15:12 ricardozanini

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

github-actions[bot] avatar Feb 02 '24 00:02 github-actions[bot]

@spolti are you still on this? :D

ricardozanini avatar Feb 02 '24 12:02 ricardozanini

Yes, sry, will try to revisit it this or next week.

spolti avatar Feb 08 '24 12:02 spolti

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

github-actions[bot] avatar Mar 25 '24 00:03 github-actions[bot]

@ribeiromiranda hi, Just got it using your tool, the version in the go.mod does not looks correct. https://github.com/galgotech/builder-gen/blob/main/go.mod#L3C1-L3C11?

go: github.com/galgotech/builder-gen@latest (in github.com/galgotech/[email protected]): go.mod:3: invalid go version '1.20.11': must match format 1.23

spolti avatar Apr 03 '24 14:04 spolti

There is a small issue on a third party lib, please take a look in the comments.

spolti avatar Apr 03 '24 19:04 spolti

There is a small issue on a third party lib, please take a look in the comments.

Changed version to 1.19

ribeiromiranda avatar Apr 05 '24 01:04 ribeiromiranda

@spolti ^

ricardozanini avatar Apr 05 '24 12:04 ricardozanini

updated. Thanks @ribeiromiranda

spolti avatar Apr 05 '24 13:04 spolti

@ribeiromiranda can you please review?

ricardozanini avatar Apr 05 '24 15:04 ricardozanini

@ricardozanini @spolti Are all inputs valid?

id: Valid DataInputSchema
version: '1.0'
specVersion: '0.8'
start: Start
dataInputSchema: "file://testdata/datainputschema.json"
...
id: Valid DataInputSchema
version: '1.0'
specVersion: '0.8'
start: Start
dataInputSchema: "{}"
...
id: Valid DataInputSchema
version: '1.0'
specVersion: '0.8'
start: Start
dataInputSchema:
  schema: "file://testdata/datainputschema.json"
...
id: Valid DataInputSchema
version: '1.0'
specVersion: '0.8'
start: Start
dataInputSchema:
  schema: "{}"
...

ribeiromiranda avatar Apr 06 '24 03:04 ribeiromiranda

@ribeiromiranda yes, it should.

ricardozanini avatar Apr 08 '24 18:04 ricardozanini

Option 2 should be invalid, since we check the schema field

if d.Schema != nil && d.Schema.Type == String {

spolti avatar Apr 25 '24 18:04 spolti

are we clear to merge this one?

spolti avatar Apr 25 '24 18:04 spolti

@ricardozanini @spolti Another question, it wasn't clear to me in the specification.

Which is right, JSON with or without quotes?

1.
```yaml
id: Valid DataInputSchema
version: '1.0'
specVersion: '0.8'
start: Start
dataInputSchema: "{ \"test\": \"value\" }"
...
2.
```yaml
id: Valid DataInputSchema
version: '1.0'
specVersion: '0.8'
start: Start
dataInputSchema: {
  "test": "value"
}
...

ribeiromiranda avatar Apr 30 '24 02:04 ribeiromiranda

@ricardozanini @spolti With the patch all cases below will work.

dataInputSchema: "{\"key\": \"value\"}"
dataInputSchema: {"key": "value"}
dataInputSchema: file://...
dataInputSchema:
  schema: "{\"key\": \"value\"}"
  failOnValidationErrors: true
dataInputSchema:
  schema: {"key": "value"}
  failOnValidationErrors: true
dataInputSchema:
  schema: file://...
  failOnValidationErrors: true 
diff --git a/model/workflow.go b/model/workflow.go
index d0ac4c7..aa72d1f 100644
--- a/model/workflow.go
+++ b/model/workflow.go
@@ -15,8 +15,9 @@
 package model
 
 import (
+	"bytes"
 	"encoding/json"
-	"regexp"
+	"errors"
 
 	"github.com/serverlessworkflow/sdk-go/v2/util"
 )
@@ -522,33 +523,41 @@ type dataInputSchemaUnmarshal DataInputSchema
 // UnmarshalJSON implements json.Unmarshaler
 func (d *DataInputSchema) UnmarshalJSON(data []byte) error {
 	d.ApplyDefault()
-	err := util.UnmarshalObject("dataInputSchema", data, (*dataInputSchemaUnmarshal)(d))
+
+	// expected: data = "{\"key\": \"value\"}"
+	//           data = {"key": "value"}
+	//	         data = "file://..."
+	//           data = { "schema": "{\"key\": \"value\"}", "failOnValidationErrors": true }
+	//           data = { "schema": {"key": "value"}, "failOnValidationErrors": true }
+	//           data = { "schema": "file://...", "failOnValidationErrors": true }
+
+	schemaString := ""
+	err := util.UnmarshalPrimitiveOrObject("dataInputSchema", data, &schemaString, (*dataInputSchemaUnmarshal)(d))
 	if err != nil {
 		return err
 	}
 
-	if d.Schema != nil && d.Schema.Type == String {
-		// Define the regex pattern to match the prefixes
-		pattern := `^(http|https|file)`
-		regex := regexp.MustCompile(pattern)
-		// if it is not external, treat as JSON object
-		if !regex.MatchString(d.Schema.StringValue) {
-			point := FromString(d.Schema.StringValue)
-			d.Schema = &point
+	if d.Schema != nil {
+		if d.Schema.Type == Map {
 			return nil
-		}
 
-		data, err := util.LoadExternalResource(d.Schema.StringValue)
-		if err != nil {
-			return err
+		} else if d.Schema.Type == String {
+			schemaString = d.Schema.StringValue
+
+		} else {
+			return errors.New("invalid dataInputSchema must be a string or object")
 		}
+	}
 
-		er := util.UnmarshalObject("schema", data, &d.Schema)
-		// clean the string value to avoid the json URI being appended
-		d.Schema.StringValue = ""
-		return er
+	if schemaString != "" {
+		data = []byte(schemaString)
+		if bytes.TrimSpace(data)[0] != '{' {
+			data = []byte("\"" + schemaString + "\"")
+		}
 	}
-	return nil
+
+	d.Schema = new(Object)
+	return util.UnmarshalObjectOrFile("schema", data, &d.Schema)
 }
 
 // ApplyDefault set the default values for Data Input Schema
diff --git a/model/workflow_test.go b/model/workflow_test.go
index 70aa2d8..a5aa42a 100644
--- a/model/workflow_test.go
+++ b/model/workflow_test.go
@@ -499,7 +499,11 @@ func TestTransitionUnmarshalJSON(t *testing.T) {
 
 func TestDataInputSchemaUnmarshalJSON(t *testing.T) {
 
-	schemaName := FromString("schema name")
+	var schemaName Object
+	err := json.Unmarshal([]byte("{\"key\": \"value\"}"), &schemaName)
+	if !assert.NoError(t, err) {
+		return
+	}
 
 	type testCase struct {
 		desp   string
@@ -511,16 +515,25 @@ func TestDataInputSchemaUnmarshalJSON(t *testing.T) {
 	testCases := []testCase{
 		{
 			desp: "string success",
-			data: `"schema name"`,
+			data: "{\"key\": \"value\"}",
 			expect: DataInputSchema{
 				Schema:                 &schemaName,
 				FailOnValidationErrors: true,
 			},
-			err: `dataInputSchema must be string or object`,
+			err: ``,
 		},
 		{
-			desp: `object success`,
-			data: `{"schema": "schema name"}`,
+			desp: "string fail",
+			data: "{\"key\": }",
+			expect: DataInputSchema{
+				Schema:                 &schemaName,
+				FailOnValidationErrors: true,
+			},
+			err: `invalid character '}' looking for beginning of value`,
+		},
+		{
+			desp: `object success (without quotes)`,
+			data: `{"key": "value"}`,
 			expect: DataInputSchema{
 				Schema:                 &schemaName,
 				FailOnValidationErrors: true,
@@ -528,22 +541,32 @@ func TestDataInputSchemaUnmarshalJSON(t *testing.T) {
 			err: ``,
 		},
 		{
-			desp: `object fail`,
-			data: `{"schema": "schema name}`,
+			desp: `schema object success`,
+			data: `{"schema": "{\"key\": \"value\"}"}`,
 			expect: DataInputSchema{
 				Schema:                 &schemaName,
 				FailOnValidationErrors: true,
 			},
-			err: `unexpected end of JSON input`,
+			err: ``,
 		},
 		{
-			desp: `object key invalid`,
-			data: `{"schema_invalid": "schema name"}`,
+			desp: `schema object success (without quotes)`,
+			data: `{"schema": {"key": "value"}}`,
 			expect: DataInputSchema{
+				Schema:                 &schemaName,
 				FailOnValidationErrors: true,
 			},
 			err: ``,
 		},
+		{
+			desp: `schema object fail`,
+			data: `{"schema": "schema name}`,
+			expect: DataInputSchema{
+				Schema:                 &schemaName,
+				FailOnValidationErrors: true,
+			},
+			err: `unexpected end of JSON input`,
+		},
 	}
 	for _, tc := range testCases {
 		t.Run(tc.desp, func(t *testing.T) {
@@ -551,13 +574,14 @@ func TestDataInputSchemaUnmarshalJSON(t *testing.T) {
 			err := json.Unmarshal([]byte(tc.data), &v)
 
 			if tc.err != "" {
-				assert.Error(t, err)
-				assert.Regexp(t, tc.err, err)
+				assert.Error(t, err, tc.desp)
+				assert.Regexp(t, tc.err, err, tc.desp)
 				return
 			}
 
-			assert.NoError(t, err)
-			assert.Equal(t, tc.expect, v)
+			assert.NoError(t, err, tc.desp)
+			assert.Equal(t, tc.expect.Schema, v.Schema, tc.desp)
+			assert.Equal(t, tc.expect.FailOnValidationErrors, v.FailOnValidationErrors, tc.desp)
 		})
 	}
 }
diff --git a/util/unmarshal.go b/util/unmarshal.go
index 9d5b1c2..d00e9d2 100644
--- a/util/unmarshal.go
+++ b/util/unmarshal.go
@@ -221,7 +221,7 @@ func UnmarshalObjectOrFile[U any](parameterName string, data []byte, valObject *
 	}
 
 	data = bytes.TrimSpace(data)
-	if data[0] == '{' && parameterName != "constants" && parameterName != "timeouts" {
+	if data[0] == '{' && parameterName != "constants" && parameterName != "timeouts" && parameterName != "schema" {
 		extractData := map[string]json.RawMessage{}
 		err = json.Unmarshal(data, &extractData)
 		if err != nil {

ribeiromiranda avatar May 04 '24 17:05 ribeiromiranda

@ricardozanini @spolti Another question, it wasn't clear to me in the specification.

Which is right, JSON with or without quotes?

1.
```yaml
id: Valid DataInputSchema
version: '1.0'
specVersion: '0.8'
start: Start
dataInputSchema: "{ \"test\": \"value\" }"
...
2.
```yaml
id: Valid DataInputSchema
version: '1.0'
specVersion: '0.8'
start: Start
dataInputSchema: {
  "test": "value"
}
...

If we can convert the { "test": "value" } into a valid JSON Schema, both are.

ricardozanini avatar May 08 '24 13:05 ricardozanini

@spolti can you apply @ribeiromiranda's patch?

ricardozanini avatar May 08 '24 13:05 ricardozanini

Done.

Thanks @ribeiromiranda

spolti avatar May 08 '24 14:05 spolti

Codecov is complaining about rate limit: Rate limit reached. Please upload with the Codecov repository upload token to resolve issue.

spolti avatar May 08 '24 14:05 spolti

@spolti I'll merge and solve this issue later.

ricardozanini avatar May 08 '24 16:05 ricardozanini