add github action for testing iotdb-go-client (#6)

diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
new file mode 100644
index 0000000..90a54fa
--- /dev/null
+++ b/.github/workflows/go.yml
@@ -0,0 +1,46 @@
+name: Go
+
+on:
+  push:
+    branches: [ main ]
+  pull_request:
+    branches: [ main ]
+
+jobs:
+
+  build:
+    name: Build
+    runs-on: ${{ matrix.os }}
+    strategy:
+      matrix:
+        os: [macos-latest, ubuntu-latest, windows-latest]
+    steps:
+
+    - name: Setup timezone
+      uses: szenius/set-timezone@v1.0
+      with:
+        timezoneLinux: "Asia/Shanghai"
+        timezoneMacos: "Asia/Shanghai"
+        timezoneWindows: "China Standard Time"
+
+    - name: Set up Go 1.x
+      uses: actions/setup-go@v2
+      with:
+        go-version: ^1.13
+
+    - name: Check out code into the Go module directory
+      uses: actions/checkout@v2
+
+    - name: Get dependencies
+      run: |
+        go get -v -t -d ./...
+        # if [ -f Gopkg.toml ]; then
+        #     curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
+        #     dep ensure
+        # fi
+
+    - name: Build
+      run: go build -v ./...
+
+    - name: Test
+      run: go test -v ./...
diff --git a/README.md b/README.md
index cb62ddd..6671503 100644
--- a/README.md
+++ b/README.md
@@ -33,6 +33,10 @@
 
 # How to Compile the Client
 
+# Prerequisites
+
+    golang >= 1.13
+
 # How to Use the Client (Quick Start)
 
 With go mod
diff --git a/README_ZH.md b/README_ZH.md
index 93e2c87..055f8f1 100644
--- a/README_ZH.md
+++ b/README_ZH.md
@@ -31,6 +31,10 @@
 
 # 如何编译
 
+# 环境准备
+
+    golang >= 1.13
+
 # 如何使用 (快速上手)
 
 使用go mod
diff --git a/client/sessiondataset.go b/client/sessiondataset.go
index 69b11a2..dca93f0 100644
--- a/client/sessiondataset.go
+++ b/client/sessiondataset.go
@@ -29,10 +29,17 @@
 	ioTDBRpcDataSet *IoTDBRpcDataSet
 }
 
+// Next prepares the next result row for reading,
+// returns true on success, or false if there is no next result row or an error
+// appened while preparing it.
+// consulted Err should be consulted to distinguish between the two cases.
+// This is not goroutine safe
 func (s *SessionDataSet) Next() (bool, error) {
 	return s.ioTDBRpcDataSet.next()
 }
 
+// GetText returns string value of column value on row.
+// This is not goroutine safe
 func (s *SessionDataSet) GetText(columnName string) string {
 	return s.ioTDBRpcDataSet.getText(columnName)
 }
diff --git a/client/tablet.go b/client/tablet.go
index 1396f5e..97a3d40 100644
--- a/client/tablet.go
+++ b/client/tablet.go
@@ -111,10 +111,48 @@
 		default:
 			return fmt.Errorf("Illegal argument value %v %v", value, reflect.TypeOf(value))
 		}
+	case TEXT:
+		values := t.values[columnIndex].([]string)
+		switch value.(type) {
+		case string:
+			values[rowIndex] = value.(string)
+		case []byte:
+			values[rowIndex] = string(value.([]byte))
+		default:
+			return fmt.Errorf("Illegal argument value %v %v", value, reflect.TypeOf(value))
+		}
 	}
 	return nil
 }
 
+func (t *Tablet) GetValueAt(columnIndex, rowIndex int) (interface{}, error) {
+	if columnIndex < 0 || columnIndex > len(t.measurementSchemas) {
+		return nil, fmt.Errorf("Illegal argument columnIndex %d", columnIndex)
+	}
+
+	if rowIndex < 0 || rowIndex > int(t.rowCount) {
+		return nil, fmt.Errorf("Illegal argument rowIndex %d", rowIndex)
+	}
+
+	schema := t.measurementSchemas[columnIndex]
+	switch schema.DataType {
+	case BOOLEAN:
+		return t.values[columnIndex].([]bool)[rowIndex], nil
+	case INT32:
+		return t.values[columnIndex].([]int32)[rowIndex], nil
+	case INT64:
+		return t.values[columnIndex].([]int64)[rowIndex], nil
+	case FLOAT:
+		return t.values[columnIndex].([]float32)[rowIndex], nil
+	case DOUBLE:
+		return t.values[columnIndex].([]float64)[rowIndex], nil
+	case TEXT:
+		return t.values[columnIndex].([]string)[rowIndex], nil
+	default:
+		return nil, fmt.Errorf("Illegal datatype %v", schema.DataType)
+	}
+}
+
 func (t *Tablet) GetTimestampBytes() []byte {
 	buff := &bytes.Buffer{}
 	for _, v := range t.timestamps {
diff --git a/client/tablet_test.go b/client/tablet_test.go
index 936f700..d747bc2 100644
--- a/client/tablet_test.go
+++ b/client/tablet_test.go
@@ -306,3 +306,86 @@
 		})
 	}
 }
+
+func TestTablet_GetValueAt(t *testing.T) {
+	type args struct {
+		columnIndex int
+		rowIndex    int
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    interface{}
+		wantErr bool
+	}{
+		{
+			name: "INT32",
+			args: args{
+				columnIndex: 0,
+				rowIndex:    0,
+			},
+			want:    int32(256),
+			wantErr: false,
+		}, {
+			name: "FLOAT64",
+			args: args{
+				columnIndex: 1,
+				rowIndex:    0,
+			},
+			want:    float64(32.768),
+			wantErr: false,
+		}, {
+			name: "INT64",
+			args: args{
+				columnIndex: 2,
+				rowIndex:    0,
+			},
+			want:    int64(65535),
+			wantErr: false,
+		}, {
+			name: "FLOAT32",
+			args: args{
+				columnIndex: 3,
+				rowIndex:    0,
+			},
+			want:    float32(36.5),
+			wantErr: false,
+		}, {
+			name: "STRING",
+			args: args{
+				columnIndex: 4,
+				rowIndex:    0,
+			},
+			want:    "Hello World!",
+			wantErr: false,
+		}, {
+			name: "BOOLEAN",
+			args: args{
+				columnIndex: 5,
+				rowIndex:    0,
+			},
+			want:    true,
+			wantErr: false,
+		},
+	}
+	if tablet, err := createTablet(1); err == nil {
+		tablet.SetValueAt(int32(256), 0, 0)
+		tablet.SetValueAt(float64(32.768), 1, 0)
+		tablet.SetValueAt(int64(65535), 2, 0)
+		tablet.SetValueAt(float32(36.5), 3, 0)
+		tablet.SetValueAt("Hello World!", 4, 0)
+		tablet.SetValueAt(true, 5, 0)
+		for _, tt := range tests {
+			t.Run(tt.name, func(t *testing.T) {
+				got, err := tablet.GetValueAt(tt.args.columnIndex, tt.args.rowIndex)
+				if (err != nil) != tt.wantErr {
+					t.Errorf("Tablet.GetValueAt() error = %v, wantErr %v", err, tt.wantErr)
+					return
+				}
+				if !reflect.DeepEqual(got, tt.want) {
+					t.Errorf("Tablet.GetValueAt() = %v, want %v", got, tt.want)
+				}
+			})
+		}
+	}
+}