...

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

Documentation: github.com/jackc/pgtype

     1  package pgtype
     2  
     3  import "fmt"
     4  
     5  // EnumType represents an enum type. While it implements Value, this is only in service of its type conversion duties
     6  // when registered as a data type in a ConnType. It should not be used directly as a Value.
     7  type EnumType struct {
     8  	value  string
     9  	status Status
    10  
    11  	typeName   string            // PostgreSQL type name
    12  	members    []string          // enum members
    13  	membersMap map[string]string // map to quickly lookup member and reuse string instead of allocating
    14  }
    15  
    16  // NewEnumType initializes a new EnumType. It retains a read-only reference to members. members must not be changed.
    17  func NewEnumType(typeName string, members []string) *EnumType {
    18  	et := &EnumType{typeName: typeName, members: members}
    19  	et.membersMap = make(map[string]string, len(members))
    20  	for _, m := range members {
    21  		et.membersMap[m] = m
    22  	}
    23  	return et
    24  }
    25  
    26  func (et *EnumType) NewTypeValue() Value {
    27  	return &EnumType{
    28  		value:  et.value,
    29  		status: et.status,
    30  
    31  		typeName:   et.typeName,
    32  		members:    et.members,
    33  		membersMap: et.membersMap,
    34  	}
    35  }
    36  
    37  func (et *EnumType) TypeName() string {
    38  	return et.typeName
    39  }
    40  
    41  func (et *EnumType) Members() []string {
    42  	return et.members
    43  }
    44  
    45  // Set assigns src to dst. Set purposely does not check that src is a member. This allows continued error free
    46  // operation in the event the PostgreSQL enum type is modified during a connection.
    47  func (dst *EnumType) Set(src interface{}) error {
    48  	if src == nil {
    49  		dst.status = Null
    50  		return nil
    51  	}
    52  
    53  	if value, ok := src.(interface{ Get() interface{} }); ok {
    54  		value2 := value.Get()
    55  		if value2 != value {
    56  			return dst.Set(value2)
    57  		}
    58  	}
    59  
    60  	switch value := src.(type) {
    61  	case string:
    62  		dst.value = value
    63  		dst.status = Present
    64  	case *string:
    65  		if value == nil {
    66  			dst.status = Null
    67  		} else {
    68  			dst.value = *value
    69  			dst.status = Present
    70  		}
    71  	case []byte:
    72  		if value == nil {
    73  			dst.status = Null
    74  		} else {
    75  			dst.value = string(value)
    76  			dst.status = Present
    77  		}
    78  	default:
    79  		if originalSrc, ok := underlyingStringType(src); ok {
    80  			return dst.Set(originalSrc)
    81  		}
    82  		return fmt.Errorf("cannot convert %v to enum %s", value, dst.typeName)
    83  	}
    84  
    85  	return nil
    86  }
    87  
    88  func (dst EnumType) Get() interface{} {
    89  	switch dst.status {
    90  	case Present:
    91  		return dst.value
    92  	case Null:
    93  		return nil
    94  	default:
    95  		return dst.status
    96  	}
    97  }
    98  
    99  func (src *EnumType) AssignTo(dst interface{}) error {
   100  	switch src.status {
   101  	case Present:
   102  		switch v := dst.(type) {
   103  		case *string:
   104  			*v = src.value
   105  			return nil
   106  		case *[]byte:
   107  			*v = make([]byte, len(src.value))
   108  			copy(*v, src.value)
   109  			return nil
   110  		default:
   111  			if nextDst, retry := GetAssignToDstType(dst); retry {
   112  				return src.AssignTo(nextDst)
   113  			}
   114  			return fmt.Errorf("unable to assign to %T", dst)
   115  		}
   116  	case Null:
   117  		return NullAssignTo(dst)
   118  	}
   119  
   120  	return fmt.Errorf("cannot decode %#v into %T", src, dst)
   121  }
   122  
   123  func (EnumType) PreferredResultFormat() int16 {
   124  	return TextFormatCode
   125  }
   126  
   127  func (dst *EnumType) DecodeText(ci *ConnInfo, src []byte) error {
   128  	if src == nil {
   129  		dst.status = Null
   130  		return nil
   131  	}
   132  
   133  	// Lookup the string in membersMap to avoid an allocation.
   134  	if s, found := dst.membersMap[string(src)]; found {
   135  		dst.value = s
   136  	} else {
   137  		// If an enum type is modified after the initial connection it is possible to receive an unexpected value.
   138  		// Gracefully handle this situation. Purposely NOT modifying members and membersMap to allow for sharing members
   139  		// and membersMap between connections.
   140  		dst.value = string(src)
   141  	}
   142  	dst.status = Present
   143  
   144  	return nil
   145  }
   146  
   147  func (dst *EnumType) DecodeBinary(ci *ConnInfo, src []byte) error {
   148  	return dst.DecodeText(ci, src)
   149  }
   150  
   151  func (EnumType) PreferredParamFormat() int16 {
   152  	return TextFormatCode
   153  }
   154  
   155  func (src EnumType) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
   156  	switch src.status {
   157  	case Null:
   158  		return nil, nil
   159  	case Undefined:
   160  		return nil, errUndefined
   161  	}
   162  
   163  	return append(buf, src.value...), nil
   164  }
   165  
   166  func (src EnumType) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
   167  	return src.EncodeText(ci, buf)
   168  }
   169  

View as plain text