...

Text file src/github.com/jackc/pgtype/typed_array.go.erb

Documentation: github.com/jackc/pgtype

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

View as plain text