package entity

import (
	"database/sql/driver"
	"encoding/json"
	"time"
)

//go:generate ../../tools/bin/goqueryset -in entity.go

var Models = []interface{}{
	//cluster profiles
	&Provider{}, &Region{}, &Zone{},

	// simplify cluster tier
	&InfraProvider{}, &InfraCompute{}, &InfraStorage{}, &InternalProfile{}, &Sku{}, &LabelProfile{}, &ProfileVersion{},

	//tenant
	&RegistrationLog{}, &EmailProviderBlocklist{}, &Tenant{}, &Quota{}, &QuotaChangeLog{},
	&User{}, &Role{}, &UserChangeLog{}, &UserInviteToken{}, &AuditLog{}, &FreeTrialPoint{},
	&GlobalDiscount{}, &Discount{}, &EmailReminder{}, &APIKey{}, &ImpersonatedUser{}, &Trial{}, &NodeUsage{},
	&SystemSetting{}, &AcknowledgeCnPolicy{}, &Project{}, &ProjectNetwork{}, &AccessLog{}, &TenantSalesforceSyncRecord{},

	//cluster
	&Cluster{}, &Connection{}, &ClusterOperation{}, &ScaleOperationTracking{}, &Import{},
	&VerifyCode{}, &ClusterTrafficUsage{}, &ClusterComponent{}, &ClusterSnapshot{},

	//backup and restore
	&BackupSchedule{}, &Backup{}, &BackupTracking{},
	&Restore{}, &RestoreTracking{},

	//old schema
	&CidrTemplate{}, &ClusterCidr{}, &GcpVpcPeering{}, &AwsVpcPeering{}, &RateLimit{},

	//replication
	&Replication{}, &ReplicationTracking{}, &CDCTask{}, &CDCSQLTask{}, &CDCKafkaTask{}, &CDCTCUMeteringRecord{},

	// integration
	&Integration{}, &UserAlert{}, &MetricsKey{}, &ProjectMetering{}, &ClusterMetering{}, &BillingReportRecord{},
}

// gen:qs
type (
	Provider struct {
		Updatable
		Versioned

		Name    Cloud               `gorm:"uniqueIndex:idx_name;not null;type:ENUM('aws', 'gcp')"`
		Regions []*Region           `gorm:"foreignkey:ProviderID"`
		Status  CloudProviderStatus `gorm:"not null;type:ENUM('active', 'inactive')"`
	}

	Region struct {
		Updatable
		Versioned

		Name              string       `gorm:"type:VARCHAR(255);uniqueIndex:idx_name_provider;not null" valid:"required,lowercase"`
		DisplayName       string       `gorm:"type:VARCHAR(255);not null"`
		ProviderID        ID           `gorm:"index;uniqueIndex:idx_name_provider;not null" valid:"required"`
		Provider          *Provider    `gorm:"foreignkey:ProviderID"`
		Zones             []*Zone      `gorm:"foreignkey:RegionID"`
		Status            RegionStatus `gorm:"not null;type:ENUM('active', 'inactive')"`
		IsPublic          *bool        `gorm:"default:true"`
		Tenants           []Tenant     `gorm:"many2many:region_tenants;"`
		DefaultBackupTime string       `gorm:"type:VARCHAR(255);not null;default:'00:00'"`
	}

	// TODO(chenfei): we should remove zone db from platfrom
	Zone struct {
		Updatable

		Name        string  `gorm:"type:VARCHAR(255);uniqueIndex:idx_name_region;not null"`
		DisplayName string  `gorm:"type:VARCHAR(255);not null"`
		RegionID    ID      `gorm:"index;uniqueIndex:idx_name_region;not null"`
		Region      *Region `gorm:"foreignkey:RegionID"`
	}

	InfraProvider struct {
		Updatable
		Versioned

		// Infra API provider type: aws | gcp | aws-free-tier
		Name       string     `gorm:"type:VARCHAR(255);uniqueIndex:idx_name;not null"`
		DeployType DeployType `gorm:"uniqueIndex:deploy_type_provider,priority:1;not null;type:ENUM('dedicated', 'shared')"`
		ProviderID ID         `gorm:"uniqueIndex:deploy_type_provider,priority:2;not null"`
		Provider   *Provider  `gorm:"foreignkey:ProviderID"`
	}

	InfraCompute struct {
		Updatable
		Versioned

		// r5.xlarge, aws_freetier_10
		InstanceType       string         `gorm:"uniqueIndex:provider_instance,priority:2;type:VARCHAR(255);not null"`
		InfraProvider      *InfraProvider `gorm:"foreignkey:InfraProviderID"`
		InfraProviderID    ID             `gorm:"uniqueIndex:provider_instance,priority:1;not null"`
		CPUNum             uint32         `gorm:"not null"`
		MemorySizeGi       uint32         `gorm:"not null"`
		LocalStorageSizeGi uint32         `gorm:"not null"`
		Regions            []Region       `gorm:"many2many:infra_compute_regions;"`
	}

	InfraStorage struct {
		Updatable
		Versioned

		InfraProvider   *InfraProvider `gorm:"foreignkey:InfraProviderID"`
		InfraProviderID ID             `gorm:"uniqueIndex:provider_name,priority:1;not null"`
		ClassName       string         `gorm:"type:VARCHAR(255);uniqueIndex:provider_name,priority:2;not null"` // such as: tikv-gp3-1000-300
		InstanceType    string         `gorm:"type:VARCHAR(255);not null"`                                      // such as: gp2, gp3, pd-ssd, local-storage
		IOPS            uint32         `gorm:"not null"`
		ThroughputMi    uint32         `gorm:"not null"`
	}

	InternalProfile struct {
		Updatable

		InfraComputeID ID            `gorm:"not null"`
		InfraCompute   *InfraCompute `gorm:"foreignkey:InfraComputeID"`
		InfraStorageID ID            `gorm:"not null"`
		InfraStorage   *InfraStorage `gorm:"foreginkey:InfraStorageID"`
		DefaultNodeNum uint32        `gorm:"not null"`
		Status         ProfileStatus `gorm:"not null;type:ENUM('active', 'inactive', 'deleted')"`
		VersionID      ID            `gorm:"not null"`
		ComponentType  ComponentName `gorm:"type:ENUM('pd', 'tikv', 'tidb', 'tiflash', 'ticdc');not null" `
		MinStorage     uint32        `gorm:"not null"`
		MaxStorage     uint32        `gorm:"not null"`
	}

	Sku struct {
		Updatable

		VersionID ID     `gorm:"not null;uniqueIndex:uniq_version_name,priority:1"`
		Name      string `gorm:"type:VARCHAR(255);uniqueIndex:uniq_version_name,priority:2;not null"`
		Price     string `gorm:"type:VARCHAR(255);not null"`
		Extra     string `gorm:"type:VARCHAR(4095);default:'{}'"`
	}

	LabelProfile struct {
		Updatable

		// 8 vCPU, unmodifiable
		Name              string           `gorm:"type:VARCHAR(255);not null"`
		InfraProviderID   ID               `gorm:"not null"`
		ProviderID        ID               `gorm:"not null"`
		InternalProfileID ID               `gorm:"not null"`
		InternalProfile   *InternalProfile `gorm:"foreignkey:InternalProfileID"`
		DeployType        DeployType       `gorm:"type:ENUM('dedicated', 'shared');not null"`
		ComponentType     ComponentName    `gorm:"type:ENUM('pd', 'tikv', 'tidb', 'tiflash', 'ticdc');not null" `
		IsPublic          bool             `gorm:"not null"`
		Status            ProfileStatus    `gorm:"not null;type:ENUM('active', 'inactive', 'deleted')"`
		VersionID         ID               `gorm:"not null"`
		Tenants           []Tenant         `gorm:"many2many:label_profile_tenants;"`
		Regions           []*Region        `gorm:"many2many:label_profile_regions;"`
		Annotation        string           `gorm:"annotation;default:''"`
		PD                *PDNode          `gorm:"type:JSON;column:pd"`
	}

	ProfileVersion struct {
		Updatable
		Versioned

		CommitID string               `gorm:"type:VARCHAR(255);uniqueIndex:uniq_cmtid;not null"`
		Status   ProfileVersionStatus `gorm:"not null;type:ENUM('syncing','using','outdated')"`
	}
)

