Pārlūkot izejas kodu

refactor(rest): return complex type as object instead of string

ngjaying 4 gadi atpakaļ
vecāks
revīzija
0f8305bb7b
4 mainītis faili ar 142 papildinājumiem un 4 dzēšanām
  1. 2 2
      xsql/ast.go
  2. 40 0
      xsql/ast_test.go
  3. 55 1
      xsql/util.go
  4. 45 1
      xsql/util_test.go

+ 2 - 2
xsql/ast.go

@@ -314,10 +314,10 @@ type StreamField struct {
 
 
 func (u *StreamField) MarshalJSON() ([]byte, error) {
 func (u *StreamField) MarshalJSON() ([]byte, error) {
 	return json.Marshal(&struct {
 	return json.Marshal(&struct {
-		FieldType string
+		FieldType interface{}
 		Name      string
 		Name      string
 	}{
 	}{
-		FieldType: PrintFieldType(u.FieldType),
+		FieldType: PrintFieldTypeForJson(u.FieldType),
 		Name:      u.Name,
 		Name:      u.Name,
 	})
 	})
 }
 }

+ 40 - 0
xsql/ast_test.go

@@ -1,6 +1,7 @@
 package xsql
 package xsql
 
 
 import (
 import (
+	"encoding/json"
 	"fmt"
 	"fmt"
 	"reflect"
 	"reflect"
 	"testing"
 	"testing"
@@ -108,3 +109,42 @@ func Test_MessageValTest(t *testing.T) {
 		}
 		}
 	}
 	}
 }
 }
+
+func Test_StreamFieldsMarshall(t *testing.T) {
+	var tests = []struct {
+		sf StreamFields
+		r  string
+	}{{
+		sf: []StreamField{
+			{Name: "USERID", FieldType: &BasicType{Type: BIGINT}},
+			{Name: "FIRST_NAME", FieldType: &BasicType{Type: STRINGS}},
+			{Name: "LAST_NAME", FieldType: &BasicType{Type: STRINGS}},
+			{Name: "NICKNAMES", FieldType: &ArrayType{Type: STRINGS}},
+			{Name: "Gender", FieldType: &BasicType{Type: BOOLEAN}},
+			{Name: "ADDRESS", FieldType: &RecType{
+				StreamFields: []StreamField{
+					{Name: "STREET_NAME", FieldType: &BasicType{Type: STRINGS}},
+					{Name: "NUMBER", FieldType: &BasicType{Type: BIGINT}},
+				},
+			}},
+		},
+		r: `[{"FieldType":"bigint","Name":"USERID"},{"FieldType":"string","Name":"FIRST_NAME"},{"FieldType":"string","Name":"LAST_NAME"},{"FieldType":{"Type":"array","ElementType":"string"},"Name":"NICKNAMES"},{"FieldType":"boolean","Name":"Gender"},{"FieldType":{"Type":"struct","Fields":[{"FieldType":"string","Name":"STREET_NAME"},{"FieldType":"bigint","Name":"NUMBER"}]},"Name":"ADDRESS"}]`,
+	}, {
+		sf: []StreamField{
+			{Name: "USERID", FieldType: &BasicType{Type: BIGINT}},
+		},
+		r: `[{"FieldType":"bigint","Name":"USERID"}]`,
+	}}
+	fmt.Printf("The test bucket size is %d.\n\n", len(tests))
+	for i, tt := range tests {
+		r, err := json.Marshal(tt.sf)
+		if err != nil {
+			t.Errorf("%d. \nmarshall error: %v", i, err)
+			t.FailNow()
+		}
+		result := string(r)
+		if !reflect.DeepEqual(tt.r, result) {
+			t.Errorf("%d. \nstmt mismatch:\n\nexp=%#v\n\ngot=%#v\n\n", i, tt.r, result)
+		}
+	}
+}

+ 55 - 1
xsql/util.go

@@ -1,6 +1,10 @@
 package xsql
 package xsql
 
 
