...

Source file src/github.com/jackc/pgtype/uuid_array.go

Documentation: github.com/jackc/pgtype

     1  // Code generated by erb. DO NOT EDIT.
     2  
     3  package pgtype
     4  
     5  import (
     6  	"database/sql/driver"
     7  	"encoding/binary"
     8  	"fmt"
     9  	"reflect"
    10  
    11  	"github.com/jackc/pgio"
    12  )
    13  
    14  type UUIDArray struct {
    15  	Elements   []UUID
    16  	Dimensions []ArrayDimension
    17  	Status     Status
    18  }
    19  
    20  func (dst *UUIDArray) Set(src interface{}) error {
    21  	// untyped nil and typed nil interfaces are different
    22  	if src == nil {
    23  		*dst = UUIDArray{Status: Null}
    24  		return nil
    25  	}
    26  
    27  	if value, ok := src.(interface{ Get() interface{} }); ok {
    28  		value2 := value.Get()
    29  		if value2 != value {
    30  			return dst.Set(value2)
    31  		}
    32  	}
    33  
    34  	// Attempt to match to select common types:
    35  	switch value := src.(type) {
    36  
    37  	case [][16]byte:
    38  		if value == nil {
    39  			*dst = UUIDArray{Status: Null}
    40  		} else if len(value) == 0 {
    41  			*dst = UUIDArray{Status: Present}
    42  		} else {
    43  			elements := make([]UUID, len(value))
    44  			for i := range value {
    45  				if err := elements[i].Set(value[i]); err != nil {
    46  					return err
    47  				}
    48  			}
    49  			*dst = UUIDArray{
    50  				Elements:   elements,
    51  				Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
    52  				Status:     Present,
    53  			}
    54  		}
    55  
    56  	case [][]byte:
    57  		if value == nil {
    58  			*dst = UUIDArray{Status: Null}
    59  		} else if len(value) == 0 {
    60  			*dst = UUIDArray{Status: Present}
    61  		} else {
    62  			elements := make([]UUID, len(value))
    63  			for i := range value {
    64  				if err := elements[i].Set(value[i]); err != nil {
    65  					return err
    66  				}
    67  			}
    68  			*dst = UUIDArray{
    69  				Elements:   elements,
    70  				Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
    71  				Status:     Present,
    72  			}
    73  		}
    74  
    75  	case []string:
    76  		if value == nil {
    77  			*dst = UUIDArray{Status: Null}
    78  		} else if len(value) == 0 {
    79  			*dst = UUIDArray{Status: Present}
    80  		} else {
    81  			elements := make([]UUID, len(value))
    82  			for i := range value {
    83  				if err := elements[i].Set(value[i]); err != nil {
    84  					return err
    85  				}
    86  			}
    87  			*dst = UUIDArray{
    88  				Elements:   elements,
    89  				Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
    90  				Status:     Present,
    91  			}
    92  		}
    93  
    94  	case []*string:
    95  		if value == nil {
    96  			*dst = UUIDArray{Status: Null}
    97  		} else if len(value) == 0 {
    98  			*dst = UUIDArray{Status: Present}
    99  		} else {
   100  			elements := make([]UUID, len(value))
   101  			for i := range value {
   102  				if err := elements[i].Set(value[i]); err != nil {
   103  					return err
   104  				}
   105  			}
   106  			*dst = UUIDArray{
   107  				Elements:   elements,
   108  				Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
   109  				Status:     Present,
   110  			}
   111  		}
   112  
   113  	case []UUID:
   114  		if value == nil {
   115  			*dst = UUIDArray{Status: Null}
   116  		} else if len(value) == 0 {
   117  			*dst = UUIDArray{Status: Present}
   118  		} else {
   119  			*dst = UUIDArray{
   120  				Elements:   value,
   121  				Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
   122  				Status:     Present,
   123  			}
   124  		}
   125  	default:
   126  		// Fallback to reflection if an optimised match was not found.
   127  		// The reflection is necessary for arrays and multidimensional slices,
   128  		// but it comes with a 20-50% performance penalty for large arrays/slices
   129  		reflectedValue := reflect.ValueOf(src)
   130  		if !reflectedValue.IsValid() || reflectedValue.IsZero() {
   131  			*dst = UUIDArray{Status: Null}
   132  			return nil
   133  		}
   134  
   135  		dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
   136  		if !ok {
   137  			return fmt.Errorf("cannot find dimensions of %v for UUIDArray", src)
   138  		}
   139  		if elementsLength == 0 {
   140  			*dst = UUIDArray{Status: Present}
   141  			return nil
   142  		}
   143  		if len(dimensions) == 0 {
   144  			if originalSrc, ok := underlyingSliceType(src); ok {
   145  				return dst.Set(originalSrc)
   146  			}
   147  			return fmt.Errorf("cannot convert %v to UUIDArray", src)
   148  		}
   149  
   150  		*dst = UUIDArray{
   151  			Elements:   make([]UUID, elementsLength),
   152  			Dimensions: dimensions,
   153  			Status:     Present,
   154  		}
   155  		elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
   156  		if err != nil {
   157  			// Maybe the target was one dimension too far, try again:
   158  			if len(dst.Dimensions) > 1 {
   159  				dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
   160  				elementsLength = 0
   161  				for _, dim := range dst.Dimensions {
   162  					if elementsLength == 0 {
   163  						elementsLength = int(dim.Length)
   164  					} else {
   165  						elementsLength *= int(dim.Length)
   166  					}
   167  				}
   168  				dst.Elements = make([]UUID, elementsLength)
   169  				elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
   170  				if err != nil {
   171  					return err
   172  				}
   173  			} else {
   174  				return err
   175  			}
   176  		}
   177  		if elementCount != len(dst.Elements) {
   178  			return fmt.Errorf("cannot convert %v to UUIDArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
   179  		}
   180  	}
   181  
   182  	return nil
   183  }
   184  
   185  func (dst *UUIDArray) setRecursive(value reflect.Value, index, dimension int) (int, error) {
   186  	switch value.Kind() {
   187  	case reflect.Array:
   188  		fallthrough
   189  	case reflect.Slice:
   190  		if len(dst.Dimensions) == dimension {
   191  			break
   192  		}
   193  
   194  		valueLen := value.Len()
   195  		if int32(valueLen) != dst.Dimensions[dimension].Length {
   196  			return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
   197  		}
   198  		for i := 0; i < valueLen; i++ {
   199  			var err error
   200  			index, err = dst.setRecursive(value.Index(i), index, dimension+1)
   201  			if err != nil {
   202  				return 0, err
   203  			}
   204  		}
   205  
   206  		return index, nil
   207  	}
   208  	if !value.CanInterface() {
   209  		return 0, fmt.Errorf("cannot convert all values to UUIDArray")
   210  	}
   211  	if err := dst.Elements[index].Set(value.Interface()); err != nil {
   212  		return 0, fmt.Errorf("%v in UUIDArray", err)
   213  	}
   214  	index++
   215  
   216  	return index, nil
   217  }
   218  
   219  func (dst UUIDArray) Get() interface{} {
   220  	switch dst.Status {
   221  	case Present:
   222  		return dst
   223  	case Null:
   224  		return nil
   225  	default:
   226  		return dst.Status
   227  	}
   228  }
   229  
   230  func (src *UUIDArray) AssignTo(dst interface{}) error {
   231  	switch src.Status {
   232  	case Present:
   233  		if len(src.Dimensions) <= 1 {
   234  			// Attempt to match to select common types:
   235  			switch v := dst.(type) {
   236  
   237  			case *[][16]byte:
   238  				*v = make([][16]byte, len(src.Elements))
   239  				for i := range src.Elements {
   240  					if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
   241  						return err
   242  					}
   243  				}
   244  				return nil
   245  
   246  			case *[][]byte:
   247  				*v = make([][]byte, len(src.Elements))
   248  				for i := range src.Elements {
   249  					if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
   250  						return err
   251  					}
   252  				}
   253  				return nil
   254  
   255  			case *[]string:
   256  				*v = make([]string, len(src.Elements))
   257  				for i := range src.Elements {
   258  					if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
   259  						return err
   260  					}
   261  				}
   262  				return nil
   263  
   264  			case *[]*string:
   265  				*v = make([]*string, len(src.Elements))
   266  				for i := range src.Elements {
   267  					if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
   268  						return err
   269  					}
   270  				}
   271  				return nil
   272  
   273  			}
   274  		}
   275  
   276  		// Try to convert to something AssignTo can use directly.
   277  		if nextDst, retry := GetAssignToDstType(dst); retry {
   278  			return src.AssignTo(nextDst)
   279  		}
   280  
   281  		// Fallback to reflection if an optimised match was not found.
   282  		// The reflection is necessary for arrays and multidimensional slices,
   283  		// but it comes with a 20-50% performance penalty for large arrays/slices
   284  		value := reflect.ValueOf(dst)
   285  		if value.Kind() == reflect.Ptr {
   286  			value = value.Elem()
   287  		}
   288  
   289  		switch value.Kind() {
   290  		case reflect.Array, reflect.Slice:
   291  		default:
   292  			return fmt.Errorf("cannot assign %T to %T", src, dst)
   293  		}
   294  
   295  		if len(src.Elements) == 0 {
   296  			if value.Kind() == reflect.Slice {
   297  				value.Set(reflect.MakeSlice(value.Type(), 0, 0))
   298  				return nil
   299  			}
   300  		}
   301  
   302  		elementCount, err := src.assignToRecursive(value, 0, 0)
   303  		if err != nil {
   304  			return err
   305  		}
   306  		if elementCount != len(src.Elements) {
   307  			return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
   308  		}
   309  
   310  		return nil
   311  	case Null:
   312  		return NullAssignTo(dst)
   313  	}
   314  
   315  	return fmt.Errorf("cannot decode %#v into %T", src, dst)
   316  }
   317  
   318  func (src *UUIDArray) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
   319  	switch kind := value.Kind(); kind {
   320  	case reflect.Array:
   321  		fallthrough
   322  	case reflect.Slice:
   323  		if len(src.Dimensions) == dimension {
   324  			break
   325  		}
   326  
   327  		length := int(src.Dimensions[dimension].Length)
   328  		if reflect.Array == kind {
   329  			typ := value.Type()
   330  			if typ.Len() != length {
   331  				return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
   332  			}
   333  			value.Set(reflect.New(typ).Elem())
   334  		} else {
   335  			value.Set(reflect.MakeSlice(value.Type(), length, length))
   336  		}
   337  
   338  		var err error
   339  		for i := 0; i < length; i++ {
   340  			index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
   341  			if err != nil {
   342  				return 0, err
   343  			}
   344  		}
   345  
   346  		return index, nil
   347  	}
   348  	if len(src.Dimensions) != dimension {
   349  		return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
   350  	}
   351  	if !value.CanAddr() {
   352  		return 0, fmt.Errorf("cannot assign all values from UUIDArray")
   353  	}
   354  	addr := value.Addr()
   355  	if !addr.CanInterface() {
   356  		return 0, fmt.Errorf("cannot assign all values from UUIDArray")
   357  	}
   358  	if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
   359  		return 0, err
   360  	}
   361  	index++
   362  	return index, nil
   363  }
   364  
   365  func (dst *UUIDArray) DecodeText(ci *ConnInfo, src []byte) error {
   366  	if src == nil {
   367  		*dst = UUIDArray{Status: Null}
   368  		return nil
   369  	}
   370  
   371  	uta, err := ParseUntypedTextArray(string(src))
   372  	if err != nil {
   373  		return err
   374  	}
   375  
   376  	var elements []UUID
   377  
   378  	if len(uta.Elements) > 0 {
   379  		elements = make([]UUID, len(uta.Elements))
   380  
   381  		for i, s := range uta.Elements {
   382  			var elem UUID
   383  			var elemSrc []byte
   384  			if s != "NULL" || uta.Quoted[i] {
   385  				elemSrc = []byte(s)
   386  			}
   387  			err = elem.DecodeText(ci, elemSrc)
   388  			if err != nil {
   389  				return err
   390  			}
   391  
   392  			elements[i] = elem
   393  		}
   394  	}
   395  
   396  	*dst = UUIDArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
   397  
   398  	return nil
   399  }
   400  
   401  func (dst *UUIDArray) DecodeBinary(ci *ConnInfo, src []byte) error {
   402  	if src == nil {
   403  		*dst = UUIDArray{Status: Null}
   404  		return nil
   405  	}
   406  
   407  	var arrayHeader ArrayHeader
   408  	rp, err := arrayHeader.DecodeBinary(ci, src)
   409  	if err != nil {
   410  		return err
   411  	}
   412  
   413  	if len(arrayHeader.Dimensions) == 0 {
   414  		*dst = UUIDArray{Dimensions: arrayHeader.Dimensions, Status: Present}
   415  		return nil
   416  	}
   417  
   418  	elementCount := arrayHeader.Dimensions[0].Length
   419  	for _, d := range arrayHeader.Dimensions[1:] {
   420  		elementCount *= d.Length
   421  	}
   422  
   423  	elements := make([]UUID, elementCount)
   424  
   425  	for i := range elements {
   426  		elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
   427  		rp += 4
   428  		var elemSrc []byte
   429  		if elemLen >= 0 {
   430  			elemSrc = src[rp : rp+elemLen]
   431  			rp += elemLen
   432  		}
   433  		err = elements[i].DecodeBinary(ci, elemSrc)
   434  		if err != nil {
   435  			return err
   436  		}
   437  	}
   438  
   439  	*dst = UUIDArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
   440  	return nil
   441  }
   442  
   443  func (src UUIDArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
   444  	switch src.Status {
   445  	case Null:
   446  		return nil, nil
   447  	case Undefined:
   448  		return nil, errUndefined
   449  	}
   450  
   451  	if len(src.Dimensions) == 0 {
   452  		return append(buf, '{', '}'), nil
   453  	}
   454  
   455  	buf = EncodeTextArrayDimensions(buf, src.Dimensions)
   456  
   457  	// dimElemCounts is the multiples of elements that each array lies on. For
   458  	// example, a single dimension array of length 4 would have a dimElemCounts of
   459  	// [4]. A multi-dimensional array of lengths [3,5,2] would have a
   460  	// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
   461  	// or '}'.
   462  	dimElemCounts := make([]int, len(src.Dimensions))
   463  	dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
   464  	for i := len(src.Dimensions) - 2; i > -1; i-- {
   465  		dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
   466  	}
   467  
   468  	inElemBuf := make([]byte, 0, 32)
   469  	for i, elem := range src.Elements {
   470  		if i > 0 {
   471  			buf = append(buf, ',')
   472  		}
   473  
   474  		for _, dec := range dimElemCounts {
   475  			if i%dec == 0 {
   476  				buf = append(buf, '{')
   477  			}
   478  		}
   479  
   480  		elemBuf, err := elem.EncodeText(ci, inElemBuf)
   481  		if err != nil {
   482  			return nil, err
   483  		}
   484  		if elemBuf == nil {
   485  			buf = append(buf, `NULL`...)
   486  		} else {
   487  			buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
   488  		}
   489  
   490  		for _, dec := range dimElemCounts {
   491  			if (i+1)%dec == 0 {
   492  				buf = append(buf, '}')
   493  			}
   494  		}
   495  	}
   496  
   497  	return buf, nil
   498  }
   499  
   500  func (src UUIDArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
   501  	switch src.Status {
   502  	case Null:
   503  		return nil, nil
   504  	case Undefined:
   505  		return nil, errUndefined
   506  	}
   507  
   508  	arrayHeader := ArrayHeader{
   509  		Dimensions: src.Dimensions,
   510  	}
   511  
   512  	if dt, ok := ci.DataTypeForName("uuid"); ok {
   513  		arrayHeader.ElementOID = int32(dt.OID)
   514  	} else {
   515  		return nil, fmt.Errorf("unable to find oid for type name %v", "uuid")
   516  	}
   517  
   518  	for i := range src.Elements {
   519  		if src.Elements[i].Status == Null {
   520  			arrayHeader.ContainsNull = true
   521  			break
   522  		}
   523  	}
   524  
   525  	buf = arrayHeader.EncodeBinary(ci, buf)
   526  
   527  	for i := range src.Elements {
   528  		sp := len(buf)
   529  		buf = pgio.AppendInt32(buf, -1)
   530  
   531  		elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
   532  		if err != nil {
   533  			return nil, err
   534  		}
   535  		if elemBuf != nil {
   536  			buf = elemBuf
   537  			pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
   538  		}
   539  	}
   540  
   541  	return buf, nil
   542  }
   543  
   544  // Scan implements the database/sql Scanner interface.
   545  func (dst *UUIDArray) Scan(src interface{}) error {
   546  	if src == nil {
   547  		return dst.DecodeText(nil, nil)
   548  	}
   549  
   550  	switch src := src.(type) {
   551  	case string:
   552  		return dst.DecodeText(nil, []byte(src))
   553  	case []byte:
   554  		srcCopy := make([]byte, len(src))
   555  		copy(srcCopy, src)
   556  		return dst.DecodeText(nil, srcCopy)
   557  	}
   558  
   559  	return fmt.Errorf("cannot scan %T", src)
   560  }
   561  
   562  // Value implements the database/sql/driver Valuer interface.
   563  func (src UUIDArray) Value() (driver.Value, error) {
   564  	buf, err := src.EncodeText(nil, nil)
   565  	if err != nil {
   566  		return nil, err
   567  	}
   568  	if buf == nil {
   569  		return nil, nil
   570  	}
   571  
   572  	return string(buf), nil
   573  }
   574  

View as plain text