github.com/aacfactory/fns-contrib/databases/sql@v1.2.84/dac/specifications/column.go (about)

     1  package specifications
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"github.com/aacfactory/errors"
     7  	"github.com/aacfactory/fns-contrib/databases/sql/dac/orders"
     8  	"reflect"
     9  	"strconv"
    10  	"strings"
    11  )
    12  
    13  const (
    14  	columnTag       = "column"
    15  	discardTagValue = "-"
    16  )
    17  
    18  const (
    19  	pkColumn        = "pk"
    20  	incrColumn      = "incr"
    21  	jsonColumn      = "json"
    22  	acbColumn       = "acb"
    23  	actColumn       = "act"
    24  	ambColumn       = "amb"
    25  	amtColumn       = "amt"
    26  	adbColumn       = "adb"
    27  	adtColumn       = "adt"
    28  	aolColumn       = "aol"
    29  	virtualColumn   = "vc"
    30  	referenceColumn = "ref"
    31  	linkColumn      = "link"
    32  	linksColumn     = "links"
    33  )
    34  
    35  const (
    36  	UnknownVirtualQueryKind VirtualQueryKind = iota
    37  	BasicVirtualQuery
    38  	ObjectVirtualQuery
    39  	ArrayVirtualQuery
    40  	AggregateVirtualQuery
    41  )
    42  
    43  type VirtualQueryKind int
    44  
    45  const (
    46  	Normal    ColumnKind = iota // column
    47  	Pk                          // column,pk{,incr}
    48  	Acb                         // column,acb
    49  	Act                         // column,act
    50  	Amb                         // column,amb
    51  	Amt                         // column,amt
    52  	Adb                         // column,adb
    53  	Adt                         // column,adt
    54  	Aol                         // column,aol
    55  	Json                        // column,json
    56  	Virtual                     // ident,vc,basic|object|array|aggregate,query|agg_func
    57  	Reference                   // column,ref,target_field
    58  	Link                        // ident,link,field+target_field
    59  	Links                       // column,links,field+target_field,orders:field@desc+field,length:10
    60  )
    61  
    62  type ColumnKind int
    63  
    64  func (kind ColumnKind) String() string {
    65  	switch kind {
    66  	case Normal:
    67  		return "normal"
    68  	case Pk:
    69  		return "pk"
    70  	case Acb:
    71  		return "acb"
    72  	case Act:
    73  		return "act"
    74  	case Amb:
    75  		return "amb"
    76  	case Amt:
    77  		return "amt"
    78  	case Adb:
    79  		return "adb"
    80  	case Adt:
    81  		return "adt"
    82  	case Aol:
    83  		return "aol"
    84  	case Json:
    85  		return "json"
    86  	case Virtual:
    87  		return "virtual"
    88  	case Reference:
    89  		return "reference"
    90  	case Link:
    91  		return "link"
    92  	case Links:
    93  		return "links"
    94  	}
    95  	return "???"
    96  }
    97  
    98  const (
    99  	UnknownType ColumnTypeName = iota
   100  	StringType
   101  	BoolType
   102  	IntType
   103  	FloatType
   104  	DatetimeType
   105  	DateType
   106  	TimeType
   107  	BytesType
   108  	ByteType
   109  	JsonType
   110  	ScanType
   111  	MappingType
   112  )
   113  
   114  type ColumnTypeName int
   115  
   116  type ColumnType struct {
   117  	Name    ColumnTypeName
   118  	Value   reflect.Type
   119  	Mapping *Specification
   120  	Options []string
   121  }
   122  
   123  func (ct *ColumnType) String() string {
   124  	switch ct.Name {
   125  	case UnknownType:
   126  		return "unknown"
   127  	case StringType:
   128  		return "string"
   129  	case BoolType:
   130  		return "bool"
   131  	case IntType:
   132  		return "int"
   133  	case FloatType:
   134  		return "float"
   135  	case DatetimeType:
   136  		return "datetime"
   137  	case DateType:
   138  		return "date"
   139  	case TimeType:
   140  		return "time"
   141  	case ByteType:
   142  		return "byte"
   143  	case BytesType:
   144  		return "bytes"
   145  	case JsonType:
   146  		return "json"
   147  	case ScanType:
   148  		return "scan"
   149  	case MappingType:
   150  		return fmt.Sprintf("mapping(%s, %s)", ct.Mapping.Key, fmt.Sprintf("%+v", ct.Options))
   151  	}
   152  	return "???"
   153  }
   154  
   155  // Column
   156  // 'column:"{name},{kind},{options}"'
   157  type Column struct {
   158  	FieldIdx    []int
   159  	Field       string
   160  	Name        string
   161  	JsonIdent   string
   162  	Kind        ColumnKind
   163  	Type        ColumnType
   164  	ValueWriter ValueWriter
   165  }
   166  
   167  func (column *Column) Incr() bool {
   168  	if len(column.Type.Options) > 0 {
   169  		return column.Type.Options[0] == incrColumn
   170  	}
   171  	return false
   172  }
   173  
   174  func (column *Column) Virtual() (kind VirtualQueryKind, query string, ok bool) {
   175  	if column.Kind == Virtual {
   176  		switch column.Type.Options[0] {
   177  		case "basic":
   178  			kind = BasicVirtualQuery
   179  		case "object":
   180  			kind = ObjectVirtualQuery
   181  		case "array":
   182  			kind = ArrayVirtualQuery
   183  			break
   184  		case "agg", "aggregate":
   185  			kind = AggregateVirtualQuery
   186  			break
   187  		default:
   188  			kind = UnknownVirtualQueryKind
   189  			break
   190  		}
   191  		query = column.Type.Options[1]
   192  		ok = true
   193  	}
   194  	return
   195  }
   196  
   197  func (column *Column) Reference() (awayField string, mapping *Specification, ok bool) {
   198  	ok = column.Kind == Reference
   199  	if ok {
   200  		awayField = column.Type.Options[0]
   201  		mapping = column.Type.Mapping
   202  	}
   203  	return
   204  }
   205  
   206  func (column *Column) Link() (hostField string, awayField string, mapping *Specification, ok bool) {
   207  	ok = column.Kind == Link
   208  	if ok {
   209  		hostField = column.Type.Options[0]
   210  		awayField = column.Type.Options[1]
   211  		mapping = column.Type.Mapping
   212  	}
   213  	return
   214  }
   215  
   216  func (column *Column) Links() (hostField string, awayField string, mapping *Specification, order orders.Orders, length int, ok bool) {
   217  	ok = column.Kind == Links
   218  	if ok {
   219  		hostField = column.Type.Options[0]
   220  		awayField = column.Type.Options[1]
   221  		mapping = column.Type.Mapping
   222  		if optLen := len(column.Type.Options); optLen > 2 {
   223  			for i := 2; i < optLen; i++ {
   224  				option := strings.TrimSpace(column.Type.Options[i])
   225  				// orders:
   226  				if idx := strings.Index(strings.ToLower(option), "orders:"); idx == 0 {
   227  					option = option[7:]
   228  					items := strings.Split(option, "+")
   229  					for _, item := range items {
   230  						item = strings.TrimSpace(item)
   231  						pos := strings.IndexByte(item, '@')
   232  						if pos == -1 {
   233  							order = orders.Asc(item)
   234  						} else {
   235  							field := strings.TrimSpace(item[0:pos])
   236  							kind := strings.ToLower(strings.TrimSpace(item[pos+1:]))
   237  							if kind == "desc" {
   238  								order = orders.Desc(field)
   239  							} else {
   240  								order = orders.Asc(field)
   241  							}
   242  						}
   243  					}
   244  				}
   245  				// length:
   246  				if idx := strings.Index(strings.ToLower(option), "length:"); idx == 0 {
   247  					option = strings.TrimSpace(option[7:])
   248  					length, _ = strconv.Atoi(option)
   249  				}
   250  			}
   251  		}
   252  	}
   253  	return
   254  }
   255  
   256  func (column *Column) Valid() bool {
   257  	if column.Type.Name == UnknownType {
   258  		return false
   259  	}
   260  	if column.Incr() {
   261  		return column.Type.Name == IntType
   262  	}
   263  	ok := false
   264  	switch column.Kind {
   265  	case Acb, Amb, Adb:
   266  		ok = column.Type.Name == IntType || column.Type.Name == StringType
   267  		break
   268  	case Act, Amt, Adt:
   269  		ok = column.Type.Name == DatetimeType || column.Type.Name == IntType
   270  		break
   271  	case Aol:
   272  		ok = column.Type.Name == IntType
   273  		break
   274  	case Reference, Link:
   275  		ok = column.Type.Value.Kind() == reflect.Struct ||
   276  			(column.Type.Value.Kind() == reflect.Ptr && column.Type.Value.Elem().Kind() == reflect.Struct)
   277  		break
   278  	case Links:
   279  		ok = column.Type.Value.Kind() == reflect.Slice &&
   280  			(column.Type.Value.Elem().Kind() == reflect.Struct ||
   281  				(column.Type.Value.Elem().Kind() == reflect.Ptr && column.Type.Value.Elem().Elem().Kind() == reflect.Struct))
   282  		break
   283  	default:
   284  		if column.Incr() {
   285  			ok = column.Type.Name == IntType
   286  			break
   287  		}
   288  		ok = true
   289  		break
   290  	}
   291  	return ok
   292  }
   293  
   294  func (column *Column) String() (s string) {
   295  	kind := column.Kind.String()
   296  	if column.Kind == Virtual {
   297  		kind = kind + fmt.Sprintf("(%+v)", column.Type.Options)
   298  	} else if column.Kind == Json {
   299  		if column.Type.Value.ConvertibleTo(bytesType) {
   300  			kind = kind + "(bytes)"
   301  		} else {
   302  			kind = kind + fmt.Sprintf("(%s)", column.Type.Value.String())
   303  		}
   304  	}
   305  	s = fmt.Sprintf(
   306  		"%s => field:%s, kind: %s, type: %s",
   307  		column.Name,
   308  		column.Field,
   309  		kind, column.Type.String(),
   310  	)
   311  	return
   312  }
   313  
   314  func (column *Column) WriteValue(field reflect.Value, value any) (err error) {
   315  	err = column.ValueWriter.Write(value, field)
   316  	return
   317  }
   318  
   319  func (column *Column) ReadValue(sv reflect.Value) (fv reflect.Value) {
   320  	for i := len(column.FieldIdx) - 1; i > -1; i-- {
   321  		sv = sv.Field(column.FieldIdx[i])
   322  	}
   323  	fv = sv
   324  	return
   325  }
   326  
   327  func newColumn(ctx context.Context, rt reflect.StructField, idx []int) (column *Column, err error) {
   328  	tag, hasTag := rt.Tag.Lookup(columnTag)
   329  	if !hasTag {
   330  		return
   331  	}
   332  	tag = strings.TrimSpace(tag)
   333  	if tag == discardTagValue {
   334  		return
   335  	}
   336  	var vw ValueWriter
   337  	kind := Normal
   338  	typ := ColumnType{
   339  		Name:    UnknownType,
   340  		Value:   rt.Type,
   341  		Mapping: nil,
   342  		Options: make([]string, 0, 1),
   343  	}
   344  	items := strings.Split(tag, ",")
   345  
   346  	name := strings.TrimSpace(items[0])
   347  	if len(items) > 1 {
   348  		items = items[1:]
   349  		kv := strings.ToLower(strings.TrimSpace(items[0]))
   350  		switch kv {
   351  		case pkColumn:
   352  			kind = Pk
   353  			if len(items) > 1 {
   354  				if strings.ToLower(items[1]) == incrColumn {
   355  					switch rt.Type.Kind() {
   356  					case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   357  						vw = &IntValue{}
   358  						break
   359  					default:
   360  						err = errors.Warning("sql: type of incr pk column failed must be int64").WithMeta("field", rt.Name)
   361  						return
   362  					}
   363  					typ.Name = IntType
   364  					typ.Options = append(typ.Options, incrColumn)
   365  				}
   366  			}
   367  			if typ.Name == UnknownType {
   368  				switch rt.Type.Kind() {
   369  				case reflect.String:
   370  					typ.Name = StringType
   371  					vw = &StringValue{}
   372  					break
   373  				case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   374  					typ.Name = IntType
   375  					vw = &IntValue{}
   376  					break
   377  				default:
   378  					err = errors.Warning("sql: type of pk column failed must be int64 or string").WithMeta("field", rt.Name)
   379  					return
   380  				}
   381  			}
   382  			break
   383  		case acbColumn:
   384  			kind = Acb
   385  			vw, typ.Name, err = NewBasicValueWriter(rt.Type)
   386  			if err != nil {
   387  				err = errors.Warning("sql: type of acb column failed must be int64 or string").WithCause(err).WithMeta("field", rt.Name)
   388  				return
   389  			}
   390  			if typ.Name != StringType && typ.Name != IntType {
   391  				err = errors.Warning("sql: type of acb column failed must be int64 or string").WithMeta("field", rt.Name)
   392  				return
   393  			}
   394  			break
   395  		case actColumn:
   396  			kind = Act
   397  			vw, typ.Name, err = NewBasicValueWriter(rt.Type)
   398  			if err != nil {
   399  				err = errors.Warning("sql: type of act column failed must be time.Time or int64").WithCause(err).WithMeta("field", rt.Name)
   400  				return
   401  			}
   402  			if typ.Name != DatetimeType && typ.Name != IntType {
   403  				err = errors.Warning("sql: type of act column failed must be time.Time or int64").WithMeta("field", rt.Name)
   404  				return
   405  			}
   406  			break
   407  		case ambColumn:
   408  			kind = Amb
   409  			vw, typ.Name, err = NewBasicValueWriter(rt.Type)
   410  			if err != nil {
   411  				err = errors.Warning("sql: type of amb column failed must be int64 or string").WithCause(err).WithMeta("field", rt.Name)
   412  				return
   413  			}
   414  			if typ.Name != StringType && typ.Name != IntType {
   415  				err = errors.Warning("sql: type of amb column failed must be int64 or string").WithMeta("field", rt.Name)
   416  				return
   417  			}
   418  			break
   419  		case amtColumn:
   420  			kind = Amt
   421  			vw, typ.Name, err = NewBasicValueWriter(rt.Type)
   422  			if err != nil {
   423  				err = errors.Warning("sql: type of amt column failed must be time.Time or int64").WithCause(err).WithMeta("field", rt.Name)
   424  				return
   425  			}
   426  			if typ.Name != DatetimeType && typ.Name != IntType {
   427  				err = errors.Warning("sql: type of amt column failed must be time.Time or int64").WithMeta("field", rt.Name)
   428  				return
   429  			}
   430  			break
   431  		case adbColumn:
   432  			kind = Adb
   433  			vw, typ.Name, err = NewBasicValueWriter(rt.Type)
   434  			if err != nil {
   435  				err = errors.Warning("sql: type of adb column failed must be int64 or string").WithCause(err).WithMeta("field", rt.Name)
   436  				return
   437  			}
   438  			if typ.Name != StringType && typ.Name != IntType {
   439  				err = errors.Warning("sql: type of adb column failed must be int64 or string").WithMeta("field", rt.Name)
   440  				return
   441  			}
   442  			break
   443  		case adtColumn:
   444  			kind = Adt
   445  			vw, typ.Name, err = NewBasicValueWriter(rt.Type)
   446  			if err != nil {
   447  				err = errors.Warning("sql: type of adt column failed must be time.Time or int64").WithCause(err).WithMeta("field", rt.Name)
   448  				return
   449  			}
   450  			if typ.Name != DatetimeType && typ.Name != IntType {
   451  				err = errors.Warning("sql: type of adt column failed must be time.Time or int64").WithMeta("field", rt.Name)
   452  				return
   453  			}
   454  			break
   455  		case aolColumn:
   456  			kind = Aol
   457  			if rt.Type.Kind() == reflect.Int64 {
   458  				typ.Name = IntType
   459  				vw = &IntValue{}
   460  			} else {
   461  				err = errors.Warning("sql: type of aol column failed must be int64").WithMeta("field", rt.Name)
   462  				return
   463  			}
   464  			break
   465  		case incrColumn:
   466  			if rt.Type.Kind() == reflect.Int64 {
   467  				typ.Name = IntType
   468  				vw = &IntValue{}
   469  			} else {
   470  				err = errors.Warning("sql: type of incr column failed must be int64").WithMeta("field", rt.Name)
   471  				return
   472  			}
   473  			typ.Options = append(typ.Options, incrColumn)
   474  		case jsonColumn:
   475  			kind = Json
   476  			typ.Name = JsonType
   477  			vw = &JsonValue{
   478  				ValueType: rt.Type,
   479  			}
   480  			break
   481  		case virtualColumn:
   482  			if len(items) < 3 {
   483  				err = errors.Warning("sql: scan virtual column failed, kind and query are required").WithMeta("field", rt.Name)
   484  				return
   485  			}
   486  			kind = Virtual
   487  			vck := strings.ToLower(strings.TrimSpace(items[1]))
   488  			valid := vck == "basic" || vck == "object" || vck == "array" || vck == "agg" || vck == "aggregate"
   489  			if !valid {
   490  				err = errors.Warning("sql: scan virtual column failed, kind is invalid").WithMeta("field", rt.Name)
   491  				return
   492  			}
   493  			typ.Options = append(typ.Options, vck, strings.TrimSpace(items[2]))
   494  			if vck == "object" || vck == "array" {
   495  				typ.Name = JsonType
   496  				vw = &JsonValue{
   497  					ValueType: rt.Type,
   498  				}
   499  			} else {
   500  				vw, typ.Name, err = NewBasicValueWriter(rt.Type)
   501  				if err != nil {
   502  					err = errors.Warning("sql: scan virtual column failed, kind is invalid").WithCause(err).WithMeta("field", rt.Name)
   503  					return
   504  				}
   505  			}
   506  			break
   507  		case referenceColumn:
   508  			if len(items) < 2 {
   509  				err = errors.Warning("sql: scan reference column failed, mapping is required").WithMeta("field", rt.Name)
   510  				return
   511  			}
   512  			kind = Reference
   513  			typ.Options = append(typ.Options, strings.TrimSpace(items[1]))
   514  			typ.Name = MappingType
   515  			vw = &MappingValue{
   516  				ValueType: rt.Type,
   517  			}
   518  			switch rt.Type.Kind() {
   519  			case reflect.Struct:
   520  				typ.Mapping, err = GetSpecification(ctx, reflect.Zero(rt.Type).Interface())
   521  				if err != nil {
   522  					err = errors.Warning("sql: scan reference column failed").WithMeta("field", rt.Name).WithCause(fmt.Errorf("reference column type must be implement Table")).WithCause(err)
   523  					return
   524  				}
   525  				break
   526  			case reflect.Ptr:
   527  				typ.Mapping, err = GetSpecification(ctx, reflect.Zero(rt.Type.Elem()).Interface())
   528  				if err != nil {
   529  					err = errors.Warning("sql: scan reference column failed").WithMeta("field", rt.Name).WithCause(fmt.Errorf("reference column type must be implement Table")).WithCause(err)
   530  					return
   531  				}
   532  				break
   533  			default:
   534  				err = errors.Warning("sql: scan reference column failed").WithMeta("field", rt.Name).WithCause(fmt.Errorf("reference column type must be struct or ptr struct"))
   535  				return
   536  			}
   537  			break
   538  		case linkColumn:
   539  			if len(items) < 2 {
   540  				err = errors.Warning("sql: scan link column failed, mapping is required").WithMeta("field", rt.Name)
   541  				return
   542  			}
   543  
   544  			mr := strings.Split(items[1], "+")
   545  			if len(mr) != 2 {
   546  				err = errors.Warning("sql: scan link column failed, mapping is invalid").WithMeta("field", rt.Name)
   547  				return
   548  			}
   549  
   550  			kind = Link
   551  			typ.Options = append(typ.Options, strings.TrimSpace(mr[0]))
   552  			typ.Options = append(typ.Options, strings.TrimSpace(mr[1]))
   553  
   554  			typ.Name = MappingType
   555  			vw = &MappingValue{
   556  				ValueType: rt.Type,
   557  			}
   558  			switch rt.Type.Kind() {
   559  			case reflect.Struct:
   560  				typ.Mapping, err = GetSpecification(ctx, reflect.Zero(rt.Type).Interface())
   561  				if err != nil {
   562  					err = errors.Warning("sql: scan link column failed").WithMeta("field", rt.Name).WithCause(fmt.Errorf("link column type must be implement Table")).WithCause(err)
   563  					return
   564  				}
   565  				break
   566  			case reflect.Ptr:
   567  				typ.Mapping, err = GetSpecification(ctx, reflect.Zero(rt.Type.Elem()).Interface())
   568  				if err != nil {
   569  					err = errors.Warning("sql: scan link column failed").WithMeta("field", rt.Name).WithCause(fmt.Errorf("link column type must be implement Table")).WithCause(err)
   570  					return
   571  				}
   572  				break
   573  			default:
   574  				err = errors.Warning("sql: scan link column failed").WithMeta("field", rt.Name).WithCause(fmt.Errorf("link column type must be struct or ptr struct"))
   575  				return
   576  			}
   577  			break
   578  		case linksColumn:
   579  			if len(items) < 2 {
   580  				err = errors.Warning("sql: scan links column failed, mapping is required").WithMeta("field", rt.Name)
   581  				return
   582  			}
   583  			mr := strings.Split(items[1], "+")
   584  			if len(mr) != 2 {
   585  				err = errors.Warning("sql: scan links column failed, mapping is invalid").WithMeta("field", rt.Name)
   586  				return
   587  			}
   588  
   589  			kind = Links
   590  			typ.Options = append(typ.Options, strings.TrimSpace(mr[0]))
   591  			typ.Options = append(typ.Options, strings.TrimSpace(mr[1]))
   592  
   593  			if len(items) > 2 {
   594  				typ.Options = append(typ.Options, items[2:]...)
   595  			}
   596  
   597  			typ.Name = MappingType
   598  			vw = &MappingValue{
   599  				ValueType: rt.Type,
   600  			}
   601  			if rt.Type.Kind() != reflect.Slice {
   602  				err = errors.Warning("sql: scan links column failed").WithMeta("field", rt.Name).WithCause(fmt.Errorf("links column type must be slice struct or slice ptr struct"))
   603  				return
   604  			}
   605  			switch rt.Type.Elem().Kind() {
   606  			case reflect.Struct:
   607  				typ.Mapping, err = GetSpecification(ctx, reflect.Zero(rt.Type.Elem()).Interface())
   608  				if err != nil {
   609  					err = errors.Warning("sql: scan links column failed").WithMeta("field", rt.Name).WithCause(fmt.Errorf("links column type must be implement Table")).WithCause(err)
   610  					return
   611  				}
   612  				break
   613  			case reflect.Ptr:
   614  				typ.Mapping, err = GetSpecification(ctx, reflect.Zero(rt.Type.Elem().Elem()).Interface())
   615  				if err != nil {
   616  					err = errors.Warning("sql: scan links column failed").WithMeta("field", rt.Name).WithCause(fmt.Errorf("links column type must be implement Table")).WithCause(err)
   617  					return
   618  				}
   619  				break
   620  			default:
   621  				err = errors.Warning("sql: scan links column failed").WithMeta("field", rt.Name).WithCause(fmt.Errorf("links column type must be struct or ptr struct"))
   622  				return
   623  			}
   624  			break
   625  		default:
   626  			err = errors.Warning("sql: unknown column options").WithMeta("field", rt.Name).WithMeta("tag", tag)
   627  			return
   628  		}
   629  	}
   630  	if typ.Name == UnknownType {
   631  		if rt.Type.ConvertibleTo(scannerType) && rt.Type.ConvertibleTo(jsonMarshalerType) {
   632  			vw = &ScanValue{}
   633  			typ.Name = ScanType
   634  		} else {
   635  			vw, typ.Name, err = NewBasicValueWriter(rt.Type)
   636  			if err != nil {
   637  				err = errors.Warning("sql: invalid column").WithCause(err).WithMeta("field", rt.Name).WithMeta("tag", tag)
   638  				return
   639  			}
   640  		}
   641  	}
   642  
   643  	// json
   644  	jsonTag, hasJsonTag := rt.Tag.Lookup(jsonColumn)
   645  	if hasJsonTag {
   646  		if idx := strings.IndexByte(jsonTag, ','); idx > 0 {
   647  			jsonTag = jsonTag[0:idx]
   648  		}
   649  		jsonTag = strings.TrimSpace(jsonTag)
   650  	} else {
   651  		jsonTag = rt.Name
   652  	}
   653  
   654  	column = &Column{
   655  		FieldIdx:    idx,
   656  		Field:       rt.Name,
   657  		Name:        name,
   658  		JsonIdent:   jsonTag,
   659  		Kind:        kind,
   660  		Type:        typ,
   661  		ValueWriter: vw,
   662  	}
   663  
   664  	if !column.Valid() {
   665  		err = errors.Warning("sql: new column failed").WithMeta("field", rt.Name).WithCause(fmt.Errorf("%v is not supported", typ.Value))
   666  		return
   667  	}
   668  	return
   669  }