// gen:qs
type (
	RegistrationLog struct {
		Base

		Name        string    `gorm:"type:VARCHAR(255);not null"`
		Email       string    `gorm:"type:VARCHAR(255);index;not null"`
		FirstName   string    `gorm:"type:VARCHAR(255);not null"`
		LastName    string    `gorm:"type:VARCHAR(255);not null"`
		UserID      ID        `gorm:"index;not null"`
		User        *User     `gorm:"foreignkey:UserID"`
		InvitedAt   time.Time `gorm:"type:TIMESTAMP;not null"`
		InvitedByID ID        `gorm:"index;not null"`
		InvitedBy   *User     `gorm:"foreignkey:InvitedByID"`
		Source      string    `gorm:"type:VARCHAR(255);not null"`
		IPAddress   string    `gorm:"type:VARCHAR(255);not null"`
	}

	EmailProviderBlocklist struct {
		Base

		Email string `gorm:"type:VARCHAR(255);uniqueIndex:idx_email;not null"`
	}

	Tenant struct {
		Updatable

		Name                      string       `gorm:"type:VARCHAR(255);not null" valid:"required"`
		Alias                     string       `gorm:"type:VARCHAR(255);not null;default:''"`
		Email                     string       `gorm:"type:VARCHAR(255);uniqueIndex:idx_email;not null" valid:"required"`
		Country                   string       `gorm:"type:VARCHAR(255);not null"`
		TimeZone                  string       `gorm:"type:VARCHAR(255);not null"`
		Status                    TenantStatus `gorm:"type:ENUM('pending', 'active', 'inactive', 'deleted', 'cleared');not null"`
		Plan                      TenantPlan   `gorm:"type:ENUM('new_user', 'free_trial', 'poc', 'on_demand');not null"`
		POCBindedPackageID        uint64
		OnDemandBindedPackageID   uint64
		DevTierBindedPackageID    uint64
		Kind                      TenantKind `gorm:"type:VARCHAR(64);default:'external'"`
		AcceptService             bool       `gorm:"not null"`
		ZendeskID                 ID
		ThirdPartyAccountProvider *string    `gorm:"type:VARCHAR(255);uniqueIndex:third_party_account,priority:2"`
		ThirdPartyAccountCode     *string    `gorm:"type:VARCHAR(255);uniqueIndex:third_party_account,priority:1"`
		Quotas                    []*Quota   `gorm:"foreignkey:TenantID"`
		BillingEmail              string     `gorm:"type:VARCHAR(255);not null"`
		Projects                  []*Project `gorm:"foreignkey:TenantID"`
		AccountManager            string     `gorm:"type:VARCHAR(255);not null;default:''"` // the email address of account manager
	}

	TenantSalesforceSyncRecord struct {
		TenantID ID   `gorm:"primarykey"`
		Synced   bool `gorm:"default:false"`
	}

	TenantPlanChangeLog struct {
		Base

		TenantID ID         `gorm:"not null"`
		Tenant   *Tenant    `gorm:"foreignkey:TenantID"`
		Plan     TenantPlan `gorm:"type:ENUM('new_user', 'free_trial', 'poc');not null"`
		NewPlan  TenantPlan `gorm:"type:ENUM('free_trial', 'poc', 'on_demand');not null"`
	}

	Project struct {
		Updatable

		TenantID    ID            `gorm:"not null"`
		Tenant      *Tenant       `gorm:"foreignkey:TenantID"`
		Name        string        `gorm:"type:VARCHAR(255);not null" valid:"required"`
		Users       []User        `gorm:"many2many:user_projects;"`
		Status      ProjectStatus `gorm:"type:ENUM('active', 'deleted', 'cleared');not null;default:'active'"`
		DeletedTime *time.Time    `gorm:"type:TIMESTAMP;deleted_time"`
	}

	ProjectNetwork struct {
		Updatable
		Versioned

		ProjectID  ID        `gorm:"index:idx_project_id_provider,unique,priority:1;not null"`
		Project    *Project  `gorm:"foreignkey:ProjectID"`
		ProviderID ID        `gorm:"index:idx_project_id_provider,unique,priority:2;not null" valid:"required"`
		Provider   *Provider `gorm:"foreignkey:ProviderID"`
		CIDR       string    `gorm:"type:VARCHAR(255);column:cidr"`
	}

	UserAlert struct {
		Updatable

		ProjectID ID       `gorm:"index:idx_project_id_user_id,unique,priority:1;not null"`
		Project   *Project `gorm:"foreignkey:ProjectID"`
		UserID    ID       `gorm:"index:idx_project_id_user_id,unique,priority:2;not null"`
		User      *User    `gorm:"foreignkey:UserID"`
	}

	EmailReminder struct {
		Base

		TenantID   ID                `gorm:"uniqueIndex:uniq_tsi;not null"`
		Tenant     *Tenant           `gorm:"foreignkey:TenantID"`
		Scene      NotificationScene `gorm:"type:VARCHAR(256);uniqueIndex:uniq_tsi;not null"`
		Identifier string            `gorm:"type:VARCHAR(256);uniqueIndex:uniq_tsi;not null"`
	}

	Quota struct {
		Updatable

		TenantID      ID            `gorm:"index;not null"`
		Tenant        *Tenant       `gorm:"foreignkey:TenantID"`
		ComponentName ComponentName `gorm:"type:ENUM('pd', 'tikv', 'tidb', 'tispark', 'tiflash', 'ticdc');not null"`
		Quota         uint32        `gorm:"not null"`
	}

	FreeTrialPoint struct {
		Base

		TenantID    ID      `gorm:"index;not null"`
		Tenant      *Tenant `gorm:"foreignkey:TenantID"`
		Amount      int64   `gorm:"not null"`
		Description string  `gorm:"type:VARCHAR(255);not null"`
	}

	Discount struct {
		Base

		TenantID     ID           `gorm:"not null"`
		Tenant       *Tenant      `gorm:"foreignkey:TenantID"`
		Discount     float64      `gorm:"type:DECIMAL(10,3);not null"`
		Description  string       `gorm:"type:VARCHAR(255);not null"`
		DiscountType DiscountType `gorm:"not null"`
		StartTime    time.Time    `gorm:"type:TIMESTAMP;not null"`
		EndTime      time.Time    `gorm:"type:TIMESTAMP;not null"`
	}

	GlobalDiscount struct {
		Base

		Discount    float64   `gorm:"type:DECIMAL(10,3);not null"`
		Description string    `gorm:"type:VARCHAR(255);not null"`
		StartTime   time.Time `gorm:"type:TIMESTAMP;not null"`
		EndTime     time.Time `gorm:"type:TIMESTAMP;not null"`
	}

	QuotaChangeLog struct {
		Base

		QuotaID     ID     `gorm:"index;not null"`
		Quota       Quota  `gorm:"foreignkey:QuotaID"`
		NewQuota    uint64 `gorm:"not null"`
		ChangedByID ID     `gorm:"not null"`
		ChangedBy   *User  `gorm:"foreignkey:ChangedByID"`
	}

	User struct {
		Updatable
		DeletedAt *time.Time `gorm:"type:TIMESTAMP;deleted_at"`

		TenantID    ID         `gorm:"index;not null"`
		Tenant      *Tenant    `gorm:"foreignkey:TenantID"`
		FirstName   string     `gorm:"type:VARCHAR(255);not null"`
		LastName    string     `gorm:"type:VARCHAR(255);not null"`
		Email       string     `gorm:"type:VARCHAR(255);uniqueIndex:idx_email;not null"`
		Status      UserStatus `gorm:"type:ENUM('inactive', 'active', 'pending');not null"`
		InvitedAt   *time.Time `gorm:"type:TIMESTAMP"`
		Job         string     `gorm:"type:VARCHAR(255);not null"`
		PhoneNumber string     `gorm:"type:VARCHAR(255);not null"`
		Roles       []Role     `gorm:"many2many:user_roles;"`
		Role        UserRole   `gorm:"type:ENUM('owner', 'member', 'billing_admin', 'audit_admin');not null; default:'member'"`
		Projects    []Project  `gorm:"many2many:user_projects;"`
	}

	ImpersonatedUser struct {
		Base

		UserID   ID      `gorm:"uniqueIndex:idx_impersonated_user;not null"`
		User     *User   `gorm:"foreignkey:UserID"`
		TenantID ID      `gorm:"not null"`
		Tenant   *Tenant `gorm:"foreignkey:TenantID"`
	}

	Role struct {
		Updatable

		TenantID   ID         `gorm:"uniqueIndex:idx_tenant_name,priority:1;not null"`
		Tenant     *Tenant    `gorm:"foreignkey:TenantID"`
		Name       string     `gorm:"type:VARCHAR(255);uniqueIndex:idx_tenant_name,priority:2;not null" valid:"required"`
		Privileges Privileges `gorm:"type:JSON"`
	}

	UserChangeLog struct {
		Base

		UserID       ID     `gorm:"index;not null"`
		User         *User  `gorm:"foreignkey:UserID"`
		Operation    string `gorm:"type:TEXT;not null"`
		OperatedByID ID     `gorm:"index;not null"`
		OperatedBy   *User  `gorm:"foreignkey:OperatedByID"`
	}

	UserInviteToken struct {
		Base

		Method    string    `gorm:"type:VARCHAR(255)"`
		Email     string    `gorm:"index;type:VARCHAR(255)"`
		TenantID  ID        `gorm:"index;tenant_id;not null"`
		BeginAt   time.Time `gorm:"type:TIMESTAMP;not null"`
		ExpireAt  time.Time `gorm:"type:TIMESTAMP;not null"`
		IsOneTime bool      `gorm:"default:false"`
	}

	AuditLog struct {
		Base

		TenantID ID      `gorm:"index;not null"`
		Tenant   *Tenant `gorm:"foreignkey:TenantID"`
		User     string  `gorm:"type:VARCHAR(255);not null"`
		Content  string  `gorm:"type:TEXT;not null"`
	}

	AccessLog struct {
		Base

		Accessor  string    `gorm:"index:idx_accessor_scene_ts,priority:1;type:VARCHAR(255);NOT NULL"`
		Scene     string    `gorm:"index:idx_accessor_scene_ts,priority:2;type:VARCHAR(255);NOT NULL"`
		Timestamp time.Time `gorm:"index:idx_accessor_scene_ts,priority:3;type:TIMESTAMP;NOT NULL"`
		Target    string    `gorm:"type:TEXT"`
	}

	Trial struct {
		Base

		CreatedByID      ID         `gorm:"not null"`
		TenantID         ID         `gorm:"not null;uniqueIndex:tenant_trial"`
		StartedAt        time.Time  `gorm:"type:TIMESTAMP;column:started_at"`
		EstimatedEndedAt *time.Time `gorm:"type:TIMESTAMP;column:estimated_ended_at"`
		EndedAt          *time.Time `gorm:"type:TIMESTAMP;column:ended_at"`
		TrialType        TrialType  `gorm:"type:ENUM('dev_tier', 'poc');not null;default:dev_tier;uniqueIndex:tenant_trial"`
	}

	NodeUsage struct {
		Updatable

		TenantID  ID      `gorm:"not null; uniqueIndex:idx_tenant;"`
		Tenant    *Tenant `gorm:"foreignkey:TenantID"`
		StartTime int64   `gorm:"not null"`
		EndTime   int64   `gorm:"not null"`
		Usage     int64   `gorm:"not null"`
	}

	SystemSetting struct {
		Updatable
		Versioned

		Value SystemSettingValue `gorm:"type:JSON"`
	}

	AcknowledgeCnPolicy struct {
		Updatable

		TenantID    ID        `gorm:"not null; uniqueIndex:idx_tenant;"`
		Tenant      *Tenant   `gorm:"foreignkey:TenantID"`
		CreatedByID ID        `gorm:"not null"`
		CreatedBy   *User     `gorm:"foreignkey:CreatedByID"`
		ConfirmTime time.Time `gorm:"type:TIMESTAMP;column:confirm_time"`
		IPAddress   string    `gorm:"type:VARCHAR(255);not null"`
	}

	MetricsKey struct {
		Updatable

		ProjectID ID       `gorm:"index:idx_project_id;not null"`
		Project   *Project `gorm:"foreignkey:ProjectID"`
		UserID    ID       `gorm:"index;not null"`
		User      *User    `gorm:"foreignkey:UserID"`
		KeyHash   string   `gorm:"type:VARCHAR(512);unique;not null"`
	}

	Integration struct {
		Updatable
		ProjectID              ID                  `gorm:"index:idx_project_id,unique;not null"`
		ProviderType           IntegrationType     `gorm:"type:ENUM('UNSPECIFIED','DATADOG','PROMETHEUS');not null;default:'UNSPECIFIED'"`
		Status                 IntegrationStatus   `gorm:"type:ENUM('UNSPECIFIED','NONE','ACTIVE','ERROR');not null;default:'UNSPECIFIED'"`
		StatusReason           string              `gorm:"type:VARCHAR(1024)"`
		Payloads               IntegrationPayloads `gorm:"type:JSON"`
		DatadogSite            DatadogSite         `gorm:"type:ENUM('UNSPECIFIED','US1','US3','US5','EU1','US1_FED')"`
		MaskedDatadogApiKey    string              `gorm:"type:VARCHAR(128)"`
		EncryptedDatadogApiKey string              `gorm:"type:VARCHAR(1024)"`
	}
)

