github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/engine/pkg/orm/model/executor.go (about)

     1  // Copyright 2022 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package model
    15  
    16  import (
    17  	"database/sql/driver"
    18  	"encoding/json"
    19  	"reflect"
    20  
    21  	engineModel "github.com/pingcap/tiflow/engine/model"
    22  	"github.com/pingcap/tiflow/pkg/errors"
    23  	"github.com/pingcap/tiflow/pkg/label"
    24  )
    25  
    26  // LabelSet is a type alias for label.Set.
    27  // It adds some extra methods for gorm to scan and convert values.
    28  type LabelSet label.Set
    29  
    30  // Value implements the driver.Valuer interface.
    31  func (s LabelSet) Value() (driver.Value, error) {
    32  	data, err := json.Marshal(s)
    33  	if err != nil {
    34  		return nil, errors.Errorf("failed to marshal LabelSet: %v", err)
    35  	}
    36  	return string(data), nil
    37  }
    38  
    39  // ToMap converts a LabelSet to a plain map.
    40  func (s LabelSet) ToMap() map[string]string {
    41  	return label.Set(s).ToMap()
    42  }
    43  
    44  // Scan implements the sql.Scanner interface.
    45  func (s *LabelSet) Scan(rawInput interface{}) error {
    46  	*s = make(LabelSet)
    47  	if rawInput == nil {
    48  		return nil
    49  	}
    50  
    51  	// As different SQL drivers might treat the JSON value differently,
    52  	// we need to handle two cases where the JSON value is passed as a string
    53  	// and a byte slice respectively.
    54  	var bytes []byte
    55  	switch input := rawInput.(type) {
    56  	case string:
    57  		// SQLite is this case.
    58  		if len(input) == 0 {
    59  			return nil
    60  		}
    61  		bytes = []byte(input)
    62  	case []byte:
    63  		// MySQL is this case.
    64  		if len(input) == 0 {
    65  			return nil
    66  		}
    67  		bytes = input
    68  	default:
    69  		return errors.Errorf("failed to scan LabelSet. "+
    70  			"Expected string or []byte, got %s", reflect.TypeOf(rawInput))
    71  	}
    72  
    73  	if err := json.Unmarshal(bytes, s); err != nil {
    74  		return errors.Annotate(err, "failed to unmarshal LabelSet")
    75  	}
    76  	return nil
    77  }
    78  
    79  // Executor records the information of an executor.
    80  type Executor struct {
    81  	Model
    82  	ID      engineModel.ExecutorID `json:"id" gorm:"column:id;type:varchar(256) not null;uniqueIndex:uni_id"`
    83  	Name    string                 `json:"name" gorm:"column:name;type:varchar(256) not null"`
    84  	Address string                 `json:"address" gorm:"column:address;type:varchar(256) not null"`
    85  
    86  	// Labels store the label set for each executor.
    87  	Labels LabelSet `json:"labels" gorm:"column:labels;type:json"`
    88  }
    89  
    90  // Map is used in gorm update.
    91  func (e *Executor) Map() map[string]interface{} {
    92  	return map[string]interface{}{
    93  		"id":      e.ID,
    94  		"name":    e.Name,
    95  		"address": e.Address,
    96  		"labels":  e.Labels,
    97  	}
    98  }