Repository: genjidb/genji (go)

Issue:
Should be able to cast null type into array
the array should be nil

Pull request description:
Be more forgiving when scanning null values in StructScan
Fixes #211

Patch:
diff --git a/cmd/genji/shell/shell.go b/cmd/genji/shell/shell.go
index becd7338..d9d07adb 100644
--- a/cmd/genji/shell/shell.go
+++ b/cmd/genji/shell/shell.go
@@ -116,13 +116,40 @@ func Run(opts *Options) error {
 		return nil
 	}
 
-	e := prompt.New(
-		sh.execute,
-		sh.completer,
+	promptOpts := []prompt.Option{
 		prompt.OptionPrefix("genji> "),
 		prompt.OptionTitle("genji"),
 		prompt.OptionLivePrefix(sh.changelivePrefix),
 		prompt.OptionHistory(history),
+	}
+
+	// If NO_COLOR env var is present, disable color. See https://no-color.org
+	if _, ok := os.LookupEnv("NO_COLOR"); ok {
+		// A list of color options we have to reset.
+		colorOpts := []func(prompt.Color) prompt.Option{
+			prompt.OptionPrefixTextColor,
+			prompt.OptionPreviewSuggestionTextColor,
+			prompt.OptionSuggestionTextColor,
+			prompt.OptionSuggestionBGColor,
+			prompt.OptionSelectedSuggestionTextColor,
+			prompt.OptionSelectedSuggestionBGColor,
+			prompt.OptionDescriptionTextColor,
+			prompt.OptionDescriptionBGColor,
+			prompt.OptionSelectedDescriptionTextColor,
+			prompt.OptionSelectedDescriptionBGColor,
+			prompt.OptionScrollbarThumbColor,
+			prompt.OptionScrollbarBGColor,
+		}
+		for _, opt := range colorOpts {
+			resetColor := opt(prompt.DefaultColor)
+			promptOpts = append(promptOpts, resetColor)
+		}
+	}
+
+	e := prompt.New(
+		sh.execute,
+		sh.completer,
+		promptOpts...,
 	)
 
 	e.Run()
@@ -146,6 +173,9 @@ func (sh *Shell) loadCommandSuggestions() {
 }
 
 func (sh *Shell) loadHistory() ([]string, error) {
+	if _, ok := os.LookupEnv("NO_HISTORY"); ok {
+		return nil, nil
+	}
 	homeDir, err := os.UserHomeDir()
 	if err != nil {
 		return nil, err
@@ -174,6 +204,9 @@ func (sh *Shell) loadHistory() ([]string, error) {
 }
 
 func (sh *Shell) dumpHistory() error {
+	if _, ok := os.LookupEnv("NO_HISTORY"); ok {
+		return nil
+	}
 	homeDir, err := os.UserHomeDir()
 	if err != nil {
 		return err
diff --git a/document/scan.go b/document/scan.go
index bdfc9cd8..42392f1d 100644
--- a/document/scan.go
+++ b/document/scan.go
@@ -244,6 +244,12 @@ func scanValue(v Value, ref reflect.Value) error {
 		ref = reflect.Indirect(ref)
 	}
 
+	// Scan nulls as Go zero values.
+	if v.Type == NullValue {
+		ref.Set(reflect.Zero(ref.Type()))
+		return nil
+	}
+
 	switch ref.Kind() {
 	case reflect.String:
 		v, err := v.CastAsText()


Test patch:
diff --git a/document/scan_test.go b/document/scan_test.go
index a137b486..3c5a3998 100644
--- a/document/scan_test.go
+++ b/document/scan_test.go
@@ -65,6 +65,7 @@ func TestScan(t *testing.T) {
 				Add("foo", document.NewTextValue("foo")).
 				Add("bar", document.NewTextValue("bar")),
 		)).
+		Add("o", document.NewNullValue()).
 		Add("p", document.NewTextValue(now.Format(time.RFC3339Nano))).
 		Add("r", document.NewDocumentValue(codec.NewDocument(buf.Bytes())))
 
@@ -88,10 +89,11 @@ func TestScan(t *testing.T) {
 	var l *foo = new(foo)
 	var m *foo
 	var n map[string]string
+	var o []int = []int{1, 2, 3}
 	var p time.Time
 	var r map[string]interface{}
 
-	err = document.Scan(doc, &a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m, &n, &p, &r)
+	err = document.Scan(doc, &a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m, &n, &o, &p, &r)
 	require.NoError(t, err)
 	require.Equal(t, a, []byte("foo"))
 	require.Equal(t, b, "bar")
@@ -108,6 +110,7 @@ func TestScan(t *testing.T) {
 	require.Equal(t, &foo{Foo: "foo", Pub: &bar}, l)
 	require.Equal(t, &foo{Foo: "foo", Pub: &bar}, m)
 	require.Equal(t, map[string]string{"foo": "foo", "bar": "bar"}, n)
+	require.Equal(t, []int(nil), o)
 	require.Equal(t, now.Format(time.RFC3339Nano), p.Format(time.RFC3339Nano))
 	require.Equal(t, map[string]interface{}{
 		"foo": map[string]interface{}{
@@ -133,14 +136,14 @@ func TestScan(t *testing.T) {
 		m := make(map[string]interface{})
 		err := document.MapScan(doc, m)
 		require.NoError(t, err)
-		require.Len(t, m, 16)
+		require.Len(t, m, 17)
 	})
 
 	t.Run("MapPtr", func(t *testing.T) {
 		var m map[string]interface{}
 		err := document.MapScan(doc, &m)
 		require.NoError(t, err)
-		require.Len(t, m, 16)
+		require.Len(t, m, 17)
 	})
 
 	t.Run("Small Slice", func(t *testing.T) {