// gen:qs
type (
	Cluster struct {
		Updatable
		Versioned
		DeletedTime          *time.Time `gorm:"type:TIMESTAMP;deleted_time"`
		CreationFinishedTime *time.Time `gorm:"type:TIMESTAMP;creation_finished_time"`

		Name                        string              `gorm:"type:VARCHAR(255);index:name_tenant;not null"`
		TenantID                    ID                  `gorm:"index:name_tenant;not null"`
		Tenant                      *Tenant             `gorm:"foreignkey:TenantID"`
		CreatedByID                 ID                  `gorm:"not null"`
		CreatedBy                   *User               `gorm:"foreignkey:CreatedByID"`
		Status                      ClusterStatus       `gorm:"type:ENUM('created', 'initializing', 'preparing', 'launching', 'normal', 'scaling', 'upgrading','recovering', 'deleted', 'cleared', 'deletecomplete');not null"`
		EncryptedRootPassword       string              `gorm:"type:VARCHAR(1024);not null;default ''"`
		EncryptedCloudAdminPassword string              `gorm:"type:VARCHAR(1024);not null;default ''"`
		PasswordProviderID          string              `gorm:"type:VARCHAR(255);default:''"`
		ComponentsV2                []*ClusterComponent `gorm:"foreignkey:ClusterID"`
		Connections                 []Connection        `gorm:"foreignkey:ClusterID"`
		Replicas                    uint                `gorm:"not null"`
		ProviderID                  ID                  `gorm:"not null"`
		Provider                    *Provider           `gorm:"foreignkey:ProviderID"`
		DeployType                  DeployType          `gorm:"type:ENUM('dedicated', 'shared')"`
		FinalBackupBeforeDelete     bool                `gorm:"column:poc_deleted;default:false"` // indicate the worker which clean deleted cluster have to make a final-backup before delete TODO(chenfei): rename column name
		Free                        bool                `gorm:"default:false"`
		ProjectID                   ID                  `gorm:"index;not null"`
		Project                     *Project            `gorm:"foreignkey:ProjectID"`

		// Not null if it's importing.
		// we set this as the importing id when user create a import
		// and set as null when user exit the importing mode
		ImportID *uint64 `gorm:"index"`

		// Not null if replication is connection
		// set it when the replictaion is creating
		// delete it when the replication is detached
		ReplicationID *uint64 `gorm:"index"`

		// the status of the readonly
		// 1 means read only status
		// 2 means force set cluster read only in db side
		// for the readonly status is sync from cluster to db, so the change from `bool` to `uint64` can compatible with exist clusters
		ReadOnly uint64 `gorm:"default:0"`

		TCUNumber uint64 `gorm:"default:0"`
	}

	ClusterConfig struct {
		Updatable

		ClusterID ID       `gorm:"unique;not null"`
		Cluster   *Cluster `gorm:"foreignkey:ClusterID"`

		// the status of the audit log: on or off
		IsAuditLogOn   bool   `gorm:"default:false"`
		AuditLogConfig string `gorm:"type:JSON;not null"`
	}

	// cluster connections
	Connection struct {
		Updatable

		ClusterID     ID                    `gorm:"index;not null"`
		Cluster       *Cluster              `gorm:"foreignkey:ClusterID"`
		Type          ClusterConnectionType `gorm:"type:ENUM('private','public');not null"`
		DSN           string                `gorm:"type:VARCHAR(255);not null"`
		CreateSuccess *bool
	}

	ClusterOperation struct {
		Updatable

		ClusterID   ID                     `gorm:"index;not null"`
		Cluster     *Cluster               `gorm:"foreignkey:ClusterID"`
		Type        ClusterOperationType   `gorm:"type:ENUM('scale');not null"`
		CompletedAt *time.Time             `gorm:"type:TIMESTAMP"`
		Status      ClusterOperationStatus `gorm:"type:ENUM('created','done');not null"`
		Content     string                 `gorm:"type:TEXT;not null"`
	}

	ClusterTrafficUsage struct {
		Updatable
		TenantID     ID     `gorm:"column:tenant_id; not null; index:t_p,priority:1"`
		ClusterID    ID     `gorm:"column:cluster_id; uniqueIndex:c_p,priority:1"`
		Period       string `gorm:"column:period; uniqueIndex:c_p,priority:2; index:t_p,priority:2"`
		IngressUsage int64  `gorm:"column:ingress_usage;not null"` // unit: byte
		EgressUsage  int64  `gorm:"column:egress_usage;not null"`  // unit: byte
	}

	ScaleOperationTracking struct {
		Updatable

		ClusterOperationID ID                           `gorm:"index;not null"`
		ClusterOperation   *ClusterOperation            `gorm:"foreignkey:ClusterOperationID"`
		Status             ScaleOperationTrackingStatus `gorm:"type:ENUM('scale-init', 'scale-pod','scale-node','done');not null"`
		Replicas           uint32
		ClusterComponentID ID                `gorm:"index;not null"`
		ClusterComponent   *ClusterComponent `gorm:"foreignkey:ClusterComponentID"`
	}

	BackupSchedule struct {
		Updatable
		Versioned
		DeletedAt *time.Time `gorm:"type:TIMESTAMP;deleted_at"`

		Name           string       `gorm:"type:VARCHAR(255);not null"`
		Type           BackupType   `gorm:"type:ENUM('auto','manual');not null"` // enum
		ClusterID      ID           `gorm:"index;not null"`
		Cluster        *Cluster     `gorm:"foreignkey:ClusterID"`
		MaxBackups     uint64       `gorm:"not null"`
		Schedule       string       `gorm:"type:VARCHAR(255);not null"`
		Targets        string       `gorm:"type:VARCHAR(4096);not null"` // filter expression
		UserID         ID           `gorm:"not null"`
		User           *User        `gorm:"foreignkey:UserID"`
		Method         BackupMethod `gorm:"type:ENUM('full','incremental');not null"` // enum
		Description    string       `gorm:"type:VARCHAR(4096);not null"`
		NextBackupTime *time.Time   `gorm:"type:TIMESTAMP"`
	}

	Backup struct {
		Updatable
		Versioned
		DeletedAt  *time.Time `gorm:"type:TIMESTAMP;deleted_at"`
		FinishedAt *time.Time `gorm:"type:TIMESTAMP;finished_at"`

		BackupScheduleID  ID `gorm:"index;not null"`
		BackupSize        int
		BackupSchedule    *BackupSchedule  `gorm:"foreignkey:BackupScheduleID"`
		Targets           string           `gorm:"type:VARCHAR(4096);not null"`                                // filter expression
		ClusterVersion    string           `gorm:"type:VARCHAR(255);not null"`                                 // not used anymore
		Status            BackupStatus     `gorm:"type:ENUM('pending','running','success','failed');not null"` // enum
		CleanedUp         *bool            `gorm:"default:false"`
		OldBackupName     string           `gorm:"type:VARCHAR(255);not null"`
		StartTimeStamp    string           `gorm:"type:VARCHAR(255);start_ts"`
		ClusterSnapshotID ID               `gorm:"index;not null"`
		ClusterSnapshot   *ClusterSnapshot `gorm:"foreignkey:ClusterSnapshotID"`
	}

	BackupTracking struct {
		Base

		BackupID    ID           `gorm:"index;not null"`
		Backup      *Backup      `gorm:"foreignkey:BackupID"`
		Status      BackupStatus `gorm:"type:ENUM('pending','running','success','failed');not null"` // enum
		Description string       `gorm:"type:VARCHAR(4096);not null"`
	}

	Restore struct {
		Updatable
		Versioned

		Name       string        `gorm:"type:VARCHAR(255);not null"`
		FinishedAt *time.Time    `gorm:"finished_at;type:TIMESTAMP;"`
		ClusterID  ID            `gorm:"index;not null"`
		Cluster    *Cluster      `gorm:"foreignkey:ClusterID"`
		Targets    string        `gorm:"type:VARCHAR(4096);not null"` // filter expression
		BackupID   ID            `gorm:"not null"`
		Backup     *Backup       `gorm:"foreignkey:BackupID"`
		Status     RestoreStatus `gorm:"type:ENUM('pending','running','success','failed');not null"` // enum
	}

	RestoreTracking struct {
		Base

		RestoreID   ID            `gorm:"index;not null"`
		Restore     *Restore      `gorm:"foreignkey:RestoreID"`
		Status      RestoreStatus `gorm:"type:ENUM('pending','running','success','failed');not null"` // enum
		Description string        `gorm:"type:VARCHAR(4096);not null"`
	}

	// Replication is a sync tool between primary and secondary cluster
	Replication struct {
		Updatable
		Versioned

		PrimaryClusterID           ID       `gorm:"not null"`
		PrimaryCluster             *Cluster `gorm:"foreignkey:PrimaryClusterID"`
		SecondaryClusterID         ID
		SecondaryCluster           *Cluster        `gorm:"foreignkey:SecondaryClusterID"`
		SecondaryClusterComponents ComponentStates `gorm:"type:JSON"`
		// for the vpc table separate to aws and gcp , so just an ID is all right
		VPCPeeringID      *uint64
		ReplicationType   ReplicationType   `gorm:"type:ENUM('cdc');not null"`                                                                 // enum
		ReplicationStatus ReplicationStatus `gorm:"type:ENUM('creating', 'failed', 'pause', 'replicating', 'detaching', 'detached');not null"` // enum
		// TSO time delta of primary cluster and secondary one
		LagTimeWhenDetach *uint64
		TenantID          ID      `gorm:"not null"`
		Tenant            *Tenant `gorm:"foreignkey:TenantID"`
		BackupID          ID      `gorm:"not null"`
		Backup            *Backup `gorm:"foreignkey:BackupID"`
		// region of the secondary cluster belong to
		// secondary cluster name
		SecondaryName string `gorm:"type:VARCHAR(255)"`
		// secondary cluster region
		SecondaryRegion string `gorm:"type:VARCHAR(255)"`
		// secondary cluster password, encrypt by kms of central, and will be deleted after cluster is created
		SecondaryPassword string `gorm:"type:VARCHAR(1024)"`
		// the ID of user created secondary cluster
		SecondaryUserID ID
		SecondaryUser   *User `gorm:"foreignkey:SecondaryUserID"`
		// the ID of user detached secondary cluster
		DetachUserID ID
		DetachUser   *User `gorm:"foreignkey:DetachUserID"`
		// force and plan will two type of detach type
		// plan detach need to wait for the secondary cluster catch up with the primary one
		DetachType DetachType `gorm:"type:ENUM('planned', 'force', 'none');not null"` // enum
		// the primary cluster TSO when detached
		DetachTso uint64
		// the cdc checkpoint TSO when catch up with primary one
		DetachCheckpointTso uint64
		// save the gc life time before replication
		PreGclifetime string
		// connector ID for trace the cdc status
		CDCTaskID ID
		Task      *CDCTask `gorm:"foreignkey:CDCTaskID"`
		// IgnoreReplication means ignore the tables without UK/PK or have sequance and replicating others
		IgnoreReplication bool `gorm:"index;default:false;not null"`
	}

	// ReplicationTracking is a table which track the status change of Replication
	ReplicationTracking struct {
		Base

		ReplicationID ID                `gorm:"index;not null"`
		Replication   *Replication      `gorm:"foreignkey:ReplicationID"`
		Status        ReplicationStatus `gorm:"type:ENUM('creating', 'failed', 'pause', 'replicating', 'detaching', 'detached');not null"` // enum
		Description   string
	}

	CDCTask struct {
		Updatable

		// record the changefeed ID
		ChangefeedId string `gorm:"index,not null"`

		// cluster ID which the cdc belongs to
		ClusterID ID
		Cluster   *Cluster `gorm:"foreignkey:ClusterID"`
		// downstream type identity the downstream protocol
		DownStreamType CDCDownStreamType `gorm:"type:ENUM('mysql','tidb', 'kafka');not null"`                                        // enum
		Status         CDCStatus         `gorm:"type:ENUM('creating', 'failed', 'pause', 'normal', 'deleting', 'deleted');not null"` // enum
		// time to sync
		StartTimeStamp  uint64
		TargetTimeStamp uint64

		// return error message if error occured
		ErrorMessage string `gorm:"type:VARCHAR(1024)"`

		// IgnoreReplication means ignore the tables without UK/PK or have sequance and replicating others
		IgnoreReplication bool `gorm:"index;default:false;not null"`
	}

	CDCTCUMeteringRecord struct {
		CostID    string     `gorm:"primary_key;not null"`
		CreatedAt time.Time  `gorm:"created_at;type:TIMESTAMP;not null;<-:create"` // create and read only
		UpdatedAt *time.Time `gorm:"updated_at;type:TIMESTAMP"`
		CostTime  time.Time
		TenantID  uint64
		ClusterID uint64
		TCUNumber uint64
		Status    CDCMeteringStatus
	}

	// if CDC downstream is tidb or mysql, the parameter is as below
	CDCSQLTask struct {
		Updatable

		CDCTaskID ID
		CDCTask   *CDCTask `gorm:"foreignkey:CDCTaskID"`
		WorkCount uint32
		// Endpoint and port of the downsteam
		DownStreamEndpoint string `gorm:"type:VARCHAR(255)"`
		DownStreamPort     string `gorm:"type:VARCHAR(255)"`
		// user and password of the downstream sql
		User     string `gorm:"type:VARCHAR(255)"`
		Password string `gorm:"type:VARCHAR(1024)"`
		// max batch transaction can be executed in downstream
		MaxTxnRow uint32
	}

	CDCKafkaTask struct {
		Updatable

		CDCTaskID ID
		CDCTask   *CDCTask `gorm:"foreignkey:CDCTaskID"`
		// Endpoint and port of the downstream
		DownStreamEndpoint string `gorm:"type:VARCHAR(255)"`
		DownStreamPort     string `gorm:"type:VARCHAR(255)"`
		// topic of downstream kafka
		Topic string `gorm:"type:VARCHAR(255)"`
		// version of kafka
		Version string `gorm:"type:VARCHAR(255)"`
		// partition num of downstream kafka
		// The number of the downstream Kafka partitions
		/// (Optional. The value must be no greater than the actual number of partitions.
		// The maximum size of data that is sent to Kafka broker each time (optional, 64MB by default)
		MaxMessageBytes string `gorm:"type:VARCHAR(255)"`
		// The protocol with which messages are output to Kafka.
		// The value options are default, canal, avro, and maxwell (default by default)
		Protocol KafkaProtocolType `gorm:"type:ENUM('default','avro', 'maxwell', 'canal-json');not null"` // enum
	}

	CidrTemplate struct {
		Updatable

		Cidr      TrafficFilters `gorm:"type:JSON"`
		ProjectID ID             `gorm:"index;not null"`
		Project   *Project       `gorm:"foreignkey:ProjectID"`
	}

	TrafficFilters struct {
		Cidrs []TrafficFilter `json:"cidrs"`
	}

	TrafficFilter struct {
		Cidr        string `gorm:"type:VARCHAR(255)" json:"cidr"`
		Description string `gorm:"type:VARCHAR(255)" json:"description"`
	}

	ClusterCidr struct {
		Updatable

		ClusterID ID             `gorm:"index;not null"`
		Cidr      TrafficFilters `gorm:"type:JSON"`
	}

	// Gcp Vpc Peering
	GcpVpcPeering struct {
		Updatable
		Versioned

		Region            string `gorm:"type:VARCHAR(255);index:project_region,priority:2"`
		TenantProjectID   string `gorm:"type:VARCHAR(255);not null"`
		TenantNetworkName string `gorm:"type:VARCHAR(255);not null"`
		TenantVpcRegion   string `gorm:"type:VARCHAR(255);not null"`
		TenantVpcCIDR     string `gorm:"type:VARCHAR(255);not null"`
		NetworkName       string `gorm:"type:VARCHAR(255);not null"`
		Status            string `gorm:"type:VARCHAR(255);not null"`
		// according peeriing type, decide to accept the vpc peering request by dbaas worker or customer
		ProjectID   ID          `gorm:"index:project_region,priority:1"`
		Project     *Project    `gorm:"foreignkey:ProjectID"`
		PeeringType PeeringType `gorm:"type:ENUM('dbaas','customer');not null;default:'customer'"`
	}

	// Aws Vpc Peering
	AwsVpcPeering struct {
		Updatable
		Versioned

		Region          string   `gorm:"type:VARCHAR(255);index:project_region,priority:2"`
		TenantAccountID string   `gorm:"type:VARCHAR(255);not null"`
		TenantRegion    string   `gorm:"type:VARCHAR(255);not null"`
		TenantVpcID     string   `gorm:"type:VARCHAR(255);not null"`
		TenantVpcCIDR   string   `gorm:"type:VARCHAR(255);not null"`
		VpcPeeringID    string   `gorm:"type:VARCHAR(255);not null"`
		PrivateHostZone string   `gorm:"type:VARCHAR(255);not null"`
		Status          string   `gorm:"type:VARCHAR(255);not null"`
		ProjectID       ID       `gorm:"index:project_region,priority:1"`
		Project         *Project `gorm:"foreignkey:ProjectID"`
		// according peering type, decide to accept the vpc peering request by dbaas worker or customer
		PeeringType PeeringType `gorm:"type:ENUM('dbaas','customer');not null;default:'customer'"`
	}

	Import struct {
		Updatable

		OldID      *uint64
		ClusterID  ID           `gorm:"not null" valid:"required"`
		Cluster    *Cluster     `gorm:"foreignkey:ClusterID"`
		Status     ImportStatus `gorm:"type:ENUM('unknown','preparing', 'importing','completed','failed', 'canceling', 'canceled');not null;default:'preparing'"` // enum
		Message    string       `gorm:"type:VARCHAR(255)"`                                                                                                        // failed message
		StartedAt  *time.Time   `gorm:"type:TIMESTAMP"`
		FinishedAt *time.Time   `gorm:"type:TIMESTAMP;index"`

		CleanUp bool `gorm:"index;default:false;not null"`

		BucketRegion string `gorm:"type:VARCHAR(255)"`
		AwsRoleArn   string `gorm:"type:VARCHAR(255);not null;default:''"`
		// 1: sql statement(dumpling default format
		// 2: aurora snapshot(parquet)
		DataFormat DataFormat
		// 1: aws s3
		// 2: GCS
		DataSourceType DataSource

		// we just pass this to lightning's config.
		// for the privilege need see https://docs.pingcap.com/tidb/stable/tidb-lightning-faq#what-is-the-privilege-requirements-for-the-target-database
		TargetUsername string `gorm:"type:VARCHAR(255)"`
		TargetPassword string `gorm:"type:VARCHAR(255)"`

		Filter          string        `gorm:"type:VARCHAR(255)"`
		CustomCSVFormat string        `gorm:"type:VARCHAR(255)"`
		OptionalArgs    *OptionalArgs `gorm:"type:JSON"`

		// Source data info
		TotalSize     *uint64
		TotalFiles    *uint32
		SourceURL     string        `gorm:"type:VARCHAR(255)"`
		CurrentTables CurrentTables `gorm:"type:JSON"`

		// In progress info
		CompletedTables  uint32
		PendingTables    uint32
		CompletedPercent uint32 // 0 ~100
	}

	VerifyCode struct {
		Base
		CodeKey    string    `gorm:"type:VARCHAR(255); uniqueIndex:idx_code_key;not null"`
		ExpireTime time.Time `gorm:"not null;"`
		Code       string    `gorm:"type:VARCHAR(255)"`
	}
)