-import "strings"
+import (
+	"encoding/json"
+	"fmt"
+	"strings"
+)
 
 
 func PrintFieldType(ft FieldType) (result string) {
 func PrintFieldType(ft FieldType) (result string) {
 	switch t := ft.(type) {
 	switch t := ft.(type) {
@@ -30,6 +34,56 @@ func PrintFieldType(ft FieldType) (result string) {
 	return
 	return
 }
 }
 
 
+func PrintFieldTypeForJson(ft FieldType) (result interface{}) {
+	r, q := doPrintFieldTypeForJson(ft)
+	if q {
+		return r
+	} else {
+		return json.RawMessage(r)
+	}
+}
+
+func doPrintFieldTypeForJson(ft FieldType) (result string, isLiteral bool) {
+	switch t := ft.(type) {
+	case *BasicType:
+		return t.Type.String(), true
+	case *ArrayType:
+		var (
+			fieldType string
+			q         bool
+		)
+		if t.FieldType != nil {
+			fieldType, q = doPrintFieldTypeForJson(t.FieldType)
+		} else {
+			fieldType, q = t.Type.String(), true
+		}
+		if q {
+			result = fmt.Sprintf(`{"Type":"array","ElementType":"%s"}`, fieldType)
+		} else {
+			result = fmt.Sprintf(`{"Type":"array","ElementType":%s}`, fieldType)
+		}
+
+	case *RecType:
+		result = `{"Type":"struct","Fields":[`
+		isFirst := true
+		for _, f := range t.StreamFields {
+			if isFirst {
+				isFirst = false
+			} else {
+				result += ","
+			}
+			fieldType, q := doPrintFieldTypeForJson(f.FieldType)
+			if q {
+				result = fmt.Sprintf(`%s{"FieldType":"%s","Name":"%s"}`, result, fieldType, f.Name)
+			} else {
+				result = fmt.Sprintf(`%s{"FieldType":"%s","Name":"%s"}`, result, fieldType, f.Name)
+			}
+		}
+		result += `]}`
+	}
+	return result, false
+}
+
 func GetStreams(stmt *SelectStatement) (result []string) {
 func GetStreams(stmt *SelectStatement) (result []string) {
 	if stmt == nil {
 	if stmt == nil {
 		return nil
 		return nil

+ 45 - 1
xsql/util_test.go

@@ -61,10 +61,54 @@ func TestLowercaseKeyMap(t *testing.T) {
 
 
 	fmt.Printf("The test bucket size is %d.\n\n", len(tests))
 	fmt.Printf("The test bucket size is %d.\n\n", len(tests))
 	for i, tt := range tests {
 	for i, tt := range tests {
-		//fmt.Printf("Parsing SQL %q.\n", tt.s)
 		result := LowercaseKeyMap(tt.src)
 		result := LowercaseKeyMap(tt.src)
 		if !reflect.DeepEqual(tt.dest, result) {
 		if !reflect.DeepEqual(tt.dest, result) {
 			t.Errorf("%d. \nstmt mismatch:\n\nexp=%#v\n\ngot=%#v\n\n", i, tt.dest, result)
 			t.Errorf("%d. \nstmt mismatch:\n\nexp=%#v\n\ngot=%#v\n\n", i, tt.dest, result)
 		}
 		}
 	}
 	}
 }
 }
+
+func TestPrintFieldType(t *testing.T) {
+	var tests = []struct {
+		ft      FieldType
+		printed string
+	}{{
+		ft: &RecType{
+			StreamFields: []StreamField{
+				{Name: "STREET_NAME", FieldType: &BasicType{Type: STRINGS}},
+				{Name: "NUMBER", FieldType: &BasicType{Type: BIGINT}},
+			},
+		},
+		printed: `{"Type":"struct","Fields":[{"FieldType":"string","Name":"STREET_NAME"},{"FieldType":"bigint","Name":"NUMBER"}]}`,
+	}, {
+		ft: &ArrayType{
+			Type: STRUCT,
+			FieldType: &RecType{
+				StreamFields: []StreamField{
+					{Name: "STREET_NAME", FieldType: &BasicType{Type: STRINGS}},
+					{Name: "NUMBER", FieldType: &BasicType{Type: BIGINT}},
+				},
+			},
+		},
+		printed: `{"Type":"array","ElementType":{"Type":"struct","Fields":[{"FieldType":"string","Name":"STREET_NAME"},{"FieldType":"bigint","Name":"NUMBER"}]}}`,
+	}, {
+		ft: &ArrayType{
+			Type:      STRUCT,
+			FieldType: &BasicType{Type: STRINGS},
+		},
+		printed: `{"Type":"array","ElementType":"string"}`,
+	}, {
+		ft: &BasicType{
+			Type: STRINGS,
+		},
+		printed: `string`,
+	}}
+	fmt.Printf("The test bucket size is %d.\n\n", len(tests))
+	for i, tt := range tests {
+		//fmt.Printf("Parsing SQL %q.\n",tt.s)
+		result, _ := doPrintFieldTypeForJson(tt.ft)
+		if !reflect.DeepEqual(tt.printed, result) {
+			t.Errorf("%d. \nstmt mismatch:\n\nexp=%#v\n\ngot=%#v\n\n", i, tt.printed, result)
+		}
+	}
+}