diff --git a/bdb/drivers/postgres.go b/bdb/drivers/postgres.go index 77dbc85..e992299 100644 --- a/bdb/drivers/postgres.go +++ b/bdb/drivers/postgres.go @@ -367,12 +367,12 @@ func getArrayType(c bdb.Column) string { return "types.BytesArray" case "bit", "interval", "uuint", "bit varying", "character", "money", "character varying", "cidr", "inet", "macaddr", "text", "uuid", "xml": return "types.StringArray" - case "bool": + case "boolean": return "types.BoolArray" case "decimal", "numeric", "double precision", "real": return "types.Float64Array" default: - return "types.GenericArray" + return "types.StringArray" } } diff --git a/boil/randomize/randomize.go b/boil/randomize/randomize.go index 2550438..2277ef2 100644 --- a/boil/randomize/randomize.go +++ b/boil/randomize/randomize.go @@ -47,7 +47,6 @@ var ( typeBoolArray = reflect.TypeOf(types.BoolArray{}) typeFloat64Array = reflect.TypeOf(types.Float64Array{}) typeStringArray = reflect.TypeOf(types.StringArray{}) - typeGenericArray = reflect.TypeOf(types.GenericArray{}) typeHstore = reflect.TypeOf(types.Hstore{}) rgxValidTime = regexp.MustCompile(`[2-9]+`) @@ -318,11 +317,7 @@ func randomizeField(s *Seed, field reflect.Value, fieldType string, canBeNull bo // If it's a Postgres array, treat it like one if strings.HasPrefix(fieldType, "ARRAY") { - if isNull { - value = getArrayNullValue(typ) - } else { - value = getArrayRandValue(s, typ) - } + value = getArrayRandValue(s, typ, fieldType) // Retrieve the value to be returned } else if kind == reflect.Struct { if isNull { @@ -347,27 +342,8 @@ func randomizeField(s *Seed, field reflect.Value, fieldType string, canBeNull bo return nil } -func getArrayNullValue(typ reflect.Type) interface{} { - fmt.Println(typ) - switch typ { - case typeInt64Array: - return types.Int64Array{} - case typeFloat64Array: - return types.Float64Array{} - case typeBoolArray: - return types.BoolArray{} - case typeStringArray: - return types.StringArray{} - case typeBytesArray: - return types.BytesArray{} - case typeGenericArray: - return types.GenericArray{} - } - - return nil -} - -func getArrayRandValue(s *Seed, typ reflect.Type) interface{} { +func getArrayRandValue(s *Seed, typ reflect.Type, fieldType string) interface{} { + fieldType = strings.TrimLeft(fieldType, "ARRAY") switch typ { case typeInt64Array: return types.Int64Array{int64(s.nextInt()), int64(s.nextInt())} @@ -376,11 +352,54 @@ func getArrayRandValue(s *Seed, typ reflect.Type) interface{} { case typeBoolArray: return types.BoolArray{s.nextInt()%2 == 0, s.nextInt()%2 == 0, s.nextInt()%2 == 0} case typeStringArray: + if fieldType == "interval" { + value := strconv.Itoa((s.nextInt()%26)+2) + " days" + return types.StringArray{value, value} + } + if fieldType == "uuid" { + value := uuid.NewV4().String() + return types.StringArray{value, value} + } + if fieldType == "box" || fieldType == "line" || fieldType == "lseg" || + fieldType == "path" || fieldType == "polygon" { + value := randBox() + return types.StringArray{value, value} + } + if fieldType == "cidr" || fieldType == "inet" { + value := randNetAddr() + return types.StringArray{value, value} + } + if fieldType == "macaddr" { + value := randMacAddr() + return types.StringArray{value, value} + } + if fieldType == "circle" { + value := randCircle() + return types.StringArray{value, value} + } + if fieldType == "pg_lsn" { + value := randLsn() + return types.StringArray{value, value} + } + if fieldType == "point" { + value := randPoint() + return types.StringArray{value, value} + } + if fieldType == "txid_snapshot" { + value := randTxID() + return types.StringArray{value, value} + } + if fieldType == "money" { + value := randMoney(s) + return types.StringArray{value, value} + } + if fieldType == "json" || fieldType == "jsonb" { + value := []byte(fmt.Sprintf(`"%s"`, randStr(s, 1))) + return types.StringArray{string(value)} + } return types.StringArray{randStr(s, 4), randStr(s, 4), randStr(s, 4)} case typeBytesArray: return types.BytesArray{randByteSlice(s, 4), randByteSlice(s, 4), randByteSlice(s, 4)} - case typeGenericArray: - return types.GenericArray{A: []types.JSON{randJSON(s, 4), randJSON(s, 4), randJSON(s, 4)}} } return nil @@ -574,17 +593,6 @@ func randByteSlice(s *Seed, ln int) []byte { return str } -func randJSON(s *Seed, ln int) types.JSON { - str := make(types.JSON, ln) - str[0] = '"' - for i := 1; i < ln-1; i++ { - str[i] = byte(s.nextInt() % 256) - } - str[ln-1] = '"' - - return str -} - func randPoint() string { a := rand.Intn(100) b := a + 1 diff --git a/boil/types/array.go b/boil/types/array.go index e8ddfab..2924fa2 100644 --- a/boil/types/array.go +++ b/boil/types/array.go @@ -184,9 +184,10 @@ func Array(a interface{}) interface { return (*Int64Array)(a) case *[]string: return (*StringArray)(a) - } - return GenericArray{a} + default: + panic(fmt.Sprintf("boil: invalid type received %T", a)) + } } // ArrayDelimiter may be optionally implemented by driver.Valuer or sql.Scanner @@ -208,7 +209,7 @@ func (a *BoolArray) Scan(src interface{}) error { return a.scanBytes([]byte(src)) } - return fmt.Errorf("pq: cannot convert %T to BoolArray", src) + return fmt.Errorf("boil: cannot convert %T to BoolArray", src) } func (a *BoolArray) scanBytes(src []byte) error { @@ -222,7 +223,7 @@ func (a *BoolArray) scanBytes(src []byte) error { b := make(BoolArray, len(elems)) for i, v := range elems { if len(v) != 1 { - return fmt.Errorf("pq: could not parse boolean array index %d: invalid boolean %q", i, v) + return fmt.Errorf("boil: could not parse boolean array index %d: invalid boolean %q", i, v) } switch v[0] { case 't': @@ -230,7 +231,7 @@ func (a *BoolArray) scanBytes(src []byte) error { case 'f': b[i] = false default: - return fmt.Errorf("pq: could not parse boolean array index %d: invalid boolean %q", i, v) + return fmt.Errorf("boil: could not parse boolean array index %d: invalid boolean %q", i, v) } } *a = b @@ -279,7 +280,7 @@ func (a *BytesArray) Scan(src interface{}) error { return a.scanBytes([]byte(src)) } - return fmt.Errorf("pq: cannot convert %T to BytesArray", src) + return fmt.Errorf("boil: cannot convert %T to BytesArray", src) } func (a *BytesArray) scanBytes(src []byte) error { @@ -348,7 +349,7 @@ func (a *Float64Array) Scan(src interface{}) error { return a.scanBytes([]byte(src)) } - return fmt.Errorf("pq: cannot convert %T to Float64Array", src) + return fmt.Errorf("boil: cannot convert %T to Float64Array", src) } func (a *Float64Array) scanBytes(src []byte) error { @@ -362,7 +363,7 @@ func (a *Float64Array) scanBytes(src []byte) error { b := make(Float64Array, len(elems)) for i, v := range elems { if b[i], err = strconv.ParseFloat(string(v), 64); err != nil { - return fmt.Errorf("pq: parsing array element index %d: %v", i, err) + return fmt.Errorf("boil: parsing array element index %d: %v", i, err) } } *a = b @@ -394,151 +395,6 @@ func (a Float64Array) Value() (driver.Value, error) { return "{}", nil } -// GenericArray implements the driver.Valuer and sql.Scanner interfaces for -// an array or slice of any dimension. -type GenericArray struct{ A interface{} } - -func (GenericArray) evaluateDestination(rt reflect.Type) (reflect.Type, func([]byte, reflect.Value) error, string) { - var assign func([]byte, reflect.Value) error - var del = "," - - // TODO calculate the assign function for other types - // TODO repeat this section on the element type of arrays or slices (multidimensional) - { - if reflect.PtrTo(rt).Implements(typeSQLScanner) { - // dest is always addressable because it is an element of a slice. - assign = func(src []byte, dest reflect.Value) (err error) { - ss := dest.Addr().Interface().(sql.Scanner) - if src == nil { - err = ss.Scan(nil) - } else { - err = ss.Scan(src) - } - return - } - goto FoundType - } - - assign = func([]byte, reflect.Value) error { - return fmt.Errorf("pq: scanning to %s is not implemented; only sql.Scanner", rt) - } - } - -FoundType: - - if ad, ok := reflect.Zero(rt).Interface().(ArrayDelimiter); ok { - del = ad.ArrayDelimiter() - } - - return rt, assign, del -} - -// Scan implements the sql.Scanner interface. -func (a GenericArray) Scan(src interface{}) error { - dpv := reflect.ValueOf(a.A) - switch { - case dpv.Kind() != reflect.Ptr: - return fmt.Errorf("pq: destination %T is not a pointer to array or slice", a.A) - case dpv.IsNil(): - return fmt.Errorf("pq: destination %T is nil", a.A) - } - - dv := dpv.Elem() - switch dv.Kind() { - case reflect.Slice: - case reflect.Array: - default: - return fmt.Errorf("pq: destination %T is not a pointer to array or slice", a.A) - } - - switch src := src.(type) { - case []byte: - return a.scanBytes(src, dv) - case string: - return a.scanBytes([]byte(src), dv) - } - - return fmt.Errorf("pq: cannot convert %T to %s", src, dv.Type()) -} - -func (a GenericArray) scanBytes(src []byte, dv reflect.Value) error { - dtype, assign, del := a.evaluateDestination(dv.Type().Elem()) - dims, elems, err := parseArray(src, []byte(del)) - if err != nil { - return err - } - - // TODO allow multidimensional - - if len(dims) > 1 { - return fmt.Errorf("pq: scanning from multidimensional ARRAY%s is not implemented", - strings.Replace(fmt.Sprint(dims), " ", "][", -1)) - } - - // Treat a zero-dimensional array like an array with a single dimension of zero. - if len(dims) == 0 { - dims = append(dims, 0) - } - - for i, rt := 0, dv.Type(); i < len(dims); i, rt = i+1, rt.Elem() { - switch rt.Kind() { - case reflect.Slice: - case reflect.Array: - if rt.Len() != dims[i] { - return fmt.Errorf("pq: cannot convert ARRAY%s to %s", - strings.Replace(fmt.Sprint(dims), " ", "][", -1), dv.Type()) - } - default: - // TODO handle multidimensional - } - } - - values := reflect.MakeSlice(reflect.SliceOf(dtype), len(elems), len(elems)) - for i, e := range elems { - if err := assign(e, values.Index(i)); err != nil { - return fmt.Errorf("pq: parsing array element index %d: %v", i, err) - } - } - - // TODO handle multidimensional - - switch dv.Kind() { - case reflect.Slice: - dv.Set(values.Slice(0, dims[0])) - case reflect.Array: - for i := 0; i < dims[0]; i++ { - dv.Index(i).Set(values.Index(i)) - } - } - - return nil -} - -// Value implements the driver.Valuer interface. -func (a GenericArray) Value() (driver.Value, error) { - if a.A == nil { - return nil, nil - } - - rv := reflect.ValueOf(a.A) - - if k := rv.Kind(); k != reflect.Array && k != reflect.Slice { - return nil, fmt.Errorf("pq: Unable to convert %T to array", a.A) - } - - if n := rv.Len(); n > 0 { - // There will be at least two curly brackets, N bytes of values, - // and N-1 bytes of delimiters. - b := make([]byte, 0, 1+2*n) - - b, _, err := appendArray(b, rv, n) - return string(b), err - } - - return "{}", nil -} - -// Int64Array represents a one-dimensional array of the PostgreSQL integer types. type Int64Array []int64 // Scan implements the sql.Scanner interface. @@ -550,7 +406,7 @@ func (a *Int64Array) Scan(src interface{}) error { return a.scanBytes([]byte(src)) } - return fmt.Errorf("pq: cannot convert %T to Int64Array", src) + return fmt.Errorf("boil: cannot convert %T to Int64Array", src) } func (a *Int64Array) scanBytes(src []byte) error { @@ -564,7 +420,7 @@ func (a *Int64Array) scanBytes(src []byte) error { b := make(Int64Array, len(elems)) for i, v := range elems { if b[i], err = strconv.ParseInt(string(v), 10, 64); err != nil { - return fmt.Errorf("pq: parsing array element index %d: %v", i, err) + return fmt.Errorf("boil: parsing array element index %d: %v", i, err) } } *a = b @@ -608,7 +464,7 @@ func (a *StringArray) Scan(src interface{}) error { return a.scanBytes([]byte(src)) } - return fmt.Errorf("pq: cannot convert %T to StringArray", src) + return fmt.Errorf("boil: cannot convert %T to StringArray", src) } func (a *StringArray) scanBytes(src []byte) error { @@ -622,7 +478,7 @@ func (a *StringArray) scanBytes(src []byte) error { b := make(StringArray, len(elems)) for i, v := range elems { if b[i] = string(v); v == nil { - return fmt.Errorf("pq: parsing array element index %d: cannot convert nil to string", i) + return fmt.Errorf("boil: parsing array element index %d: cannot convert nil to string", i) } } *a = b @@ -753,7 +609,7 @@ func parseArray(src, del []byte) (dims []int, elems [][]byte, err error) { var depth, i int if len(src) < 1 || src[0] != '{' { - return nil, nil, fmt.Errorf("pq: unable to parse array; expected %q at offset %d", '{', 0) + return nil, nil, fmt.Errorf("boil: unable to parse array; expected %q at offset %d", '{', 0) } Open: @@ -803,7 +659,7 @@ Element: if bytes.HasPrefix(src[i:], del) || src[i] == '}' { elem := src[start:i] if len(elem) == 0 { - return nil, nil, fmt.Errorf("pq: unable to parse array; unexpected %q at offset %d", src[i], i) + return nil, nil, fmt.Errorf("boil: unable to parse array; unexpected %q at offset %d", src[i], i) } if bytes.Equal(elem, []byte("NULL")) { elem = nil @@ -825,7 +681,7 @@ Element: depth-- i++ } else { - return nil, nil, fmt.Errorf("pq: unable to parse array; unexpected %q at offset %d", src[i], i) + return nil, nil, fmt.Errorf("boil: unable to parse array; unexpected %q at offset %d", src[i], i) } } @@ -835,16 +691,16 @@ Close: depth-- i++ } else { - return nil, nil, fmt.Errorf("pq: unable to parse array; unexpected %q at offset %d", src[i], i) + return nil, nil, fmt.Errorf("boil: unable to parse array; unexpected %q at offset %d", src[i], i) } } if depth > 0 { - err = fmt.Errorf("pq: unable to parse array; expected %q at offset %d", '}', i) + err = fmt.Errorf("boil: unable to parse array; expected %q at offset %d", '}', i) } if err == nil { for _, d := range dims { if (len(elems) % d) != 0 { - err = fmt.Errorf("pq: multidimensional arrays must have elements with matching dimensions") + err = fmt.Errorf("boil: multidimensional arrays must have elements with matching dimensions") } } } @@ -857,7 +713,7 @@ func scanLinearArray(src, del []byte, typ string) (elems [][]byte, err error) { return nil, err } if len(dims) > 1 { - return nil, fmt.Errorf("pq: cannot convert ARRAY%s to %s", strings.Replace(fmt.Sprint(dims), " ", "][", -1), typ) + return nil, fmt.Errorf("boil: cannot convert ARRAY%s to %s", strings.Replace(fmt.Sprint(dims), " ", "][", -1), typ) } return elems, err } diff --git a/boil/types/array_test.go b/boil/types/array_test.go index 6e24e44..27e68cf 100644 --- a/boil/types/array_test.go +++ b/boil/types/array_test.go @@ -20,7 +20,6 @@ package types import ( - "bytes" "database/sql" "database/sql/driver" "math/rand" @@ -125,19 +124,6 @@ func TestArrayScanner(t *testing.T) { if _, ok := s.(*StringArray); !ok { t.Errorf("Expected *StringArray, got %T", s) } - - for _, tt := range []interface{}{ - &[]sql.Scanner{}, - &[][]bool{}, - &[][]float64{}, - &[][]int64{}, - &[][]string{}, - } { - s = Array(tt) - if _, ok := s.(GenericArray); !ok { - t.Errorf("Expected GenericArray for %T, got %T", tt, s) - } - } } func TestArrayValuer(t *testing.T) { @@ -162,20 +148,6 @@ func TestArrayValuer(t *testing.T) { if _, ok := v.(*StringArray); !ok { t.Errorf("Expected *StringArray, got %T", v) } - - for _, tt := range []interface{}{ - nil, - []driver.Value{}, - [][]bool{}, - [][]float64{}, - [][]int64{}, - [][]string{}, - } { - v = Array(tt) - if _, ok := v.(GenericArray); !ok { - t.Errorf("Expected GenericArray for %T, got %T", tt, v) - } - } } func TestBoolArrayScanUnsupported(t *testing.T) { @@ -826,300 +798,3 @@ func BenchmarkStringArrayValue(b *testing.B) { a.Value() } } - -func TestGenericArrayScanUnsupported(t *testing.T) { - var s string - var ss []string - - for _, tt := range []struct { - src, dest interface{} - err string - }{ - {nil, nil, "destination <nil> is not a pointer to array or slice"}, - {nil, true, "destination bool is not a pointer to array or slice"}, - {nil, &s, "destination *string is not a pointer to array or slice"}, - {nil, ss, "destination []string is not a pointer to array or slice"}, - {true, &ss, "bool to []string"}, - {`{{x}}`, &ss, "multidimensional ARRAY[1][1] is not implemented"}, - {`{{x},{x}}`, &ss, "multidimensional ARRAY[2][1] is not implemented"}, - {`{x}`, &ss, "scanning to string is not implemented"}, - } { - err := GenericArray{tt.dest}.Scan(tt.src) - - if err == nil { - t.Fatalf("Expected error for [%#v %#v]", tt.src, tt.dest) - } - if !strings.Contains(err.Error(), tt.err) { - t.Errorf("Expected error to contain %q for [%#v %#v], got %q", tt.err, tt.src, tt.dest, err) - } - } -} - -func TestGenericArrayScanScannerArrayBytes(t *testing.T) { - src, expected, nsa := []byte(`{NULL,abc,"\""}`), - [3]sql.NullString{{}, {String: `abc`, Valid: true}, {String: `"`, Valid: true}}, - [3]sql.NullString{{String: ``, Valid: true}, {}, {}} - - if err := (GenericArray{&nsa}).Scan(src); err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if !reflect.DeepEqual(nsa, expected) { - t.Errorf("Expected %v, got %v", expected, nsa) - } -} - -func TestGenericArrayScanScannerArrayString(t *testing.T) { - src, expected, nsa := `{NULL,"\"",xyz}`, - [3]sql.NullString{{}, {String: `"`, Valid: true}, {String: `xyz`, Valid: true}}, - [3]sql.NullString{{String: ``, Valid: true}, {}, {}} - - if err := (GenericArray{&nsa}).Scan(src); err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if !reflect.DeepEqual(nsa, expected) { - t.Errorf("Expected %v, got %v", expected, nsa) - } -} - -func TestGenericArrayScanScannerSliceBytes(t *testing.T) { - src, expected, nss := []byte(`{NULL,abc,"\""}`), - []sql.NullString{{}, {String: `abc`, Valid: true}, {String: `"`, Valid: true}}, - []sql.NullString{{String: ``, Valid: true}, {}, {}, {}, {}} - - if err := (GenericArray{&nss}).Scan(src); err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if !reflect.DeepEqual(nss, expected) { - t.Errorf("Expected %v, got %v", expected, nss) - } -} - -func BenchmarkGenericArrayScanScannerSliceBytes(b *testing.B) { - var a GenericArray - var x interface{} = []byte(`{a,b,c,d,e,f,g,h,i,j}`) - var y interface{} = []byte(`{"\a","\b","\c","\d","\e","\f","\g","\h","\i","\j"}`) - - for i := 0; i < b.N; i++ { - a = GenericArray{new([]sql.NullString)} - a.Scan(x) - a = GenericArray{new([]sql.NullString)} - a.Scan(y) - } -} - -func TestGenericArrayScanScannerSliceString(t *testing.T) { - src, expected, nss := `{NULL,"\"",xyz}`, - []sql.NullString{{}, {String: `"`, Valid: true}, {String: `xyz`, Valid: true}}, - []sql.NullString{{String: ``, Valid: true}, {}, {}} - - if err := (GenericArray{&nss}).Scan(src); err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if !reflect.DeepEqual(nss, expected) { - t.Errorf("Expected %v, got %v", expected, nss) - } -} - -type TildeNullInt64 struct{ sql.NullInt64 } - -func (TildeNullInt64) ArrayDelimiter() string { return "~" } - -func TestGenericArrayScanDelimiter(t *testing.T) { - src, expected, tnis := `{12~NULL~76}`, - []TildeNullInt64{{sql.NullInt64{Int64: 12, Valid: true}}, {}, {sql.NullInt64{Int64: 76, Valid: true}}}, - []TildeNullInt64{{sql.NullInt64{Int64: 0, Valid: true}}, {}} - - if err := (GenericArray{&tnis}).Scan(src); err != nil { - t.Fatalf("Expected no error for %#v, got %v", src, err) - } - if !reflect.DeepEqual(tnis, expected) { - t.Errorf("Expected %v for %#v, got %v", expected, src, tnis) - } -} - -func TestGenericArrayScanErrors(t *testing.T) { - var sa [1]string - var nis []sql.NullInt64 - var pss *[]string - - for _, tt := range []struct { - src, dest interface{} - err string - }{ - {nil, pss, "destination *[]string is nil"}, - {`{`, &sa, "unable to parse"}, - {`{}`, &sa, "cannot convert ARRAY[0] to [1]string"}, - {`{x,x}`, &sa, "cannot convert ARRAY[2] to [1]string"}, - {`{x}`, &nis, `parsing array element index 0: converting`}, - } { - err := GenericArray{tt.dest}.Scan(tt.src) - - if err == nil { - t.Fatalf("Expected error for [%#v %#v]", tt.src, tt.dest) - } - if !strings.Contains(err.Error(), tt.err) { - t.Errorf("Expected error to contain %q for [%#v %#v], got %q", tt.err, tt.src, tt.dest, err) - } - } -} - -func TestGenericArrayValueUnsupported(t *testing.T) { - _, err := GenericArray{true}.Value() - - if err == nil { - t.Fatal("Expected error for bool") - } - if !strings.Contains(err.Error(), "bool to array") { - t.Errorf("Expected type to be mentioned, got %q", err) - } -} - -type ByteArrayValuer [1]byte -type ByteSliceValuer []byte -type FuncArrayValuer struct { - delimiter func() string - value func() (driver.Value, error) -} - -func (a ByteArrayValuer) Value() (driver.Value, error) { return a[:], nil } -func (b ByteSliceValuer) Value() (driver.Value, error) { return []byte(b), nil } -func (f FuncArrayValuer) ArrayDelimiter() string { return f.delimiter() } -func (f FuncArrayValuer) Value() (driver.Value, error) { return f.value() } - -func TestGenericArrayValue(t *testing.T) { - result, err := GenericArray{nil}.Value() - - if err != nil { - t.Fatalf("Expected no error for nil, got %v", err) - } - if result != nil { - t.Errorf("Expected nil, got %q", result) - } - - Tilde := func(v driver.Value) FuncArrayValuer { - return FuncArrayValuer{ - func() string { return "~" }, - func() (driver.Value, error) { return v, nil }} - } - - for _, tt := range []struct { - result string - input interface{} - }{ - {`{}`, []bool{}}, - {`{true}`, []bool{true}}, - {`{true,false}`, []bool{true, false}}, - {`{true,false}`, [2]bool{true, false}}, - - {`{}`, [][]int{{}}}, - {`{}`, [][]int{{}, {}}}, - {`{{1}}`, [][]int{{1}}}, - {`{{1},{2}}`, [][]int{{1}, {2}}}, - {`{{1,2},{3,4}}`, [][]int{{1, 2}, {3, 4}}}, - {`{{1,2},{3,4}}`, [2][2]int{{1, 2}, {3, 4}}}, - - {`{"a","\\b","c\"","d,e"}`, []string{`a`, `\b`, `c"`, `d,e`}}, - {`{"a","\\b","c\"","d,e"}`, [][]byte{{'a'}, {'\\', 'b'}, {'c', '"'}, {'d', ',', 'e'}}}, - - {`{NULL}`, []*int{nil}}, - {`{0,NULL}`, []*int{new(int), nil}}, - - {`{NULL}`, []sql.NullString{{}}}, - {`{"\"",NULL}`, []sql.NullString{{String: `"`, Valid: true}, {}}}, - - {`{"a","b"}`, []ByteArrayValuer{{'a'}, {'b'}}}, - {`{{"a","b"},{"c","d"}}`, [][]ByteArrayValuer{{{'a'}, {'b'}}, {{'c'}, {'d'}}}}, - - {`{"e","f"}`, []ByteSliceValuer{{'e'}, {'f'}}}, - {`{{"e","f"},{"g","h"}}`, [][]ByteSliceValuer{{{'e'}, {'f'}}, {{'g'}, {'h'}}}}, - - {`{1~2}`, []FuncArrayValuer{Tilde(int64(1)), Tilde(int64(2))}}, - {`{{1~2}~{3~4}}`, [][]FuncArrayValuer{{Tilde(int64(1)), Tilde(int64(2))}, {Tilde(int64(3)), Tilde(int64(4))}}}, - } { - result, err := GenericArray{tt.input}.Value() - - if err != nil { - t.Fatalf("Expected no error for %q, got %v", tt.input, err) - } - if !reflect.DeepEqual(result, tt.result) { - t.Errorf("Expected %q for %q, got %q", tt.result, tt.input, result) - } - } -} - -func TestGenericArrayValueErrors(t *testing.T) { - var v []interface{} - - v = []interface{}{func() {}} - if _, err := (GenericArray{v}).Value(); err == nil { - t.Errorf("Expected error for %q, got nil", v) - } - - v = []interface{}{nil, func() {}} - if _, err := (GenericArray{v}).Value(); err == nil { - t.Errorf("Expected error for %q, got nil", v) - } -} - -func BenchmarkGenericArrayValueBools(b *testing.B) { - rand.Seed(1) - x := make([]bool, 10) - for i := 0; i < len(x); i++ { - x[i] = rand.Intn(2) == 0 - } - a := GenericArray{x} - - for i := 0; i < b.N; i++ { - a.Value() - } -} - -func BenchmarkGenericArrayValueFloat64s(b *testing.B) { - rand.Seed(1) - x := make([]float64, 10) - for i := 0; i < len(x); i++ { - x[i] = rand.NormFloat64() - } - a := GenericArray{x} - - for i := 0; i < b.N; i++ { - a.Value() - } -} - -func BenchmarkGenericArrayValueInt64s(b *testing.B) { - rand.Seed(1) - x := make([]int64, 10) - for i := 0; i < len(x); i++ { - x[i] = rand.Int63() - } - a := GenericArray{x} - - for i := 0; i < b.N; i++ { - a.Value() - } -} - -func BenchmarkGenericArrayValueByteSlices(b *testing.B) { - x := make([][]byte, 10) - for i := 0; i < len(x); i++ { - x[i] = bytes.Repeat([]byte(`abc"def\ghi`), 5) - } - a := GenericArray{x} - - for i := 0; i < b.N; i++ { - a.Value() - } -} - -func BenchmarkGenericArrayValueStrings(b *testing.B) { - x := make([]string, 10) - for i := 0; i < len(x); i++ { - x[i] = strings.Repeat(`abc"def\ghi`, 5) - } - a := GenericArray{x} - - for i := 0; i < b.N; i++ { - a.Value() - } -} diff --git a/imports.go b/imports.go index ced6daa..5fc0896 100644 --- a/imports.go +++ b/imports.go @@ -305,9 +305,6 @@ var importsBasedOnType = map[string]imports{ "types.BytesArray": { thirdParty: importList{`"github.com/vattle/sqlboiler/boil/types"`}, }, - "types.GenericArray": { - thirdParty: importList{`"github.com/vattle/sqlboiler/boil/types"`}, - }, "types.Int64Array": { thirdParty: importList{`"github.com/vattle/sqlboiler/boil/types"`}, }, diff --git a/testdata/test_schema.sql b/testdata/test_schema.sql index 9dd4953..14beeca 100644 --- a/testdata/test_schema.sql +++ b/testdata/test_schema.sql @@ -194,3 +194,22 @@ create table enemies ( enemies character varying, primary key (enemies) ); + +create table fun_arrays ( + id serial, + fun_one integer[] null, + fun_two integer[] not null, + fun_three boolean[] null, + fun_four boolean[] not null, + fun_five varchar[] null, + fun_six varchar[] not null, + fun_seven decimal[] null, + fun_eight decimal[] not null, + fun_nine bytea[] null, + fun_ten bytea[] not null, + fun_eleven jsonb[] null, + fun_twelve jsonb[] not null, + fun_thirteen json[] null, + fun_fourteen json[] not null, + primary key (id) +)