// gen:qs
type RateLimit struct {
	Updatable
	LimitKey        string  `gorm:"type:VARCHAR(255);uniqueIndex:idx_limit_key;not null" valid:"required"`
	RequestsPerUnit uint32  `gorm:"not null"`
	Active          bool    `gorm:"default:false"`
	Methods         Methods `gorm:"type:JSON"`
}

type Methods struct {
	Methods []Method `json:"methods"`
}

type Method struct {
	Name string
}

func (m Methods) Value() (driver.Value, error) {
	b, err := json.Marshal(m)
	return string(b), err
}

func (m *Methods) Scan(input interface{}) error {
	return json.Unmarshal(input.([]byte), m)
}

// Value marshal json
func (c TrafficFilters) Value() (driver.Value, error) {
	b, err := json.Marshal(c)
	return string(b), err
}

// Scan unmarshal json
func (c *TrafficFilters) Scan(input interface{}) error {
	return json.Unmarshal(input.([]byte), c)
}

type CurrentTable struct {
	Name             string `json:"name"`
	Size             uint64 `json:"size"`
	CompletedPercent uint32 `json:"completed_percent"` // 0 ~100
}

type CurrentTables struct {
	Tables []*CurrentTable `json:"tables"`
}

// Value marshal json
func (c CurrentTables) Value() (driver.Value, error) {
	b, err := json.Marshal(c)
	return string(b), err
}

// Scan unmarshal json
func (c *CurrentTables) Scan(input interface{}) error {
	return json.Unmarshal(input.([]byte), c)
}

type OptionalArgs struct {
	ObjectNamePattern  string `json:"object_name_pattern"`
	TargetTablePattern string `json:"target_table_pattern"`
}

// Value marshal json
func (args OptionalArgs) Value() (driver.Value, error) {
	b, err := json.Marshal(args)
	return string(b), err
}

// Scan unmarshal json
func (args *OptionalArgs) Scan(input interface{}) error {
	return json.Unmarshal(input.([]byte), args)
}

// gen:qs
type APIKey struct {
	Updatable

	// The tenant that this API can be used for.
	TenantID ID
	// The user is inside tenant DB. Before DB schema refactoring we will not use it to join the user table.
	// CreatedBy     *User  `gorm:"foreignkey:CreatedByID"`
	CreatedByID ID     `gorm:"not null" valid:"required"`
	Name        string `gorm:"not null;size:50" valid:"required"`
	KeyHash     string `gorm:"not null;size:128;unique" valid:"required"` // The SHA256 of the API key.
}

type IDList struct {
	IDs []ID `json:"ids"`
}

// Value marshal json
func (c IDList) Value() (driver.Value, error) {
	b, err := json.Marshal(c)
	return string(b), err
}

// Scan unmarshal json
func (c *IDList) Scan(input interface{}) error {
	return json.Unmarshal(input.([]byte), c)
}

type Privileges struct {
	Privileges []Privilege `json:"privileges"`
}

type Privilege struct {
	Resource  string `json:"resource"`
	Operation string `json:"operation"`
}

func (c Privileges) Value() (driver.Value, error) {
	b, err := json.Marshal(c)
	return string(b), err
}

func (c *Privileges) Scan(input interface{}) error {
	return json.Unmarshal(input.([]byte), c)
}

func (id ID) Uint64() uint64 {
	return uint64(id)
}

type EnableDevTier struct {
	EnableOnAws bool `json:"enable_on_aws"`
	EnableOnGcp bool `json:"enable_on_gcp"`
}

type SystemSettingValue struct {
	EnableDevTier EnableDevTier `json:"enable_dev_tier"`
}

func (m SystemSettingValue) Value() (driver.Value, error) {
	b, err := json.Marshal(m)
	return string(b), err
}

func (m *SystemSettingValue) Scan(input interface{}) error {
	return json.Unmarshal(input.([]byte), m)
}

type IntegrationPayloads struct {
	Payloads []IntegrationPayload `json:"payloads"`
}

func (p IntegrationPayloads) Value() (driver.Value, error) {
	b, err := json.Marshal(p)
	return string(b), err
}

func (p *IntegrationPayloads) Scan(input interface{}) error {
	return json.Unmarshal(input.([]byte), p)
}

func (c ComponentStates) Value() (driver.Value, error) {
	b, err := json.Marshal(c)
	return string(b), err
}

func (c *ComponentStates) Scan(input interface{}) error {
	return json.Unmarshal(input.([]byte), c)
}

type ComponentStates struct {
	Components []ComponentState `json:"components"`
}

type ComponentState struct {
	ComponentType     ComponentName `json:"component_type"`
	CloudProviderName string        `json:"cloud_provider_name"`
	RegionName        string        `json:"region_name"`
	LabelProfileID    ID            `json:"label_profile_id"`
	InternalProfileID ID            `json:"internal_profile_id"`
	Replicas          uint32        `json:"replicas"`
	StorageSizeGi     uint32        `json:"storage_size_gi"`
}

type ClusterMeteringStates struct {
	ClusterComponents []*ComponentState `json:"cluster_components"`
	ClusterStatus     ClusterStatus     `json:"cluster_status"`
}

func (m ClusterMeteringStates) Value() (driver.Value, error) {
	b, err := json.Marshal(m)
	return string(b), err
}

func (m *ClusterMeteringStates) Scan(input interface{}) error {
	return json.Unmarshal(input.([]byte), m)
}

type BackupStates struct {
	Cost  int64 `json:"cost"`
	Usage int64 `json:"usage"`
}

type NetworkDetailState struct {
	Unit  string `json:"unit"`
	Cost  int64  `json:"cost"`
	Usage int64  `json:"usage"`
}

type NetworkDetailStates []NetworkDetailState

type ProjectMeteringStates struct {
	NetworkDetailStates NetworkDetailStates `json:"network_detail_states"`
	BackupStates        BackupStates        `json:"backup_states"`
}

func (m ProjectMeteringStates) Value() (driver.Value, error) {
	b, err := json.Marshal(m)
	return string(b), err
}

func (m *ProjectMeteringStates) Scan(input interface{}) error {
	return json.Unmarshal(input.([]byte), m)
}

type ProjectMetering struct {
	Updatable

	TenantID  ID        `gorm:"index;not null"`
	ProjectID ID        `gorm:"not null;uniqueIndex:unq_pid_sts,priority:1"`
	StartTS   time.Time `gorm:"timestamp;uniqueIndex:unq_pid_sts,priority:2"`
	EndTS     time.Time `gorm:"timestamp"`
	Latest    bool      `gorm:"not null;default true"`

	ProjectMeteringStates ProjectMeteringStates `gorm:"type:JSON"`
}

type ClusterMetering struct {
	Updatable

	TenantID  ID        `gorm:"index;not null"`
	ProjectID ID        `gorm:"index;not null"`
	ClusterID ID        `gorm:"not null;uniqueIndex:unq_cid_sts,priority:1"`
	StartTS   time.Time `gorm:"timestamp;uniqueIndex:unq_cid_sts,priority:2"`
	EndTS     time.Time `gorm:"timestamp"`
	Latest    bool      `gorm:"not null;default true"`

	ClusterMeteringStates ClusterMeteringStates `gorm:"type:JSON"`
}

func (m MeteringReportData) Value() (driver.Value, error) {
	b, err := json.Marshal(m)
	return string(b), err
}

func (m *MeteringReportData) Scan(input interface{}) error {
	return json.Unmarshal(input.([]byte), m)
}

type MeteringReportDataItem struct {
	CostID        string            `json:"cost_id"`
	SKU           string            `json:"sku"`
	CostTimeStamp int64             `json:"cost_time_stamp"`
	Cost          int64             `json:"cost"`
	Labels        map[string]string `json:"labels"`
	Memo          string            `json:"memo"`
}

type MeteringReportData struct {
	Items []*MeteringReportDataItem `json:"items"`
}

// gen:qs
type BillingReportRecord struct {
	Updatable

	Data              MeteringReportData `gorm:"type:JSON"`
	Status            string             `gorm:"not null;type:ENUM('synced', 'unsynced')"`
	ProjectMeteringID ID                 `gorm:"not null;default '0';index"`
	ClusterMeteringID ID                 `gorm:"not null;default '0';index"`
	TenantID          ID                 `gorm:"not null;index"`
}

// gen:qs
type ClusterComponent struct {
	Updatable

	TenantID          ID               `gorm:"not null;index"`
	ProjectID         ID               `gorm:"not null;index"`
	ClusterID         ID               `gorm:"not null;uniqueIndex:unq_cid_ctype_rid,priority:1"`
	Cluster           *Cluster         `gorm:"foreignkey:ClusterID"`
	ComponentType     ComponentName    `gorm:"not null;uniqueIndex:unq_cid_ctype_rid,priority:2;type:ENUM('pd', 'tikv', 'tidb', 'tiflash', 'ticdc')"`
	RegionID          ID               `gorm:"index;uniqueIndex:unq_cid_ctype_rid,priority:3;not null"`
	Region            *Region          `gorm:"foreignkey:RegionID"`
	StorageSizeGi     uint32           `gorm:"not null"`
	Replicas          uint32           `gorm:"not null"`
	InternalProfileID ID               `gorm:"index;not null"`
	InternalProfile   *InternalProfile `gorm:"foreignkey:InternalProfileID"`
	LabelProfileID    ID               `gorm:"index;not null"`
	LabelProfile      *LabelProfile    `gorm:"foreignkey:LabelProfileID"`
}

// Used to backup and restore the cluster with the same configuration as the original cluster
// gen:qs
type ClusterSnapshot struct {
	Updatable
	Versioned

	TenantID        ID              `gorm:"index;not null"`
	ProjectID       ID              `gorm:"index;not null"`
	ClusterID       ID              `gorm:"index;not null"`
	Cluster         *Cluster        `gorm:"foreignkey:ClusterID"`
	ComponentStates ComponentStates `gorm:"type:JSON"`
}

type PDNode struct {
	NodeName string `json:"node_name"`
	NodeNum  int    `json:"node_num"`
}

// Value marshal json
func (args PDNode) Value() (driver.Value, error) {
	b, err := json.Marshal(args)
	return string(b), err
}

// Scan unmarshal json
func (args *PDNode) Scan(input interface{}) error {
	return json.Unmarshal(input.([]byte), args)
}
