diff --git a/backend/cmd/server/wire.go b/backend/cmd/server/wire.go index 64709b5b..9bfa2717 100644 --- a/backend/cmd/server/wire.go +++ b/backend/cmd/server/wire.go @@ -97,6 +97,7 @@ func provideCleanup( scheduledTestRunner *service.ScheduledTestRunnerService, backupSvc *service.BackupService, paymentOrderExpiry *service.PaymentOrderExpiryService, + channelMonitorRunner *service.ChannelMonitorRunner, ) func() { return func() { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -239,6 +240,12 @@ func provideCleanup( } return nil }}, + {"ChannelMonitorRunner", func() error { + if channelMonitorRunner != nil { + channelMonitorRunner.Stop() + } + return nil + }}, } infraSteps := []cleanupStep{ diff --git a/backend/cmd/server/wire_gen.go b/backend/cmd/server/wire_gen.go index 407f3026..93270e7e 100644 --- a/backend/cmd/server/wire_gen.go +++ b/backend/cmd/server/wire_gen.go @@ -176,7 +176,7 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) { claudeTokenProvider := service.ProvideClaudeTokenProvider(accountRepository, geminiTokenCache, oAuthService, oAuthRefreshAPI) digestSessionStore := service.NewDigestSessionStore() channelRepository := repository.NewChannelRepository(db) - channelService := service.NewChannelService(channelRepository, apiKeyAuthCacheInvalidator) + channelService := service.NewChannelService(channelRepository, groupRepository, apiKeyAuthCacheInvalidator, pricingService) modelPricingResolver := service.NewModelPricingResolver(channelService, billingService) balanceNotifyService := service.ProvideBalanceNotifyService(emailService, settingRepository, accountRepository) gatewayService := service.NewGatewayService(accountRepository, groupRepository, usageLogRepository, usageBillingRepository, userRepository, userSubscriptionRepository, userGroupRateRepository, gatewayCache, configConfig, schedulerSnapshotService, concurrencyService, billingService, rateLimitService, billingCacheService, identityService, httpUpstream, deferredService, claudeTokenProvider, sessionLimitCache, rpmCache, digestSessionStore, settingService, tlsFingerprintProfileService, channelService, modelPricingResolver, balanceNotifyService) @@ -221,8 +221,21 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) { scheduledTestService := service.ProvideScheduledTestService(scheduledTestPlanRepository, scheduledTestResultRepository) scheduledTestHandler := admin.NewScheduledTestHandler(scheduledTestService) channelHandler := admin.NewChannelHandler(channelService, billingService) + sqlDB, err := repository.ProvideSQLDB(client) + if err != nil { + return nil, err + } + channelMonitorRepository := repository.NewChannelMonitorRepository(client, sqlDB) + channelMonitorRequestTemplateRepository := repository.NewChannelMonitorRequestTemplateRepository(client, sqlDB) + channelMonitorRequestTemplateService := service.NewChannelMonitorRequestTemplateService(channelMonitorRequestTemplateRepository) + channelMonitorRequestTemplateHandler := admin.NewChannelMonitorRequestTemplateHandler(channelMonitorRequestTemplateService) + channelMonitorService := service.ProvideChannelMonitorService(channelMonitorRepository, secretEncryptor) + channelMonitorHandler := admin.NewChannelMonitorHandler(channelMonitorService) + channelMonitorUserHandler := handler.NewChannelMonitorUserHandler(channelMonitorService, settingService) + channelMonitorRunner := service.ProvideChannelMonitorRunner(channelMonitorService, settingService) paymentHandler := admin.NewPaymentHandler(paymentService, paymentConfigService) - adminHandlers := handler.ProvideAdminHandlers(dashboardHandler, adminUserHandler, groupHandler, accountHandler, adminAnnouncementHandler, dataManagementHandler, backupHandler, oAuthHandler, openAIOAuthHandler, geminiOAuthHandler, antigravityOAuthHandler, proxyHandler, adminRedeemHandler, promoHandler, settingHandler, opsHandler, systemHandler, adminSubscriptionHandler, adminUsageHandler, userAttributeHandler, errorPassthroughHandler, tlsFingerprintProfileHandler, adminAPIKeyHandler, scheduledTestHandler, channelHandler, paymentHandler) + availableChannelUserHandler := handler.NewAvailableChannelHandler(channelService, apiKeyService, settingService) + adminHandlers := handler.ProvideAdminHandlers(dashboardHandler, adminUserHandler, groupHandler, accountHandler, adminAnnouncementHandler, dataManagementHandler, backupHandler, oAuthHandler, openAIOAuthHandler, geminiOAuthHandler, antigravityOAuthHandler, proxyHandler, adminRedeemHandler, promoHandler, settingHandler, opsHandler, systemHandler, adminSubscriptionHandler, adminUsageHandler, userAttributeHandler, errorPassthroughHandler, tlsFingerprintProfileHandler, adminAPIKeyHandler, scheduledTestHandler, channelHandler, channelMonitorHandler, channelMonitorRequestTemplateHandler, paymentHandler) usageRecordWorkerPool := service.NewUsageRecordWorkerPool(configConfig) userMsgQueueCache := repository.NewUserMsgQueueCache(redisClient) userMessageQueueService := service.ProvideUserMessageQueueService(userMsgQueueCache, rpmCache, configConfig) @@ -234,7 +247,7 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) { paymentWebhookHandler := handler.NewPaymentWebhookHandler(paymentService, registry) idempotencyCoordinator := service.ProvideIdempotencyCoordinator(idempotencyRepository, configConfig) idempotencyCleanupService := service.ProvideIdempotencyCleanupService(idempotencyRepository, configConfig) - handlers := handler.ProvideHandlers(authHandler, userHandler, apiKeyHandler, usageHandler, redeemHandler, subscriptionHandler, announcementHandler, adminHandlers, gatewayHandler, openAIGatewayHandler, handlerSettingHandler, totpHandler, handlerPaymentHandler, paymentWebhookHandler, idempotencyCoordinator, idempotencyCleanupService) + handlers := handler.ProvideHandlers(authHandler, userHandler, apiKeyHandler, usageHandler, redeemHandler, subscriptionHandler, announcementHandler, channelMonitorUserHandler, adminHandlers, gatewayHandler, openAIGatewayHandler, handlerSettingHandler, totpHandler, handlerPaymentHandler, paymentWebhookHandler, availableChannelUserHandler, idempotencyCoordinator, idempotencyCleanupService) jwtAuthMiddleware := middleware.NewJWTAuthMiddleware(authService, userService) adminAuthMiddleware := middleware.NewAdminAuthMiddleware(authService, userService, settingService) apiKeyAuthMiddleware := middleware.NewAPIKeyAuthMiddleware(apiKeyService, subscriptionService, configConfig) @@ -243,14 +256,14 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) { opsMetricsCollector := service.ProvideOpsMetricsCollector(opsRepository, settingRepository, accountRepository, concurrencyService, db, redisClient, configConfig) opsAggregationService := service.ProvideOpsAggregationService(opsRepository, settingRepository, db, redisClient, configConfig) opsAlertEvaluatorService := service.ProvideOpsAlertEvaluatorService(opsService, opsRepository, emailService, redisClient, configConfig) - opsCleanupService := service.ProvideOpsCleanupService(opsRepository, db, redisClient, configConfig) + opsCleanupService := service.ProvideOpsCleanupService(opsRepository, db, redisClient, configConfig, channelMonitorService) opsScheduledReportService := service.ProvideOpsScheduledReportService(opsService, userService, emailService, redisClient, configConfig) tokenRefreshService := service.ProvideTokenRefreshService(accountRepository, oAuthService, openAIOAuthService, geminiOAuthService, antigravityOAuthService, compositeTokenCacheInvalidator, schedulerCache, configConfig, tempUnschedCache, privacyClientFactory, proxyRepository, oAuthRefreshAPI) accountExpiryService := service.ProvideAccountExpiryService(accountRepository) subscriptionExpiryService := service.ProvideSubscriptionExpiryService(userSubscriptionRepository) scheduledTestRunnerService := service.ProvideScheduledTestRunnerService(scheduledTestPlanRepository, scheduledTestService, accountTestService, rateLimitService, configConfig) paymentOrderExpiryService := service.ProvidePaymentOrderExpiryService(paymentService) - v := provideCleanup(client, redisClient, opsMetricsCollector, opsAggregationService, opsAlertEvaluatorService, opsCleanupService, opsScheduledReportService, opsSystemLogSink, schedulerSnapshotService, tokenRefreshService, accountExpiryService, subscriptionExpiryService, usageCleanupService, idempotencyCleanupService, pricingService, emailQueueService, billingCacheService, usageRecordWorkerPool, subscriptionService, oAuthService, openAIOAuthService, geminiOAuthService, antigravityOAuthService, openAIGatewayService, scheduledTestRunnerService, backupService, paymentOrderExpiryService) + v := provideCleanup(client, redisClient, opsMetricsCollector, opsAggregationService, opsAlertEvaluatorService, opsCleanupService, opsScheduledReportService, opsSystemLogSink, schedulerSnapshotService, tokenRefreshService, accountExpiryService, subscriptionExpiryService, usageCleanupService, idempotencyCleanupService, pricingService, emailQueueService, billingCacheService, usageRecordWorkerPool, subscriptionService, oAuthService, openAIOAuthService, geminiOAuthService, antigravityOAuthService, openAIGatewayService, scheduledTestRunnerService, backupService, paymentOrderExpiryService, channelMonitorRunner) application := &Application{ Server: httpServer, Cleanup: v, @@ -304,6 +317,7 @@ func provideCleanup( scheduledTestRunner *service.ScheduledTestRunnerService, backupSvc *service.BackupService, paymentOrderExpiry *service.PaymentOrderExpiryService, + channelMonitorRunner *service.ChannelMonitorRunner, ) func() { return func() { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -445,6 +459,12 @@ func provideCleanup( } return nil }}, + {"ChannelMonitorRunner", func() error { + if channelMonitorRunner != nil { + channelMonitorRunner.Stop() + } + return nil + }}, } infraSteps := []cleanupStep{ diff --git a/backend/cmd/server/wire_gen_test.go b/backend/cmd/server/wire_gen_test.go index cb07862d..5ccd67fb 100644 --- a/backend/cmd/server/wire_gen_test.go +++ b/backend/cmd/server/wire_gen_test.go @@ -76,6 +76,7 @@ func TestProvideCleanup_WithMinimalDependencies_NoPanic(t *testing.T) { nil, // scheduledTestRunner nil, // backupSvc nil, // paymentOrderExpiry + nil, // channelMonitorRunner ) require.NotPanics(t, func() { diff --git a/backend/ent/channelmonitor.go b/backend/ent/channelmonitor.go new file mode 100644 index 00000000..dbb73362 --- /dev/null +++ b/backend/ent/channelmonitor.go @@ -0,0 +1,359 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "encoding/json" + "fmt" + "strings" + "time" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" +) + +// ChannelMonitor is the model entity for the ChannelMonitor schema. +type ChannelMonitor struct { + config `json:"-"` + // ID of the ent. + ID int64 `json:"id,omitempty"` + // CreatedAt holds the value of the "created_at" field. + CreatedAt time.Time `json:"created_at,omitempty"` + // UpdatedAt holds the value of the "updated_at" field. + UpdatedAt time.Time `json:"updated_at,omitempty"` + // Name holds the value of the "name" field. + Name string `json:"name,omitempty"` + // Provider holds the value of the "provider" field. + Provider channelmonitor.Provider `json:"provider,omitempty"` + // Provider base origin, e.g. https://api.openai.com + Endpoint string `json:"endpoint,omitempty"` + // AES-256-GCM encrypted API key + APIKeyEncrypted string `json:"-"` + // PrimaryModel holds the value of the "primary_model" field. + PrimaryModel string `json:"primary_model,omitempty"` + // Additional model names to test alongside primary_model + ExtraModels []string `json:"extra_models,omitempty"` + // GroupName holds the value of the "group_name" field. + GroupName string `json:"group_name,omitempty"` + // Enabled holds the value of the "enabled" field. + Enabled bool `json:"enabled,omitempty"` + // IntervalSeconds holds the value of the "interval_seconds" field. + IntervalSeconds int `json:"interval_seconds,omitempty"` + // LastCheckedAt holds the value of the "last_checked_at" field. + LastCheckedAt *time.Time `json:"last_checked_at,omitempty"` + // CreatedBy holds the value of the "created_by" field. + CreatedBy int64 `json:"created_by,omitempty"` + // TemplateID holds the value of the "template_id" field. + TemplateID *int64 `json:"template_id,omitempty"` + // ExtraHeaders holds the value of the "extra_headers" field. + ExtraHeaders map[string]string `json:"extra_headers,omitempty"` + // BodyOverrideMode holds the value of the "body_override_mode" field. + BodyOverrideMode string `json:"body_override_mode,omitempty"` + // BodyOverride holds the value of the "body_override" field. + BodyOverride map[string]interface{} `json:"body_override,omitempty"` + // Edges holds the relations/edges for other nodes in the graph. + // The values are being populated by the ChannelMonitorQuery when eager-loading is set. + Edges ChannelMonitorEdges `json:"edges"` + selectValues sql.SelectValues +} + +// ChannelMonitorEdges holds the relations/edges for other nodes in the graph. +type ChannelMonitorEdges struct { + // History holds the value of the history edge. + History []*ChannelMonitorHistory `json:"history,omitempty"` + // DailyRollups holds the value of the daily_rollups edge. + DailyRollups []*ChannelMonitorDailyRollup `json:"daily_rollups,omitempty"` + // RequestTemplate holds the value of the request_template edge. + RequestTemplate *ChannelMonitorRequestTemplate `json:"request_template,omitempty"` + // loadedTypes holds the information for reporting if a + // type was loaded (or requested) in eager-loading or not. + loadedTypes [3]bool +} + +// HistoryOrErr returns the History value or an error if the edge +// was not loaded in eager-loading. +func (e ChannelMonitorEdges) HistoryOrErr() ([]*ChannelMonitorHistory, error) { + if e.loadedTypes[0] { + return e.History, nil + } + return nil, &NotLoadedError{edge: "history"} +} + +// DailyRollupsOrErr returns the DailyRollups value or an error if the edge +// was not loaded in eager-loading. +func (e ChannelMonitorEdges) DailyRollupsOrErr() ([]*ChannelMonitorDailyRollup, error) { + if e.loadedTypes[1] { + return e.DailyRollups, nil + } + return nil, &NotLoadedError{edge: "daily_rollups"} +} + +// RequestTemplateOrErr returns the RequestTemplate value or an error if the edge +// was not loaded in eager-loading, or loaded but was not found. +func (e ChannelMonitorEdges) RequestTemplateOrErr() (*ChannelMonitorRequestTemplate, error) { + if e.RequestTemplate != nil { + return e.RequestTemplate, nil + } else if e.loadedTypes[2] { + return nil, &NotFoundError{label: channelmonitorrequesttemplate.Label} + } + return nil, &NotLoadedError{edge: "request_template"} +} + +// scanValues returns the types for scanning values from sql.Rows. +func (*ChannelMonitor) scanValues(columns []string) ([]any, error) { + values := make([]any, len(columns)) + for i := range columns { + switch columns[i] { + case channelmonitor.FieldExtraModels, channelmonitor.FieldExtraHeaders, channelmonitor.FieldBodyOverride: + values[i] = new([]byte) + case channelmonitor.FieldEnabled: + values[i] = new(sql.NullBool) + case channelmonitor.FieldID, channelmonitor.FieldIntervalSeconds, channelmonitor.FieldCreatedBy, channelmonitor.FieldTemplateID: + values[i] = new(sql.NullInt64) + case channelmonitor.FieldName, channelmonitor.FieldProvider, channelmonitor.FieldEndpoint, channelmonitor.FieldAPIKeyEncrypted, channelmonitor.FieldPrimaryModel, channelmonitor.FieldGroupName, channelmonitor.FieldBodyOverrideMode: + values[i] = new(sql.NullString) + case channelmonitor.FieldCreatedAt, channelmonitor.FieldUpdatedAt, channelmonitor.FieldLastCheckedAt: + values[i] = new(sql.NullTime) + default: + values[i] = new(sql.UnknownType) + } + } + return values, nil +} + +// assignValues assigns the values that were returned from sql.Rows (after scanning) +// to the ChannelMonitor fields. +func (_m *ChannelMonitor) assignValues(columns []string, values []any) error { + if m, n := len(values), len(columns); m < n { + return fmt.Errorf("mismatch number of scan values: %d != %d", m, n) + } + for i := range columns { + switch columns[i] { + case channelmonitor.FieldID: + value, ok := values[i].(*sql.NullInt64) + if !ok { + return fmt.Errorf("unexpected type %T for field id", value) + } + _m.ID = int64(value.Int64) + case channelmonitor.FieldCreatedAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field created_at", values[i]) + } else if value.Valid { + _m.CreatedAt = value.Time + } + case channelmonitor.FieldUpdatedAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field updated_at", values[i]) + } else if value.Valid { + _m.UpdatedAt = value.Time + } + case channelmonitor.FieldName: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field name", values[i]) + } else if value.Valid { + _m.Name = value.String + } + case channelmonitor.FieldProvider: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field provider", values[i]) + } else if value.Valid { + _m.Provider = channelmonitor.Provider(value.String) + } + case channelmonitor.FieldEndpoint: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field endpoint", values[i]) + } else if value.Valid { + _m.Endpoint = value.String + } + case channelmonitor.FieldAPIKeyEncrypted: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field api_key_encrypted", values[i]) + } else if value.Valid { + _m.APIKeyEncrypted = value.String + } + case channelmonitor.FieldPrimaryModel: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field primary_model", values[i]) + } else if value.Valid { + _m.PrimaryModel = value.String + } + case channelmonitor.FieldExtraModels: + if value, ok := values[i].(*[]byte); !ok { + return fmt.Errorf("unexpected type %T for field extra_models", values[i]) + } else if value != nil && len(*value) > 0 { + if err := json.Unmarshal(*value, &_m.ExtraModels); err != nil { + return fmt.Errorf("unmarshal field extra_models: %w", err) + } + } + case channelmonitor.FieldGroupName: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field group_name", values[i]) + } else if value.Valid { + _m.GroupName = value.String + } + case channelmonitor.FieldEnabled: + if value, ok := values[i].(*sql.NullBool); !ok { + return fmt.Errorf("unexpected type %T for field enabled", values[i]) + } else if value.Valid { + _m.Enabled = value.Bool + } + case channelmonitor.FieldIntervalSeconds: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field interval_seconds", values[i]) + } else if value.Valid { + _m.IntervalSeconds = int(value.Int64) + } + case channelmonitor.FieldLastCheckedAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field last_checked_at", values[i]) + } else if value.Valid { + _m.LastCheckedAt = new(time.Time) + *_m.LastCheckedAt = value.Time + } + case channelmonitor.FieldCreatedBy: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field created_by", values[i]) + } else if value.Valid { + _m.CreatedBy = value.Int64 + } + case channelmonitor.FieldTemplateID: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field template_id", values[i]) + } else if value.Valid { + _m.TemplateID = new(int64) + *_m.TemplateID = value.Int64 + } + case channelmonitor.FieldExtraHeaders: + if value, ok := values[i].(*[]byte); !ok { + return fmt.Errorf("unexpected type %T for field extra_headers", values[i]) + } else if value != nil && len(*value) > 0 { + if err := json.Unmarshal(*value, &_m.ExtraHeaders); err != nil { + return fmt.Errorf("unmarshal field extra_headers: %w", err) + } + } + case channelmonitor.FieldBodyOverrideMode: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field body_override_mode", values[i]) + } else if value.Valid { + _m.BodyOverrideMode = value.String + } + case channelmonitor.FieldBodyOverride: + if value, ok := values[i].(*[]byte); !ok { + return fmt.Errorf("unexpected type %T for field body_override", values[i]) + } else if value != nil && len(*value) > 0 { + if err := json.Unmarshal(*value, &_m.BodyOverride); err != nil { + return fmt.Errorf("unmarshal field body_override: %w", err) + } + } + default: + _m.selectValues.Set(columns[i], values[i]) + } + } + return nil +} + +// Value returns the ent.Value that was dynamically selected and assigned to the ChannelMonitor. +// This includes values selected through modifiers, order, etc. +func (_m *ChannelMonitor) Value(name string) (ent.Value, error) { + return _m.selectValues.Get(name) +} + +// QueryHistory queries the "history" edge of the ChannelMonitor entity. +func (_m *ChannelMonitor) QueryHistory() *ChannelMonitorHistoryQuery { + return NewChannelMonitorClient(_m.config).QueryHistory(_m) +} + +// QueryDailyRollups queries the "daily_rollups" edge of the ChannelMonitor entity. +func (_m *ChannelMonitor) QueryDailyRollups() *ChannelMonitorDailyRollupQuery { + return NewChannelMonitorClient(_m.config).QueryDailyRollups(_m) +} + +// QueryRequestTemplate queries the "request_template" edge of the ChannelMonitor entity. +func (_m *ChannelMonitor) QueryRequestTemplate() *ChannelMonitorRequestTemplateQuery { + return NewChannelMonitorClient(_m.config).QueryRequestTemplate(_m) +} + +// Update returns a builder for updating this ChannelMonitor. +// Note that you need to call ChannelMonitor.Unwrap() before calling this method if this ChannelMonitor +// was returned from a transaction, and the transaction was committed or rolled back. +func (_m *ChannelMonitor) Update() *ChannelMonitorUpdateOne { + return NewChannelMonitorClient(_m.config).UpdateOne(_m) +} + +// Unwrap unwraps the ChannelMonitor entity that was returned from a transaction after it was closed, +// so that all future queries will be executed through the driver which created the transaction. +func (_m *ChannelMonitor) Unwrap() *ChannelMonitor { + _tx, ok := _m.config.driver.(*txDriver) + if !ok { + panic("ent: ChannelMonitor is not a transactional entity") + } + _m.config.driver = _tx.drv + return _m +} + +// String implements the fmt.Stringer. +func (_m *ChannelMonitor) String() string { + var builder strings.Builder + builder.WriteString("ChannelMonitor(") + builder.WriteString(fmt.Sprintf("id=%v, ", _m.ID)) + builder.WriteString("created_at=") + builder.WriteString(_m.CreatedAt.Format(time.ANSIC)) + builder.WriteString(", ") + builder.WriteString("updated_at=") + builder.WriteString(_m.UpdatedAt.Format(time.ANSIC)) + builder.WriteString(", ") + builder.WriteString("name=") + builder.WriteString(_m.Name) + builder.WriteString(", ") + builder.WriteString("provider=") + builder.WriteString(fmt.Sprintf("%v", _m.Provider)) + builder.WriteString(", ") + builder.WriteString("endpoint=") + builder.WriteString(_m.Endpoint) + builder.WriteString(", ") + builder.WriteString("api_key_encrypted=") + builder.WriteString(", ") + builder.WriteString("primary_model=") + builder.WriteString(_m.PrimaryModel) + builder.WriteString(", ") + builder.WriteString("extra_models=") + builder.WriteString(fmt.Sprintf("%v", _m.ExtraModels)) + builder.WriteString(", ") + builder.WriteString("group_name=") + builder.WriteString(_m.GroupName) + builder.WriteString(", ") + builder.WriteString("enabled=") + builder.WriteString(fmt.Sprintf("%v", _m.Enabled)) + builder.WriteString(", ") + builder.WriteString("interval_seconds=") + builder.WriteString(fmt.Sprintf("%v", _m.IntervalSeconds)) + builder.WriteString(", ") + if v := _m.LastCheckedAt; v != nil { + builder.WriteString("last_checked_at=") + builder.WriteString(v.Format(time.ANSIC)) + } + builder.WriteString(", ") + builder.WriteString("created_by=") + builder.WriteString(fmt.Sprintf("%v", _m.CreatedBy)) + builder.WriteString(", ") + if v := _m.TemplateID; v != nil { + builder.WriteString("template_id=") + builder.WriteString(fmt.Sprintf("%v", *v)) + } + builder.WriteString(", ") + builder.WriteString("extra_headers=") + builder.WriteString(fmt.Sprintf("%v", _m.ExtraHeaders)) + builder.WriteString(", ") + builder.WriteString("body_override_mode=") + builder.WriteString(_m.BodyOverrideMode) + builder.WriteString(", ") + builder.WriteString("body_override=") + builder.WriteString(fmt.Sprintf("%v", _m.BodyOverride)) + builder.WriteByte(')') + return builder.String() +} + +// ChannelMonitors is a parsable slice of ChannelMonitor. +type ChannelMonitors []*ChannelMonitor diff --git a/backend/ent/channelmonitor/channelmonitor.go b/backend/ent/channelmonitor/channelmonitor.go new file mode 100644 index 00000000..e5a6bfe7 --- /dev/null +++ b/backend/ent/channelmonitor/channelmonitor.go @@ -0,0 +1,304 @@ +// Code generated by ent, DO NOT EDIT. + +package channelmonitor + +import ( + "fmt" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" +) + +const ( + // Label holds the string label denoting the channelmonitor type in the database. + Label = "channel_monitor" + // FieldID holds the string denoting the id field in the database. + FieldID = "id" + // FieldCreatedAt holds the string denoting the created_at field in the database. + FieldCreatedAt = "created_at" + // FieldUpdatedAt holds the string denoting the updated_at field in the database. + FieldUpdatedAt = "updated_at" + // FieldName holds the string denoting the name field in the database. + FieldName = "name" + // FieldProvider holds the string denoting the provider field in the database. + FieldProvider = "provider" + // FieldEndpoint holds the string denoting the endpoint field in the database. + FieldEndpoint = "endpoint" + // FieldAPIKeyEncrypted holds the string denoting the api_key_encrypted field in the database. + FieldAPIKeyEncrypted = "api_key_encrypted" + // FieldPrimaryModel holds the string denoting the primary_model field in the database. + FieldPrimaryModel = "primary_model" + // FieldExtraModels holds the string denoting the extra_models field in the database. + FieldExtraModels = "extra_models" + // FieldGroupName holds the string denoting the group_name field in the database. + FieldGroupName = "group_name" + // FieldEnabled holds the string denoting the enabled field in the database. + FieldEnabled = "enabled" + // FieldIntervalSeconds holds the string denoting the interval_seconds field in the database. + FieldIntervalSeconds = "interval_seconds" + // FieldLastCheckedAt holds the string denoting the last_checked_at field in the database. + FieldLastCheckedAt = "last_checked_at" + // FieldCreatedBy holds the string denoting the created_by field in the database. + FieldCreatedBy = "created_by" + // FieldTemplateID holds the string denoting the template_id field in the database. + FieldTemplateID = "template_id" + // FieldExtraHeaders holds the string denoting the extra_headers field in the database. + FieldExtraHeaders = "extra_headers" + // FieldBodyOverrideMode holds the string denoting the body_override_mode field in the database. + FieldBodyOverrideMode = "body_override_mode" + // FieldBodyOverride holds the string denoting the body_override field in the database. + FieldBodyOverride = "body_override" + // EdgeHistory holds the string denoting the history edge name in mutations. + EdgeHistory = "history" + // EdgeDailyRollups holds the string denoting the daily_rollups edge name in mutations. + EdgeDailyRollups = "daily_rollups" + // EdgeRequestTemplate holds the string denoting the request_template edge name in mutations. + EdgeRequestTemplate = "request_template" + // Table holds the table name of the channelmonitor in the database. + Table = "channel_monitors" + // HistoryTable is the table that holds the history relation/edge. + HistoryTable = "channel_monitor_histories" + // HistoryInverseTable is the table name for the ChannelMonitorHistory entity. + // It exists in this package in order to avoid circular dependency with the "channelmonitorhistory" package. + HistoryInverseTable = "channel_monitor_histories" + // HistoryColumn is the table column denoting the history relation/edge. + HistoryColumn = "monitor_id" + // DailyRollupsTable is the table that holds the daily_rollups relation/edge. + DailyRollupsTable = "channel_monitor_daily_rollups" + // DailyRollupsInverseTable is the table name for the ChannelMonitorDailyRollup entity. + // It exists in this package in order to avoid circular dependency with the "channelmonitordailyrollup" package. + DailyRollupsInverseTable = "channel_monitor_daily_rollups" + // DailyRollupsColumn is the table column denoting the daily_rollups relation/edge. + DailyRollupsColumn = "monitor_id" + // RequestTemplateTable is the table that holds the request_template relation/edge. + RequestTemplateTable = "channel_monitors" + // RequestTemplateInverseTable is the table name for the ChannelMonitorRequestTemplate entity. + // It exists in this package in order to avoid circular dependency with the "channelmonitorrequesttemplate" package. + RequestTemplateInverseTable = "channel_monitor_request_templates" + // RequestTemplateColumn is the table column denoting the request_template relation/edge. + RequestTemplateColumn = "template_id" +) + +// Columns holds all SQL columns for channelmonitor fields. +var Columns = []string{ + FieldID, + FieldCreatedAt, + FieldUpdatedAt, + FieldName, + FieldProvider, + FieldEndpoint, + FieldAPIKeyEncrypted, + FieldPrimaryModel, + FieldExtraModels, + FieldGroupName, + FieldEnabled, + FieldIntervalSeconds, + FieldLastCheckedAt, + FieldCreatedBy, + FieldTemplateID, + FieldExtraHeaders, + FieldBodyOverrideMode, + FieldBodyOverride, +} + +// ValidColumn reports if the column name is valid (part of the table columns). +func ValidColumn(column string) bool { + for i := range Columns { + if column == Columns[i] { + return true + } + } + return false +} + +var ( + // DefaultCreatedAt holds the default value on creation for the "created_at" field. + DefaultCreatedAt func() time.Time + // DefaultUpdatedAt holds the default value on creation for the "updated_at" field. + DefaultUpdatedAt func() time.Time + // UpdateDefaultUpdatedAt holds the default value on update for the "updated_at" field. + UpdateDefaultUpdatedAt func() time.Time + // NameValidator is a validator for the "name" field. It is called by the builders before save. + NameValidator func(string) error + // EndpointValidator is a validator for the "endpoint" field. It is called by the builders before save. + EndpointValidator func(string) error + // APIKeyEncryptedValidator is a validator for the "api_key_encrypted" field. It is called by the builders before save. + APIKeyEncryptedValidator func(string) error + // PrimaryModelValidator is a validator for the "primary_model" field. It is called by the builders before save. + PrimaryModelValidator func(string) error + // DefaultExtraModels holds the default value on creation for the "extra_models" field. + DefaultExtraModels []string + // DefaultGroupName holds the default value on creation for the "group_name" field. + DefaultGroupName string + // GroupNameValidator is a validator for the "group_name" field. It is called by the builders before save. + GroupNameValidator func(string) error + // DefaultEnabled holds the default value on creation for the "enabled" field. + DefaultEnabled bool + // IntervalSecondsValidator is a validator for the "interval_seconds" field. It is called by the builders before save. + IntervalSecondsValidator func(int) error + // DefaultExtraHeaders holds the default value on creation for the "extra_headers" field. + DefaultExtraHeaders map[string]string + // DefaultBodyOverrideMode holds the default value on creation for the "body_override_mode" field. + DefaultBodyOverrideMode string + // BodyOverrideModeValidator is a validator for the "body_override_mode" field. It is called by the builders before save. + BodyOverrideModeValidator func(string) error +) + +// Provider defines the type for the "provider" enum field. +type Provider string + +// Provider values. +const ( + ProviderOpenai Provider = "openai" + ProviderAnthropic Provider = "anthropic" + ProviderGemini Provider = "gemini" +) + +func (pr Provider) String() string { + return string(pr) +} + +// ProviderValidator is a validator for the "provider" field enum values. It is called by the builders before save. +func ProviderValidator(pr Provider) error { + switch pr { + case ProviderOpenai, ProviderAnthropic, ProviderGemini: + return nil + default: + return fmt.Errorf("channelmonitor: invalid enum value for provider field: %q", pr) + } +} + +// OrderOption defines the ordering options for the ChannelMonitor queries. +type OrderOption func(*sql.Selector) + +// ByID orders the results by the id field. +func ByID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldID, opts...).ToFunc() +} + +// ByCreatedAt orders the results by the created_at field. +func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldCreatedAt, opts...).ToFunc() +} + +// ByUpdatedAt orders the results by the updated_at field. +func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc() +} + +// ByName orders the results by the name field. +func ByName(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldName, opts...).ToFunc() +} + +// ByProvider orders the results by the provider field. +func ByProvider(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldProvider, opts...).ToFunc() +} + +// ByEndpoint orders the results by the endpoint field. +func ByEndpoint(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldEndpoint, opts...).ToFunc() +} + +// ByAPIKeyEncrypted orders the results by the api_key_encrypted field. +func ByAPIKeyEncrypted(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldAPIKeyEncrypted, opts...).ToFunc() +} + +// ByPrimaryModel orders the results by the primary_model field. +func ByPrimaryModel(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldPrimaryModel, opts...).ToFunc() +} + +// ByGroupName orders the results by the group_name field. +func ByGroupName(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldGroupName, opts...).ToFunc() +} + +// ByEnabled orders the results by the enabled field. +func ByEnabled(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldEnabled, opts...).ToFunc() +} + +// ByIntervalSeconds orders the results by the interval_seconds field. +func ByIntervalSeconds(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldIntervalSeconds, opts...).ToFunc() +} + +// ByLastCheckedAt orders the results by the last_checked_at field. +func ByLastCheckedAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldLastCheckedAt, opts...).ToFunc() +} + +// ByCreatedBy orders the results by the created_by field. +func ByCreatedBy(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldCreatedBy, opts...).ToFunc() +} + +// ByTemplateID orders the results by the template_id field. +func ByTemplateID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldTemplateID, opts...).ToFunc() +} + +// ByBodyOverrideMode orders the results by the body_override_mode field. +func ByBodyOverrideMode(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldBodyOverrideMode, opts...).ToFunc() +} + +// ByHistoryCount orders the results by history count. +func ByHistoryCount(opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborsCount(s, newHistoryStep(), opts...) + } +} + +// ByHistory orders the results by history terms. +func ByHistory(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newHistoryStep(), append([]sql.OrderTerm{term}, terms...)...) + } +} + +// ByDailyRollupsCount orders the results by daily_rollups count. +func ByDailyRollupsCount(opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborsCount(s, newDailyRollupsStep(), opts...) + } +} + +// ByDailyRollups orders the results by daily_rollups terms. +func ByDailyRollups(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newDailyRollupsStep(), append([]sql.OrderTerm{term}, terms...)...) + } +} + +// ByRequestTemplateField orders the results by request_template field. +func ByRequestTemplateField(field string, opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newRequestTemplateStep(), sql.OrderByField(field, opts...)) + } +} +func newHistoryStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(HistoryInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, HistoryTable, HistoryColumn), + ) +} +func newDailyRollupsStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(DailyRollupsInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, DailyRollupsTable, DailyRollupsColumn), + ) +} +func newRequestTemplateStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(RequestTemplateInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, RequestTemplateTable, RequestTemplateColumn), + ) +} diff --git a/backend/ent/channelmonitor/where.go b/backend/ent/channelmonitor/where.go new file mode 100644 index 00000000..755d83a3 --- /dev/null +++ b/backend/ent/channelmonitor/where.go @@ -0,0 +1,885 @@ +// Code generated by ent, DO NOT EDIT. + +package channelmonitor + +import ( + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// ID filters vertices based on their ID field. +func ID(id int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldID, id)) +} + +// IDEQ applies the EQ predicate on the ID field. +func IDEQ(id int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldID, id)) +} + +// IDNEQ applies the NEQ predicate on the ID field. +func IDNEQ(id int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNEQ(FieldID, id)) +} + +// IDIn applies the In predicate on the ID field. +func IDIn(ids ...int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldIn(FieldID, ids...)) +} + +// IDNotIn applies the NotIn predicate on the ID field. +func IDNotIn(ids ...int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNotIn(FieldID, ids...)) +} + +// IDGT applies the GT predicate on the ID field. +func IDGT(id int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGT(FieldID, id)) +} + +// IDGTE applies the GTE predicate on the ID field. +func IDGTE(id int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGTE(FieldID, id)) +} + +// IDLT applies the LT predicate on the ID field. +func IDLT(id int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLT(FieldID, id)) +} + +// IDLTE applies the LTE predicate on the ID field. +func IDLTE(id int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLTE(FieldID, id)) +} + +// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ. +func CreatedAt(v time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldCreatedAt, v)) +} + +// UpdatedAt applies equality check predicate on the "updated_at" field. It's identical to UpdatedAtEQ. +func UpdatedAt(v time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldUpdatedAt, v)) +} + +// Name applies equality check predicate on the "name" field. It's identical to NameEQ. +func Name(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldName, v)) +} + +// Endpoint applies equality check predicate on the "endpoint" field. It's identical to EndpointEQ. +func Endpoint(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldEndpoint, v)) +} + +// APIKeyEncrypted applies equality check predicate on the "api_key_encrypted" field. It's identical to APIKeyEncryptedEQ. +func APIKeyEncrypted(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldAPIKeyEncrypted, v)) +} + +// PrimaryModel applies equality check predicate on the "primary_model" field. It's identical to PrimaryModelEQ. +func PrimaryModel(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldPrimaryModel, v)) +} + +// GroupName applies equality check predicate on the "group_name" field. It's identical to GroupNameEQ. +func GroupName(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldGroupName, v)) +} + +// Enabled applies equality check predicate on the "enabled" field. It's identical to EnabledEQ. +func Enabled(v bool) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldEnabled, v)) +} + +// IntervalSeconds applies equality check predicate on the "interval_seconds" field. It's identical to IntervalSecondsEQ. +func IntervalSeconds(v int) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldIntervalSeconds, v)) +} + +// LastCheckedAt applies equality check predicate on the "last_checked_at" field. It's identical to LastCheckedAtEQ. +func LastCheckedAt(v time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldLastCheckedAt, v)) +} + +// CreatedBy applies equality check predicate on the "created_by" field. It's identical to CreatedByEQ. +func CreatedBy(v int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldCreatedBy, v)) +} + +// TemplateID applies equality check predicate on the "template_id" field. It's identical to TemplateIDEQ. +func TemplateID(v int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldTemplateID, v)) +} + +// BodyOverrideMode applies equality check predicate on the "body_override_mode" field. It's identical to BodyOverrideModeEQ. +func BodyOverrideMode(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldBodyOverrideMode, v)) +} + +// CreatedAtEQ applies the EQ predicate on the "created_at" field. +func CreatedAtEQ(v time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldCreatedAt, v)) +} + +// CreatedAtNEQ applies the NEQ predicate on the "created_at" field. +func CreatedAtNEQ(v time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNEQ(FieldCreatedAt, v)) +} + +// CreatedAtIn applies the In predicate on the "created_at" field. +func CreatedAtIn(vs ...time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldIn(FieldCreatedAt, vs...)) +} + +// CreatedAtNotIn applies the NotIn predicate on the "created_at" field. +func CreatedAtNotIn(vs ...time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNotIn(FieldCreatedAt, vs...)) +} + +// CreatedAtGT applies the GT predicate on the "created_at" field. +func CreatedAtGT(v time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGT(FieldCreatedAt, v)) +} + +// CreatedAtGTE applies the GTE predicate on the "created_at" field. +func CreatedAtGTE(v time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGTE(FieldCreatedAt, v)) +} + +// CreatedAtLT applies the LT predicate on the "created_at" field. +func CreatedAtLT(v time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLT(FieldCreatedAt, v)) +} + +// CreatedAtLTE applies the LTE predicate on the "created_at" field. +func CreatedAtLTE(v time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLTE(FieldCreatedAt, v)) +} + +// UpdatedAtEQ applies the EQ predicate on the "updated_at" field. +func UpdatedAtEQ(v time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldUpdatedAt, v)) +} + +// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field. +func UpdatedAtNEQ(v time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNEQ(FieldUpdatedAt, v)) +} + +// UpdatedAtIn applies the In predicate on the "updated_at" field. +func UpdatedAtIn(vs ...time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldIn(FieldUpdatedAt, vs...)) +} + +// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field. +func UpdatedAtNotIn(vs ...time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNotIn(FieldUpdatedAt, vs...)) +} + +// UpdatedAtGT applies the GT predicate on the "updated_at" field. +func UpdatedAtGT(v time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGT(FieldUpdatedAt, v)) +} + +// UpdatedAtGTE applies the GTE predicate on the "updated_at" field. +func UpdatedAtGTE(v time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGTE(FieldUpdatedAt, v)) +} + +// UpdatedAtLT applies the LT predicate on the "updated_at" field. +func UpdatedAtLT(v time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLT(FieldUpdatedAt, v)) +} + +// UpdatedAtLTE applies the LTE predicate on the "updated_at" field. +func UpdatedAtLTE(v time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLTE(FieldUpdatedAt, v)) +} + +// NameEQ applies the EQ predicate on the "name" field. +func NameEQ(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldName, v)) +} + +// NameNEQ applies the NEQ predicate on the "name" field. +func NameNEQ(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNEQ(FieldName, v)) +} + +// NameIn applies the In predicate on the "name" field. +func NameIn(vs ...string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldIn(FieldName, vs...)) +} + +// NameNotIn applies the NotIn predicate on the "name" field. +func NameNotIn(vs ...string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNotIn(FieldName, vs...)) +} + +// NameGT applies the GT predicate on the "name" field. +func NameGT(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGT(FieldName, v)) +} + +// NameGTE applies the GTE predicate on the "name" field. +func NameGTE(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGTE(FieldName, v)) +} + +// NameLT applies the LT predicate on the "name" field. +func NameLT(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLT(FieldName, v)) +} + +// NameLTE applies the LTE predicate on the "name" field. +func NameLTE(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLTE(FieldName, v)) +} + +// NameContains applies the Contains predicate on the "name" field. +func NameContains(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldContains(FieldName, v)) +} + +// NameHasPrefix applies the HasPrefix predicate on the "name" field. +func NameHasPrefix(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldHasPrefix(FieldName, v)) +} + +// NameHasSuffix applies the HasSuffix predicate on the "name" field. +func NameHasSuffix(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldHasSuffix(FieldName, v)) +} + +// NameEqualFold applies the EqualFold predicate on the "name" field. +func NameEqualFold(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEqualFold(FieldName, v)) +} + +// NameContainsFold applies the ContainsFold predicate on the "name" field. +func NameContainsFold(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldContainsFold(FieldName, v)) +} + +// ProviderEQ applies the EQ predicate on the "provider" field. +func ProviderEQ(v Provider) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldProvider, v)) +} + +// ProviderNEQ applies the NEQ predicate on the "provider" field. +func ProviderNEQ(v Provider) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNEQ(FieldProvider, v)) +} + +// ProviderIn applies the In predicate on the "provider" field. +func ProviderIn(vs ...Provider) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldIn(FieldProvider, vs...)) +} + +// ProviderNotIn applies the NotIn predicate on the "provider" field. +func ProviderNotIn(vs ...Provider) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNotIn(FieldProvider, vs...)) +} + +// EndpointEQ applies the EQ predicate on the "endpoint" field. +func EndpointEQ(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldEndpoint, v)) +} + +// EndpointNEQ applies the NEQ predicate on the "endpoint" field. +func EndpointNEQ(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNEQ(FieldEndpoint, v)) +} + +// EndpointIn applies the In predicate on the "endpoint" field. +func EndpointIn(vs ...string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldIn(FieldEndpoint, vs...)) +} + +// EndpointNotIn applies the NotIn predicate on the "endpoint" field. +func EndpointNotIn(vs ...string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNotIn(FieldEndpoint, vs...)) +} + +// EndpointGT applies the GT predicate on the "endpoint" field. +func EndpointGT(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGT(FieldEndpoint, v)) +} + +// EndpointGTE applies the GTE predicate on the "endpoint" field. +func EndpointGTE(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGTE(FieldEndpoint, v)) +} + +// EndpointLT applies the LT predicate on the "endpoint" field. +func EndpointLT(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLT(FieldEndpoint, v)) +} + +// EndpointLTE applies the LTE predicate on the "endpoint" field. +func EndpointLTE(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLTE(FieldEndpoint, v)) +} + +// EndpointContains applies the Contains predicate on the "endpoint" field. +func EndpointContains(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldContains(FieldEndpoint, v)) +} + +// EndpointHasPrefix applies the HasPrefix predicate on the "endpoint" field. +func EndpointHasPrefix(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldHasPrefix(FieldEndpoint, v)) +} + +// EndpointHasSuffix applies the HasSuffix predicate on the "endpoint" field. +func EndpointHasSuffix(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldHasSuffix(FieldEndpoint, v)) +} + +// EndpointEqualFold applies the EqualFold predicate on the "endpoint" field. +func EndpointEqualFold(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEqualFold(FieldEndpoint, v)) +} + +// EndpointContainsFold applies the ContainsFold predicate on the "endpoint" field. +func EndpointContainsFold(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldContainsFold(FieldEndpoint, v)) +} + +// APIKeyEncryptedEQ applies the EQ predicate on the "api_key_encrypted" field. +func APIKeyEncryptedEQ(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldAPIKeyEncrypted, v)) +} + +// APIKeyEncryptedNEQ applies the NEQ predicate on the "api_key_encrypted" field. +func APIKeyEncryptedNEQ(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNEQ(FieldAPIKeyEncrypted, v)) +} + +// APIKeyEncryptedIn applies the In predicate on the "api_key_encrypted" field. +func APIKeyEncryptedIn(vs ...string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldIn(FieldAPIKeyEncrypted, vs...)) +} + +// APIKeyEncryptedNotIn applies the NotIn predicate on the "api_key_encrypted" field. +func APIKeyEncryptedNotIn(vs ...string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNotIn(FieldAPIKeyEncrypted, vs...)) +} + +// APIKeyEncryptedGT applies the GT predicate on the "api_key_encrypted" field. +func APIKeyEncryptedGT(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGT(FieldAPIKeyEncrypted, v)) +} + +// APIKeyEncryptedGTE applies the GTE predicate on the "api_key_encrypted" field. +func APIKeyEncryptedGTE(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGTE(FieldAPIKeyEncrypted, v)) +} + +// APIKeyEncryptedLT applies the LT predicate on the "api_key_encrypted" field. +func APIKeyEncryptedLT(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLT(FieldAPIKeyEncrypted, v)) +} + +// APIKeyEncryptedLTE applies the LTE predicate on the "api_key_encrypted" field. +func APIKeyEncryptedLTE(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLTE(FieldAPIKeyEncrypted, v)) +} + +// APIKeyEncryptedContains applies the Contains predicate on the "api_key_encrypted" field. +func APIKeyEncryptedContains(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldContains(FieldAPIKeyEncrypted, v)) +} + +// APIKeyEncryptedHasPrefix applies the HasPrefix predicate on the "api_key_encrypted" field. +func APIKeyEncryptedHasPrefix(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldHasPrefix(FieldAPIKeyEncrypted, v)) +} + +// APIKeyEncryptedHasSuffix applies the HasSuffix predicate on the "api_key_encrypted" field. +func APIKeyEncryptedHasSuffix(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldHasSuffix(FieldAPIKeyEncrypted, v)) +} + +// APIKeyEncryptedEqualFold applies the EqualFold predicate on the "api_key_encrypted" field. +func APIKeyEncryptedEqualFold(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEqualFold(FieldAPIKeyEncrypted, v)) +} + +// APIKeyEncryptedContainsFold applies the ContainsFold predicate on the "api_key_encrypted" field. +func APIKeyEncryptedContainsFold(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldContainsFold(FieldAPIKeyEncrypted, v)) +} + +// PrimaryModelEQ applies the EQ predicate on the "primary_model" field. +func PrimaryModelEQ(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldPrimaryModel, v)) +} + +// PrimaryModelNEQ applies the NEQ predicate on the "primary_model" field. +func PrimaryModelNEQ(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNEQ(FieldPrimaryModel, v)) +} + +// PrimaryModelIn applies the In predicate on the "primary_model" field. +func PrimaryModelIn(vs ...string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldIn(FieldPrimaryModel, vs...)) +} + +// PrimaryModelNotIn applies the NotIn predicate on the "primary_model" field. +func PrimaryModelNotIn(vs ...string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNotIn(FieldPrimaryModel, vs...)) +} + +// PrimaryModelGT applies the GT predicate on the "primary_model" field. +func PrimaryModelGT(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGT(FieldPrimaryModel, v)) +} + +// PrimaryModelGTE applies the GTE predicate on the "primary_model" field. +func PrimaryModelGTE(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGTE(FieldPrimaryModel, v)) +} + +// PrimaryModelLT applies the LT predicate on the "primary_model" field. +func PrimaryModelLT(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLT(FieldPrimaryModel, v)) +} + +// PrimaryModelLTE applies the LTE predicate on the "primary_model" field. +func PrimaryModelLTE(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLTE(FieldPrimaryModel, v)) +} + +// PrimaryModelContains applies the Contains predicate on the "primary_model" field. +func PrimaryModelContains(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldContains(FieldPrimaryModel, v)) +} + +// PrimaryModelHasPrefix applies the HasPrefix predicate on the "primary_model" field. +func PrimaryModelHasPrefix(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldHasPrefix(FieldPrimaryModel, v)) +} + +// PrimaryModelHasSuffix applies the HasSuffix predicate on the "primary_model" field. +func PrimaryModelHasSuffix(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldHasSuffix(FieldPrimaryModel, v)) +} + +// PrimaryModelEqualFold applies the EqualFold predicate on the "primary_model" field. +func PrimaryModelEqualFold(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEqualFold(FieldPrimaryModel, v)) +} + +// PrimaryModelContainsFold applies the ContainsFold predicate on the "primary_model" field. +func PrimaryModelContainsFold(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldContainsFold(FieldPrimaryModel, v)) +} + +// GroupNameEQ applies the EQ predicate on the "group_name" field. +func GroupNameEQ(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldGroupName, v)) +} + +// GroupNameNEQ applies the NEQ predicate on the "group_name" field. +func GroupNameNEQ(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNEQ(FieldGroupName, v)) +} + +// GroupNameIn applies the In predicate on the "group_name" field. +func GroupNameIn(vs ...string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldIn(FieldGroupName, vs...)) +} + +// GroupNameNotIn applies the NotIn predicate on the "group_name" field. +func GroupNameNotIn(vs ...string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNotIn(FieldGroupName, vs...)) +} + +// GroupNameGT applies the GT predicate on the "group_name" field. +func GroupNameGT(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGT(FieldGroupName, v)) +} + +// GroupNameGTE applies the GTE predicate on the "group_name" field. +func GroupNameGTE(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGTE(FieldGroupName, v)) +} + +// GroupNameLT applies the LT predicate on the "group_name" field. +func GroupNameLT(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLT(FieldGroupName, v)) +} + +// GroupNameLTE applies the LTE predicate on the "group_name" field. +func GroupNameLTE(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLTE(FieldGroupName, v)) +} + +// GroupNameContains applies the Contains predicate on the "group_name" field. +func GroupNameContains(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldContains(FieldGroupName, v)) +} + +// GroupNameHasPrefix applies the HasPrefix predicate on the "group_name" field. +func GroupNameHasPrefix(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldHasPrefix(FieldGroupName, v)) +} + +// GroupNameHasSuffix applies the HasSuffix predicate on the "group_name" field. +func GroupNameHasSuffix(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldHasSuffix(FieldGroupName, v)) +} + +// GroupNameIsNil applies the IsNil predicate on the "group_name" field. +func GroupNameIsNil() predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldIsNull(FieldGroupName)) +} + +// GroupNameNotNil applies the NotNil predicate on the "group_name" field. +func GroupNameNotNil() predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNotNull(FieldGroupName)) +} + +// GroupNameEqualFold applies the EqualFold predicate on the "group_name" field. +func GroupNameEqualFold(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEqualFold(FieldGroupName, v)) +} + +// GroupNameContainsFold applies the ContainsFold predicate on the "group_name" field. +func GroupNameContainsFold(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldContainsFold(FieldGroupName, v)) +} + +// EnabledEQ applies the EQ predicate on the "enabled" field. +func EnabledEQ(v bool) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldEnabled, v)) +} + +// EnabledNEQ applies the NEQ predicate on the "enabled" field. +func EnabledNEQ(v bool) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNEQ(FieldEnabled, v)) +} + +// IntervalSecondsEQ applies the EQ predicate on the "interval_seconds" field. +func IntervalSecondsEQ(v int) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldIntervalSeconds, v)) +} + +// IntervalSecondsNEQ applies the NEQ predicate on the "interval_seconds" field. +func IntervalSecondsNEQ(v int) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNEQ(FieldIntervalSeconds, v)) +} + +// IntervalSecondsIn applies the In predicate on the "interval_seconds" field. +func IntervalSecondsIn(vs ...int) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldIn(FieldIntervalSeconds, vs...)) +} + +// IntervalSecondsNotIn applies the NotIn predicate on the "interval_seconds" field. +func IntervalSecondsNotIn(vs ...int) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNotIn(FieldIntervalSeconds, vs...)) +} + +// IntervalSecondsGT applies the GT predicate on the "interval_seconds" field. +func IntervalSecondsGT(v int) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGT(FieldIntervalSeconds, v)) +} + +// IntervalSecondsGTE applies the GTE predicate on the "interval_seconds" field. +func IntervalSecondsGTE(v int) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGTE(FieldIntervalSeconds, v)) +} + +// IntervalSecondsLT applies the LT predicate on the "interval_seconds" field. +func IntervalSecondsLT(v int) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLT(FieldIntervalSeconds, v)) +} + +// IntervalSecondsLTE applies the LTE predicate on the "interval_seconds" field. +func IntervalSecondsLTE(v int) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLTE(FieldIntervalSeconds, v)) +} + +// LastCheckedAtEQ applies the EQ predicate on the "last_checked_at" field. +func LastCheckedAtEQ(v time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldLastCheckedAt, v)) +} + +// LastCheckedAtNEQ applies the NEQ predicate on the "last_checked_at" field. +func LastCheckedAtNEQ(v time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNEQ(FieldLastCheckedAt, v)) +} + +// LastCheckedAtIn applies the In predicate on the "last_checked_at" field. +func LastCheckedAtIn(vs ...time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldIn(FieldLastCheckedAt, vs...)) +} + +// LastCheckedAtNotIn applies the NotIn predicate on the "last_checked_at" field. +func LastCheckedAtNotIn(vs ...time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNotIn(FieldLastCheckedAt, vs...)) +} + +// LastCheckedAtGT applies the GT predicate on the "last_checked_at" field. +func LastCheckedAtGT(v time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGT(FieldLastCheckedAt, v)) +} + +// LastCheckedAtGTE applies the GTE predicate on the "last_checked_at" field. +func LastCheckedAtGTE(v time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGTE(FieldLastCheckedAt, v)) +} + +// LastCheckedAtLT applies the LT predicate on the "last_checked_at" field. +func LastCheckedAtLT(v time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLT(FieldLastCheckedAt, v)) +} + +// LastCheckedAtLTE applies the LTE predicate on the "last_checked_at" field. +func LastCheckedAtLTE(v time.Time) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLTE(FieldLastCheckedAt, v)) +} + +// LastCheckedAtIsNil applies the IsNil predicate on the "last_checked_at" field. +func LastCheckedAtIsNil() predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldIsNull(FieldLastCheckedAt)) +} + +// LastCheckedAtNotNil applies the NotNil predicate on the "last_checked_at" field. +func LastCheckedAtNotNil() predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNotNull(FieldLastCheckedAt)) +} + +// CreatedByEQ applies the EQ predicate on the "created_by" field. +func CreatedByEQ(v int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldCreatedBy, v)) +} + +// CreatedByNEQ applies the NEQ predicate on the "created_by" field. +func CreatedByNEQ(v int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNEQ(FieldCreatedBy, v)) +} + +// CreatedByIn applies the In predicate on the "created_by" field. +func CreatedByIn(vs ...int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldIn(FieldCreatedBy, vs...)) +} + +// CreatedByNotIn applies the NotIn predicate on the "created_by" field. +func CreatedByNotIn(vs ...int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNotIn(FieldCreatedBy, vs...)) +} + +// CreatedByGT applies the GT predicate on the "created_by" field. +func CreatedByGT(v int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGT(FieldCreatedBy, v)) +} + +// CreatedByGTE applies the GTE predicate on the "created_by" field. +func CreatedByGTE(v int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGTE(FieldCreatedBy, v)) +} + +// CreatedByLT applies the LT predicate on the "created_by" field. +func CreatedByLT(v int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLT(FieldCreatedBy, v)) +} + +// CreatedByLTE applies the LTE predicate on the "created_by" field. +func CreatedByLTE(v int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLTE(FieldCreatedBy, v)) +} + +// TemplateIDEQ applies the EQ predicate on the "template_id" field. +func TemplateIDEQ(v int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldTemplateID, v)) +} + +// TemplateIDNEQ applies the NEQ predicate on the "template_id" field. +func TemplateIDNEQ(v int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNEQ(FieldTemplateID, v)) +} + +// TemplateIDIn applies the In predicate on the "template_id" field. +func TemplateIDIn(vs ...int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldIn(FieldTemplateID, vs...)) +} + +// TemplateIDNotIn applies the NotIn predicate on the "template_id" field. +func TemplateIDNotIn(vs ...int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNotIn(FieldTemplateID, vs...)) +} + +// TemplateIDIsNil applies the IsNil predicate on the "template_id" field. +func TemplateIDIsNil() predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldIsNull(FieldTemplateID)) +} + +// TemplateIDNotNil applies the NotNil predicate on the "template_id" field. +func TemplateIDNotNil() predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNotNull(FieldTemplateID)) +} + +// BodyOverrideModeEQ applies the EQ predicate on the "body_override_mode" field. +func BodyOverrideModeEQ(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeNEQ applies the NEQ predicate on the "body_override_mode" field. +func BodyOverrideModeNEQ(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNEQ(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeIn applies the In predicate on the "body_override_mode" field. +func BodyOverrideModeIn(vs ...string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldIn(FieldBodyOverrideMode, vs...)) +} + +// BodyOverrideModeNotIn applies the NotIn predicate on the "body_override_mode" field. +func BodyOverrideModeNotIn(vs ...string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNotIn(FieldBodyOverrideMode, vs...)) +} + +// BodyOverrideModeGT applies the GT predicate on the "body_override_mode" field. +func BodyOverrideModeGT(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGT(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeGTE applies the GTE predicate on the "body_override_mode" field. +func BodyOverrideModeGTE(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGTE(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeLT applies the LT predicate on the "body_override_mode" field. +func BodyOverrideModeLT(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLT(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeLTE applies the LTE predicate on the "body_override_mode" field. +func BodyOverrideModeLTE(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLTE(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeContains applies the Contains predicate on the "body_override_mode" field. +func BodyOverrideModeContains(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldContains(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeHasPrefix applies the HasPrefix predicate on the "body_override_mode" field. +func BodyOverrideModeHasPrefix(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldHasPrefix(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeHasSuffix applies the HasSuffix predicate on the "body_override_mode" field. +func BodyOverrideModeHasSuffix(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldHasSuffix(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeEqualFold applies the EqualFold predicate on the "body_override_mode" field. +func BodyOverrideModeEqualFold(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEqualFold(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeContainsFold applies the ContainsFold predicate on the "body_override_mode" field. +func BodyOverrideModeContainsFold(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldContainsFold(FieldBodyOverrideMode, v)) +} + +// BodyOverrideIsNil applies the IsNil predicate on the "body_override" field. +func BodyOverrideIsNil() predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldIsNull(FieldBodyOverride)) +} + +// BodyOverrideNotNil applies the NotNil predicate on the "body_override" field. +func BodyOverrideNotNil() predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNotNull(FieldBodyOverride)) +} + +// HasHistory applies the HasEdge predicate on the "history" edge. +func HasHistory() predicate.ChannelMonitor { + return predicate.ChannelMonitor(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, HistoryTable, HistoryColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasHistoryWith applies the HasEdge predicate on the "history" edge with a given conditions (other predicates). +func HasHistoryWith(preds ...predicate.ChannelMonitorHistory) predicate.ChannelMonitor { + return predicate.ChannelMonitor(func(s *sql.Selector) { + step := newHistoryStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + +// HasDailyRollups applies the HasEdge predicate on the "daily_rollups" edge. +func HasDailyRollups() predicate.ChannelMonitor { + return predicate.ChannelMonitor(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, DailyRollupsTable, DailyRollupsColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasDailyRollupsWith applies the HasEdge predicate on the "daily_rollups" edge with a given conditions (other predicates). +func HasDailyRollupsWith(preds ...predicate.ChannelMonitorDailyRollup) predicate.ChannelMonitor { + return predicate.ChannelMonitor(func(s *sql.Selector) { + step := newDailyRollupsStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + +// HasRequestTemplate applies the HasEdge predicate on the "request_template" edge. +func HasRequestTemplate() predicate.ChannelMonitor { + return predicate.ChannelMonitor(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, RequestTemplateTable, RequestTemplateColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasRequestTemplateWith applies the HasEdge predicate on the "request_template" edge with a given conditions (other predicates). +func HasRequestTemplateWith(preds ...predicate.ChannelMonitorRequestTemplate) predicate.ChannelMonitor { + return predicate.ChannelMonitor(func(s *sql.Selector) { + step := newRequestTemplateStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + +// And groups predicates with the AND operator between them. +func And(predicates ...predicate.ChannelMonitor) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.AndPredicates(predicates...)) +} + +// Or groups predicates with the OR operator between them. +func Or(predicates ...predicate.ChannelMonitor) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.OrPredicates(predicates...)) +} + +// Not applies the not operator on the given predicate. +func Not(p predicate.ChannelMonitor) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.NotPredicates(p)) +} diff --git a/backend/ent/channelmonitor_create.go b/backend/ent/channelmonitor_create.go new file mode 100644 index 00000000..2f70c300 --- /dev/null +++ b/backend/ent/channelmonitor_create.go @@ -0,0 +1,1610 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitordailyrollup" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" +) + +// ChannelMonitorCreate is the builder for creating a ChannelMonitor entity. +type ChannelMonitorCreate struct { + config + mutation *ChannelMonitorMutation + hooks []Hook + conflict []sql.ConflictOption +} + +// SetCreatedAt sets the "created_at" field. +func (_c *ChannelMonitorCreate) SetCreatedAt(v time.Time) *ChannelMonitorCreate { + _c.mutation.SetCreatedAt(v) + return _c +} + +// SetNillableCreatedAt sets the "created_at" field if the given value is not nil. +func (_c *ChannelMonitorCreate) SetNillableCreatedAt(v *time.Time) *ChannelMonitorCreate { + if v != nil { + _c.SetCreatedAt(*v) + } + return _c +} + +// SetUpdatedAt sets the "updated_at" field. +func (_c *ChannelMonitorCreate) SetUpdatedAt(v time.Time) *ChannelMonitorCreate { + _c.mutation.SetUpdatedAt(v) + return _c +} + +// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil. +func (_c *ChannelMonitorCreate) SetNillableUpdatedAt(v *time.Time) *ChannelMonitorCreate { + if v != nil { + _c.SetUpdatedAt(*v) + } + return _c +} + +// SetName sets the "name" field. +func (_c *ChannelMonitorCreate) SetName(v string) *ChannelMonitorCreate { + _c.mutation.SetName(v) + return _c +} + +// SetProvider sets the "provider" field. +func (_c *ChannelMonitorCreate) SetProvider(v channelmonitor.Provider) *ChannelMonitorCreate { + _c.mutation.SetProvider(v) + return _c +} + +// SetEndpoint sets the "endpoint" field. +func (_c *ChannelMonitorCreate) SetEndpoint(v string) *ChannelMonitorCreate { + _c.mutation.SetEndpoint(v) + return _c +} + +// SetAPIKeyEncrypted sets the "api_key_encrypted" field. +func (_c *ChannelMonitorCreate) SetAPIKeyEncrypted(v string) *ChannelMonitorCreate { + _c.mutation.SetAPIKeyEncrypted(v) + return _c +} + +// SetPrimaryModel sets the "primary_model" field. +func (_c *ChannelMonitorCreate) SetPrimaryModel(v string) *ChannelMonitorCreate { + _c.mutation.SetPrimaryModel(v) + return _c +} + +// SetExtraModels sets the "extra_models" field. +func (_c *ChannelMonitorCreate) SetExtraModels(v []string) *ChannelMonitorCreate { + _c.mutation.SetExtraModels(v) + return _c +} + +// SetGroupName sets the "group_name" field. +func (_c *ChannelMonitorCreate) SetGroupName(v string) *ChannelMonitorCreate { + _c.mutation.SetGroupName(v) + return _c +} + +// SetNillableGroupName sets the "group_name" field if the given value is not nil. +func (_c *ChannelMonitorCreate) SetNillableGroupName(v *string) *ChannelMonitorCreate { + if v != nil { + _c.SetGroupName(*v) + } + return _c +} + +// SetEnabled sets the "enabled" field. +func (_c *ChannelMonitorCreate) SetEnabled(v bool) *ChannelMonitorCreate { + _c.mutation.SetEnabled(v) + return _c +} + +// SetNillableEnabled sets the "enabled" field if the given value is not nil. +func (_c *ChannelMonitorCreate) SetNillableEnabled(v *bool) *ChannelMonitorCreate { + if v != nil { + _c.SetEnabled(*v) + } + return _c +} + +// SetIntervalSeconds sets the "interval_seconds" field. +func (_c *ChannelMonitorCreate) SetIntervalSeconds(v int) *ChannelMonitorCreate { + _c.mutation.SetIntervalSeconds(v) + return _c +} + +// SetLastCheckedAt sets the "last_checked_at" field. +func (_c *ChannelMonitorCreate) SetLastCheckedAt(v time.Time) *ChannelMonitorCreate { + _c.mutation.SetLastCheckedAt(v) + return _c +} + +// SetNillableLastCheckedAt sets the "last_checked_at" field if the given value is not nil. +func (_c *ChannelMonitorCreate) SetNillableLastCheckedAt(v *time.Time) *ChannelMonitorCreate { + if v != nil { + _c.SetLastCheckedAt(*v) + } + return _c +} + +// SetCreatedBy sets the "created_by" field. +func (_c *ChannelMonitorCreate) SetCreatedBy(v int64) *ChannelMonitorCreate { + _c.mutation.SetCreatedBy(v) + return _c +} + +// SetTemplateID sets the "template_id" field. +func (_c *ChannelMonitorCreate) SetTemplateID(v int64) *ChannelMonitorCreate { + _c.mutation.SetTemplateID(v) + return _c +} + +// SetNillableTemplateID sets the "template_id" field if the given value is not nil. +func (_c *ChannelMonitorCreate) SetNillableTemplateID(v *int64) *ChannelMonitorCreate { + if v != nil { + _c.SetTemplateID(*v) + } + return _c +} + +// SetExtraHeaders sets the "extra_headers" field. +func (_c *ChannelMonitorCreate) SetExtraHeaders(v map[string]string) *ChannelMonitorCreate { + _c.mutation.SetExtraHeaders(v) + return _c +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (_c *ChannelMonitorCreate) SetBodyOverrideMode(v string) *ChannelMonitorCreate { + _c.mutation.SetBodyOverrideMode(v) + return _c +} + +// SetNillableBodyOverrideMode sets the "body_override_mode" field if the given value is not nil. +func (_c *ChannelMonitorCreate) SetNillableBodyOverrideMode(v *string) *ChannelMonitorCreate { + if v != nil { + _c.SetBodyOverrideMode(*v) + } + return _c +} + +// SetBodyOverride sets the "body_override" field. +func (_c *ChannelMonitorCreate) SetBodyOverride(v map[string]interface{}) *ChannelMonitorCreate { + _c.mutation.SetBodyOverride(v) + return _c +} + +// AddHistoryIDs adds the "history" edge to the ChannelMonitorHistory entity by IDs. +func (_c *ChannelMonitorCreate) AddHistoryIDs(ids ...int64) *ChannelMonitorCreate { + _c.mutation.AddHistoryIDs(ids...) + return _c +} + +// AddHistory adds the "history" edges to the ChannelMonitorHistory entity. +func (_c *ChannelMonitorCreate) AddHistory(v ...*ChannelMonitorHistory) *ChannelMonitorCreate { + ids := make([]int64, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _c.AddHistoryIDs(ids...) +} + +// AddDailyRollupIDs adds the "daily_rollups" edge to the ChannelMonitorDailyRollup entity by IDs. +func (_c *ChannelMonitorCreate) AddDailyRollupIDs(ids ...int64) *ChannelMonitorCreate { + _c.mutation.AddDailyRollupIDs(ids...) + return _c +} + +// AddDailyRollups adds the "daily_rollups" edges to the ChannelMonitorDailyRollup entity. +func (_c *ChannelMonitorCreate) AddDailyRollups(v ...*ChannelMonitorDailyRollup) *ChannelMonitorCreate { + ids := make([]int64, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _c.AddDailyRollupIDs(ids...) +} + +// SetRequestTemplateID sets the "request_template" edge to the ChannelMonitorRequestTemplate entity by ID. +func (_c *ChannelMonitorCreate) SetRequestTemplateID(id int64) *ChannelMonitorCreate { + _c.mutation.SetRequestTemplateID(id) + return _c +} + +// SetNillableRequestTemplateID sets the "request_template" edge to the ChannelMonitorRequestTemplate entity by ID if the given value is not nil. +func (_c *ChannelMonitorCreate) SetNillableRequestTemplateID(id *int64) *ChannelMonitorCreate { + if id != nil { + _c = _c.SetRequestTemplateID(*id) + } + return _c +} + +// SetRequestTemplate sets the "request_template" edge to the ChannelMonitorRequestTemplate entity. +func (_c *ChannelMonitorCreate) SetRequestTemplate(v *ChannelMonitorRequestTemplate) *ChannelMonitorCreate { + return _c.SetRequestTemplateID(v.ID) +} + +// Mutation returns the ChannelMonitorMutation object of the builder. +func (_c *ChannelMonitorCreate) Mutation() *ChannelMonitorMutation { + return _c.mutation +} + +// Save creates the ChannelMonitor in the database. +func (_c *ChannelMonitorCreate) Save(ctx context.Context) (*ChannelMonitor, error) { + _c.defaults() + return withHooks(ctx, _c.sqlSave, _c.mutation, _c.hooks) +} + +// SaveX calls Save and panics if Save returns an error. +func (_c *ChannelMonitorCreate) SaveX(ctx context.Context) *ChannelMonitor { + v, err := _c.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (_c *ChannelMonitorCreate) Exec(ctx context.Context) error { + _, err := _c.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_c *ChannelMonitorCreate) ExecX(ctx context.Context) { + if err := _c.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (_c *ChannelMonitorCreate) defaults() { + if _, ok := _c.mutation.CreatedAt(); !ok { + v := channelmonitor.DefaultCreatedAt() + _c.mutation.SetCreatedAt(v) + } + if _, ok := _c.mutation.UpdatedAt(); !ok { + v := channelmonitor.DefaultUpdatedAt() + _c.mutation.SetUpdatedAt(v) + } + if _, ok := _c.mutation.ExtraModels(); !ok { + v := channelmonitor.DefaultExtraModels + _c.mutation.SetExtraModels(v) + } + if _, ok := _c.mutation.GroupName(); !ok { + v := channelmonitor.DefaultGroupName + _c.mutation.SetGroupName(v) + } + if _, ok := _c.mutation.Enabled(); !ok { + v := channelmonitor.DefaultEnabled + _c.mutation.SetEnabled(v) + } + if _, ok := _c.mutation.ExtraHeaders(); !ok { + v := channelmonitor.DefaultExtraHeaders + _c.mutation.SetExtraHeaders(v) + } + if _, ok := _c.mutation.BodyOverrideMode(); !ok { + v := channelmonitor.DefaultBodyOverrideMode + _c.mutation.SetBodyOverrideMode(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_c *ChannelMonitorCreate) check() error { + if _, ok := _c.mutation.CreatedAt(); !ok { + return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "ChannelMonitor.created_at"`)} + } + if _, ok := _c.mutation.UpdatedAt(); !ok { + return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "ChannelMonitor.updated_at"`)} + } + if _, ok := _c.mutation.Name(); !ok { + return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "ChannelMonitor.name"`)} + } + if v, ok := _c.mutation.Name(); ok { + if err := channelmonitor.NameValidator(v); err != nil { + return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.name": %w`, err)} + } + } + if _, ok := _c.mutation.Provider(); !ok { + return &ValidationError{Name: "provider", err: errors.New(`ent: missing required field "ChannelMonitor.provider"`)} + } + if v, ok := _c.mutation.Provider(); ok { + if err := channelmonitor.ProviderValidator(v); err != nil { + return &ValidationError{Name: "provider", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.provider": %w`, err)} + } + } + if _, ok := _c.mutation.Endpoint(); !ok { + return &ValidationError{Name: "endpoint", err: errors.New(`ent: missing required field "ChannelMonitor.endpoint"`)} + } + if v, ok := _c.mutation.Endpoint(); ok { + if err := channelmonitor.EndpointValidator(v); err != nil { + return &ValidationError{Name: "endpoint", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.endpoint": %w`, err)} + } + } + if _, ok := _c.mutation.APIKeyEncrypted(); !ok { + return &ValidationError{Name: "api_key_encrypted", err: errors.New(`ent: missing required field "ChannelMonitor.api_key_encrypted"`)} + } + if v, ok := _c.mutation.APIKeyEncrypted(); ok { + if err := channelmonitor.APIKeyEncryptedValidator(v); err != nil { + return &ValidationError{Name: "api_key_encrypted", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.api_key_encrypted": %w`, err)} + } + } + if _, ok := _c.mutation.PrimaryModel(); !ok { + return &ValidationError{Name: "primary_model", err: errors.New(`ent: missing required field "ChannelMonitor.primary_model"`)} + } + if v, ok := _c.mutation.PrimaryModel(); ok { + if err := channelmonitor.PrimaryModelValidator(v); err != nil { + return &ValidationError{Name: "primary_model", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.primary_model": %w`, err)} + } + } + if _, ok := _c.mutation.ExtraModels(); !ok { + return &ValidationError{Name: "extra_models", err: errors.New(`ent: missing required field "ChannelMonitor.extra_models"`)} + } + if v, ok := _c.mutation.GroupName(); ok { + if err := channelmonitor.GroupNameValidator(v); err != nil { + return &ValidationError{Name: "group_name", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.group_name": %w`, err)} + } + } + if _, ok := _c.mutation.Enabled(); !ok { + return &ValidationError{Name: "enabled", err: errors.New(`ent: missing required field "ChannelMonitor.enabled"`)} + } + if _, ok := _c.mutation.IntervalSeconds(); !ok { + return &ValidationError{Name: "interval_seconds", err: errors.New(`ent: missing required field "ChannelMonitor.interval_seconds"`)} + } + if v, ok := _c.mutation.IntervalSeconds(); ok { + if err := channelmonitor.IntervalSecondsValidator(v); err != nil { + return &ValidationError{Name: "interval_seconds", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.interval_seconds": %w`, err)} + } + } + if _, ok := _c.mutation.CreatedBy(); !ok { + return &ValidationError{Name: "created_by", err: errors.New(`ent: missing required field "ChannelMonitor.created_by"`)} + } + if _, ok := _c.mutation.ExtraHeaders(); !ok { + return &ValidationError{Name: "extra_headers", err: errors.New(`ent: missing required field "ChannelMonitor.extra_headers"`)} + } + if _, ok := _c.mutation.BodyOverrideMode(); !ok { + return &ValidationError{Name: "body_override_mode", err: errors.New(`ent: missing required field "ChannelMonitor.body_override_mode"`)} + } + if v, ok := _c.mutation.BodyOverrideMode(); ok { + if err := channelmonitor.BodyOverrideModeValidator(v); err != nil { + return &ValidationError{Name: "body_override_mode", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.body_override_mode": %w`, err)} + } + } + return nil +} + +func (_c *ChannelMonitorCreate) sqlSave(ctx context.Context) (*ChannelMonitor, error) { + if err := _c.check(); err != nil { + return nil, err + } + _node, _spec := _c.createSpec() + if err := sqlgraph.CreateNode(ctx, _c.driver, _spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + id := _spec.ID.Value.(int64) + _node.ID = int64(id) + _c.mutation.id = &_node.ID + _c.mutation.done = true + return _node, nil +} + +func (_c *ChannelMonitorCreate) createSpec() (*ChannelMonitor, *sqlgraph.CreateSpec) { + var ( + _node = &ChannelMonitor{config: _c.config} + _spec = sqlgraph.NewCreateSpec(channelmonitor.Table, sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64)) + ) + _spec.OnConflict = _c.conflict + if value, ok := _c.mutation.CreatedAt(); ok { + _spec.SetField(channelmonitor.FieldCreatedAt, field.TypeTime, value) + _node.CreatedAt = value + } + if value, ok := _c.mutation.UpdatedAt(); ok { + _spec.SetField(channelmonitor.FieldUpdatedAt, field.TypeTime, value) + _node.UpdatedAt = value + } + if value, ok := _c.mutation.Name(); ok { + _spec.SetField(channelmonitor.FieldName, field.TypeString, value) + _node.Name = value + } + if value, ok := _c.mutation.Provider(); ok { + _spec.SetField(channelmonitor.FieldProvider, field.TypeEnum, value) + _node.Provider = value + } + if value, ok := _c.mutation.Endpoint(); ok { + _spec.SetField(channelmonitor.FieldEndpoint, field.TypeString, value) + _node.Endpoint = value + } + if value, ok := _c.mutation.APIKeyEncrypted(); ok { + _spec.SetField(channelmonitor.FieldAPIKeyEncrypted, field.TypeString, value) + _node.APIKeyEncrypted = value + } + if value, ok := _c.mutation.PrimaryModel(); ok { + _spec.SetField(channelmonitor.FieldPrimaryModel, field.TypeString, value) + _node.PrimaryModel = value + } + if value, ok := _c.mutation.ExtraModels(); ok { + _spec.SetField(channelmonitor.FieldExtraModels, field.TypeJSON, value) + _node.ExtraModels = value + } + if value, ok := _c.mutation.GroupName(); ok { + _spec.SetField(channelmonitor.FieldGroupName, field.TypeString, value) + _node.GroupName = value + } + if value, ok := _c.mutation.Enabled(); ok { + _spec.SetField(channelmonitor.FieldEnabled, field.TypeBool, value) + _node.Enabled = value + } + if value, ok := _c.mutation.IntervalSeconds(); ok { + _spec.SetField(channelmonitor.FieldIntervalSeconds, field.TypeInt, value) + _node.IntervalSeconds = value + } + if value, ok := _c.mutation.LastCheckedAt(); ok { + _spec.SetField(channelmonitor.FieldLastCheckedAt, field.TypeTime, value) + _node.LastCheckedAt = &value + } + if value, ok := _c.mutation.CreatedBy(); ok { + _spec.SetField(channelmonitor.FieldCreatedBy, field.TypeInt64, value) + _node.CreatedBy = value + } + if value, ok := _c.mutation.ExtraHeaders(); ok { + _spec.SetField(channelmonitor.FieldExtraHeaders, field.TypeJSON, value) + _node.ExtraHeaders = value + } + if value, ok := _c.mutation.BodyOverrideMode(); ok { + _spec.SetField(channelmonitor.FieldBodyOverrideMode, field.TypeString, value) + _node.BodyOverrideMode = value + } + if value, ok := _c.mutation.BodyOverride(); ok { + _spec.SetField(channelmonitor.FieldBodyOverride, field.TypeJSON, value) + _node.BodyOverride = value + } + if nodes := _c.mutation.HistoryIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: channelmonitor.HistoryTable, + Columns: []string{channelmonitor.HistoryColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitorhistory.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges = append(_spec.Edges, edge) + } + if nodes := _c.mutation.DailyRollupsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: channelmonitor.DailyRollupsTable, + Columns: []string{channelmonitor.DailyRollupsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitordailyrollup.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges = append(_spec.Edges, edge) + } + if nodes := _c.mutation.RequestTemplateIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: channelmonitor.RequestTemplateTable, + Columns: []string{channelmonitor.RequestTemplateColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitorrequesttemplate.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _node.TemplateID = &nodes[0] + _spec.Edges = append(_spec.Edges, edge) + } + return _node, _spec +} + +// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause +// of the `INSERT` statement. For example: +// +// client.ChannelMonitor.Create(). +// SetCreatedAt(v). +// OnConflict( +// // Update the row with the new values +// // the was proposed for insertion. +// sql.ResolveWithNewValues(), +// ). +// // Override some of the fields with custom +// // update values. +// Update(func(u *ent.ChannelMonitorUpsert) { +// SetCreatedAt(v+v). +// }). +// Exec(ctx) +func (_c *ChannelMonitorCreate) OnConflict(opts ...sql.ConflictOption) *ChannelMonitorUpsertOne { + _c.conflict = opts + return &ChannelMonitorUpsertOne{ + create: _c, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.ChannelMonitor.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (_c *ChannelMonitorCreate) OnConflictColumns(columns ...string) *ChannelMonitorUpsertOne { + _c.conflict = append(_c.conflict, sql.ConflictColumns(columns...)) + return &ChannelMonitorUpsertOne{ + create: _c, + } +} + +type ( + // ChannelMonitorUpsertOne is the builder for "upsert"-ing + // one ChannelMonitor node. + ChannelMonitorUpsertOne struct { + create *ChannelMonitorCreate + } + + // ChannelMonitorUpsert is the "OnConflict" setter. + ChannelMonitorUpsert struct { + *sql.UpdateSet + } +) + +// SetUpdatedAt sets the "updated_at" field. +func (u *ChannelMonitorUpsert) SetUpdatedAt(v time.Time) *ChannelMonitorUpsert { + u.Set(channelmonitor.FieldUpdatedAt, v) + return u +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *ChannelMonitorUpsert) UpdateUpdatedAt() *ChannelMonitorUpsert { + u.SetExcluded(channelmonitor.FieldUpdatedAt) + return u +} + +// SetName sets the "name" field. +func (u *ChannelMonitorUpsert) SetName(v string) *ChannelMonitorUpsert { + u.Set(channelmonitor.FieldName, v) + return u +} + +// UpdateName sets the "name" field to the value that was provided on create. +func (u *ChannelMonitorUpsert) UpdateName() *ChannelMonitorUpsert { + u.SetExcluded(channelmonitor.FieldName) + return u +} + +// SetProvider sets the "provider" field. +func (u *ChannelMonitorUpsert) SetProvider(v channelmonitor.Provider) *ChannelMonitorUpsert { + u.Set(channelmonitor.FieldProvider, v) + return u +} + +// UpdateProvider sets the "provider" field to the value that was provided on create. +func (u *ChannelMonitorUpsert) UpdateProvider() *ChannelMonitorUpsert { + u.SetExcluded(channelmonitor.FieldProvider) + return u +} + +// SetEndpoint sets the "endpoint" field. +func (u *ChannelMonitorUpsert) SetEndpoint(v string) *ChannelMonitorUpsert { + u.Set(channelmonitor.FieldEndpoint, v) + return u +} + +// UpdateEndpoint sets the "endpoint" field to the value that was provided on create. +func (u *ChannelMonitorUpsert) UpdateEndpoint() *ChannelMonitorUpsert { + u.SetExcluded(channelmonitor.FieldEndpoint) + return u +} + +// SetAPIKeyEncrypted sets the "api_key_encrypted" field. +func (u *ChannelMonitorUpsert) SetAPIKeyEncrypted(v string) *ChannelMonitorUpsert { + u.Set(channelmonitor.FieldAPIKeyEncrypted, v) + return u +} + +// UpdateAPIKeyEncrypted sets the "api_key_encrypted" field to the value that was provided on create. +func (u *ChannelMonitorUpsert) UpdateAPIKeyEncrypted() *ChannelMonitorUpsert { + u.SetExcluded(channelmonitor.FieldAPIKeyEncrypted) + return u +} + +// SetPrimaryModel sets the "primary_model" field. +func (u *ChannelMonitorUpsert) SetPrimaryModel(v string) *ChannelMonitorUpsert { + u.Set(channelmonitor.FieldPrimaryModel, v) + return u +} + +// UpdatePrimaryModel sets the "primary_model" field to the value that was provided on create. +func (u *ChannelMonitorUpsert) UpdatePrimaryModel() *ChannelMonitorUpsert { + u.SetExcluded(channelmonitor.FieldPrimaryModel) + return u +} + +// SetExtraModels sets the "extra_models" field. +func (u *ChannelMonitorUpsert) SetExtraModels(v []string) *ChannelMonitorUpsert { + u.Set(channelmonitor.FieldExtraModels, v) + return u +} + +// UpdateExtraModels sets the "extra_models" field to the value that was provided on create. +func (u *ChannelMonitorUpsert) UpdateExtraModels() *ChannelMonitorUpsert { + u.SetExcluded(channelmonitor.FieldExtraModels) + return u +} + +// SetGroupName sets the "group_name" field. +func (u *ChannelMonitorUpsert) SetGroupName(v string) *ChannelMonitorUpsert { + u.Set(channelmonitor.FieldGroupName, v) + return u +} + +// UpdateGroupName sets the "group_name" field to the value that was provided on create. +func (u *ChannelMonitorUpsert) UpdateGroupName() *ChannelMonitorUpsert { + u.SetExcluded(channelmonitor.FieldGroupName) + return u +} + +// ClearGroupName clears the value of the "group_name" field. +func (u *ChannelMonitorUpsert) ClearGroupName() *ChannelMonitorUpsert { + u.SetNull(channelmonitor.FieldGroupName) + return u +} + +// SetEnabled sets the "enabled" field. +func (u *ChannelMonitorUpsert) SetEnabled(v bool) *ChannelMonitorUpsert { + u.Set(channelmonitor.FieldEnabled, v) + return u +} + +// UpdateEnabled sets the "enabled" field to the value that was provided on create. +func (u *ChannelMonitorUpsert) UpdateEnabled() *ChannelMonitorUpsert { + u.SetExcluded(channelmonitor.FieldEnabled) + return u +} + +// SetIntervalSeconds sets the "interval_seconds" field. +func (u *ChannelMonitorUpsert) SetIntervalSeconds(v int) *ChannelMonitorUpsert { + u.Set(channelmonitor.FieldIntervalSeconds, v) + return u +} + +// UpdateIntervalSeconds sets the "interval_seconds" field to the value that was provided on create. +func (u *ChannelMonitorUpsert) UpdateIntervalSeconds() *ChannelMonitorUpsert { + u.SetExcluded(channelmonitor.FieldIntervalSeconds) + return u +} + +// AddIntervalSeconds adds v to the "interval_seconds" field. +func (u *ChannelMonitorUpsert) AddIntervalSeconds(v int) *ChannelMonitorUpsert { + u.Add(channelmonitor.FieldIntervalSeconds, v) + return u +} + +// SetLastCheckedAt sets the "last_checked_at" field. +func (u *ChannelMonitorUpsert) SetLastCheckedAt(v time.Time) *ChannelMonitorUpsert { + u.Set(channelmonitor.FieldLastCheckedAt, v) + return u +} + +// UpdateLastCheckedAt sets the "last_checked_at" field to the value that was provided on create. +func (u *ChannelMonitorUpsert) UpdateLastCheckedAt() *ChannelMonitorUpsert { + u.SetExcluded(channelmonitor.FieldLastCheckedAt) + return u +} + +// ClearLastCheckedAt clears the value of the "last_checked_at" field. +func (u *ChannelMonitorUpsert) ClearLastCheckedAt() *ChannelMonitorUpsert { + u.SetNull(channelmonitor.FieldLastCheckedAt) + return u +} + +// SetCreatedBy sets the "created_by" field. +func (u *ChannelMonitorUpsert) SetCreatedBy(v int64) *ChannelMonitorUpsert { + u.Set(channelmonitor.FieldCreatedBy, v) + return u +} + +// UpdateCreatedBy sets the "created_by" field to the value that was provided on create. +func (u *ChannelMonitorUpsert) UpdateCreatedBy() *ChannelMonitorUpsert { + u.SetExcluded(channelmonitor.FieldCreatedBy) + return u +} + +// AddCreatedBy adds v to the "created_by" field. +func (u *ChannelMonitorUpsert) AddCreatedBy(v int64) *ChannelMonitorUpsert { + u.Add(channelmonitor.FieldCreatedBy, v) + return u +} + +// SetTemplateID sets the "template_id" field. +func (u *ChannelMonitorUpsert) SetTemplateID(v int64) *ChannelMonitorUpsert { + u.Set(channelmonitor.FieldTemplateID, v) + return u +} + +// UpdateTemplateID sets the "template_id" field to the value that was provided on create. +func (u *ChannelMonitorUpsert) UpdateTemplateID() *ChannelMonitorUpsert { + u.SetExcluded(channelmonitor.FieldTemplateID) + return u +} + +// ClearTemplateID clears the value of the "template_id" field. +func (u *ChannelMonitorUpsert) ClearTemplateID() *ChannelMonitorUpsert { + u.SetNull(channelmonitor.FieldTemplateID) + return u +} + +// SetExtraHeaders sets the "extra_headers" field. +func (u *ChannelMonitorUpsert) SetExtraHeaders(v map[string]string) *ChannelMonitorUpsert { + u.Set(channelmonitor.FieldExtraHeaders, v) + return u +} + +// UpdateExtraHeaders sets the "extra_headers" field to the value that was provided on create. +func (u *ChannelMonitorUpsert) UpdateExtraHeaders() *ChannelMonitorUpsert { + u.SetExcluded(channelmonitor.FieldExtraHeaders) + return u +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (u *ChannelMonitorUpsert) SetBodyOverrideMode(v string) *ChannelMonitorUpsert { + u.Set(channelmonitor.FieldBodyOverrideMode, v) + return u +} + +// UpdateBodyOverrideMode sets the "body_override_mode" field to the value that was provided on create. +func (u *ChannelMonitorUpsert) UpdateBodyOverrideMode() *ChannelMonitorUpsert { + u.SetExcluded(channelmonitor.FieldBodyOverrideMode) + return u +} + +// SetBodyOverride sets the "body_override" field. +func (u *ChannelMonitorUpsert) SetBodyOverride(v map[string]interface{}) *ChannelMonitorUpsert { + u.Set(channelmonitor.FieldBodyOverride, v) + return u +} + +// UpdateBodyOverride sets the "body_override" field to the value that was provided on create. +func (u *ChannelMonitorUpsert) UpdateBodyOverride() *ChannelMonitorUpsert { + u.SetExcluded(channelmonitor.FieldBodyOverride) + return u +} + +// ClearBodyOverride clears the value of the "body_override" field. +func (u *ChannelMonitorUpsert) ClearBodyOverride() *ChannelMonitorUpsert { + u.SetNull(channelmonitor.FieldBodyOverride) + return u +} + +// UpdateNewValues updates the mutable fields using the new values that were set on create. +// Using this option is equivalent to using: +// +// client.ChannelMonitor.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// ). +// Exec(ctx) +func (u *ChannelMonitorUpsertOne) UpdateNewValues() *ChannelMonitorUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues()) + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) { + if _, exists := u.create.mutation.CreatedAt(); exists { + s.SetIgnore(channelmonitor.FieldCreatedAt) + } + })) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.ChannelMonitor.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *ChannelMonitorUpsertOne) Ignore() *ChannelMonitorUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore()) + return u +} + +// DoNothing configures the conflict_action to `DO NOTHING`. +// Supported only by SQLite and PostgreSQL. +func (u *ChannelMonitorUpsertOne) DoNothing() *ChannelMonitorUpsertOne { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the ChannelMonitorCreate.OnConflict +// documentation for more info. +func (u *ChannelMonitorUpsertOne) Update(set func(*ChannelMonitorUpsert)) *ChannelMonitorUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&ChannelMonitorUpsert{UpdateSet: update}) + })) + return u +} + +// SetUpdatedAt sets the "updated_at" field. +func (u *ChannelMonitorUpsertOne) SetUpdatedAt(v time.Time) *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetUpdatedAt(v) + }) +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *ChannelMonitorUpsertOne) UpdateUpdatedAt() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateUpdatedAt() + }) +} + +// SetName sets the "name" field. +func (u *ChannelMonitorUpsertOne) SetName(v string) *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetName(v) + }) +} + +// UpdateName sets the "name" field to the value that was provided on create. +func (u *ChannelMonitorUpsertOne) UpdateName() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateName() + }) +} + +// SetProvider sets the "provider" field. +func (u *ChannelMonitorUpsertOne) SetProvider(v channelmonitor.Provider) *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetProvider(v) + }) +} + +// UpdateProvider sets the "provider" field to the value that was provided on create. +func (u *ChannelMonitorUpsertOne) UpdateProvider() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateProvider() + }) +} + +// SetEndpoint sets the "endpoint" field. +func (u *ChannelMonitorUpsertOne) SetEndpoint(v string) *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetEndpoint(v) + }) +} + +// UpdateEndpoint sets the "endpoint" field to the value that was provided on create. +func (u *ChannelMonitorUpsertOne) UpdateEndpoint() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateEndpoint() + }) +} + +// SetAPIKeyEncrypted sets the "api_key_encrypted" field. +func (u *ChannelMonitorUpsertOne) SetAPIKeyEncrypted(v string) *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetAPIKeyEncrypted(v) + }) +} + +// UpdateAPIKeyEncrypted sets the "api_key_encrypted" field to the value that was provided on create. +func (u *ChannelMonitorUpsertOne) UpdateAPIKeyEncrypted() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateAPIKeyEncrypted() + }) +} + +// SetPrimaryModel sets the "primary_model" field. +func (u *ChannelMonitorUpsertOne) SetPrimaryModel(v string) *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetPrimaryModel(v) + }) +} + +// UpdatePrimaryModel sets the "primary_model" field to the value that was provided on create. +func (u *ChannelMonitorUpsertOne) UpdatePrimaryModel() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdatePrimaryModel() + }) +} + +// SetExtraModels sets the "extra_models" field. +func (u *ChannelMonitorUpsertOne) SetExtraModels(v []string) *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetExtraModels(v) + }) +} + +// UpdateExtraModels sets the "extra_models" field to the value that was provided on create. +func (u *ChannelMonitorUpsertOne) UpdateExtraModels() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateExtraModels() + }) +} + +// SetGroupName sets the "group_name" field. +func (u *ChannelMonitorUpsertOne) SetGroupName(v string) *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetGroupName(v) + }) +} + +// UpdateGroupName sets the "group_name" field to the value that was provided on create. +func (u *ChannelMonitorUpsertOne) UpdateGroupName() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateGroupName() + }) +} + +// ClearGroupName clears the value of the "group_name" field. +func (u *ChannelMonitorUpsertOne) ClearGroupName() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.ClearGroupName() + }) +} + +// SetEnabled sets the "enabled" field. +func (u *ChannelMonitorUpsertOne) SetEnabled(v bool) *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetEnabled(v) + }) +} + +// UpdateEnabled sets the "enabled" field to the value that was provided on create. +func (u *ChannelMonitorUpsertOne) UpdateEnabled() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateEnabled() + }) +} + +// SetIntervalSeconds sets the "interval_seconds" field. +func (u *ChannelMonitorUpsertOne) SetIntervalSeconds(v int) *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetIntervalSeconds(v) + }) +} + +// AddIntervalSeconds adds v to the "interval_seconds" field. +func (u *ChannelMonitorUpsertOne) AddIntervalSeconds(v int) *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.AddIntervalSeconds(v) + }) +} + +// UpdateIntervalSeconds sets the "interval_seconds" field to the value that was provided on create. +func (u *ChannelMonitorUpsertOne) UpdateIntervalSeconds() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateIntervalSeconds() + }) +} + +// SetLastCheckedAt sets the "last_checked_at" field. +func (u *ChannelMonitorUpsertOne) SetLastCheckedAt(v time.Time) *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetLastCheckedAt(v) + }) +} + +// UpdateLastCheckedAt sets the "last_checked_at" field to the value that was provided on create. +func (u *ChannelMonitorUpsertOne) UpdateLastCheckedAt() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateLastCheckedAt() + }) +} + +// ClearLastCheckedAt clears the value of the "last_checked_at" field. +func (u *ChannelMonitorUpsertOne) ClearLastCheckedAt() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.ClearLastCheckedAt() + }) +} + +// SetCreatedBy sets the "created_by" field. +func (u *ChannelMonitorUpsertOne) SetCreatedBy(v int64) *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetCreatedBy(v) + }) +} + +// AddCreatedBy adds v to the "created_by" field. +func (u *ChannelMonitorUpsertOne) AddCreatedBy(v int64) *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.AddCreatedBy(v) + }) +} + +// UpdateCreatedBy sets the "created_by" field to the value that was provided on create. +func (u *ChannelMonitorUpsertOne) UpdateCreatedBy() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateCreatedBy() + }) +} + +// SetTemplateID sets the "template_id" field. +func (u *ChannelMonitorUpsertOne) SetTemplateID(v int64) *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetTemplateID(v) + }) +} + +// UpdateTemplateID sets the "template_id" field to the value that was provided on create. +func (u *ChannelMonitorUpsertOne) UpdateTemplateID() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateTemplateID() + }) +} + +// ClearTemplateID clears the value of the "template_id" field. +func (u *ChannelMonitorUpsertOne) ClearTemplateID() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.ClearTemplateID() + }) +} + +// SetExtraHeaders sets the "extra_headers" field. +func (u *ChannelMonitorUpsertOne) SetExtraHeaders(v map[string]string) *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetExtraHeaders(v) + }) +} + +// UpdateExtraHeaders sets the "extra_headers" field to the value that was provided on create. +func (u *ChannelMonitorUpsertOne) UpdateExtraHeaders() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateExtraHeaders() + }) +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (u *ChannelMonitorUpsertOne) SetBodyOverrideMode(v string) *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetBodyOverrideMode(v) + }) +} + +// UpdateBodyOverrideMode sets the "body_override_mode" field to the value that was provided on create. +func (u *ChannelMonitorUpsertOne) UpdateBodyOverrideMode() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateBodyOverrideMode() + }) +} + +// SetBodyOverride sets the "body_override" field. +func (u *ChannelMonitorUpsertOne) SetBodyOverride(v map[string]interface{}) *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetBodyOverride(v) + }) +} + +// UpdateBodyOverride sets the "body_override" field to the value that was provided on create. +func (u *ChannelMonitorUpsertOne) UpdateBodyOverride() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateBodyOverride() + }) +} + +// ClearBodyOverride clears the value of the "body_override" field. +func (u *ChannelMonitorUpsertOne) ClearBodyOverride() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.ClearBodyOverride() + }) +} + +// Exec executes the query. +func (u *ChannelMonitorUpsertOne) Exec(ctx context.Context) error { + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for ChannelMonitorCreate.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *ChannelMonitorUpsertOne) ExecX(ctx context.Context) { + if err := u.create.Exec(ctx); err != nil { + panic(err) + } +} + +// Exec executes the UPSERT query and returns the inserted/updated ID. +func (u *ChannelMonitorUpsertOne) ID(ctx context.Context) (id int64, err error) { + node, err := u.create.Save(ctx) + if err != nil { + return id, err + } + return node.ID, nil +} + +// IDX is like ID, but panics if an error occurs. +func (u *ChannelMonitorUpsertOne) IDX(ctx context.Context) int64 { + id, err := u.ID(ctx) + if err != nil { + panic(err) + } + return id +} + +// ChannelMonitorCreateBulk is the builder for creating many ChannelMonitor entities in bulk. +type ChannelMonitorCreateBulk struct { + config + err error + builders []*ChannelMonitorCreate + conflict []sql.ConflictOption +} + +// Save creates the ChannelMonitor entities in the database. +func (_c *ChannelMonitorCreateBulk) Save(ctx context.Context) ([]*ChannelMonitor, error) { + if _c.err != nil { + return nil, _c.err + } + specs := make([]*sqlgraph.CreateSpec, len(_c.builders)) + nodes := make([]*ChannelMonitor, len(_c.builders)) + mutators := make([]Mutator, len(_c.builders)) + for i := range _c.builders { + func(i int, root context.Context) { + builder := _c.builders[i] + builder.defaults() + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*ChannelMonitorMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + if err := builder.check(); err != nil { + return nil, err + } + builder.mutation = mutation + var err error + nodes[i], specs[i] = builder.createSpec() + if i < len(mutators)-1 { + _, err = mutators[i+1].Mutate(root, _c.builders[i+1].mutation) + } else { + spec := &sqlgraph.BatchCreateSpec{Nodes: specs} + spec.OnConflict = _c.conflict + // Invoke the actual operation on the latest mutation in the chain. + if err = sqlgraph.BatchCreate(ctx, _c.driver, spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + } + } + if err != nil { + return nil, err + } + mutation.id = &nodes[i].ID + if specs[i].ID.Value != nil { + id := specs[i].ID.Value.(int64) + nodes[i].ID = int64(id) + } + mutation.done = true + return nodes[i], nil + }) + for i := len(builder.hooks) - 1; i >= 0; i-- { + mut = builder.hooks[i](mut) + } + mutators[i] = mut + }(i, ctx) + } + if len(mutators) > 0 { + if _, err := mutators[0].Mutate(ctx, _c.builders[0].mutation); err != nil { + return nil, err + } + } + return nodes, nil +} + +// SaveX is like Save, but panics if an error occurs. +func (_c *ChannelMonitorCreateBulk) SaveX(ctx context.Context) []*ChannelMonitor { + v, err := _c.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (_c *ChannelMonitorCreateBulk) Exec(ctx context.Context) error { + _, err := _c.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_c *ChannelMonitorCreateBulk) ExecX(ctx context.Context) { + if err := _c.Exec(ctx); err != nil { + panic(err) + } +} + +// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause +// of the `INSERT` statement. For example: +// +// client.ChannelMonitor.CreateBulk(builders...). +// OnConflict( +// // Update the row with the new values +// // the was proposed for insertion. +// sql.ResolveWithNewValues(), +// ). +// // Override some of the fields with custom +// // update values. +// Update(func(u *ent.ChannelMonitorUpsert) { +// SetCreatedAt(v+v). +// }). +// Exec(ctx) +func (_c *ChannelMonitorCreateBulk) OnConflict(opts ...sql.ConflictOption) *ChannelMonitorUpsertBulk { + _c.conflict = opts + return &ChannelMonitorUpsertBulk{ + create: _c, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.ChannelMonitor.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (_c *ChannelMonitorCreateBulk) OnConflictColumns(columns ...string) *ChannelMonitorUpsertBulk { + _c.conflict = append(_c.conflict, sql.ConflictColumns(columns...)) + return &ChannelMonitorUpsertBulk{ + create: _c, + } +} + +// ChannelMonitorUpsertBulk is the builder for "upsert"-ing +// a bulk of ChannelMonitor nodes. +type ChannelMonitorUpsertBulk struct { + create *ChannelMonitorCreateBulk +} + +// UpdateNewValues updates the mutable fields using the new values that +// were set on create. Using this option is equivalent to using: +// +// client.ChannelMonitor.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// ). +// Exec(ctx) +func (u *ChannelMonitorUpsertBulk) UpdateNewValues() *ChannelMonitorUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues()) + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) { + for _, b := range u.create.builders { + if _, exists := b.mutation.CreatedAt(); exists { + s.SetIgnore(channelmonitor.FieldCreatedAt) + } + } + })) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.ChannelMonitor.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *ChannelMonitorUpsertBulk) Ignore() *ChannelMonitorUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore()) + return u +} + +// DoNothing configures the conflict_action to `DO NOTHING`. +// Supported only by SQLite and PostgreSQL. +func (u *ChannelMonitorUpsertBulk) DoNothing() *ChannelMonitorUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the ChannelMonitorCreateBulk.OnConflict +// documentation for more info. +func (u *ChannelMonitorUpsertBulk) Update(set func(*ChannelMonitorUpsert)) *ChannelMonitorUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&ChannelMonitorUpsert{UpdateSet: update}) + })) + return u +} + +// SetUpdatedAt sets the "updated_at" field. +func (u *ChannelMonitorUpsertBulk) SetUpdatedAt(v time.Time) *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetUpdatedAt(v) + }) +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *ChannelMonitorUpsertBulk) UpdateUpdatedAt() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateUpdatedAt() + }) +} + +// SetName sets the "name" field. +func (u *ChannelMonitorUpsertBulk) SetName(v string) *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetName(v) + }) +} + +// UpdateName sets the "name" field to the value that was provided on create. +func (u *ChannelMonitorUpsertBulk) UpdateName() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateName() + }) +} + +// SetProvider sets the "provider" field. +func (u *ChannelMonitorUpsertBulk) SetProvider(v channelmonitor.Provider) *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetProvider(v) + }) +} + +// UpdateProvider sets the "provider" field to the value that was provided on create. +func (u *ChannelMonitorUpsertBulk) UpdateProvider() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateProvider() + }) +} + +// SetEndpoint sets the "endpoint" field. +func (u *ChannelMonitorUpsertBulk) SetEndpoint(v string) *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetEndpoint(v) + }) +} + +// UpdateEndpoint sets the "endpoint" field to the value that was provided on create. +func (u *ChannelMonitorUpsertBulk) UpdateEndpoint() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateEndpoint() + }) +} + +// SetAPIKeyEncrypted sets the "api_key_encrypted" field. +func (u *ChannelMonitorUpsertBulk) SetAPIKeyEncrypted(v string) *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetAPIKeyEncrypted(v) + }) +} + +// UpdateAPIKeyEncrypted sets the "api_key_encrypted" field to the value that was provided on create. +func (u *ChannelMonitorUpsertBulk) UpdateAPIKeyEncrypted() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateAPIKeyEncrypted() + }) +} + +// SetPrimaryModel sets the "primary_model" field. +func (u *ChannelMonitorUpsertBulk) SetPrimaryModel(v string) *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetPrimaryModel(v) + }) +} + +// UpdatePrimaryModel sets the "primary_model" field to the value that was provided on create. +func (u *ChannelMonitorUpsertBulk) UpdatePrimaryModel() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdatePrimaryModel() + }) +} + +// SetExtraModels sets the "extra_models" field. +func (u *ChannelMonitorUpsertBulk) SetExtraModels(v []string) *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetExtraModels(v) + }) +} + +// UpdateExtraModels sets the "extra_models" field to the value that was provided on create. +func (u *ChannelMonitorUpsertBulk) UpdateExtraModels() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateExtraModels() + }) +} + +// SetGroupName sets the "group_name" field. +func (u *ChannelMonitorUpsertBulk) SetGroupName(v string) *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetGroupName(v) + }) +} + +// UpdateGroupName sets the "group_name" field to the value that was provided on create. +func (u *ChannelMonitorUpsertBulk) UpdateGroupName() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateGroupName() + }) +} + +// ClearGroupName clears the value of the "group_name" field. +func (u *ChannelMonitorUpsertBulk) ClearGroupName() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.ClearGroupName() + }) +} + +// SetEnabled sets the "enabled" field. +func (u *ChannelMonitorUpsertBulk) SetEnabled(v bool) *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetEnabled(v) + }) +} + +// UpdateEnabled sets the "enabled" field to the value that was provided on create. +func (u *ChannelMonitorUpsertBulk) UpdateEnabled() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateEnabled() + }) +} + +// SetIntervalSeconds sets the "interval_seconds" field. +func (u *ChannelMonitorUpsertBulk) SetIntervalSeconds(v int) *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetIntervalSeconds(v) + }) +} + +// AddIntervalSeconds adds v to the "interval_seconds" field. +func (u *ChannelMonitorUpsertBulk) AddIntervalSeconds(v int) *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.AddIntervalSeconds(v) + }) +} + +// UpdateIntervalSeconds sets the "interval_seconds" field to the value that was provided on create. +func (u *ChannelMonitorUpsertBulk) UpdateIntervalSeconds() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateIntervalSeconds() + }) +} + +// SetLastCheckedAt sets the "last_checked_at" field. +func (u *ChannelMonitorUpsertBulk) SetLastCheckedAt(v time.Time) *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetLastCheckedAt(v) + }) +} + +// UpdateLastCheckedAt sets the "last_checked_at" field to the value that was provided on create. +func (u *ChannelMonitorUpsertBulk) UpdateLastCheckedAt() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateLastCheckedAt() + }) +} + +// ClearLastCheckedAt clears the value of the "last_checked_at" field. +func (u *ChannelMonitorUpsertBulk) ClearLastCheckedAt() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.ClearLastCheckedAt() + }) +} + +// SetCreatedBy sets the "created_by" field. +func (u *ChannelMonitorUpsertBulk) SetCreatedBy(v int64) *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetCreatedBy(v) + }) +} + +// AddCreatedBy adds v to the "created_by" field. +func (u *ChannelMonitorUpsertBulk) AddCreatedBy(v int64) *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.AddCreatedBy(v) + }) +} + +// UpdateCreatedBy sets the "created_by" field to the value that was provided on create. +func (u *ChannelMonitorUpsertBulk) UpdateCreatedBy() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateCreatedBy() + }) +} + +// SetTemplateID sets the "template_id" field. +func (u *ChannelMonitorUpsertBulk) SetTemplateID(v int64) *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetTemplateID(v) + }) +} + +// UpdateTemplateID sets the "template_id" field to the value that was provided on create. +func (u *ChannelMonitorUpsertBulk) UpdateTemplateID() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateTemplateID() + }) +} + +// ClearTemplateID clears the value of the "template_id" field. +func (u *ChannelMonitorUpsertBulk) ClearTemplateID() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.ClearTemplateID() + }) +} + +// SetExtraHeaders sets the "extra_headers" field. +func (u *ChannelMonitorUpsertBulk) SetExtraHeaders(v map[string]string) *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetExtraHeaders(v) + }) +} + +// UpdateExtraHeaders sets the "extra_headers" field to the value that was provided on create. +func (u *ChannelMonitorUpsertBulk) UpdateExtraHeaders() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateExtraHeaders() + }) +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (u *ChannelMonitorUpsertBulk) SetBodyOverrideMode(v string) *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetBodyOverrideMode(v) + }) +} + +// UpdateBodyOverrideMode sets the "body_override_mode" field to the value that was provided on create. +func (u *ChannelMonitorUpsertBulk) UpdateBodyOverrideMode() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateBodyOverrideMode() + }) +} + +// SetBodyOverride sets the "body_override" field. +func (u *ChannelMonitorUpsertBulk) SetBodyOverride(v map[string]interface{}) *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetBodyOverride(v) + }) +} + +// UpdateBodyOverride sets the "body_override" field to the value that was provided on create. +func (u *ChannelMonitorUpsertBulk) UpdateBodyOverride() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateBodyOverride() + }) +} + +// ClearBodyOverride clears the value of the "body_override" field. +func (u *ChannelMonitorUpsertBulk) ClearBodyOverride() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.ClearBodyOverride() + }) +} + +// Exec executes the query. +func (u *ChannelMonitorUpsertBulk) Exec(ctx context.Context) error { + if u.create.err != nil { + return u.create.err + } + for i, b := range u.create.builders { + if len(b.conflict) != 0 { + return fmt.Errorf("ent: OnConflict was set for builder %d. Set it on the ChannelMonitorCreateBulk instead", i) + } + } + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for ChannelMonitorCreateBulk.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *ChannelMonitorUpsertBulk) ExecX(ctx context.Context) { + if err := u.create.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/backend/ent/channelmonitor_delete.go b/backend/ent/channelmonitor_delete.go new file mode 100644 index 00000000..500dbb48 --- /dev/null +++ b/backend/ent/channelmonitor_delete.go @@ -0,0 +1,88 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// ChannelMonitorDelete is the builder for deleting a ChannelMonitor entity. +type ChannelMonitorDelete struct { + config + hooks []Hook + mutation *ChannelMonitorMutation +} + +// Where appends a list predicates to the ChannelMonitorDelete builder. +func (_d *ChannelMonitorDelete) Where(ps ...predicate.ChannelMonitor) *ChannelMonitorDelete { + _d.mutation.Where(ps...) + return _d +} + +// Exec executes the deletion query and returns how many vertices were deleted. +func (_d *ChannelMonitorDelete) Exec(ctx context.Context) (int, error) { + return withHooks(ctx, _d.sqlExec, _d.mutation, _d.hooks) +} + +// ExecX is like Exec, but panics if an error occurs. +func (_d *ChannelMonitorDelete) ExecX(ctx context.Context) int { + n, err := _d.Exec(ctx) + if err != nil { + panic(err) + } + return n +} + +func (_d *ChannelMonitorDelete) sqlExec(ctx context.Context) (int, error) { + _spec := sqlgraph.NewDeleteSpec(channelmonitor.Table, sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64)) + if ps := _d.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + affected, err := sqlgraph.DeleteNodes(ctx, _d.driver, _spec) + if err != nil && sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + _d.mutation.done = true + return affected, err +} + +// ChannelMonitorDeleteOne is the builder for deleting a single ChannelMonitor entity. +type ChannelMonitorDeleteOne struct { + _d *ChannelMonitorDelete +} + +// Where appends a list predicates to the ChannelMonitorDelete builder. +func (_d *ChannelMonitorDeleteOne) Where(ps ...predicate.ChannelMonitor) *ChannelMonitorDeleteOne { + _d._d.mutation.Where(ps...) + return _d +} + +// Exec executes the deletion query. +func (_d *ChannelMonitorDeleteOne) Exec(ctx context.Context) error { + n, err := _d._d.Exec(ctx) + switch { + case err != nil: + return err + case n == 0: + return &NotFoundError{channelmonitor.Label} + default: + return nil + } +} + +// ExecX is like Exec, but panics if an error occurs. +func (_d *ChannelMonitorDeleteOne) ExecX(ctx context.Context) { + if err := _d.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/backend/ent/channelmonitor_query.go b/backend/ent/channelmonitor_query.go new file mode 100644 index 00000000..b6722e78 --- /dev/null +++ b/backend/ent/channelmonitor_query.go @@ -0,0 +1,797 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "database/sql/driver" + "fmt" + "math" + + "entgo.io/ent" + "entgo.io/ent/dialect" + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitordailyrollup" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// ChannelMonitorQuery is the builder for querying ChannelMonitor entities. +type ChannelMonitorQuery struct { + config + ctx *QueryContext + order []channelmonitor.OrderOption + inters []Interceptor + predicates []predicate.ChannelMonitor + withHistory *ChannelMonitorHistoryQuery + withDailyRollups *ChannelMonitorDailyRollupQuery + withRequestTemplate *ChannelMonitorRequestTemplateQuery + modifiers []func(*sql.Selector) + // intermediate query (i.e. traversal path). + sql *sql.Selector + path func(context.Context) (*sql.Selector, error) +} + +// Where adds a new predicate for the ChannelMonitorQuery builder. +func (_q *ChannelMonitorQuery) Where(ps ...predicate.ChannelMonitor) *ChannelMonitorQuery { + _q.predicates = append(_q.predicates, ps...) + return _q +} + +// Limit the number of records to be returned by this query. +func (_q *ChannelMonitorQuery) Limit(limit int) *ChannelMonitorQuery { + _q.ctx.Limit = &limit + return _q +} + +// Offset to start from. +func (_q *ChannelMonitorQuery) Offset(offset int) *ChannelMonitorQuery { + _q.ctx.Offset = &offset + return _q +} + +// Unique configures the query builder to filter duplicate records on query. +// By default, unique is set to true, and can be disabled using this method. +func (_q *ChannelMonitorQuery) Unique(unique bool) *ChannelMonitorQuery { + _q.ctx.Unique = &unique + return _q +} + +// Order specifies how the records should be ordered. +func (_q *ChannelMonitorQuery) Order(o ...channelmonitor.OrderOption) *ChannelMonitorQuery { + _q.order = append(_q.order, o...) + return _q +} + +// QueryHistory chains the current query on the "history" edge. +func (_q *ChannelMonitorQuery) QueryHistory() *ChannelMonitorHistoryQuery { + query := (&ChannelMonitorHistoryClient{config: _q.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := _q.prepareQuery(ctx); err != nil { + return nil, err + } + selector := _q.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(channelmonitor.Table, channelmonitor.FieldID, selector), + sqlgraph.To(channelmonitorhistory.Table, channelmonitorhistory.FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, channelmonitor.HistoryTable, channelmonitor.HistoryColumn), + ) + fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step) + return fromU, nil + } + return query +} + +// QueryDailyRollups chains the current query on the "daily_rollups" edge. +func (_q *ChannelMonitorQuery) QueryDailyRollups() *ChannelMonitorDailyRollupQuery { + query := (&ChannelMonitorDailyRollupClient{config: _q.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := _q.prepareQuery(ctx); err != nil { + return nil, err + } + selector := _q.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(channelmonitor.Table, channelmonitor.FieldID, selector), + sqlgraph.To(channelmonitordailyrollup.Table, channelmonitordailyrollup.FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, channelmonitor.DailyRollupsTable, channelmonitor.DailyRollupsColumn), + ) + fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step) + return fromU, nil + } + return query +} + +// QueryRequestTemplate chains the current query on the "request_template" edge. +func (_q *ChannelMonitorQuery) QueryRequestTemplate() *ChannelMonitorRequestTemplateQuery { + query := (&ChannelMonitorRequestTemplateClient{config: _q.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := _q.prepareQuery(ctx); err != nil { + return nil, err + } + selector := _q.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(channelmonitor.Table, channelmonitor.FieldID, selector), + sqlgraph.To(channelmonitorrequesttemplate.Table, channelmonitorrequesttemplate.FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, channelmonitor.RequestTemplateTable, channelmonitor.RequestTemplateColumn), + ) + fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step) + return fromU, nil + } + return query +} + +// First returns the first ChannelMonitor entity from the query. +// Returns a *NotFoundError when no ChannelMonitor was found. +func (_q *ChannelMonitorQuery) First(ctx context.Context) (*ChannelMonitor, error) { + nodes, err := _q.Limit(1).All(setContextOp(ctx, _q.ctx, ent.OpQueryFirst)) + if err != nil { + return nil, err + } + if len(nodes) == 0 { + return nil, &NotFoundError{channelmonitor.Label} + } + return nodes[0], nil +} + +// FirstX is like First, but panics if an error occurs. +func (_q *ChannelMonitorQuery) FirstX(ctx context.Context) *ChannelMonitor { + node, err := _q.First(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return node +} + +// FirstID returns the first ChannelMonitor ID from the query. +// Returns a *NotFoundError when no ChannelMonitor ID was found. +func (_q *ChannelMonitorQuery) FirstID(ctx context.Context) (id int64, err error) { + var ids []int64 + if ids, err = _q.Limit(1).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryFirstID)); err != nil { + return + } + if len(ids) == 0 { + err = &NotFoundError{channelmonitor.Label} + return + } + return ids[0], nil +} + +// FirstIDX is like FirstID, but panics if an error occurs. +func (_q *ChannelMonitorQuery) FirstIDX(ctx context.Context) int64 { + id, err := _q.FirstID(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return id +} + +// Only returns a single ChannelMonitor entity found by the query, ensuring it only returns one. +// Returns a *NotSingularError when more than one ChannelMonitor entity is found. +// Returns a *NotFoundError when no ChannelMonitor entities are found. +func (_q *ChannelMonitorQuery) Only(ctx context.Context) (*ChannelMonitor, error) { + nodes, err := _q.Limit(2).All(setContextOp(ctx, _q.ctx, ent.OpQueryOnly)) + if err != nil { + return nil, err + } + switch len(nodes) { + case 1: + return nodes[0], nil + case 0: + return nil, &NotFoundError{channelmonitor.Label} + default: + return nil, &NotSingularError{channelmonitor.Label} + } +} + +// OnlyX is like Only, but panics if an error occurs. +func (_q *ChannelMonitorQuery) OnlyX(ctx context.Context) *ChannelMonitor { + node, err := _q.Only(ctx) + if err != nil { + panic(err) + } + return node +} + +// OnlyID is like Only, but returns the only ChannelMonitor ID in the query. +// Returns a *NotSingularError when more than one ChannelMonitor ID is found. +// Returns a *NotFoundError when no entities are found. +func (_q *ChannelMonitorQuery) OnlyID(ctx context.Context) (id int64, err error) { + var ids []int64 + if ids, err = _q.Limit(2).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryOnlyID)); err != nil { + return + } + switch len(ids) { + case 1: + id = ids[0] + case 0: + err = &NotFoundError{channelmonitor.Label} + default: + err = &NotSingularError{channelmonitor.Label} + } + return +} + +// OnlyIDX is like OnlyID, but panics if an error occurs. +func (_q *ChannelMonitorQuery) OnlyIDX(ctx context.Context) int64 { + id, err := _q.OnlyID(ctx) + if err != nil { + panic(err) + } + return id +} + +// All executes the query and returns a list of ChannelMonitors. +func (_q *ChannelMonitorQuery) All(ctx context.Context) ([]*ChannelMonitor, error) { + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryAll) + if err := _q.prepareQuery(ctx); err != nil { + return nil, err + } + qr := querierAll[[]*ChannelMonitor, *ChannelMonitorQuery]() + return withInterceptors[[]*ChannelMonitor](ctx, _q, qr, _q.inters) +} + +// AllX is like All, but panics if an error occurs. +func (_q *ChannelMonitorQuery) AllX(ctx context.Context) []*ChannelMonitor { + nodes, err := _q.All(ctx) + if err != nil { + panic(err) + } + return nodes +} + +// IDs executes the query and returns a list of ChannelMonitor IDs. +func (_q *ChannelMonitorQuery) IDs(ctx context.Context) (ids []int64, err error) { + if _q.ctx.Unique == nil && _q.path != nil { + _q.Unique(true) + } + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryIDs) + if err = _q.Select(channelmonitor.FieldID).Scan(ctx, &ids); err != nil { + return nil, err + } + return ids, nil +} + +// IDsX is like IDs, but panics if an error occurs. +func (_q *ChannelMonitorQuery) IDsX(ctx context.Context) []int64 { + ids, err := _q.IDs(ctx) + if err != nil { + panic(err) + } + return ids +} + +// Count returns the count of the given query. +func (_q *ChannelMonitorQuery) Count(ctx context.Context) (int, error) { + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryCount) + if err := _q.prepareQuery(ctx); err != nil { + return 0, err + } + return withInterceptors[int](ctx, _q, querierCount[*ChannelMonitorQuery](), _q.inters) +} + +// CountX is like Count, but panics if an error occurs. +func (_q *ChannelMonitorQuery) CountX(ctx context.Context) int { + count, err := _q.Count(ctx) + if err != nil { + panic(err) + } + return count +} + +// Exist returns true if the query has elements in the graph. +func (_q *ChannelMonitorQuery) Exist(ctx context.Context) (bool, error) { + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryExist) + switch _, err := _q.FirstID(ctx); { + case IsNotFound(err): + return false, nil + case err != nil: + return false, fmt.Errorf("ent: check existence: %w", err) + default: + return true, nil + } +} + +// ExistX is like Exist, but panics if an error occurs. +func (_q *ChannelMonitorQuery) ExistX(ctx context.Context) bool { + exist, err := _q.Exist(ctx) + if err != nil { + panic(err) + } + return exist +} + +// Clone returns a duplicate of the ChannelMonitorQuery builder, including all associated steps. It can be +// used to prepare common query builders and use them differently after the clone is made. +func (_q *ChannelMonitorQuery) Clone() *ChannelMonitorQuery { + if _q == nil { + return nil + } + return &ChannelMonitorQuery{ + config: _q.config, + ctx: _q.ctx.Clone(), + order: append([]channelmonitor.OrderOption{}, _q.order...), + inters: append([]Interceptor{}, _q.inters...), + predicates: append([]predicate.ChannelMonitor{}, _q.predicates...), + withHistory: _q.withHistory.Clone(), + withDailyRollups: _q.withDailyRollups.Clone(), + withRequestTemplate: _q.withRequestTemplate.Clone(), + // clone intermediate query. + sql: _q.sql.Clone(), + path: _q.path, + } +} + +// WithHistory tells the query-builder to eager-load the nodes that are connected to +// the "history" edge. The optional arguments are used to configure the query builder of the edge. +func (_q *ChannelMonitorQuery) WithHistory(opts ...func(*ChannelMonitorHistoryQuery)) *ChannelMonitorQuery { + query := (&ChannelMonitorHistoryClient{config: _q.config}).Query() + for _, opt := range opts { + opt(query) + } + _q.withHistory = query + return _q +} + +// WithDailyRollups tells the query-builder to eager-load the nodes that are connected to +// the "daily_rollups" edge. The optional arguments are used to configure the query builder of the edge. +func (_q *ChannelMonitorQuery) WithDailyRollups(opts ...func(*ChannelMonitorDailyRollupQuery)) *ChannelMonitorQuery { + query := (&ChannelMonitorDailyRollupClient{config: _q.config}).Query() + for _, opt := range opts { + opt(query) + } + _q.withDailyRollups = query + return _q +} + +// WithRequestTemplate tells the query-builder to eager-load the nodes that are connected to +// the "request_template" edge. The optional arguments are used to configure the query builder of the edge. +func (_q *ChannelMonitorQuery) WithRequestTemplate(opts ...func(*ChannelMonitorRequestTemplateQuery)) *ChannelMonitorQuery { + query := (&ChannelMonitorRequestTemplateClient{config: _q.config}).Query() + for _, opt := range opts { + opt(query) + } + _q.withRequestTemplate = query + return _q +} + +// GroupBy is used to group vertices by one or more fields/columns. +// It is often used with aggregate functions, like: count, max, mean, min, sum. +// +// Example: +// +// var v []struct { +// CreatedAt time.Time `json:"created_at,omitempty"` +// Count int `json:"count,omitempty"` +// } +// +// client.ChannelMonitor.Query(). +// GroupBy(channelmonitor.FieldCreatedAt). +// Aggregate(ent.Count()). +// Scan(ctx, &v) +func (_q *ChannelMonitorQuery) GroupBy(field string, fields ...string) *ChannelMonitorGroupBy { + _q.ctx.Fields = append([]string{field}, fields...) + grbuild := &ChannelMonitorGroupBy{build: _q} + grbuild.flds = &_q.ctx.Fields + grbuild.label = channelmonitor.Label + grbuild.scan = grbuild.Scan + return grbuild +} + +// Select allows the selection one or more fields/columns for the given query, +// instead of selecting all fields in the entity. +// +// Example: +// +// var v []struct { +// CreatedAt time.Time `json:"created_at,omitempty"` +// } +// +// client.ChannelMonitor.Query(). +// Select(channelmonitor.FieldCreatedAt). +// Scan(ctx, &v) +func (_q *ChannelMonitorQuery) Select(fields ...string) *ChannelMonitorSelect { + _q.ctx.Fields = append(_q.ctx.Fields, fields...) + sbuild := &ChannelMonitorSelect{ChannelMonitorQuery: _q} + sbuild.label = channelmonitor.Label + sbuild.flds, sbuild.scan = &_q.ctx.Fields, sbuild.Scan + return sbuild +} + +// Aggregate returns a ChannelMonitorSelect configured with the given aggregations. +func (_q *ChannelMonitorQuery) Aggregate(fns ...AggregateFunc) *ChannelMonitorSelect { + return _q.Select().Aggregate(fns...) +} + +func (_q *ChannelMonitorQuery) prepareQuery(ctx context.Context) error { + for _, inter := range _q.inters { + if inter == nil { + return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)") + } + if trv, ok := inter.(Traverser); ok { + if err := trv.Traverse(ctx, _q); err != nil { + return err + } + } + } + for _, f := range _q.ctx.Fields { + if !channelmonitor.ValidColumn(f) { + return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + } + if _q.path != nil { + prev, err := _q.path(ctx) + if err != nil { + return err + } + _q.sql = prev + } + return nil +} + +func (_q *ChannelMonitorQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*ChannelMonitor, error) { + var ( + nodes = []*ChannelMonitor{} + _spec = _q.querySpec() + loadedTypes = [3]bool{ + _q.withHistory != nil, + _q.withDailyRollups != nil, + _q.withRequestTemplate != nil, + } + ) + _spec.ScanValues = func(columns []string) ([]any, error) { + return (*ChannelMonitor).scanValues(nil, columns) + } + _spec.Assign = func(columns []string, values []any) error { + node := &ChannelMonitor{config: _q.config} + nodes = append(nodes, node) + node.Edges.loadedTypes = loadedTypes + return node.assignValues(columns, values) + } + if len(_q.modifiers) > 0 { + _spec.Modifiers = _q.modifiers + } + for i := range hooks { + hooks[i](ctx, _spec) + } + if err := sqlgraph.QueryNodes(ctx, _q.driver, _spec); err != nil { + return nil, err + } + if len(nodes) == 0 { + return nodes, nil + } + if query := _q.withHistory; query != nil { + if err := _q.loadHistory(ctx, query, nodes, + func(n *ChannelMonitor) { n.Edges.History = []*ChannelMonitorHistory{} }, + func(n *ChannelMonitor, e *ChannelMonitorHistory) { n.Edges.History = append(n.Edges.History, e) }); err != nil { + return nil, err + } + } + if query := _q.withDailyRollups; query != nil { + if err := _q.loadDailyRollups(ctx, query, nodes, + func(n *ChannelMonitor) { n.Edges.DailyRollups = []*ChannelMonitorDailyRollup{} }, + func(n *ChannelMonitor, e *ChannelMonitorDailyRollup) { + n.Edges.DailyRollups = append(n.Edges.DailyRollups, e) + }); err != nil { + return nil, err + } + } + if query := _q.withRequestTemplate; query != nil { + if err := _q.loadRequestTemplate(ctx, query, nodes, nil, + func(n *ChannelMonitor, e *ChannelMonitorRequestTemplate) { n.Edges.RequestTemplate = e }); err != nil { + return nil, err + } + } + return nodes, nil +} + +func (_q *ChannelMonitorQuery) loadHistory(ctx context.Context, query *ChannelMonitorHistoryQuery, nodes []*ChannelMonitor, init func(*ChannelMonitor), assign func(*ChannelMonitor, *ChannelMonitorHistory)) error { + fks := make([]driver.Value, 0, len(nodes)) + nodeids := make(map[int64]*ChannelMonitor) + for i := range nodes { + fks = append(fks, nodes[i].ID) + nodeids[nodes[i].ID] = nodes[i] + if init != nil { + init(nodes[i]) + } + } + if len(query.ctx.Fields) > 0 { + query.ctx.AppendFieldOnce(channelmonitorhistory.FieldMonitorID) + } + query.Where(predicate.ChannelMonitorHistory(func(s *sql.Selector) { + s.Where(sql.InValues(s.C(channelmonitor.HistoryColumn), fks...)) + })) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + fk := n.MonitorID + node, ok := nodeids[fk] + if !ok { + return fmt.Errorf(`unexpected referenced foreign-key "monitor_id" returned %v for node %v`, fk, n.ID) + } + assign(node, n) + } + return nil +} +func (_q *ChannelMonitorQuery) loadDailyRollups(ctx context.Context, query *ChannelMonitorDailyRollupQuery, nodes []*ChannelMonitor, init func(*ChannelMonitor), assign func(*ChannelMonitor, *ChannelMonitorDailyRollup)) error { + fks := make([]driver.Value, 0, len(nodes)) + nodeids := make(map[int64]*ChannelMonitor) + for i := range nodes { + fks = append(fks, nodes[i].ID) + nodeids[nodes[i].ID] = nodes[i] + if init != nil { + init(nodes[i]) + } + } + if len(query.ctx.Fields) > 0 { + query.ctx.AppendFieldOnce(channelmonitordailyrollup.FieldMonitorID) + } + query.Where(predicate.ChannelMonitorDailyRollup(func(s *sql.Selector) { + s.Where(sql.InValues(s.C(channelmonitor.DailyRollupsColumn), fks...)) + })) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + fk := n.MonitorID + node, ok := nodeids[fk] + if !ok { + return fmt.Errorf(`unexpected referenced foreign-key "monitor_id" returned %v for node %v`, fk, n.ID) + } + assign(node, n) + } + return nil +} +func (_q *ChannelMonitorQuery) loadRequestTemplate(ctx context.Context, query *ChannelMonitorRequestTemplateQuery, nodes []*ChannelMonitor, init func(*ChannelMonitor), assign func(*ChannelMonitor, *ChannelMonitorRequestTemplate)) error { + ids := make([]int64, 0, len(nodes)) + nodeids := make(map[int64][]*ChannelMonitor) + for i := range nodes { + if nodes[i].TemplateID == nil { + continue + } + fk := *nodes[i].TemplateID + if _, ok := nodeids[fk]; !ok { + ids = append(ids, fk) + } + nodeids[fk] = append(nodeids[fk], nodes[i]) + } + if len(ids) == 0 { + return nil + } + query.Where(channelmonitorrequesttemplate.IDIn(ids...)) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + nodes, ok := nodeids[n.ID] + if !ok { + return fmt.Errorf(`unexpected foreign-key "template_id" returned %v`, n.ID) + } + for i := range nodes { + assign(nodes[i], n) + } + } + return nil +} + +func (_q *ChannelMonitorQuery) sqlCount(ctx context.Context) (int, error) { + _spec := _q.querySpec() + if len(_q.modifiers) > 0 { + _spec.Modifiers = _q.modifiers + } + _spec.Node.Columns = _q.ctx.Fields + if len(_q.ctx.Fields) > 0 { + _spec.Unique = _q.ctx.Unique != nil && *_q.ctx.Unique + } + return sqlgraph.CountNodes(ctx, _q.driver, _spec) +} + +func (_q *ChannelMonitorQuery) querySpec() *sqlgraph.QuerySpec { + _spec := sqlgraph.NewQuerySpec(channelmonitor.Table, channelmonitor.Columns, sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64)) + _spec.From = _q.sql + if unique := _q.ctx.Unique; unique != nil { + _spec.Unique = *unique + } else if _q.path != nil { + _spec.Unique = true + } + if fields := _q.ctx.Fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, channelmonitor.FieldID) + for i := range fields { + if fields[i] != channelmonitor.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) + } + } + if _q.withRequestTemplate != nil { + _spec.Node.AddColumnOnce(channelmonitor.FieldTemplateID) + } + } + if ps := _q.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if limit := _q.ctx.Limit; limit != nil { + _spec.Limit = *limit + } + if offset := _q.ctx.Offset; offset != nil { + _spec.Offset = *offset + } + if ps := _q.order; len(ps) > 0 { + _spec.Order = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + return _spec +} + +func (_q *ChannelMonitorQuery) sqlQuery(ctx context.Context) *sql.Selector { + builder := sql.Dialect(_q.driver.Dialect()) + t1 := builder.Table(channelmonitor.Table) + columns := _q.ctx.Fields + if len(columns) == 0 { + columns = channelmonitor.Columns + } + selector := builder.Select(t1.Columns(columns...)...).From(t1) + if _q.sql != nil { + selector = _q.sql + selector.Select(selector.Columns(columns...)...) + } + if _q.ctx.Unique != nil && *_q.ctx.Unique { + selector.Distinct() + } + for _, m := range _q.modifiers { + m(selector) + } + for _, p := range _q.predicates { + p(selector) + } + for _, p := range _q.order { + p(selector) + } + if offset := _q.ctx.Offset; offset != nil { + // limit is mandatory for offset clause. We start + // with default value, and override it below if needed. + selector.Offset(*offset).Limit(math.MaxInt32) + } + if limit := _q.ctx.Limit; limit != nil { + selector.Limit(*limit) + } + return selector +} + +// ForUpdate locks the selected rows against concurrent updates, and prevent them from being +// updated, deleted or "selected ... for update" by other sessions, until the transaction is +// either committed or rolled-back. +func (_q *ChannelMonitorQuery) ForUpdate(opts ...sql.LockOption) *ChannelMonitorQuery { + if _q.driver.Dialect() == dialect.Postgres { + _q.Unique(false) + } + _q.modifiers = append(_q.modifiers, func(s *sql.Selector) { + s.ForUpdate(opts...) + }) + return _q +} + +// ForShare behaves similarly to ForUpdate, except that it acquires a shared mode lock +// on any rows that are read. Other sessions can read the rows, but cannot modify them +// until your transaction commits. +func (_q *ChannelMonitorQuery) ForShare(opts ...sql.LockOption) *ChannelMonitorQuery { + if _q.driver.Dialect() == dialect.Postgres { + _q.Unique(false) + } + _q.modifiers = append(_q.modifiers, func(s *sql.Selector) { + s.ForShare(opts...) + }) + return _q +} + +// ChannelMonitorGroupBy is the group-by builder for ChannelMonitor entities. +type ChannelMonitorGroupBy struct { + selector + build *ChannelMonitorQuery +} + +// Aggregate adds the given aggregation functions to the group-by query. +func (_g *ChannelMonitorGroupBy) Aggregate(fns ...AggregateFunc) *ChannelMonitorGroupBy { + _g.fns = append(_g.fns, fns...) + return _g +} + +// Scan applies the selector query and scans the result into the given value. +func (_g *ChannelMonitorGroupBy) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, _g.build.ctx, ent.OpQueryGroupBy) + if err := _g.build.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*ChannelMonitorQuery, *ChannelMonitorGroupBy](ctx, _g.build, _g, _g.build.inters, v) +} + +func (_g *ChannelMonitorGroupBy) sqlScan(ctx context.Context, root *ChannelMonitorQuery, v any) error { + selector := root.sqlQuery(ctx).Select() + aggregation := make([]string, 0, len(_g.fns)) + for _, fn := range _g.fns { + aggregation = append(aggregation, fn(selector)) + } + if len(selector.SelectedColumns()) == 0 { + columns := make([]string, 0, len(*_g.flds)+len(_g.fns)) + for _, f := range *_g.flds { + columns = append(columns, selector.C(f)) + } + columns = append(columns, aggregation...) + selector.Select(columns...) + } + selector.GroupBy(selector.Columns(*_g.flds...)...) + if err := selector.Err(); err != nil { + return err + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := _g.build.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} + +// ChannelMonitorSelect is the builder for selecting fields of ChannelMonitor entities. +type ChannelMonitorSelect struct { + *ChannelMonitorQuery + selector +} + +// Aggregate adds the given aggregation functions to the selector query. +func (_s *ChannelMonitorSelect) Aggregate(fns ...AggregateFunc) *ChannelMonitorSelect { + _s.fns = append(_s.fns, fns...) + return _s +} + +// Scan applies the selector query and scans the result into the given value. +func (_s *ChannelMonitorSelect) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, _s.ctx, ent.OpQuerySelect) + if err := _s.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*ChannelMonitorQuery, *ChannelMonitorSelect](ctx, _s.ChannelMonitorQuery, _s, _s.inters, v) +} + +func (_s *ChannelMonitorSelect) sqlScan(ctx context.Context, root *ChannelMonitorQuery, v any) error { + selector := root.sqlQuery(ctx) + aggregation := make([]string, 0, len(_s.fns)) + for _, fn := range _s.fns { + aggregation = append(aggregation, fn(selector)) + } + switch n := len(*_s.selector.flds); { + case n == 0 && len(aggregation) > 0: + selector.Select(aggregation...) + case n != 0 && len(aggregation) > 0: + selector.AppendSelect(aggregation...) + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := _s.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} diff --git a/backend/ent/channelmonitor_update.go b/backend/ent/channelmonitor_update.go new file mode 100644 index 00000000..4bbcd564 --- /dev/null +++ b/backend/ent/channelmonitor_update.go @@ -0,0 +1,1328 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/dialect/sql/sqljson" + "entgo.io/ent/schema/field" + "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitordailyrollup" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// ChannelMonitorUpdate is the builder for updating ChannelMonitor entities. +type ChannelMonitorUpdate struct { + config + hooks []Hook + mutation *ChannelMonitorMutation +} + +// Where appends a list predicates to the ChannelMonitorUpdate builder. +func (_u *ChannelMonitorUpdate) Where(ps ...predicate.ChannelMonitor) *ChannelMonitorUpdate { + _u.mutation.Where(ps...) + return _u +} + +// SetUpdatedAt sets the "updated_at" field. +func (_u *ChannelMonitorUpdate) SetUpdatedAt(v time.Time) *ChannelMonitorUpdate { + _u.mutation.SetUpdatedAt(v) + return _u +} + +// SetName sets the "name" field. +func (_u *ChannelMonitorUpdate) SetName(v string) *ChannelMonitorUpdate { + _u.mutation.SetName(v) + return _u +} + +// SetNillableName sets the "name" field if the given value is not nil. +func (_u *ChannelMonitorUpdate) SetNillableName(v *string) *ChannelMonitorUpdate { + if v != nil { + _u.SetName(*v) + } + return _u +} + +// SetProvider sets the "provider" field. +func (_u *ChannelMonitorUpdate) SetProvider(v channelmonitor.Provider) *ChannelMonitorUpdate { + _u.mutation.SetProvider(v) + return _u +} + +// SetNillableProvider sets the "provider" field if the given value is not nil. +func (_u *ChannelMonitorUpdate) SetNillableProvider(v *channelmonitor.Provider) *ChannelMonitorUpdate { + if v != nil { + _u.SetProvider(*v) + } + return _u +} + +// SetEndpoint sets the "endpoint" field. +func (_u *ChannelMonitorUpdate) SetEndpoint(v string) *ChannelMonitorUpdate { + _u.mutation.SetEndpoint(v) + return _u +} + +// SetNillableEndpoint sets the "endpoint" field if the given value is not nil. +func (_u *ChannelMonitorUpdate) SetNillableEndpoint(v *string) *ChannelMonitorUpdate { + if v != nil { + _u.SetEndpoint(*v) + } + return _u +} + +// SetAPIKeyEncrypted sets the "api_key_encrypted" field. +func (_u *ChannelMonitorUpdate) SetAPIKeyEncrypted(v string) *ChannelMonitorUpdate { + _u.mutation.SetAPIKeyEncrypted(v) + return _u +} + +// SetNillableAPIKeyEncrypted sets the "api_key_encrypted" field if the given value is not nil. +func (_u *ChannelMonitorUpdate) SetNillableAPIKeyEncrypted(v *string) *ChannelMonitorUpdate { + if v != nil { + _u.SetAPIKeyEncrypted(*v) + } + return _u +} + +// SetPrimaryModel sets the "primary_model" field. +func (_u *ChannelMonitorUpdate) SetPrimaryModel(v string) *ChannelMonitorUpdate { + _u.mutation.SetPrimaryModel(v) + return _u +} + +// SetNillablePrimaryModel sets the "primary_model" field if the given value is not nil. +func (_u *ChannelMonitorUpdate) SetNillablePrimaryModel(v *string) *ChannelMonitorUpdate { + if v != nil { + _u.SetPrimaryModel(*v) + } + return _u +} + +// SetExtraModels sets the "extra_models" field. +func (_u *ChannelMonitorUpdate) SetExtraModels(v []string) *ChannelMonitorUpdate { + _u.mutation.SetExtraModels(v) + return _u +} + +// AppendExtraModels appends value to the "extra_models" field. +func (_u *ChannelMonitorUpdate) AppendExtraModels(v []string) *ChannelMonitorUpdate { + _u.mutation.AppendExtraModels(v) + return _u +} + +// SetGroupName sets the "group_name" field. +func (_u *ChannelMonitorUpdate) SetGroupName(v string) *ChannelMonitorUpdate { + _u.mutation.SetGroupName(v) + return _u +} + +// SetNillableGroupName sets the "group_name" field if the given value is not nil. +func (_u *ChannelMonitorUpdate) SetNillableGroupName(v *string) *ChannelMonitorUpdate { + if v != nil { + _u.SetGroupName(*v) + } + return _u +} + +// ClearGroupName clears the value of the "group_name" field. +func (_u *ChannelMonitorUpdate) ClearGroupName() *ChannelMonitorUpdate { + _u.mutation.ClearGroupName() + return _u +} + +// SetEnabled sets the "enabled" field. +func (_u *ChannelMonitorUpdate) SetEnabled(v bool) *ChannelMonitorUpdate { + _u.mutation.SetEnabled(v) + return _u +} + +// SetNillableEnabled sets the "enabled" field if the given value is not nil. +func (_u *ChannelMonitorUpdate) SetNillableEnabled(v *bool) *ChannelMonitorUpdate { + if v != nil { + _u.SetEnabled(*v) + } + return _u +} + +// SetIntervalSeconds sets the "interval_seconds" field. +func (_u *ChannelMonitorUpdate) SetIntervalSeconds(v int) *ChannelMonitorUpdate { + _u.mutation.ResetIntervalSeconds() + _u.mutation.SetIntervalSeconds(v) + return _u +} + +// SetNillableIntervalSeconds sets the "interval_seconds" field if the given value is not nil. +func (_u *ChannelMonitorUpdate) SetNillableIntervalSeconds(v *int) *ChannelMonitorUpdate { + if v != nil { + _u.SetIntervalSeconds(*v) + } + return _u +} + +// AddIntervalSeconds adds value to the "interval_seconds" field. +func (_u *ChannelMonitorUpdate) AddIntervalSeconds(v int) *ChannelMonitorUpdate { + _u.mutation.AddIntervalSeconds(v) + return _u +} + +// SetLastCheckedAt sets the "last_checked_at" field. +func (_u *ChannelMonitorUpdate) SetLastCheckedAt(v time.Time) *ChannelMonitorUpdate { + _u.mutation.SetLastCheckedAt(v) + return _u +} + +// SetNillableLastCheckedAt sets the "last_checked_at" field if the given value is not nil. +func (_u *ChannelMonitorUpdate) SetNillableLastCheckedAt(v *time.Time) *ChannelMonitorUpdate { + if v != nil { + _u.SetLastCheckedAt(*v) + } + return _u +} + +// ClearLastCheckedAt clears the value of the "last_checked_at" field. +func (_u *ChannelMonitorUpdate) ClearLastCheckedAt() *ChannelMonitorUpdate { + _u.mutation.ClearLastCheckedAt() + return _u +} + +// SetCreatedBy sets the "created_by" field. +func (_u *ChannelMonitorUpdate) SetCreatedBy(v int64) *ChannelMonitorUpdate { + _u.mutation.ResetCreatedBy() + _u.mutation.SetCreatedBy(v) + return _u +} + +// SetNillableCreatedBy sets the "created_by" field if the given value is not nil. +func (_u *ChannelMonitorUpdate) SetNillableCreatedBy(v *int64) *ChannelMonitorUpdate { + if v != nil { + _u.SetCreatedBy(*v) + } + return _u +} + +// AddCreatedBy adds value to the "created_by" field. +func (_u *ChannelMonitorUpdate) AddCreatedBy(v int64) *ChannelMonitorUpdate { + _u.mutation.AddCreatedBy(v) + return _u +} + +// SetTemplateID sets the "template_id" field. +func (_u *ChannelMonitorUpdate) SetTemplateID(v int64) *ChannelMonitorUpdate { + _u.mutation.SetTemplateID(v) + return _u +} + +// SetNillableTemplateID sets the "template_id" field if the given value is not nil. +func (_u *ChannelMonitorUpdate) SetNillableTemplateID(v *int64) *ChannelMonitorUpdate { + if v != nil { + _u.SetTemplateID(*v) + } + return _u +} + +// ClearTemplateID clears the value of the "template_id" field. +func (_u *ChannelMonitorUpdate) ClearTemplateID() *ChannelMonitorUpdate { + _u.mutation.ClearTemplateID() + return _u +} + +// SetExtraHeaders sets the "extra_headers" field. +func (_u *ChannelMonitorUpdate) SetExtraHeaders(v map[string]string) *ChannelMonitorUpdate { + _u.mutation.SetExtraHeaders(v) + return _u +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (_u *ChannelMonitorUpdate) SetBodyOverrideMode(v string) *ChannelMonitorUpdate { + _u.mutation.SetBodyOverrideMode(v) + return _u +} + +// SetNillableBodyOverrideMode sets the "body_override_mode" field if the given value is not nil. +func (_u *ChannelMonitorUpdate) SetNillableBodyOverrideMode(v *string) *ChannelMonitorUpdate { + if v != nil { + _u.SetBodyOverrideMode(*v) + } + return _u +} + +// SetBodyOverride sets the "body_override" field. +func (_u *ChannelMonitorUpdate) SetBodyOverride(v map[string]interface{}) *ChannelMonitorUpdate { + _u.mutation.SetBodyOverride(v) + return _u +} + +// ClearBodyOverride clears the value of the "body_override" field. +func (_u *ChannelMonitorUpdate) ClearBodyOverride() *ChannelMonitorUpdate { + _u.mutation.ClearBodyOverride() + return _u +} + +// AddHistoryIDs adds the "history" edge to the ChannelMonitorHistory entity by IDs. +func (_u *ChannelMonitorUpdate) AddHistoryIDs(ids ...int64) *ChannelMonitorUpdate { + _u.mutation.AddHistoryIDs(ids...) + return _u +} + +// AddHistory adds the "history" edges to the ChannelMonitorHistory entity. +func (_u *ChannelMonitorUpdate) AddHistory(v ...*ChannelMonitorHistory) *ChannelMonitorUpdate { + ids := make([]int64, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _u.AddHistoryIDs(ids...) +} + +// AddDailyRollupIDs adds the "daily_rollups" edge to the ChannelMonitorDailyRollup entity by IDs. +func (_u *ChannelMonitorUpdate) AddDailyRollupIDs(ids ...int64) *ChannelMonitorUpdate { + _u.mutation.AddDailyRollupIDs(ids...) + return _u +} + +// AddDailyRollups adds the "daily_rollups" edges to the ChannelMonitorDailyRollup entity. +func (_u *ChannelMonitorUpdate) AddDailyRollups(v ...*ChannelMonitorDailyRollup) *ChannelMonitorUpdate { + ids := make([]int64, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _u.AddDailyRollupIDs(ids...) +} + +// SetRequestTemplateID sets the "request_template" edge to the ChannelMonitorRequestTemplate entity by ID. +func (_u *ChannelMonitorUpdate) SetRequestTemplateID(id int64) *ChannelMonitorUpdate { + _u.mutation.SetRequestTemplateID(id) + return _u +} + +// SetNillableRequestTemplateID sets the "request_template" edge to the ChannelMonitorRequestTemplate entity by ID if the given value is not nil. +func (_u *ChannelMonitorUpdate) SetNillableRequestTemplateID(id *int64) *ChannelMonitorUpdate { + if id != nil { + _u = _u.SetRequestTemplateID(*id) + } + return _u +} + +// SetRequestTemplate sets the "request_template" edge to the ChannelMonitorRequestTemplate entity. +func (_u *ChannelMonitorUpdate) SetRequestTemplate(v *ChannelMonitorRequestTemplate) *ChannelMonitorUpdate { + return _u.SetRequestTemplateID(v.ID) +} + +// Mutation returns the ChannelMonitorMutation object of the builder. +func (_u *ChannelMonitorUpdate) Mutation() *ChannelMonitorMutation { + return _u.mutation +} + +// ClearHistory clears all "history" edges to the ChannelMonitorHistory entity. +func (_u *ChannelMonitorUpdate) ClearHistory() *ChannelMonitorUpdate { + _u.mutation.ClearHistory() + return _u +} + +// RemoveHistoryIDs removes the "history" edge to ChannelMonitorHistory entities by IDs. +func (_u *ChannelMonitorUpdate) RemoveHistoryIDs(ids ...int64) *ChannelMonitorUpdate { + _u.mutation.RemoveHistoryIDs(ids...) + return _u +} + +// RemoveHistory removes "history" edges to ChannelMonitorHistory entities. +func (_u *ChannelMonitorUpdate) RemoveHistory(v ...*ChannelMonitorHistory) *ChannelMonitorUpdate { + ids := make([]int64, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _u.RemoveHistoryIDs(ids...) +} + +// ClearDailyRollups clears all "daily_rollups" edges to the ChannelMonitorDailyRollup entity. +func (_u *ChannelMonitorUpdate) ClearDailyRollups() *ChannelMonitorUpdate { + _u.mutation.ClearDailyRollups() + return _u +} + +// RemoveDailyRollupIDs removes the "daily_rollups" edge to ChannelMonitorDailyRollup entities by IDs. +func (_u *ChannelMonitorUpdate) RemoveDailyRollupIDs(ids ...int64) *ChannelMonitorUpdate { + _u.mutation.RemoveDailyRollupIDs(ids...) + return _u +} + +// RemoveDailyRollups removes "daily_rollups" edges to ChannelMonitorDailyRollup entities. +func (_u *ChannelMonitorUpdate) RemoveDailyRollups(v ...*ChannelMonitorDailyRollup) *ChannelMonitorUpdate { + ids := make([]int64, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _u.RemoveDailyRollupIDs(ids...) +} + +// ClearRequestTemplate clears the "request_template" edge to the ChannelMonitorRequestTemplate entity. +func (_u *ChannelMonitorUpdate) ClearRequestTemplate() *ChannelMonitorUpdate { + _u.mutation.ClearRequestTemplate() + return _u +} + +// Save executes the query and returns the number of nodes affected by the update operation. +func (_u *ChannelMonitorUpdate) Save(ctx context.Context) (int, error) { + _u.defaults() + return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (_u *ChannelMonitorUpdate) SaveX(ctx context.Context) int { + affected, err := _u.Save(ctx) + if err != nil { + panic(err) + } + return affected +} + +// Exec executes the query. +func (_u *ChannelMonitorUpdate) Exec(ctx context.Context) error { + _, err := _u.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_u *ChannelMonitorUpdate) ExecX(ctx context.Context) { + if err := _u.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (_u *ChannelMonitorUpdate) defaults() { + if _, ok := _u.mutation.UpdatedAt(); !ok { + v := channelmonitor.UpdateDefaultUpdatedAt() + _u.mutation.SetUpdatedAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_u *ChannelMonitorUpdate) check() error { + if v, ok := _u.mutation.Name(); ok { + if err := channelmonitor.NameValidator(v); err != nil { + return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.name": %w`, err)} + } + } + if v, ok := _u.mutation.Provider(); ok { + if err := channelmonitor.ProviderValidator(v); err != nil { + return &ValidationError{Name: "provider", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.provider": %w`, err)} + } + } + if v, ok := _u.mutation.Endpoint(); ok { + if err := channelmonitor.EndpointValidator(v); err != nil { + return &ValidationError{Name: "endpoint", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.endpoint": %w`, err)} + } + } + if v, ok := _u.mutation.APIKeyEncrypted(); ok { + if err := channelmonitor.APIKeyEncryptedValidator(v); err != nil { + return &ValidationError{Name: "api_key_encrypted", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.api_key_encrypted": %w`, err)} + } + } + if v, ok := _u.mutation.PrimaryModel(); ok { + if err := channelmonitor.PrimaryModelValidator(v); err != nil { + return &ValidationError{Name: "primary_model", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.primary_model": %w`, err)} + } + } + if v, ok := _u.mutation.GroupName(); ok { + if err := channelmonitor.GroupNameValidator(v); err != nil { + return &ValidationError{Name: "group_name", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.group_name": %w`, err)} + } + } + if v, ok := _u.mutation.IntervalSeconds(); ok { + if err := channelmonitor.IntervalSecondsValidator(v); err != nil { + return &ValidationError{Name: "interval_seconds", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.interval_seconds": %w`, err)} + } + } + if v, ok := _u.mutation.BodyOverrideMode(); ok { + if err := channelmonitor.BodyOverrideModeValidator(v); err != nil { + return &ValidationError{Name: "body_override_mode", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.body_override_mode": %w`, err)} + } + } + return nil +} + +func (_u *ChannelMonitorUpdate) sqlSave(ctx context.Context) (_node int, err error) { + if err := _u.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(channelmonitor.Table, channelmonitor.Columns, sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64)) + if ps := _u.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := _u.mutation.UpdatedAt(); ok { + _spec.SetField(channelmonitor.FieldUpdatedAt, field.TypeTime, value) + } + if value, ok := _u.mutation.Name(); ok { + _spec.SetField(channelmonitor.FieldName, field.TypeString, value) + } + if value, ok := _u.mutation.Provider(); ok { + _spec.SetField(channelmonitor.FieldProvider, field.TypeEnum, value) + } + if value, ok := _u.mutation.Endpoint(); ok { + _spec.SetField(channelmonitor.FieldEndpoint, field.TypeString, value) + } + if value, ok := _u.mutation.APIKeyEncrypted(); ok { + _spec.SetField(channelmonitor.FieldAPIKeyEncrypted, field.TypeString, value) + } + if value, ok := _u.mutation.PrimaryModel(); ok { + _spec.SetField(channelmonitor.FieldPrimaryModel, field.TypeString, value) + } + if value, ok := _u.mutation.ExtraModels(); ok { + _spec.SetField(channelmonitor.FieldExtraModels, field.TypeJSON, value) + } + if value, ok := _u.mutation.AppendedExtraModels(); ok { + _spec.AddModifier(func(u *sql.UpdateBuilder) { + sqljson.Append(u, channelmonitor.FieldExtraModels, value) + }) + } + if value, ok := _u.mutation.GroupName(); ok { + _spec.SetField(channelmonitor.FieldGroupName, field.TypeString, value) + } + if _u.mutation.GroupNameCleared() { + _spec.ClearField(channelmonitor.FieldGroupName, field.TypeString) + } + if value, ok := _u.mutation.Enabled(); ok { + _spec.SetField(channelmonitor.FieldEnabled, field.TypeBool, value) + } + if value, ok := _u.mutation.IntervalSeconds(); ok { + _spec.SetField(channelmonitor.FieldIntervalSeconds, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedIntervalSeconds(); ok { + _spec.AddField(channelmonitor.FieldIntervalSeconds, field.TypeInt, value) + } + if value, ok := _u.mutation.LastCheckedAt(); ok { + _spec.SetField(channelmonitor.FieldLastCheckedAt, field.TypeTime, value) + } + if _u.mutation.LastCheckedAtCleared() { + _spec.ClearField(channelmonitor.FieldLastCheckedAt, field.TypeTime) + } + if value, ok := _u.mutation.CreatedBy(); ok { + _spec.SetField(channelmonitor.FieldCreatedBy, field.TypeInt64, value) + } + if value, ok := _u.mutation.AddedCreatedBy(); ok { + _spec.AddField(channelmonitor.FieldCreatedBy, field.TypeInt64, value) + } + if value, ok := _u.mutation.ExtraHeaders(); ok { + _spec.SetField(channelmonitor.FieldExtraHeaders, field.TypeJSON, value) + } + if value, ok := _u.mutation.BodyOverrideMode(); ok { + _spec.SetField(channelmonitor.FieldBodyOverrideMode, field.TypeString, value) + } + if value, ok := _u.mutation.BodyOverride(); ok { + _spec.SetField(channelmonitor.FieldBodyOverride, field.TypeJSON, value) + } + if _u.mutation.BodyOverrideCleared() { + _spec.ClearField(channelmonitor.FieldBodyOverride, field.TypeJSON) + } + if _u.mutation.HistoryCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: channelmonitor.HistoryTable, + Columns: []string{channelmonitor.HistoryColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitorhistory.FieldID, field.TypeInt64), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.RemovedHistoryIDs(); len(nodes) > 0 && !_u.mutation.HistoryCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: channelmonitor.HistoryTable, + Columns: []string{channelmonitor.HistoryColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitorhistory.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.HistoryIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: channelmonitor.HistoryTable, + Columns: []string{channelmonitor.HistoryColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitorhistory.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if _u.mutation.DailyRollupsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: channelmonitor.DailyRollupsTable, + Columns: []string{channelmonitor.DailyRollupsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitordailyrollup.FieldID, field.TypeInt64), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.RemovedDailyRollupsIDs(); len(nodes) > 0 && !_u.mutation.DailyRollupsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: channelmonitor.DailyRollupsTable, + Columns: []string{channelmonitor.DailyRollupsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitordailyrollup.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.DailyRollupsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: channelmonitor.DailyRollupsTable, + Columns: []string{channelmonitor.DailyRollupsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitordailyrollup.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if _u.mutation.RequestTemplateCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: channelmonitor.RequestTemplateTable, + Columns: []string{channelmonitor.RequestTemplateColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitorrequesttemplate.FieldID, field.TypeInt64), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.RequestTemplateIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: channelmonitor.RequestTemplateTable, + Columns: []string{channelmonitor.RequestTemplateColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitorrequesttemplate.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if _node, err = sqlgraph.UpdateNodes(ctx, _u.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{channelmonitor.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return 0, err + } + _u.mutation.done = true + return _node, nil +} + +// ChannelMonitorUpdateOne is the builder for updating a single ChannelMonitor entity. +type ChannelMonitorUpdateOne struct { + config + fields []string + hooks []Hook + mutation *ChannelMonitorMutation +} + +// SetUpdatedAt sets the "updated_at" field. +func (_u *ChannelMonitorUpdateOne) SetUpdatedAt(v time.Time) *ChannelMonitorUpdateOne { + _u.mutation.SetUpdatedAt(v) + return _u +} + +// SetName sets the "name" field. +func (_u *ChannelMonitorUpdateOne) SetName(v string) *ChannelMonitorUpdateOne { + _u.mutation.SetName(v) + return _u +} + +// SetNillableName sets the "name" field if the given value is not nil. +func (_u *ChannelMonitorUpdateOne) SetNillableName(v *string) *ChannelMonitorUpdateOne { + if v != nil { + _u.SetName(*v) + } + return _u +} + +// SetProvider sets the "provider" field. +func (_u *ChannelMonitorUpdateOne) SetProvider(v channelmonitor.Provider) *ChannelMonitorUpdateOne { + _u.mutation.SetProvider(v) + return _u +} + +// SetNillableProvider sets the "provider" field if the given value is not nil. +func (_u *ChannelMonitorUpdateOne) SetNillableProvider(v *channelmonitor.Provider) *ChannelMonitorUpdateOne { + if v != nil { + _u.SetProvider(*v) + } + return _u +} + +// SetEndpoint sets the "endpoint" field. +func (_u *ChannelMonitorUpdateOne) SetEndpoint(v string) *ChannelMonitorUpdateOne { + _u.mutation.SetEndpoint(v) + return _u +} + +// SetNillableEndpoint sets the "endpoint" field if the given value is not nil. +func (_u *ChannelMonitorUpdateOne) SetNillableEndpoint(v *string) *ChannelMonitorUpdateOne { + if v != nil { + _u.SetEndpoint(*v) + } + return _u +} + +// SetAPIKeyEncrypted sets the "api_key_encrypted" field. +func (_u *ChannelMonitorUpdateOne) SetAPIKeyEncrypted(v string) *ChannelMonitorUpdateOne { + _u.mutation.SetAPIKeyEncrypted(v) + return _u +} + +// SetNillableAPIKeyEncrypted sets the "api_key_encrypted" field if the given value is not nil. +func (_u *ChannelMonitorUpdateOne) SetNillableAPIKeyEncrypted(v *string) *ChannelMonitorUpdateOne { + if v != nil { + _u.SetAPIKeyEncrypted(*v) + } + return _u +} + +// SetPrimaryModel sets the "primary_model" field. +func (_u *ChannelMonitorUpdateOne) SetPrimaryModel(v string) *ChannelMonitorUpdateOne { + _u.mutation.SetPrimaryModel(v) + return _u +} + +// SetNillablePrimaryModel sets the "primary_model" field if the given value is not nil. +func (_u *ChannelMonitorUpdateOne) SetNillablePrimaryModel(v *string) *ChannelMonitorUpdateOne { + if v != nil { + _u.SetPrimaryModel(*v) + } + return _u +} + +// SetExtraModels sets the "extra_models" field. +func (_u *ChannelMonitorUpdateOne) SetExtraModels(v []string) *ChannelMonitorUpdateOne { + _u.mutation.SetExtraModels(v) + return _u +} + +// AppendExtraModels appends value to the "extra_models" field. +func (_u *ChannelMonitorUpdateOne) AppendExtraModels(v []string) *ChannelMonitorUpdateOne { + _u.mutation.AppendExtraModels(v) + return _u +} + +// SetGroupName sets the "group_name" field. +func (_u *ChannelMonitorUpdateOne) SetGroupName(v string) *ChannelMonitorUpdateOne { + _u.mutation.SetGroupName(v) + return _u +} + +// SetNillableGroupName sets the "group_name" field if the given value is not nil. +func (_u *ChannelMonitorUpdateOne) SetNillableGroupName(v *string) *ChannelMonitorUpdateOne { + if v != nil { + _u.SetGroupName(*v) + } + return _u +} + +// ClearGroupName clears the value of the "group_name" field. +func (_u *ChannelMonitorUpdateOne) ClearGroupName() *ChannelMonitorUpdateOne { + _u.mutation.ClearGroupName() + return _u +} + +// SetEnabled sets the "enabled" field. +func (_u *ChannelMonitorUpdateOne) SetEnabled(v bool) *ChannelMonitorUpdateOne { + _u.mutation.SetEnabled(v) + return _u +} + +// SetNillableEnabled sets the "enabled" field if the given value is not nil. +func (_u *ChannelMonitorUpdateOne) SetNillableEnabled(v *bool) *ChannelMonitorUpdateOne { + if v != nil { + _u.SetEnabled(*v) + } + return _u +} + +// SetIntervalSeconds sets the "interval_seconds" field. +func (_u *ChannelMonitorUpdateOne) SetIntervalSeconds(v int) *ChannelMonitorUpdateOne { + _u.mutation.ResetIntervalSeconds() + _u.mutation.SetIntervalSeconds(v) + return _u +} + +// SetNillableIntervalSeconds sets the "interval_seconds" field if the given value is not nil. +func (_u *ChannelMonitorUpdateOne) SetNillableIntervalSeconds(v *int) *ChannelMonitorUpdateOne { + if v != nil { + _u.SetIntervalSeconds(*v) + } + return _u +} + +// AddIntervalSeconds adds value to the "interval_seconds" field. +func (_u *ChannelMonitorUpdateOne) AddIntervalSeconds(v int) *ChannelMonitorUpdateOne { + _u.mutation.AddIntervalSeconds(v) + return _u +} + +// SetLastCheckedAt sets the "last_checked_at" field. +func (_u *ChannelMonitorUpdateOne) SetLastCheckedAt(v time.Time) *ChannelMonitorUpdateOne { + _u.mutation.SetLastCheckedAt(v) + return _u +} + +// SetNillableLastCheckedAt sets the "last_checked_at" field if the given value is not nil. +func (_u *ChannelMonitorUpdateOne) SetNillableLastCheckedAt(v *time.Time) *ChannelMonitorUpdateOne { + if v != nil { + _u.SetLastCheckedAt(*v) + } + return _u +} + +// ClearLastCheckedAt clears the value of the "last_checked_at" field. +func (_u *ChannelMonitorUpdateOne) ClearLastCheckedAt() *ChannelMonitorUpdateOne { + _u.mutation.ClearLastCheckedAt() + return _u +} + +// SetCreatedBy sets the "created_by" field. +func (_u *ChannelMonitorUpdateOne) SetCreatedBy(v int64) *ChannelMonitorUpdateOne { + _u.mutation.ResetCreatedBy() + _u.mutation.SetCreatedBy(v) + return _u +} + +// SetNillableCreatedBy sets the "created_by" field if the given value is not nil. +func (_u *ChannelMonitorUpdateOne) SetNillableCreatedBy(v *int64) *ChannelMonitorUpdateOne { + if v != nil { + _u.SetCreatedBy(*v) + } + return _u +} + +// AddCreatedBy adds value to the "created_by" field. +func (_u *ChannelMonitorUpdateOne) AddCreatedBy(v int64) *ChannelMonitorUpdateOne { + _u.mutation.AddCreatedBy(v) + return _u +} + +// SetTemplateID sets the "template_id" field. +func (_u *ChannelMonitorUpdateOne) SetTemplateID(v int64) *ChannelMonitorUpdateOne { + _u.mutation.SetTemplateID(v) + return _u +} + +// SetNillableTemplateID sets the "template_id" field if the given value is not nil. +func (_u *ChannelMonitorUpdateOne) SetNillableTemplateID(v *int64) *ChannelMonitorUpdateOne { + if v != nil { + _u.SetTemplateID(*v) + } + return _u +} + +// ClearTemplateID clears the value of the "template_id" field. +func (_u *ChannelMonitorUpdateOne) ClearTemplateID() *ChannelMonitorUpdateOne { + _u.mutation.ClearTemplateID() + return _u +} + +// SetExtraHeaders sets the "extra_headers" field. +func (_u *ChannelMonitorUpdateOne) SetExtraHeaders(v map[string]string) *ChannelMonitorUpdateOne { + _u.mutation.SetExtraHeaders(v) + return _u +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (_u *ChannelMonitorUpdateOne) SetBodyOverrideMode(v string) *ChannelMonitorUpdateOne { + _u.mutation.SetBodyOverrideMode(v) + return _u +} + +// SetNillableBodyOverrideMode sets the "body_override_mode" field if the given value is not nil. +func (_u *ChannelMonitorUpdateOne) SetNillableBodyOverrideMode(v *string) *ChannelMonitorUpdateOne { + if v != nil { + _u.SetBodyOverrideMode(*v) + } + return _u +} + +// SetBodyOverride sets the "body_override" field. +func (_u *ChannelMonitorUpdateOne) SetBodyOverride(v map[string]interface{}) *ChannelMonitorUpdateOne { + _u.mutation.SetBodyOverride(v) + return _u +} + +// ClearBodyOverride clears the value of the "body_override" field. +func (_u *ChannelMonitorUpdateOne) ClearBodyOverride() *ChannelMonitorUpdateOne { + _u.mutation.ClearBodyOverride() + return _u +} + +// AddHistoryIDs adds the "history" edge to the ChannelMonitorHistory entity by IDs. +func (_u *ChannelMonitorUpdateOne) AddHistoryIDs(ids ...int64) *ChannelMonitorUpdateOne { + _u.mutation.AddHistoryIDs(ids...) + return _u +} + +// AddHistory adds the "history" edges to the ChannelMonitorHistory entity. +func (_u *ChannelMonitorUpdateOne) AddHistory(v ...*ChannelMonitorHistory) *ChannelMonitorUpdateOne { + ids := make([]int64, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _u.AddHistoryIDs(ids...) +} + +// AddDailyRollupIDs adds the "daily_rollups" edge to the ChannelMonitorDailyRollup entity by IDs. +func (_u *ChannelMonitorUpdateOne) AddDailyRollupIDs(ids ...int64) *ChannelMonitorUpdateOne { + _u.mutation.AddDailyRollupIDs(ids...) + return _u +} + +// AddDailyRollups adds the "daily_rollups" edges to the ChannelMonitorDailyRollup entity. +func (_u *ChannelMonitorUpdateOne) AddDailyRollups(v ...*ChannelMonitorDailyRollup) *ChannelMonitorUpdateOne { + ids := make([]int64, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _u.AddDailyRollupIDs(ids...) +} + +// SetRequestTemplateID sets the "request_template" edge to the ChannelMonitorRequestTemplate entity by ID. +func (_u *ChannelMonitorUpdateOne) SetRequestTemplateID(id int64) *ChannelMonitorUpdateOne { + _u.mutation.SetRequestTemplateID(id) + return _u +} + +// SetNillableRequestTemplateID sets the "request_template" edge to the ChannelMonitorRequestTemplate entity by ID if the given value is not nil. +func (_u *ChannelMonitorUpdateOne) SetNillableRequestTemplateID(id *int64) *ChannelMonitorUpdateOne { + if id != nil { + _u = _u.SetRequestTemplateID(*id) + } + return _u +} + +// SetRequestTemplate sets the "request_template" edge to the ChannelMonitorRequestTemplate entity. +func (_u *ChannelMonitorUpdateOne) SetRequestTemplate(v *ChannelMonitorRequestTemplate) *ChannelMonitorUpdateOne { + return _u.SetRequestTemplateID(v.ID) +} + +// Mutation returns the ChannelMonitorMutation object of the builder. +func (_u *ChannelMonitorUpdateOne) Mutation() *ChannelMonitorMutation { + return _u.mutation +} + +// ClearHistory clears all "history" edges to the ChannelMonitorHistory entity. +func (_u *ChannelMonitorUpdateOne) ClearHistory() *ChannelMonitorUpdateOne { + _u.mutation.ClearHistory() + return _u +} + +// RemoveHistoryIDs removes the "history" edge to ChannelMonitorHistory entities by IDs. +func (_u *ChannelMonitorUpdateOne) RemoveHistoryIDs(ids ...int64) *ChannelMonitorUpdateOne { + _u.mutation.RemoveHistoryIDs(ids...) + return _u +} + +// RemoveHistory removes "history" edges to ChannelMonitorHistory entities. +func (_u *ChannelMonitorUpdateOne) RemoveHistory(v ...*ChannelMonitorHistory) *ChannelMonitorUpdateOne { + ids := make([]int64, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _u.RemoveHistoryIDs(ids...) +} + +// ClearDailyRollups clears all "daily_rollups" edges to the ChannelMonitorDailyRollup entity. +func (_u *ChannelMonitorUpdateOne) ClearDailyRollups() *ChannelMonitorUpdateOne { + _u.mutation.ClearDailyRollups() + return _u +} + +// RemoveDailyRollupIDs removes the "daily_rollups" edge to ChannelMonitorDailyRollup entities by IDs. +func (_u *ChannelMonitorUpdateOne) RemoveDailyRollupIDs(ids ...int64) *ChannelMonitorUpdateOne { + _u.mutation.RemoveDailyRollupIDs(ids...) + return _u +} + +// RemoveDailyRollups removes "daily_rollups" edges to ChannelMonitorDailyRollup entities. +func (_u *ChannelMonitorUpdateOne) RemoveDailyRollups(v ...*ChannelMonitorDailyRollup) *ChannelMonitorUpdateOne { + ids := make([]int64, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _u.RemoveDailyRollupIDs(ids...) +} + +// ClearRequestTemplate clears the "request_template" edge to the ChannelMonitorRequestTemplate entity. +func (_u *ChannelMonitorUpdateOne) ClearRequestTemplate() *ChannelMonitorUpdateOne { + _u.mutation.ClearRequestTemplate() + return _u +} + +// Where appends a list predicates to the ChannelMonitorUpdate builder. +func (_u *ChannelMonitorUpdateOne) Where(ps ...predicate.ChannelMonitor) *ChannelMonitorUpdateOne { + _u.mutation.Where(ps...) + return _u +} + +// Select allows selecting one or more fields (columns) of the returned entity. +// The default is selecting all fields defined in the entity schema. +func (_u *ChannelMonitorUpdateOne) Select(field string, fields ...string) *ChannelMonitorUpdateOne { + _u.fields = append([]string{field}, fields...) + return _u +} + +// Save executes the query and returns the updated ChannelMonitor entity. +func (_u *ChannelMonitorUpdateOne) Save(ctx context.Context) (*ChannelMonitor, error) { + _u.defaults() + return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (_u *ChannelMonitorUpdateOne) SaveX(ctx context.Context) *ChannelMonitor { + node, err := _u.Save(ctx) + if err != nil { + panic(err) + } + return node +} + +// Exec executes the query on the entity. +func (_u *ChannelMonitorUpdateOne) Exec(ctx context.Context) error { + _, err := _u.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_u *ChannelMonitorUpdateOne) ExecX(ctx context.Context) { + if err := _u.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (_u *ChannelMonitorUpdateOne) defaults() { + if _, ok := _u.mutation.UpdatedAt(); !ok { + v := channelmonitor.UpdateDefaultUpdatedAt() + _u.mutation.SetUpdatedAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_u *ChannelMonitorUpdateOne) check() error { + if v, ok := _u.mutation.Name(); ok { + if err := channelmonitor.NameValidator(v); err != nil { + return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.name": %w`, err)} + } + } + if v, ok := _u.mutation.Provider(); ok { + if err := channelmonitor.ProviderValidator(v); err != nil { + return &ValidationError{Name: "provider", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.provider": %w`, err)} + } + } + if v, ok := _u.mutation.Endpoint(); ok { + if err := channelmonitor.EndpointValidator(v); err != nil { + return &ValidationError{Name: "endpoint", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.endpoint": %w`, err)} + } + } + if v, ok := _u.mutation.APIKeyEncrypted(); ok { + if err := channelmonitor.APIKeyEncryptedValidator(v); err != nil { + return &ValidationError{Name: "api_key_encrypted", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.api_key_encrypted": %w`, err)} + } + } + if v, ok := _u.mutation.PrimaryModel(); ok { + if err := channelmonitor.PrimaryModelValidator(v); err != nil { + return &ValidationError{Name: "primary_model", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.primary_model": %w`, err)} + } + } + if v, ok := _u.mutation.GroupName(); ok { + if err := channelmonitor.GroupNameValidator(v); err != nil { + return &ValidationError{Name: "group_name", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.group_name": %w`, err)} + } + } + if v, ok := _u.mutation.IntervalSeconds(); ok { + if err := channelmonitor.IntervalSecondsValidator(v); err != nil { + return &ValidationError{Name: "interval_seconds", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.interval_seconds": %w`, err)} + } + } + if v, ok := _u.mutation.BodyOverrideMode(); ok { + if err := channelmonitor.BodyOverrideModeValidator(v); err != nil { + return &ValidationError{Name: "body_override_mode", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.body_override_mode": %w`, err)} + } + } + return nil +} + +func (_u *ChannelMonitorUpdateOne) sqlSave(ctx context.Context) (_node *ChannelMonitor, err error) { + if err := _u.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(channelmonitor.Table, channelmonitor.Columns, sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64)) + id, ok := _u.mutation.ID() + if !ok { + return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "ChannelMonitor.id" for update`)} + } + _spec.Node.ID.Value = id + if fields := _u.fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, channelmonitor.FieldID) + for _, f := range fields { + if !channelmonitor.ValidColumn(f) { + return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + if f != channelmonitor.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, f) + } + } + } + if ps := _u.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := _u.mutation.UpdatedAt(); ok { + _spec.SetField(channelmonitor.FieldUpdatedAt, field.TypeTime, value) + } + if value, ok := _u.mutation.Name(); ok { + _spec.SetField(channelmonitor.FieldName, field.TypeString, value) + } + if value, ok := _u.mutation.Provider(); ok { + _spec.SetField(channelmonitor.FieldProvider, field.TypeEnum, value) + } + if value, ok := _u.mutation.Endpoint(); ok { + _spec.SetField(channelmonitor.FieldEndpoint, field.TypeString, value) + } + if value, ok := _u.mutation.APIKeyEncrypted(); ok { + _spec.SetField(channelmonitor.FieldAPIKeyEncrypted, field.TypeString, value) + } + if value, ok := _u.mutation.PrimaryModel(); ok { + _spec.SetField(channelmonitor.FieldPrimaryModel, field.TypeString, value) + } + if value, ok := _u.mutation.ExtraModels(); ok { + _spec.SetField(channelmonitor.FieldExtraModels, field.TypeJSON, value) + } + if value, ok := _u.mutation.AppendedExtraModels(); ok { + _spec.AddModifier(func(u *sql.UpdateBuilder) { + sqljson.Append(u, channelmonitor.FieldExtraModels, value) + }) + } + if value, ok := _u.mutation.GroupName(); ok { + _spec.SetField(channelmonitor.FieldGroupName, field.TypeString, value) + } + if _u.mutation.GroupNameCleared() { + _spec.ClearField(channelmonitor.FieldGroupName, field.TypeString) + } + if value, ok := _u.mutation.Enabled(); ok { + _spec.SetField(channelmonitor.FieldEnabled, field.TypeBool, value) + } + if value, ok := _u.mutation.IntervalSeconds(); ok { + _spec.SetField(channelmonitor.FieldIntervalSeconds, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedIntervalSeconds(); ok { + _spec.AddField(channelmonitor.FieldIntervalSeconds, field.TypeInt, value) + } + if value, ok := _u.mutation.LastCheckedAt(); ok { + _spec.SetField(channelmonitor.FieldLastCheckedAt, field.TypeTime, value) + } + if _u.mutation.LastCheckedAtCleared() { + _spec.ClearField(channelmonitor.FieldLastCheckedAt, field.TypeTime) + } + if value, ok := _u.mutation.CreatedBy(); ok { + _spec.SetField(channelmonitor.FieldCreatedBy, field.TypeInt64, value) + } + if value, ok := _u.mutation.AddedCreatedBy(); ok { + _spec.AddField(channelmonitor.FieldCreatedBy, field.TypeInt64, value) + } + if value, ok := _u.mutation.ExtraHeaders(); ok { + _spec.SetField(channelmonitor.FieldExtraHeaders, field.TypeJSON, value) + } + if value, ok := _u.mutation.BodyOverrideMode(); ok { + _spec.SetField(channelmonitor.FieldBodyOverrideMode, field.TypeString, value) + } + if value, ok := _u.mutation.BodyOverride(); ok { + _spec.SetField(channelmonitor.FieldBodyOverride, field.TypeJSON, value) + } + if _u.mutation.BodyOverrideCleared() { + _spec.ClearField(channelmonitor.FieldBodyOverride, field.TypeJSON) + } + if _u.mutation.HistoryCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: channelmonitor.HistoryTable, + Columns: []string{channelmonitor.HistoryColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitorhistory.FieldID, field.TypeInt64), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.RemovedHistoryIDs(); len(nodes) > 0 && !_u.mutation.HistoryCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: channelmonitor.HistoryTable, + Columns: []string{channelmonitor.HistoryColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitorhistory.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.HistoryIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: channelmonitor.HistoryTable, + Columns: []string{channelmonitor.HistoryColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitorhistory.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if _u.mutation.DailyRollupsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: channelmonitor.DailyRollupsTable, + Columns: []string{channelmonitor.DailyRollupsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitordailyrollup.FieldID, field.TypeInt64), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.RemovedDailyRollupsIDs(); len(nodes) > 0 && !_u.mutation.DailyRollupsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: channelmonitor.DailyRollupsTable, + Columns: []string{channelmonitor.DailyRollupsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitordailyrollup.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.DailyRollupsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: channelmonitor.DailyRollupsTable, + Columns: []string{channelmonitor.DailyRollupsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitordailyrollup.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if _u.mutation.RequestTemplateCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: channelmonitor.RequestTemplateTable, + Columns: []string{channelmonitor.RequestTemplateColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitorrequesttemplate.FieldID, field.TypeInt64), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.RequestTemplateIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: channelmonitor.RequestTemplateTable, + Columns: []string{channelmonitor.RequestTemplateColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitorrequesttemplate.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + _node = &ChannelMonitor{config: _u.config} + _spec.Assign = _node.assignValues + _spec.ScanValues = _node.scanValues + if err = sqlgraph.UpdateNode(ctx, _u.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{channelmonitor.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + _u.mutation.done = true + return _node, nil +} diff --git a/backend/ent/channelmonitordailyrollup.go b/backend/ent/channelmonitordailyrollup.go new file mode 100644 index 00000000..78a5f489 --- /dev/null +++ b/backend/ent/channelmonitordailyrollup.go @@ -0,0 +1,278 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "fmt" + "strings" + "time" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitordailyrollup" +) + +// ChannelMonitorDailyRollup is the model entity for the ChannelMonitorDailyRollup schema. +type ChannelMonitorDailyRollup struct { + config `json:"-"` + // ID of the ent. + ID int64 `json:"id,omitempty"` + // MonitorID holds the value of the "monitor_id" field. + MonitorID int64 `json:"monitor_id,omitempty"` + // Model holds the value of the "model" field. + Model string `json:"model,omitempty"` + // BucketDate holds the value of the "bucket_date" field. + BucketDate time.Time `json:"bucket_date,omitempty"` + // TotalChecks holds the value of the "total_checks" field. + TotalChecks int `json:"total_checks,omitempty"` + // OkCount holds the value of the "ok_count" field. + OkCount int `json:"ok_count,omitempty"` + // OperationalCount holds the value of the "operational_count" field. + OperationalCount int `json:"operational_count,omitempty"` + // DegradedCount holds the value of the "degraded_count" field. + DegradedCount int `json:"degraded_count,omitempty"` + // FailedCount holds the value of the "failed_count" field. + FailedCount int `json:"failed_count,omitempty"` + // ErrorCount holds the value of the "error_count" field. + ErrorCount int `json:"error_count,omitempty"` + // SumLatencyMs holds the value of the "sum_latency_ms" field. + SumLatencyMs int64 `json:"sum_latency_ms,omitempty"` + // CountLatency holds the value of the "count_latency" field. + CountLatency int `json:"count_latency,omitempty"` + // SumPingLatencyMs holds the value of the "sum_ping_latency_ms" field. + SumPingLatencyMs int64 `json:"sum_ping_latency_ms,omitempty"` + // CountPingLatency holds the value of the "count_ping_latency" field. + CountPingLatency int `json:"count_ping_latency,omitempty"` + // ComputedAt holds the value of the "computed_at" field. + ComputedAt time.Time `json:"computed_at,omitempty"` + // Edges holds the relations/edges for other nodes in the graph. + // The values are being populated by the ChannelMonitorDailyRollupQuery when eager-loading is set. + Edges ChannelMonitorDailyRollupEdges `json:"edges"` + selectValues sql.SelectValues +} + +// ChannelMonitorDailyRollupEdges holds the relations/edges for other nodes in the graph. +type ChannelMonitorDailyRollupEdges struct { + // Monitor holds the value of the monitor edge. + Monitor *ChannelMonitor `json:"monitor,omitempty"` + // loadedTypes holds the information for reporting if a + // type was loaded (or requested) in eager-loading or not. + loadedTypes [1]bool +} + +// MonitorOrErr returns the Monitor value or an error if the edge +// was not loaded in eager-loading, or loaded but was not found. +func (e ChannelMonitorDailyRollupEdges) MonitorOrErr() (*ChannelMonitor, error) { + if e.Monitor != nil { + return e.Monitor, nil + } else if e.loadedTypes[0] { + return nil, &NotFoundError{label: channelmonitor.Label} + } + return nil, &NotLoadedError{edge: "monitor"} +} + +// scanValues returns the types for scanning values from sql.Rows. +func (*ChannelMonitorDailyRollup) scanValues(columns []string) ([]any, error) { + values := make([]any, len(columns)) + for i := range columns { + switch columns[i] { + case channelmonitordailyrollup.FieldID, channelmonitordailyrollup.FieldMonitorID, channelmonitordailyrollup.FieldTotalChecks, channelmonitordailyrollup.FieldOkCount, channelmonitordailyrollup.FieldOperationalCount, channelmonitordailyrollup.FieldDegradedCount, channelmonitordailyrollup.FieldFailedCount, channelmonitordailyrollup.FieldErrorCount, channelmonitordailyrollup.FieldSumLatencyMs, channelmonitordailyrollup.FieldCountLatency, channelmonitordailyrollup.FieldSumPingLatencyMs, channelmonitordailyrollup.FieldCountPingLatency: + values[i] = new(sql.NullInt64) + case channelmonitordailyrollup.FieldModel: + values[i] = new(sql.NullString) + case channelmonitordailyrollup.FieldBucketDate, channelmonitordailyrollup.FieldComputedAt: + values[i] = new(sql.NullTime) + default: + values[i] = new(sql.UnknownType) + } + } + return values, nil +} + +// assignValues assigns the values that were returned from sql.Rows (after scanning) +// to the ChannelMonitorDailyRollup fields. +func (_m *ChannelMonitorDailyRollup) assignValues(columns []string, values []any) error { + if m, n := len(values), len(columns); m < n { + return fmt.Errorf("mismatch number of scan values: %d != %d", m, n) + } + for i := range columns { + switch columns[i] { + case channelmonitordailyrollup.FieldID: + value, ok := values[i].(*sql.NullInt64) + if !ok { + return fmt.Errorf("unexpected type %T for field id", value) + } + _m.ID = int64(value.Int64) + case channelmonitordailyrollup.FieldMonitorID: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field monitor_id", values[i]) + } else if value.Valid { + _m.MonitorID = value.Int64 + } + case channelmonitordailyrollup.FieldModel: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field model", values[i]) + } else if value.Valid { + _m.Model = value.String + } + case channelmonitordailyrollup.FieldBucketDate: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field bucket_date", values[i]) + } else if value.Valid { + _m.BucketDate = value.Time + } + case channelmonitordailyrollup.FieldTotalChecks: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field total_checks", values[i]) + } else if value.Valid { + _m.TotalChecks = int(value.Int64) + } + case channelmonitordailyrollup.FieldOkCount: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field ok_count", values[i]) + } else if value.Valid { + _m.OkCount = int(value.Int64) + } + case channelmonitordailyrollup.FieldOperationalCount: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field operational_count", values[i]) + } else if value.Valid { + _m.OperationalCount = int(value.Int64) + } + case channelmonitordailyrollup.FieldDegradedCount: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field degraded_count", values[i]) + } else if value.Valid { + _m.DegradedCount = int(value.Int64) + } + case channelmonitordailyrollup.FieldFailedCount: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field failed_count", values[i]) + } else if value.Valid { + _m.FailedCount = int(value.Int64) + } + case channelmonitordailyrollup.FieldErrorCount: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field error_count", values[i]) + } else if value.Valid { + _m.ErrorCount = int(value.Int64) + } + case channelmonitordailyrollup.FieldSumLatencyMs: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field sum_latency_ms", values[i]) + } else if value.Valid { + _m.SumLatencyMs = value.Int64 + } + case channelmonitordailyrollup.FieldCountLatency: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field count_latency", values[i]) + } else if value.Valid { + _m.CountLatency = int(value.Int64) + } + case channelmonitordailyrollup.FieldSumPingLatencyMs: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field sum_ping_latency_ms", values[i]) + } else if value.Valid { + _m.SumPingLatencyMs = value.Int64 + } + case channelmonitordailyrollup.FieldCountPingLatency: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field count_ping_latency", values[i]) + } else if value.Valid { + _m.CountPingLatency = int(value.Int64) + } + case channelmonitordailyrollup.FieldComputedAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field computed_at", values[i]) + } else if value.Valid { + _m.ComputedAt = value.Time + } + default: + _m.selectValues.Set(columns[i], values[i]) + } + } + return nil +} + +// Value returns the ent.Value that was dynamically selected and assigned to the ChannelMonitorDailyRollup. +// This includes values selected through modifiers, order, etc. +func (_m *ChannelMonitorDailyRollup) Value(name string) (ent.Value, error) { + return _m.selectValues.Get(name) +} + +// QueryMonitor queries the "monitor" edge of the ChannelMonitorDailyRollup entity. +func (_m *ChannelMonitorDailyRollup) QueryMonitor() *ChannelMonitorQuery { + return NewChannelMonitorDailyRollupClient(_m.config).QueryMonitor(_m) +} + +// Update returns a builder for updating this ChannelMonitorDailyRollup. +// Note that you need to call ChannelMonitorDailyRollup.Unwrap() before calling this method if this ChannelMonitorDailyRollup +// was returned from a transaction, and the transaction was committed or rolled back. +func (_m *ChannelMonitorDailyRollup) Update() *ChannelMonitorDailyRollupUpdateOne { + return NewChannelMonitorDailyRollupClient(_m.config).UpdateOne(_m) +} + +// Unwrap unwraps the ChannelMonitorDailyRollup entity that was returned from a transaction after it was closed, +// so that all future queries will be executed through the driver which created the transaction. +func (_m *ChannelMonitorDailyRollup) Unwrap() *ChannelMonitorDailyRollup { + _tx, ok := _m.config.driver.(*txDriver) + if !ok { + panic("ent: ChannelMonitorDailyRollup is not a transactional entity") + } + _m.config.driver = _tx.drv + return _m +} + +// String implements the fmt.Stringer. +func (_m *ChannelMonitorDailyRollup) String() string { + var builder strings.Builder + builder.WriteString("ChannelMonitorDailyRollup(") + builder.WriteString(fmt.Sprintf("id=%v, ", _m.ID)) + builder.WriteString("monitor_id=") + builder.WriteString(fmt.Sprintf("%v", _m.MonitorID)) + builder.WriteString(", ") + builder.WriteString("model=") + builder.WriteString(_m.Model) + builder.WriteString(", ") + builder.WriteString("bucket_date=") + builder.WriteString(_m.BucketDate.Format(time.ANSIC)) + builder.WriteString(", ") + builder.WriteString("total_checks=") + builder.WriteString(fmt.Sprintf("%v", _m.TotalChecks)) + builder.WriteString(", ") + builder.WriteString("ok_count=") + builder.WriteString(fmt.Sprintf("%v", _m.OkCount)) + builder.WriteString(", ") + builder.WriteString("operational_count=") + builder.WriteString(fmt.Sprintf("%v", _m.OperationalCount)) + builder.WriteString(", ") + builder.WriteString("degraded_count=") + builder.WriteString(fmt.Sprintf("%v", _m.DegradedCount)) + builder.WriteString(", ") + builder.WriteString("failed_count=") + builder.WriteString(fmt.Sprintf("%v", _m.FailedCount)) + builder.WriteString(", ") + builder.WriteString("error_count=") + builder.WriteString(fmt.Sprintf("%v", _m.ErrorCount)) + builder.WriteString(", ") + builder.WriteString("sum_latency_ms=") + builder.WriteString(fmt.Sprintf("%v", _m.SumLatencyMs)) + builder.WriteString(", ") + builder.WriteString("count_latency=") + builder.WriteString(fmt.Sprintf("%v", _m.CountLatency)) + builder.WriteString(", ") + builder.WriteString("sum_ping_latency_ms=") + builder.WriteString(fmt.Sprintf("%v", _m.SumPingLatencyMs)) + builder.WriteString(", ") + builder.WriteString("count_ping_latency=") + builder.WriteString(fmt.Sprintf("%v", _m.CountPingLatency)) + builder.WriteString(", ") + builder.WriteString("computed_at=") + builder.WriteString(_m.ComputedAt.Format(time.ANSIC)) + builder.WriteByte(')') + return builder.String() +} + +// ChannelMonitorDailyRollups is a parsable slice of ChannelMonitorDailyRollup. +type ChannelMonitorDailyRollups []*ChannelMonitorDailyRollup diff --git a/backend/ent/channelmonitordailyrollup/channelmonitordailyrollup.go b/backend/ent/channelmonitordailyrollup/channelmonitordailyrollup.go new file mode 100644 index 00000000..e7cb9307 --- /dev/null +++ b/backend/ent/channelmonitordailyrollup/channelmonitordailyrollup.go @@ -0,0 +1,206 @@ +// Code generated by ent, DO NOT EDIT. + +package channelmonitordailyrollup + +import ( + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" +) + +const ( + // Label holds the string label denoting the channelmonitordailyrollup type in the database. + Label = "channel_monitor_daily_rollup" + // FieldID holds the string denoting the id field in the database. + FieldID = "id" + // FieldMonitorID holds the string denoting the monitor_id field in the database. + FieldMonitorID = "monitor_id" + // FieldModel holds the string denoting the model field in the database. + FieldModel = "model" + // FieldBucketDate holds the string denoting the bucket_date field in the database. + FieldBucketDate = "bucket_date" + // FieldTotalChecks holds the string denoting the total_checks field in the database. + FieldTotalChecks = "total_checks" + // FieldOkCount holds the string denoting the ok_count field in the database. + FieldOkCount = "ok_count" + // FieldOperationalCount holds the string denoting the operational_count field in the database. + FieldOperationalCount = "operational_count" + // FieldDegradedCount holds the string denoting the degraded_count field in the database. + FieldDegradedCount = "degraded_count" + // FieldFailedCount holds the string denoting the failed_count field in the database. + FieldFailedCount = "failed_count" + // FieldErrorCount holds the string denoting the error_count field in the database. + FieldErrorCount = "error_count" + // FieldSumLatencyMs holds the string denoting the sum_latency_ms field in the database. + FieldSumLatencyMs = "sum_latency_ms" + // FieldCountLatency holds the string denoting the count_latency field in the database. + FieldCountLatency = "count_latency" + // FieldSumPingLatencyMs holds the string denoting the sum_ping_latency_ms field in the database. + FieldSumPingLatencyMs = "sum_ping_latency_ms" + // FieldCountPingLatency holds the string denoting the count_ping_latency field in the database. + FieldCountPingLatency = "count_ping_latency" + // FieldComputedAt holds the string denoting the computed_at field in the database. + FieldComputedAt = "computed_at" + // EdgeMonitor holds the string denoting the monitor edge name in mutations. + EdgeMonitor = "monitor" + // Table holds the table name of the channelmonitordailyrollup in the database. + Table = "channel_monitor_daily_rollups" + // MonitorTable is the table that holds the monitor relation/edge. + MonitorTable = "channel_monitor_daily_rollups" + // MonitorInverseTable is the table name for the ChannelMonitor entity. + // It exists in this package in order to avoid circular dependency with the "channelmonitor" package. + MonitorInverseTable = "channel_monitors" + // MonitorColumn is the table column denoting the monitor relation/edge. + MonitorColumn = "monitor_id" +) + +// Columns holds all SQL columns for channelmonitordailyrollup fields. +var Columns = []string{ + FieldID, + FieldMonitorID, + FieldModel, + FieldBucketDate, + FieldTotalChecks, + FieldOkCount, + FieldOperationalCount, + FieldDegradedCount, + FieldFailedCount, + FieldErrorCount, + FieldSumLatencyMs, + FieldCountLatency, + FieldSumPingLatencyMs, + FieldCountPingLatency, + FieldComputedAt, +} + +// ValidColumn reports if the column name is valid (part of the table columns). +func ValidColumn(column string) bool { + for i := range Columns { + if column == Columns[i] { + return true + } + } + return false +} + +var ( + // ModelValidator is a validator for the "model" field. It is called by the builders before save. + ModelValidator func(string) error + // DefaultTotalChecks holds the default value on creation for the "total_checks" field. + DefaultTotalChecks int + // DefaultOkCount holds the default value on creation for the "ok_count" field. + DefaultOkCount int + // DefaultOperationalCount holds the default value on creation for the "operational_count" field. + DefaultOperationalCount int + // DefaultDegradedCount holds the default value on creation for the "degraded_count" field. + DefaultDegradedCount int + // DefaultFailedCount holds the default value on creation for the "failed_count" field. + DefaultFailedCount int + // DefaultErrorCount holds the default value on creation for the "error_count" field. + DefaultErrorCount int + // DefaultSumLatencyMs holds the default value on creation for the "sum_latency_ms" field. + DefaultSumLatencyMs int64 + // DefaultCountLatency holds the default value on creation for the "count_latency" field. + DefaultCountLatency int + // DefaultSumPingLatencyMs holds the default value on creation for the "sum_ping_latency_ms" field. + DefaultSumPingLatencyMs int64 + // DefaultCountPingLatency holds the default value on creation for the "count_ping_latency" field. + DefaultCountPingLatency int + // DefaultComputedAt holds the default value on creation for the "computed_at" field. + DefaultComputedAt func() time.Time + // UpdateDefaultComputedAt holds the default value on update for the "computed_at" field. + UpdateDefaultComputedAt func() time.Time +) + +// OrderOption defines the ordering options for the ChannelMonitorDailyRollup queries. +type OrderOption func(*sql.Selector) + +// ByID orders the results by the id field. +func ByID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldID, opts...).ToFunc() +} + +// ByMonitorID orders the results by the monitor_id field. +func ByMonitorID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldMonitorID, opts...).ToFunc() +} + +// ByModel orders the results by the model field. +func ByModel(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldModel, opts...).ToFunc() +} + +// ByBucketDate orders the results by the bucket_date field. +func ByBucketDate(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldBucketDate, opts...).ToFunc() +} + +// ByTotalChecks orders the results by the total_checks field. +func ByTotalChecks(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldTotalChecks, opts...).ToFunc() +} + +// ByOkCount orders the results by the ok_count field. +func ByOkCount(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldOkCount, opts...).ToFunc() +} + +// ByOperationalCount orders the results by the operational_count field. +func ByOperationalCount(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldOperationalCount, opts...).ToFunc() +} + +// ByDegradedCount orders the results by the degraded_count field. +func ByDegradedCount(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldDegradedCount, opts...).ToFunc() +} + +// ByFailedCount orders the results by the failed_count field. +func ByFailedCount(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldFailedCount, opts...).ToFunc() +} + +// ByErrorCount orders the results by the error_count field. +func ByErrorCount(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldErrorCount, opts...).ToFunc() +} + +// BySumLatencyMs orders the results by the sum_latency_ms field. +func BySumLatencyMs(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldSumLatencyMs, opts...).ToFunc() +} + +// ByCountLatency orders the results by the count_latency field. +func ByCountLatency(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldCountLatency, opts...).ToFunc() +} + +// BySumPingLatencyMs orders the results by the sum_ping_latency_ms field. +func BySumPingLatencyMs(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldSumPingLatencyMs, opts...).ToFunc() +} + +// ByCountPingLatency orders the results by the count_ping_latency field. +func ByCountPingLatency(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldCountPingLatency, opts...).ToFunc() +} + +// ByComputedAt orders the results by the computed_at field. +func ByComputedAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldComputedAt, opts...).ToFunc() +} + +// ByMonitorField orders the results by monitor field. +func ByMonitorField(field string, opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newMonitorStep(), sql.OrderByField(field, opts...)) + } +} +func newMonitorStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(MonitorInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, MonitorTable, MonitorColumn), + ) +} diff --git a/backend/ent/channelmonitordailyrollup/where.go b/backend/ent/channelmonitordailyrollup/where.go new file mode 100644 index 00000000..424c957e --- /dev/null +++ b/backend/ent/channelmonitordailyrollup/where.go @@ -0,0 +1,729 @@ +// Code generated by ent, DO NOT EDIT. + +package channelmonitordailyrollup + +import ( + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// ID filters vertices based on their ID field. +func ID(id int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldID, id)) +} + +// IDEQ applies the EQ predicate on the ID field. +func IDEQ(id int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldID, id)) +} + +// IDNEQ applies the NEQ predicate on the ID field. +func IDNEQ(id int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNEQ(FieldID, id)) +} + +// IDIn applies the In predicate on the ID field. +func IDIn(ids ...int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldIn(FieldID, ids...)) +} + +// IDNotIn applies the NotIn predicate on the ID field. +func IDNotIn(ids ...int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNotIn(FieldID, ids...)) +} + +// IDGT applies the GT predicate on the ID field. +func IDGT(id int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGT(FieldID, id)) +} + +// IDGTE applies the GTE predicate on the ID field. +func IDGTE(id int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGTE(FieldID, id)) +} + +// IDLT applies the LT predicate on the ID field. +func IDLT(id int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLT(FieldID, id)) +} + +// IDLTE applies the LTE predicate on the ID field. +func IDLTE(id int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLTE(FieldID, id)) +} + +// MonitorID applies equality check predicate on the "monitor_id" field. It's identical to MonitorIDEQ. +func MonitorID(v int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldMonitorID, v)) +} + +// Model applies equality check predicate on the "model" field. It's identical to ModelEQ. +func Model(v string) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldModel, v)) +} + +// BucketDate applies equality check predicate on the "bucket_date" field. It's identical to BucketDateEQ. +func BucketDate(v time.Time) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldBucketDate, v)) +} + +// TotalChecks applies equality check predicate on the "total_checks" field. It's identical to TotalChecksEQ. +func TotalChecks(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldTotalChecks, v)) +} + +// OkCount applies equality check predicate on the "ok_count" field. It's identical to OkCountEQ. +func OkCount(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldOkCount, v)) +} + +// OperationalCount applies equality check predicate on the "operational_count" field. It's identical to OperationalCountEQ. +func OperationalCount(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldOperationalCount, v)) +} + +// DegradedCount applies equality check predicate on the "degraded_count" field. It's identical to DegradedCountEQ. +func DegradedCount(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldDegradedCount, v)) +} + +// FailedCount applies equality check predicate on the "failed_count" field. It's identical to FailedCountEQ. +func FailedCount(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldFailedCount, v)) +} + +// ErrorCount applies equality check predicate on the "error_count" field. It's identical to ErrorCountEQ. +func ErrorCount(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldErrorCount, v)) +} + +// SumLatencyMs applies equality check predicate on the "sum_latency_ms" field. It's identical to SumLatencyMsEQ. +func SumLatencyMs(v int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldSumLatencyMs, v)) +} + +// CountLatency applies equality check predicate on the "count_latency" field. It's identical to CountLatencyEQ. +func CountLatency(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldCountLatency, v)) +} + +// SumPingLatencyMs applies equality check predicate on the "sum_ping_latency_ms" field. It's identical to SumPingLatencyMsEQ. +func SumPingLatencyMs(v int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldSumPingLatencyMs, v)) +} + +// CountPingLatency applies equality check predicate on the "count_ping_latency" field. It's identical to CountPingLatencyEQ. +func CountPingLatency(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldCountPingLatency, v)) +} + +// ComputedAt applies equality check predicate on the "computed_at" field. It's identical to ComputedAtEQ. +func ComputedAt(v time.Time) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldComputedAt, v)) +} + +// MonitorIDEQ applies the EQ predicate on the "monitor_id" field. +func MonitorIDEQ(v int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldMonitorID, v)) +} + +// MonitorIDNEQ applies the NEQ predicate on the "monitor_id" field. +func MonitorIDNEQ(v int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNEQ(FieldMonitorID, v)) +} + +// MonitorIDIn applies the In predicate on the "monitor_id" field. +func MonitorIDIn(vs ...int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldIn(FieldMonitorID, vs...)) +} + +// MonitorIDNotIn applies the NotIn predicate on the "monitor_id" field. +func MonitorIDNotIn(vs ...int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNotIn(FieldMonitorID, vs...)) +} + +// ModelEQ applies the EQ predicate on the "model" field. +func ModelEQ(v string) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldModel, v)) +} + +// ModelNEQ applies the NEQ predicate on the "model" field. +func ModelNEQ(v string) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNEQ(FieldModel, v)) +} + +// ModelIn applies the In predicate on the "model" field. +func ModelIn(vs ...string) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldIn(FieldModel, vs...)) +} + +// ModelNotIn applies the NotIn predicate on the "model" field. +func ModelNotIn(vs ...string) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNotIn(FieldModel, vs...)) +} + +// ModelGT applies the GT predicate on the "model" field. +func ModelGT(v string) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGT(FieldModel, v)) +} + +// ModelGTE applies the GTE predicate on the "model" field. +func ModelGTE(v string) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGTE(FieldModel, v)) +} + +// ModelLT applies the LT predicate on the "model" field. +func ModelLT(v string) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLT(FieldModel, v)) +} + +// ModelLTE applies the LTE predicate on the "model" field. +func ModelLTE(v string) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLTE(FieldModel, v)) +} + +// ModelContains applies the Contains predicate on the "model" field. +func ModelContains(v string) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldContains(FieldModel, v)) +} + +// ModelHasPrefix applies the HasPrefix predicate on the "model" field. +func ModelHasPrefix(v string) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldHasPrefix(FieldModel, v)) +} + +// ModelHasSuffix applies the HasSuffix predicate on the "model" field. +func ModelHasSuffix(v string) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldHasSuffix(FieldModel, v)) +} + +// ModelEqualFold applies the EqualFold predicate on the "model" field. +func ModelEqualFold(v string) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEqualFold(FieldModel, v)) +} + +// ModelContainsFold applies the ContainsFold predicate on the "model" field. +func ModelContainsFold(v string) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldContainsFold(FieldModel, v)) +} + +// BucketDateEQ applies the EQ predicate on the "bucket_date" field. +func BucketDateEQ(v time.Time) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldBucketDate, v)) +} + +// BucketDateNEQ applies the NEQ predicate on the "bucket_date" field. +func BucketDateNEQ(v time.Time) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNEQ(FieldBucketDate, v)) +} + +// BucketDateIn applies the In predicate on the "bucket_date" field. +func BucketDateIn(vs ...time.Time) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldIn(FieldBucketDate, vs...)) +} + +// BucketDateNotIn applies the NotIn predicate on the "bucket_date" field. +func BucketDateNotIn(vs ...time.Time) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNotIn(FieldBucketDate, vs...)) +} + +// BucketDateGT applies the GT predicate on the "bucket_date" field. +func BucketDateGT(v time.Time) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGT(FieldBucketDate, v)) +} + +// BucketDateGTE applies the GTE predicate on the "bucket_date" field. +func BucketDateGTE(v time.Time) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGTE(FieldBucketDate, v)) +} + +// BucketDateLT applies the LT predicate on the "bucket_date" field. +func BucketDateLT(v time.Time) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLT(FieldBucketDate, v)) +} + +// BucketDateLTE applies the LTE predicate on the "bucket_date" field. +func BucketDateLTE(v time.Time) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLTE(FieldBucketDate, v)) +} + +// TotalChecksEQ applies the EQ predicate on the "total_checks" field. +func TotalChecksEQ(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldTotalChecks, v)) +} + +// TotalChecksNEQ applies the NEQ predicate on the "total_checks" field. +func TotalChecksNEQ(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNEQ(FieldTotalChecks, v)) +} + +// TotalChecksIn applies the In predicate on the "total_checks" field. +func TotalChecksIn(vs ...int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldIn(FieldTotalChecks, vs...)) +} + +// TotalChecksNotIn applies the NotIn predicate on the "total_checks" field. +func TotalChecksNotIn(vs ...int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNotIn(FieldTotalChecks, vs...)) +} + +// TotalChecksGT applies the GT predicate on the "total_checks" field. +func TotalChecksGT(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGT(FieldTotalChecks, v)) +} + +// TotalChecksGTE applies the GTE predicate on the "total_checks" field. +func TotalChecksGTE(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGTE(FieldTotalChecks, v)) +} + +// TotalChecksLT applies the LT predicate on the "total_checks" field. +func TotalChecksLT(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLT(FieldTotalChecks, v)) +} + +// TotalChecksLTE applies the LTE predicate on the "total_checks" field. +func TotalChecksLTE(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLTE(FieldTotalChecks, v)) +} + +// OkCountEQ applies the EQ predicate on the "ok_count" field. +func OkCountEQ(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldOkCount, v)) +} + +// OkCountNEQ applies the NEQ predicate on the "ok_count" field. +func OkCountNEQ(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNEQ(FieldOkCount, v)) +} + +// OkCountIn applies the In predicate on the "ok_count" field. +func OkCountIn(vs ...int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldIn(FieldOkCount, vs...)) +} + +// OkCountNotIn applies the NotIn predicate on the "ok_count" field. +func OkCountNotIn(vs ...int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNotIn(FieldOkCount, vs...)) +} + +// OkCountGT applies the GT predicate on the "ok_count" field. +func OkCountGT(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGT(FieldOkCount, v)) +} + +// OkCountGTE applies the GTE predicate on the "ok_count" field. +func OkCountGTE(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGTE(FieldOkCount, v)) +} + +// OkCountLT applies the LT predicate on the "ok_count" field. +func OkCountLT(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLT(FieldOkCount, v)) +} + +// OkCountLTE applies the LTE predicate on the "ok_count" field. +func OkCountLTE(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLTE(FieldOkCount, v)) +} + +// OperationalCountEQ applies the EQ predicate on the "operational_count" field. +func OperationalCountEQ(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldOperationalCount, v)) +} + +// OperationalCountNEQ applies the NEQ predicate on the "operational_count" field. +func OperationalCountNEQ(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNEQ(FieldOperationalCount, v)) +} + +// OperationalCountIn applies the In predicate on the "operational_count" field. +func OperationalCountIn(vs ...int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldIn(FieldOperationalCount, vs...)) +} + +// OperationalCountNotIn applies the NotIn predicate on the "operational_count" field. +func OperationalCountNotIn(vs ...int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNotIn(FieldOperationalCount, vs...)) +} + +// OperationalCountGT applies the GT predicate on the "operational_count" field. +func OperationalCountGT(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGT(FieldOperationalCount, v)) +} + +// OperationalCountGTE applies the GTE predicate on the "operational_count" field. +func OperationalCountGTE(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGTE(FieldOperationalCount, v)) +} + +// OperationalCountLT applies the LT predicate on the "operational_count" field. +func OperationalCountLT(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLT(FieldOperationalCount, v)) +} + +// OperationalCountLTE applies the LTE predicate on the "operational_count" field. +func OperationalCountLTE(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLTE(FieldOperationalCount, v)) +} + +// DegradedCountEQ applies the EQ predicate on the "degraded_count" field. +func DegradedCountEQ(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldDegradedCount, v)) +} + +// DegradedCountNEQ applies the NEQ predicate on the "degraded_count" field. +func DegradedCountNEQ(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNEQ(FieldDegradedCount, v)) +} + +// DegradedCountIn applies the In predicate on the "degraded_count" field. +func DegradedCountIn(vs ...int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldIn(FieldDegradedCount, vs...)) +} + +// DegradedCountNotIn applies the NotIn predicate on the "degraded_count" field. +func DegradedCountNotIn(vs ...int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNotIn(FieldDegradedCount, vs...)) +} + +// DegradedCountGT applies the GT predicate on the "degraded_count" field. +func DegradedCountGT(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGT(FieldDegradedCount, v)) +} + +// DegradedCountGTE applies the GTE predicate on the "degraded_count" field. +func DegradedCountGTE(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGTE(FieldDegradedCount, v)) +} + +// DegradedCountLT applies the LT predicate on the "degraded_count" field. +func DegradedCountLT(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLT(FieldDegradedCount, v)) +} + +// DegradedCountLTE applies the LTE predicate on the "degraded_count" field. +func DegradedCountLTE(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLTE(FieldDegradedCount, v)) +} + +// FailedCountEQ applies the EQ predicate on the "failed_count" field. +func FailedCountEQ(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldFailedCount, v)) +} + +// FailedCountNEQ applies the NEQ predicate on the "failed_count" field. +func FailedCountNEQ(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNEQ(FieldFailedCount, v)) +} + +// FailedCountIn applies the In predicate on the "failed_count" field. +func FailedCountIn(vs ...int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldIn(FieldFailedCount, vs...)) +} + +// FailedCountNotIn applies the NotIn predicate on the "failed_count" field. +func FailedCountNotIn(vs ...int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNotIn(FieldFailedCount, vs...)) +} + +// FailedCountGT applies the GT predicate on the "failed_count" field. +func FailedCountGT(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGT(FieldFailedCount, v)) +} + +// FailedCountGTE applies the GTE predicate on the "failed_count" field. +func FailedCountGTE(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGTE(FieldFailedCount, v)) +} + +// FailedCountLT applies the LT predicate on the "failed_count" field. +func FailedCountLT(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLT(FieldFailedCount, v)) +} + +// FailedCountLTE applies the LTE predicate on the "failed_count" field. +func FailedCountLTE(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLTE(FieldFailedCount, v)) +} + +// ErrorCountEQ applies the EQ predicate on the "error_count" field. +func ErrorCountEQ(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldErrorCount, v)) +} + +// ErrorCountNEQ applies the NEQ predicate on the "error_count" field. +func ErrorCountNEQ(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNEQ(FieldErrorCount, v)) +} + +// ErrorCountIn applies the In predicate on the "error_count" field. +func ErrorCountIn(vs ...int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldIn(FieldErrorCount, vs...)) +} + +// ErrorCountNotIn applies the NotIn predicate on the "error_count" field. +func ErrorCountNotIn(vs ...int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNotIn(FieldErrorCount, vs...)) +} + +// ErrorCountGT applies the GT predicate on the "error_count" field. +func ErrorCountGT(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGT(FieldErrorCount, v)) +} + +// ErrorCountGTE applies the GTE predicate on the "error_count" field. +func ErrorCountGTE(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGTE(FieldErrorCount, v)) +} + +// ErrorCountLT applies the LT predicate on the "error_count" field. +func ErrorCountLT(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLT(FieldErrorCount, v)) +} + +// ErrorCountLTE applies the LTE predicate on the "error_count" field. +func ErrorCountLTE(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLTE(FieldErrorCount, v)) +} + +// SumLatencyMsEQ applies the EQ predicate on the "sum_latency_ms" field. +func SumLatencyMsEQ(v int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldSumLatencyMs, v)) +} + +// SumLatencyMsNEQ applies the NEQ predicate on the "sum_latency_ms" field. +func SumLatencyMsNEQ(v int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNEQ(FieldSumLatencyMs, v)) +} + +// SumLatencyMsIn applies the In predicate on the "sum_latency_ms" field. +func SumLatencyMsIn(vs ...int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldIn(FieldSumLatencyMs, vs...)) +} + +// SumLatencyMsNotIn applies the NotIn predicate on the "sum_latency_ms" field. +func SumLatencyMsNotIn(vs ...int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNotIn(FieldSumLatencyMs, vs...)) +} + +// SumLatencyMsGT applies the GT predicate on the "sum_latency_ms" field. +func SumLatencyMsGT(v int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGT(FieldSumLatencyMs, v)) +} + +// SumLatencyMsGTE applies the GTE predicate on the "sum_latency_ms" field. +func SumLatencyMsGTE(v int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGTE(FieldSumLatencyMs, v)) +} + +// SumLatencyMsLT applies the LT predicate on the "sum_latency_ms" field. +func SumLatencyMsLT(v int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLT(FieldSumLatencyMs, v)) +} + +// SumLatencyMsLTE applies the LTE predicate on the "sum_latency_ms" field. +func SumLatencyMsLTE(v int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLTE(FieldSumLatencyMs, v)) +} + +// CountLatencyEQ applies the EQ predicate on the "count_latency" field. +func CountLatencyEQ(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldCountLatency, v)) +} + +// CountLatencyNEQ applies the NEQ predicate on the "count_latency" field. +func CountLatencyNEQ(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNEQ(FieldCountLatency, v)) +} + +// CountLatencyIn applies the In predicate on the "count_latency" field. +func CountLatencyIn(vs ...int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldIn(FieldCountLatency, vs...)) +} + +// CountLatencyNotIn applies the NotIn predicate on the "count_latency" field. +func CountLatencyNotIn(vs ...int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNotIn(FieldCountLatency, vs...)) +} + +// CountLatencyGT applies the GT predicate on the "count_latency" field. +func CountLatencyGT(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGT(FieldCountLatency, v)) +} + +// CountLatencyGTE applies the GTE predicate on the "count_latency" field. +func CountLatencyGTE(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGTE(FieldCountLatency, v)) +} + +// CountLatencyLT applies the LT predicate on the "count_latency" field. +func CountLatencyLT(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLT(FieldCountLatency, v)) +} + +// CountLatencyLTE applies the LTE predicate on the "count_latency" field. +func CountLatencyLTE(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLTE(FieldCountLatency, v)) +} + +// SumPingLatencyMsEQ applies the EQ predicate on the "sum_ping_latency_ms" field. +func SumPingLatencyMsEQ(v int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldSumPingLatencyMs, v)) +} + +// SumPingLatencyMsNEQ applies the NEQ predicate on the "sum_ping_latency_ms" field. +func SumPingLatencyMsNEQ(v int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNEQ(FieldSumPingLatencyMs, v)) +} + +// SumPingLatencyMsIn applies the In predicate on the "sum_ping_latency_ms" field. +func SumPingLatencyMsIn(vs ...int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldIn(FieldSumPingLatencyMs, vs...)) +} + +// SumPingLatencyMsNotIn applies the NotIn predicate on the "sum_ping_latency_ms" field. +func SumPingLatencyMsNotIn(vs ...int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNotIn(FieldSumPingLatencyMs, vs...)) +} + +// SumPingLatencyMsGT applies the GT predicate on the "sum_ping_latency_ms" field. +func SumPingLatencyMsGT(v int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGT(FieldSumPingLatencyMs, v)) +} + +// SumPingLatencyMsGTE applies the GTE predicate on the "sum_ping_latency_ms" field. +func SumPingLatencyMsGTE(v int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGTE(FieldSumPingLatencyMs, v)) +} + +// SumPingLatencyMsLT applies the LT predicate on the "sum_ping_latency_ms" field. +func SumPingLatencyMsLT(v int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLT(FieldSumPingLatencyMs, v)) +} + +// SumPingLatencyMsLTE applies the LTE predicate on the "sum_ping_latency_ms" field. +func SumPingLatencyMsLTE(v int64) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLTE(FieldSumPingLatencyMs, v)) +} + +// CountPingLatencyEQ applies the EQ predicate on the "count_ping_latency" field. +func CountPingLatencyEQ(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldCountPingLatency, v)) +} + +// CountPingLatencyNEQ applies the NEQ predicate on the "count_ping_latency" field. +func CountPingLatencyNEQ(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNEQ(FieldCountPingLatency, v)) +} + +// CountPingLatencyIn applies the In predicate on the "count_ping_latency" field. +func CountPingLatencyIn(vs ...int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldIn(FieldCountPingLatency, vs...)) +} + +// CountPingLatencyNotIn applies the NotIn predicate on the "count_ping_latency" field. +func CountPingLatencyNotIn(vs ...int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNotIn(FieldCountPingLatency, vs...)) +} + +// CountPingLatencyGT applies the GT predicate on the "count_ping_latency" field. +func CountPingLatencyGT(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGT(FieldCountPingLatency, v)) +} + +// CountPingLatencyGTE applies the GTE predicate on the "count_ping_latency" field. +func CountPingLatencyGTE(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGTE(FieldCountPingLatency, v)) +} + +// CountPingLatencyLT applies the LT predicate on the "count_ping_latency" field. +func CountPingLatencyLT(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLT(FieldCountPingLatency, v)) +} + +// CountPingLatencyLTE applies the LTE predicate on the "count_ping_latency" field. +func CountPingLatencyLTE(v int) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLTE(FieldCountPingLatency, v)) +} + +// ComputedAtEQ applies the EQ predicate on the "computed_at" field. +func ComputedAtEQ(v time.Time) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldEQ(FieldComputedAt, v)) +} + +// ComputedAtNEQ applies the NEQ predicate on the "computed_at" field. +func ComputedAtNEQ(v time.Time) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNEQ(FieldComputedAt, v)) +} + +// ComputedAtIn applies the In predicate on the "computed_at" field. +func ComputedAtIn(vs ...time.Time) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldIn(FieldComputedAt, vs...)) +} + +// ComputedAtNotIn applies the NotIn predicate on the "computed_at" field. +func ComputedAtNotIn(vs ...time.Time) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldNotIn(FieldComputedAt, vs...)) +} + +// ComputedAtGT applies the GT predicate on the "computed_at" field. +func ComputedAtGT(v time.Time) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGT(FieldComputedAt, v)) +} + +// ComputedAtGTE applies the GTE predicate on the "computed_at" field. +func ComputedAtGTE(v time.Time) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldGTE(FieldComputedAt, v)) +} + +// ComputedAtLT applies the LT predicate on the "computed_at" field. +func ComputedAtLT(v time.Time) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLT(FieldComputedAt, v)) +} + +// ComputedAtLTE applies the LTE predicate on the "computed_at" field. +func ComputedAtLTE(v time.Time) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.FieldLTE(FieldComputedAt, v)) +} + +// HasMonitor applies the HasEdge predicate on the "monitor" edge. +func HasMonitor() predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, MonitorTable, MonitorColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasMonitorWith applies the HasEdge predicate on the "monitor" edge with a given conditions (other predicates). +func HasMonitorWith(preds ...predicate.ChannelMonitor) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(func(s *sql.Selector) { + step := newMonitorStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + +// And groups predicates with the AND operator between them. +func And(predicates ...predicate.ChannelMonitorDailyRollup) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.AndPredicates(predicates...)) +} + +// Or groups predicates with the OR operator between them. +func Or(predicates ...predicate.ChannelMonitorDailyRollup) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.OrPredicates(predicates...)) +} + +// Not applies the not operator on the given predicate. +func Not(p predicate.ChannelMonitorDailyRollup) predicate.ChannelMonitorDailyRollup { + return predicate.ChannelMonitorDailyRollup(sql.NotPredicates(p)) +} diff --git a/backend/ent/channelmonitordailyrollup_create.go b/backend/ent/channelmonitordailyrollup_create.go new file mode 100644 index 00000000..5f8754ba --- /dev/null +++ b/backend/ent/channelmonitordailyrollup_create.go @@ -0,0 +1,1509 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitordailyrollup" +) + +// ChannelMonitorDailyRollupCreate is the builder for creating a ChannelMonitorDailyRollup entity. +type ChannelMonitorDailyRollupCreate struct { + config + mutation *ChannelMonitorDailyRollupMutation + hooks []Hook + conflict []sql.ConflictOption +} + +// SetMonitorID sets the "monitor_id" field. +func (_c *ChannelMonitorDailyRollupCreate) SetMonitorID(v int64) *ChannelMonitorDailyRollupCreate { + _c.mutation.SetMonitorID(v) + return _c +} + +// SetModel sets the "model" field. +func (_c *ChannelMonitorDailyRollupCreate) SetModel(v string) *ChannelMonitorDailyRollupCreate { + _c.mutation.SetModel(v) + return _c +} + +// SetBucketDate sets the "bucket_date" field. +func (_c *ChannelMonitorDailyRollupCreate) SetBucketDate(v time.Time) *ChannelMonitorDailyRollupCreate { + _c.mutation.SetBucketDate(v) + return _c +} + +// SetTotalChecks sets the "total_checks" field. +func (_c *ChannelMonitorDailyRollupCreate) SetTotalChecks(v int) *ChannelMonitorDailyRollupCreate { + _c.mutation.SetTotalChecks(v) + return _c +} + +// SetNillableTotalChecks sets the "total_checks" field if the given value is not nil. +func (_c *ChannelMonitorDailyRollupCreate) SetNillableTotalChecks(v *int) *ChannelMonitorDailyRollupCreate { + if v != nil { + _c.SetTotalChecks(*v) + } + return _c +} + +// SetOkCount sets the "ok_count" field. +func (_c *ChannelMonitorDailyRollupCreate) SetOkCount(v int) *ChannelMonitorDailyRollupCreate { + _c.mutation.SetOkCount(v) + return _c +} + +// SetNillableOkCount sets the "ok_count" field if the given value is not nil. +func (_c *ChannelMonitorDailyRollupCreate) SetNillableOkCount(v *int) *ChannelMonitorDailyRollupCreate { + if v != nil { + _c.SetOkCount(*v) + } + return _c +} + +// SetOperationalCount sets the "operational_count" field. +func (_c *ChannelMonitorDailyRollupCreate) SetOperationalCount(v int) *ChannelMonitorDailyRollupCreate { + _c.mutation.SetOperationalCount(v) + return _c +} + +// SetNillableOperationalCount sets the "operational_count" field if the given value is not nil. +func (_c *ChannelMonitorDailyRollupCreate) SetNillableOperationalCount(v *int) *ChannelMonitorDailyRollupCreate { + if v != nil { + _c.SetOperationalCount(*v) + } + return _c +} + +// SetDegradedCount sets the "degraded_count" field. +func (_c *ChannelMonitorDailyRollupCreate) SetDegradedCount(v int) *ChannelMonitorDailyRollupCreate { + _c.mutation.SetDegradedCount(v) + return _c +} + +// SetNillableDegradedCount sets the "degraded_count" field if the given value is not nil. +func (_c *ChannelMonitorDailyRollupCreate) SetNillableDegradedCount(v *int) *ChannelMonitorDailyRollupCreate { + if v != nil { + _c.SetDegradedCount(*v) + } + return _c +} + +// SetFailedCount sets the "failed_count" field. +func (_c *ChannelMonitorDailyRollupCreate) SetFailedCount(v int) *ChannelMonitorDailyRollupCreate { + _c.mutation.SetFailedCount(v) + return _c +} + +// SetNillableFailedCount sets the "failed_count" field if the given value is not nil. +func (_c *ChannelMonitorDailyRollupCreate) SetNillableFailedCount(v *int) *ChannelMonitorDailyRollupCreate { + if v != nil { + _c.SetFailedCount(*v) + } + return _c +} + +// SetErrorCount sets the "error_count" field. +func (_c *ChannelMonitorDailyRollupCreate) SetErrorCount(v int) *ChannelMonitorDailyRollupCreate { + _c.mutation.SetErrorCount(v) + return _c +} + +// SetNillableErrorCount sets the "error_count" field if the given value is not nil. +func (_c *ChannelMonitorDailyRollupCreate) SetNillableErrorCount(v *int) *ChannelMonitorDailyRollupCreate { + if v != nil { + _c.SetErrorCount(*v) + } + return _c +} + +// SetSumLatencyMs sets the "sum_latency_ms" field. +func (_c *ChannelMonitorDailyRollupCreate) SetSumLatencyMs(v int64) *ChannelMonitorDailyRollupCreate { + _c.mutation.SetSumLatencyMs(v) + return _c +} + +// SetNillableSumLatencyMs sets the "sum_latency_ms" field if the given value is not nil. +func (_c *ChannelMonitorDailyRollupCreate) SetNillableSumLatencyMs(v *int64) *ChannelMonitorDailyRollupCreate { + if v != nil { + _c.SetSumLatencyMs(*v) + } + return _c +} + +// SetCountLatency sets the "count_latency" field. +func (_c *ChannelMonitorDailyRollupCreate) SetCountLatency(v int) *ChannelMonitorDailyRollupCreate { + _c.mutation.SetCountLatency(v) + return _c +} + +// SetNillableCountLatency sets the "count_latency" field if the given value is not nil. +func (_c *ChannelMonitorDailyRollupCreate) SetNillableCountLatency(v *int) *ChannelMonitorDailyRollupCreate { + if v != nil { + _c.SetCountLatency(*v) + } + return _c +} + +// SetSumPingLatencyMs sets the "sum_ping_latency_ms" field. +func (_c *ChannelMonitorDailyRollupCreate) SetSumPingLatencyMs(v int64) *ChannelMonitorDailyRollupCreate { + _c.mutation.SetSumPingLatencyMs(v) + return _c +} + +// SetNillableSumPingLatencyMs sets the "sum_ping_latency_ms" field if the given value is not nil. +func (_c *ChannelMonitorDailyRollupCreate) SetNillableSumPingLatencyMs(v *int64) *ChannelMonitorDailyRollupCreate { + if v != nil { + _c.SetSumPingLatencyMs(*v) + } + return _c +} + +// SetCountPingLatency sets the "count_ping_latency" field. +func (_c *ChannelMonitorDailyRollupCreate) SetCountPingLatency(v int) *ChannelMonitorDailyRollupCreate { + _c.mutation.SetCountPingLatency(v) + return _c +} + +// SetNillableCountPingLatency sets the "count_ping_latency" field if the given value is not nil. +func (_c *ChannelMonitorDailyRollupCreate) SetNillableCountPingLatency(v *int) *ChannelMonitorDailyRollupCreate { + if v != nil { + _c.SetCountPingLatency(*v) + } + return _c +} + +// SetComputedAt sets the "computed_at" field. +func (_c *ChannelMonitorDailyRollupCreate) SetComputedAt(v time.Time) *ChannelMonitorDailyRollupCreate { + _c.mutation.SetComputedAt(v) + return _c +} + +// SetNillableComputedAt sets the "computed_at" field if the given value is not nil. +func (_c *ChannelMonitorDailyRollupCreate) SetNillableComputedAt(v *time.Time) *ChannelMonitorDailyRollupCreate { + if v != nil { + _c.SetComputedAt(*v) + } + return _c +} + +// SetMonitor sets the "monitor" edge to the ChannelMonitor entity. +func (_c *ChannelMonitorDailyRollupCreate) SetMonitor(v *ChannelMonitor) *ChannelMonitorDailyRollupCreate { + return _c.SetMonitorID(v.ID) +} + +// Mutation returns the ChannelMonitorDailyRollupMutation object of the builder. +func (_c *ChannelMonitorDailyRollupCreate) Mutation() *ChannelMonitorDailyRollupMutation { + return _c.mutation +} + +// Save creates the ChannelMonitorDailyRollup in the database. +func (_c *ChannelMonitorDailyRollupCreate) Save(ctx context.Context) (*ChannelMonitorDailyRollup, error) { + _c.defaults() + return withHooks(ctx, _c.sqlSave, _c.mutation, _c.hooks) +} + +// SaveX calls Save and panics if Save returns an error. +func (_c *ChannelMonitorDailyRollupCreate) SaveX(ctx context.Context) *ChannelMonitorDailyRollup { + v, err := _c.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (_c *ChannelMonitorDailyRollupCreate) Exec(ctx context.Context) error { + _, err := _c.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_c *ChannelMonitorDailyRollupCreate) ExecX(ctx context.Context) { + if err := _c.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (_c *ChannelMonitorDailyRollupCreate) defaults() { + if _, ok := _c.mutation.TotalChecks(); !ok { + v := channelmonitordailyrollup.DefaultTotalChecks + _c.mutation.SetTotalChecks(v) + } + if _, ok := _c.mutation.OkCount(); !ok { + v := channelmonitordailyrollup.DefaultOkCount + _c.mutation.SetOkCount(v) + } + if _, ok := _c.mutation.OperationalCount(); !ok { + v := channelmonitordailyrollup.DefaultOperationalCount + _c.mutation.SetOperationalCount(v) + } + if _, ok := _c.mutation.DegradedCount(); !ok { + v := channelmonitordailyrollup.DefaultDegradedCount + _c.mutation.SetDegradedCount(v) + } + if _, ok := _c.mutation.FailedCount(); !ok { + v := channelmonitordailyrollup.DefaultFailedCount + _c.mutation.SetFailedCount(v) + } + if _, ok := _c.mutation.ErrorCount(); !ok { + v := channelmonitordailyrollup.DefaultErrorCount + _c.mutation.SetErrorCount(v) + } + if _, ok := _c.mutation.SumLatencyMs(); !ok { + v := channelmonitordailyrollup.DefaultSumLatencyMs + _c.mutation.SetSumLatencyMs(v) + } + if _, ok := _c.mutation.CountLatency(); !ok { + v := channelmonitordailyrollup.DefaultCountLatency + _c.mutation.SetCountLatency(v) + } + if _, ok := _c.mutation.SumPingLatencyMs(); !ok { + v := channelmonitordailyrollup.DefaultSumPingLatencyMs + _c.mutation.SetSumPingLatencyMs(v) + } + if _, ok := _c.mutation.CountPingLatency(); !ok { + v := channelmonitordailyrollup.DefaultCountPingLatency + _c.mutation.SetCountPingLatency(v) + } + if _, ok := _c.mutation.ComputedAt(); !ok { + v := channelmonitordailyrollup.DefaultComputedAt() + _c.mutation.SetComputedAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_c *ChannelMonitorDailyRollupCreate) check() error { + if _, ok := _c.mutation.MonitorID(); !ok { + return &ValidationError{Name: "monitor_id", err: errors.New(`ent: missing required field "ChannelMonitorDailyRollup.monitor_id"`)} + } + if _, ok := _c.mutation.Model(); !ok { + return &ValidationError{Name: "model", err: errors.New(`ent: missing required field "ChannelMonitorDailyRollup.model"`)} + } + if v, ok := _c.mutation.Model(); ok { + if err := channelmonitordailyrollup.ModelValidator(v); err != nil { + return &ValidationError{Name: "model", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorDailyRollup.model": %w`, err)} + } + } + if _, ok := _c.mutation.BucketDate(); !ok { + return &ValidationError{Name: "bucket_date", err: errors.New(`ent: missing required field "ChannelMonitorDailyRollup.bucket_date"`)} + } + if _, ok := _c.mutation.TotalChecks(); !ok { + return &ValidationError{Name: "total_checks", err: errors.New(`ent: missing required field "ChannelMonitorDailyRollup.total_checks"`)} + } + if _, ok := _c.mutation.OkCount(); !ok { + return &ValidationError{Name: "ok_count", err: errors.New(`ent: missing required field "ChannelMonitorDailyRollup.ok_count"`)} + } + if _, ok := _c.mutation.OperationalCount(); !ok { + return &ValidationError{Name: "operational_count", err: errors.New(`ent: missing required field "ChannelMonitorDailyRollup.operational_count"`)} + } + if _, ok := _c.mutation.DegradedCount(); !ok { + return &ValidationError{Name: "degraded_count", err: errors.New(`ent: missing required field "ChannelMonitorDailyRollup.degraded_count"`)} + } + if _, ok := _c.mutation.FailedCount(); !ok { + return &ValidationError{Name: "failed_count", err: errors.New(`ent: missing required field "ChannelMonitorDailyRollup.failed_count"`)} + } + if _, ok := _c.mutation.ErrorCount(); !ok { + return &ValidationError{Name: "error_count", err: errors.New(`ent: missing required field "ChannelMonitorDailyRollup.error_count"`)} + } + if _, ok := _c.mutation.SumLatencyMs(); !ok { + return &ValidationError{Name: "sum_latency_ms", err: errors.New(`ent: missing required field "ChannelMonitorDailyRollup.sum_latency_ms"`)} + } + if _, ok := _c.mutation.CountLatency(); !ok { + return &ValidationError{Name: "count_latency", err: errors.New(`ent: missing required field "ChannelMonitorDailyRollup.count_latency"`)} + } + if _, ok := _c.mutation.SumPingLatencyMs(); !ok { + return &ValidationError{Name: "sum_ping_latency_ms", err: errors.New(`ent: missing required field "ChannelMonitorDailyRollup.sum_ping_latency_ms"`)} + } + if _, ok := _c.mutation.CountPingLatency(); !ok { + return &ValidationError{Name: "count_ping_latency", err: errors.New(`ent: missing required field "ChannelMonitorDailyRollup.count_ping_latency"`)} + } + if _, ok := _c.mutation.ComputedAt(); !ok { + return &ValidationError{Name: "computed_at", err: errors.New(`ent: missing required field "ChannelMonitorDailyRollup.computed_at"`)} + } + if len(_c.mutation.MonitorIDs()) == 0 { + return &ValidationError{Name: "monitor", err: errors.New(`ent: missing required edge "ChannelMonitorDailyRollup.monitor"`)} + } + return nil +} + +func (_c *ChannelMonitorDailyRollupCreate) sqlSave(ctx context.Context) (*ChannelMonitorDailyRollup, error) { + if err := _c.check(); err != nil { + return nil, err + } + _node, _spec := _c.createSpec() + if err := sqlgraph.CreateNode(ctx, _c.driver, _spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + id := _spec.ID.Value.(int64) + _node.ID = int64(id) + _c.mutation.id = &_node.ID + _c.mutation.done = true + return _node, nil +} + +func (_c *ChannelMonitorDailyRollupCreate) createSpec() (*ChannelMonitorDailyRollup, *sqlgraph.CreateSpec) { + var ( + _node = &ChannelMonitorDailyRollup{config: _c.config} + _spec = sqlgraph.NewCreateSpec(channelmonitordailyrollup.Table, sqlgraph.NewFieldSpec(channelmonitordailyrollup.FieldID, field.TypeInt64)) + ) + _spec.OnConflict = _c.conflict + if value, ok := _c.mutation.Model(); ok { + _spec.SetField(channelmonitordailyrollup.FieldModel, field.TypeString, value) + _node.Model = value + } + if value, ok := _c.mutation.BucketDate(); ok { + _spec.SetField(channelmonitordailyrollup.FieldBucketDate, field.TypeTime, value) + _node.BucketDate = value + } + if value, ok := _c.mutation.TotalChecks(); ok { + _spec.SetField(channelmonitordailyrollup.FieldTotalChecks, field.TypeInt, value) + _node.TotalChecks = value + } + if value, ok := _c.mutation.OkCount(); ok { + _spec.SetField(channelmonitordailyrollup.FieldOkCount, field.TypeInt, value) + _node.OkCount = value + } + if value, ok := _c.mutation.OperationalCount(); ok { + _spec.SetField(channelmonitordailyrollup.FieldOperationalCount, field.TypeInt, value) + _node.OperationalCount = value + } + if value, ok := _c.mutation.DegradedCount(); ok { + _spec.SetField(channelmonitordailyrollup.FieldDegradedCount, field.TypeInt, value) + _node.DegradedCount = value + } + if value, ok := _c.mutation.FailedCount(); ok { + _spec.SetField(channelmonitordailyrollup.FieldFailedCount, field.TypeInt, value) + _node.FailedCount = value + } + if value, ok := _c.mutation.ErrorCount(); ok { + _spec.SetField(channelmonitordailyrollup.FieldErrorCount, field.TypeInt, value) + _node.ErrorCount = value + } + if value, ok := _c.mutation.SumLatencyMs(); ok { + _spec.SetField(channelmonitordailyrollup.FieldSumLatencyMs, field.TypeInt64, value) + _node.SumLatencyMs = value + } + if value, ok := _c.mutation.CountLatency(); ok { + _spec.SetField(channelmonitordailyrollup.FieldCountLatency, field.TypeInt, value) + _node.CountLatency = value + } + if value, ok := _c.mutation.SumPingLatencyMs(); ok { + _spec.SetField(channelmonitordailyrollup.FieldSumPingLatencyMs, field.TypeInt64, value) + _node.SumPingLatencyMs = value + } + if value, ok := _c.mutation.CountPingLatency(); ok { + _spec.SetField(channelmonitordailyrollup.FieldCountPingLatency, field.TypeInt, value) + _node.CountPingLatency = value + } + if value, ok := _c.mutation.ComputedAt(); ok { + _spec.SetField(channelmonitordailyrollup.FieldComputedAt, field.TypeTime, value) + _node.ComputedAt = value + } + if nodes := _c.mutation.MonitorIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: channelmonitordailyrollup.MonitorTable, + Columns: []string{channelmonitordailyrollup.MonitorColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _node.MonitorID = nodes[0] + _spec.Edges = append(_spec.Edges, edge) + } + return _node, _spec +} + +// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause +// of the `INSERT` statement. For example: +// +// client.ChannelMonitorDailyRollup.Create(). +// SetMonitorID(v). +// OnConflict( +// // Update the row with the new values +// // the was proposed for insertion. +// sql.ResolveWithNewValues(), +// ). +// // Override some of the fields with custom +// // update values. +// Update(func(u *ent.ChannelMonitorDailyRollupUpsert) { +// SetMonitorID(v+v). +// }). +// Exec(ctx) +func (_c *ChannelMonitorDailyRollupCreate) OnConflict(opts ...sql.ConflictOption) *ChannelMonitorDailyRollupUpsertOne { + _c.conflict = opts + return &ChannelMonitorDailyRollupUpsertOne{ + create: _c, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.ChannelMonitorDailyRollup.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (_c *ChannelMonitorDailyRollupCreate) OnConflictColumns(columns ...string) *ChannelMonitorDailyRollupUpsertOne { + _c.conflict = append(_c.conflict, sql.ConflictColumns(columns...)) + return &ChannelMonitorDailyRollupUpsertOne{ + create: _c, + } +} + +type ( + // ChannelMonitorDailyRollupUpsertOne is the builder for "upsert"-ing + // one ChannelMonitorDailyRollup node. + ChannelMonitorDailyRollupUpsertOne struct { + create *ChannelMonitorDailyRollupCreate + } + + // ChannelMonitorDailyRollupUpsert is the "OnConflict" setter. + ChannelMonitorDailyRollupUpsert struct { + *sql.UpdateSet + } +) + +// SetMonitorID sets the "monitor_id" field. +func (u *ChannelMonitorDailyRollupUpsert) SetMonitorID(v int64) *ChannelMonitorDailyRollupUpsert { + u.Set(channelmonitordailyrollup.FieldMonitorID, v) + return u +} + +// UpdateMonitorID sets the "monitor_id" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsert) UpdateMonitorID() *ChannelMonitorDailyRollupUpsert { + u.SetExcluded(channelmonitordailyrollup.FieldMonitorID) + return u +} + +// SetModel sets the "model" field. +func (u *ChannelMonitorDailyRollupUpsert) SetModel(v string) *ChannelMonitorDailyRollupUpsert { + u.Set(channelmonitordailyrollup.FieldModel, v) + return u +} + +// UpdateModel sets the "model" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsert) UpdateModel() *ChannelMonitorDailyRollupUpsert { + u.SetExcluded(channelmonitordailyrollup.FieldModel) + return u +} + +// SetBucketDate sets the "bucket_date" field. +func (u *ChannelMonitorDailyRollupUpsert) SetBucketDate(v time.Time) *ChannelMonitorDailyRollupUpsert { + u.Set(channelmonitordailyrollup.FieldBucketDate, v) + return u +} + +// UpdateBucketDate sets the "bucket_date" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsert) UpdateBucketDate() *ChannelMonitorDailyRollupUpsert { + u.SetExcluded(channelmonitordailyrollup.FieldBucketDate) + return u +} + +// SetTotalChecks sets the "total_checks" field. +func (u *ChannelMonitorDailyRollupUpsert) SetTotalChecks(v int) *ChannelMonitorDailyRollupUpsert { + u.Set(channelmonitordailyrollup.FieldTotalChecks, v) + return u +} + +// UpdateTotalChecks sets the "total_checks" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsert) UpdateTotalChecks() *ChannelMonitorDailyRollupUpsert { + u.SetExcluded(channelmonitordailyrollup.FieldTotalChecks) + return u +} + +// AddTotalChecks adds v to the "total_checks" field. +func (u *ChannelMonitorDailyRollupUpsert) AddTotalChecks(v int) *ChannelMonitorDailyRollupUpsert { + u.Add(channelmonitordailyrollup.FieldTotalChecks, v) + return u +} + +// SetOkCount sets the "ok_count" field. +func (u *ChannelMonitorDailyRollupUpsert) SetOkCount(v int) *ChannelMonitorDailyRollupUpsert { + u.Set(channelmonitordailyrollup.FieldOkCount, v) + return u +} + +// UpdateOkCount sets the "ok_count" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsert) UpdateOkCount() *ChannelMonitorDailyRollupUpsert { + u.SetExcluded(channelmonitordailyrollup.FieldOkCount) + return u +} + +// AddOkCount adds v to the "ok_count" field. +func (u *ChannelMonitorDailyRollupUpsert) AddOkCount(v int) *ChannelMonitorDailyRollupUpsert { + u.Add(channelmonitordailyrollup.FieldOkCount, v) + return u +} + +// SetOperationalCount sets the "operational_count" field. +func (u *ChannelMonitorDailyRollupUpsert) SetOperationalCount(v int) *ChannelMonitorDailyRollupUpsert { + u.Set(channelmonitordailyrollup.FieldOperationalCount, v) + return u +} + +// UpdateOperationalCount sets the "operational_count" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsert) UpdateOperationalCount() *ChannelMonitorDailyRollupUpsert { + u.SetExcluded(channelmonitordailyrollup.FieldOperationalCount) + return u +} + +// AddOperationalCount adds v to the "operational_count" field. +func (u *ChannelMonitorDailyRollupUpsert) AddOperationalCount(v int) *ChannelMonitorDailyRollupUpsert { + u.Add(channelmonitordailyrollup.FieldOperationalCount, v) + return u +} + +// SetDegradedCount sets the "degraded_count" field. +func (u *ChannelMonitorDailyRollupUpsert) SetDegradedCount(v int) *ChannelMonitorDailyRollupUpsert { + u.Set(channelmonitordailyrollup.FieldDegradedCount, v) + return u +} + +// UpdateDegradedCount sets the "degraded_count" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsert) UpdateDegradedCount() *ChannelMonitorDailyRollupUpsert { + u.SetExcluded(channelmonitordailyrollup.FieldDegradedCount) + return u +} + +// AddDegradedCount adds v to the "degraded_count" field. +func (u *ChannelMonitorDailyRollupUpsert) AddDegradedCount(v int) *ChannelMonitorDailyRollupUpsert { + u.Add(channelmonitordailyrollup.FieldDegradedCount, v) + return u +} + +// SetFailedCount sets the "failed_count" field. +func (u *ChannelMonitorDailyRollupUpsert) SetFailedCount(v int) *ChannelMonitorDailyRollupUpsert { + u.Set(channelmonitordailyrollup.FieldFailedCount, v) + return u +} + +// UpdateFailedCount sets the "failed_count" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsert) UpdateFailedCount() *ChannelMonitorDailyRollupUpsert { + u.SetExcluded(channelmonitordailyrollup.FieldFailedCount) + return u +} + +// AddFailedCount adds v to the "failed_count" field. +func (u *ChannelMonitorDailyRollupUpsert) AddFailedCount(v int) *ChannelMonitorDailyRollupUpsert { + u.Add(channelmonitordailyrollup.FieldFailedCount, v) + return u +} + +// SetErrorCount sets the "error_count" field. +func (u *ChannelMonitorDailyRollupUpsert) SetErrorCount(v int) *ChannelMonitorDailyRollupUpsert { + u.Set(channelmonitordailyrollup.FieldErrorCount, v) + return u +} + +// UpdateErrorCount sets the "error_count" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsert) UpdateErrorCount() *ChannelMonitorDailyRollupUpsert { + u.SetExcluded(channelmonitordailyrollup.FieldErrorCount) + return u +} + +// AddErrorCount adds v to the "error_count" field. +func (u *ChannelMonitorDailyRollupUpsert) AddErrorCount(v int) *ChannelMonitorDailyRollupUpsert { + u.Add(channelmonitordailyrollup.FieldErrorCount, v) + return u +} + +// SetSumLatencyMs sets the "sum_latency_ms" field. +func (u *ChannelMonitorDailyRollupUpsert) SetSumLatencyMs(v int64) *ChannelMonitorDailyRollupUpsert { + u.Set(channelmonitordailyrollup.FieldSumLatencyMs, v) + return u +} + +// UpdateSumLatencyMs sets the "sum_latency_ms" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsert) UpdateSumLatencyMs() *ChannelMonitorDailyRollupUpsert { + u.SetExcluded(channelmonitordailyrollup.FieldSumLatencyMs) + return u +} + +// AddSumLatencyMs adds v to the "sum_latency_ms" field. +func (u *ChannelMonitorDailyRollupUpsert) AddSumLatencyMs(v int64) *ChannelMonitorDailyRollupUpsert { + u.Add(channelmonitordailyrollup.FieldSumLatencyMs, v) + return u +} + +// SetCountLatency sets the "count_latency" field. +func (u *ChannelMonitorDailyRollupUpsert) SetCountLatency(v int) *ChannelMonitorDailyRollupUpsert { + u.Set(channelmonitordailyrollup.FieldCountLatency, v) + return u +} + +// UpdateCountLatency sets the "count_latency" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsert) UpdateCountLatency() *ChannelMonitorDailyRollupUpsert { + u.SetExcluded(channelmonitordailyrollup.FieldCountLatency) + return u +} + +// AddCountLatency adds v to the "count_latency" field. +func (u *ChannelMonitorDailyRollupUpsert) AddCountLatency(v int) *ChannelMonitorDailyRollupUpsert { + u.Add(channelmonitordailyrollup.FieldCountLatency, v) + return u +} + +// SetSumPingLatencyMs sets the "sum_ping_latency_ms" field. +func (u *ChannelMonitorDailyRollupUpsert) SetSumPingLatencyMs(v int64) *ChannelMonitorDailyRollupUpsert { + u.Set(channelmonitordailyrollup.FieldSumPingLatencyMs, v) + return u +} + +// UpdateSumPingLatencyMs sets the "sum_ping_latency_ms" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsert) UpdateSumPingLatencyMs() *ChannelMonitorDailyRollupUpsert { + u.SetExcluded(channelmonitordailyrollup.FieldSumPingLatencyMs) + return u +} + +// AddSumPingLatencyMs adds v to the "sum_ping_latency_ms" field. +func (u *ChannelMonitorDailyRollupUpsert) AddSumPingLatencyMs(v int64) *ChannelMonitorDailyRollupUpsert { + u.Add(channelmonitordailyrollup.FieldSumPingLatencyMs, v) + return u +} + +// SetCountPingLatency sets the "count_ping_latency" field. +func (u *ChannelMonitorDailyRollupUpsert) SetCountPingLatency(v int) *ChannelMonitorDailyRollupUpsert { + u.Set(channelmonitordailyrollup.FieldCountPingLatency, v) + return u +} + +// UpdateCountPingLatency sets the "count_ping_latency" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsert) UpdateCountPingLatency() *ChannelMonitorDailyRollupUpsert { + u.SetExcluded(channelmonitordailyrollup.FieldCountPingLatency) + return u +} + +// AddCountPingLatency adds v to the "count_ping_latency" field. +func (u *ChannelMonitorDailyRollupUpsert) AddCountPingLatency(v int) *ChannelMonitorDailyRollupUpsert { + u.Add(channelmonitordailyrollup.FieldCountPingLatency, v) + return u +} + +// SetComputedAt sets the "computed_at" field. +func (u *ChannelMonitorDailyRollupUpsert) SetComputedAt(v time.Time) *ChannelMonitorDailyRollupUpsert { + u.Set(channelmonitordailyrollup.FieldComputedAt, v) + return u +} + +// UpdateComputedAt sets the "computed_at" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsert) UpdateComputedAt() *ChannelMonitorDailyRollupUpsert { + u.SetExcluded(channelmonitordailyrollup.FieldComputedAt) + return u +} + +// UpdateNewValues updates the mutable fields using the new values that were set on create. +// Using this option is equivalent to using: +// +// client.ChannelMonitorDailyRollup.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// ). +// Exec(ctx) +func (u *ChannelMonitorDailyRollupUpsertOne) UpdateNewValues() *ChannelMonitorDailyRollupUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues()) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.ChannelMonitorDailyRollup.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *ChannelMonitorDailyRollupUpsertOne) Ignore() *ChannelMonitorDailyRollupUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore()) + return u +} + +// DoNothing configures the conflict_action to `DO NOTHING`. +// Supported only by SQLite and PostgreSQL. +func (u *ChannelMonitorDailyRollupUpsertOne) DoNothing() *ChannelMonitorDailyRollupUpsertOne { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the ChannelMonitorDailyRollupCreate.OnConflict +// documentation for more info. +func (u *ChannelMonitorDailyRollupUpsertOne) Update(set func(*ChannelMonitorDailyRollupUpsert)) *ChannelMonitorDailyRollupUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&ChannelMonitorDailyRollupUpsert{UpdateSet: update}) + })) + return u +} + +// SetMonitorID sets the "monitor_id" field. +func (u *ChannelMonitorDailyRollupUpsertOne) SetMonitorID(v int64) *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetMonitorID(v) + }) +} + +// UpdateMonitorID sets the "monitor_id" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertOne) UpdateMonitorID() *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateMonitorID() + }) +} + +// SetModel sets the "model" field. +func (u *ChannelMonitorDailyRollupUpsertOne) SetModel(v string) *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetModel(v) + }) +} + +// UpdateModel sets the "model" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertOne) UpdateModel() *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateModel() + }) +} + +// SetBucketDate sets the "bucket_date" field. +func (u *ChannelMonitorDailyRollupUpsertOne) SetBucketDate(v time.Time) *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetBucketDate(v) + }) +} + +// UpdateBucketDate sets the "bucket_date" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertOne) UpdateBucketDate() *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateBucketDate() + }) +} + +// SetTotalChecks sets the "total_checks" field. +func (u *ChannelMonitorDailyRollupUpsertOne) SetTotalChecks(v int) *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetTotalChecks(v) + }) +} + +// AddTotalChecks adds v to the "total_checks" field. +func (u *ChannelMonitorDailyRollupUpsertOne) AddTotalChecks(v int) *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.AddTotalChecks(v) + }) +} + +// UpdateTotalChecks sets the "total_checks" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertOne) UpdateTotalChecks() *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateTotalChecks() + }) +} + +// SetOkCount sets the "ok_count" field. +func (u *ChannelMonitorDailyRollupUpsertOne) SetOkCount(v int) *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetOkCount(v) + }) +} + +// AddOkCount adds v to the "ok_count" field. +func (u *ChannelMonitorDailyRollupUpsertOne) AddOkCount(v int) *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.AddOkCount(v) + }) +} + +// UpdateOkCount sets the "ok_count" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertOne) UpdateOkCount() *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateOkCount() + }) +} + +// SetOperationalCount sets the "operational_count" field. +func (u *ChannelMonitorDailyRollupUpsertOne) SetOperationalCount(v int) *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetOperationalCount(v) + }) +} + +// AddOperationalCount adds v to the "operational_count" field. +func (u *ChannelMonitorDailyRollupUpsertOne) AddOperationalCount(v int) *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.AddOperationalCount(v) + }) +} + +// UpdateOperationalCount sets the "operational_count" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertOne) UpdateOperationalCount() *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateOperationalCount() + }) +} + +// SetDegradedCount sets the "degraded_count" field. +func (u *ChannelMonitorDailyRollupUpsertOne) SetDegradedCount(v int) *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetDegradedCount(v) + }) +} + +// AddDegradedCount adds v to the "degraded_count" field. +func (u *ChannelMonitorDailyRollupUpsertOne) AddDegradedCount(v int) *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.AddDegradedCount(v) + }) +} + +// UpdateDegradedCount sets the "degraded_count" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertOne) UpdateDegradedCount() *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateDegradedCount() + }) +} + +// SetFailedCount sets the "failed_count" field. +func (u *ChannelMonitorDailyRollupUpsertOne) SetFailedCount(v int) *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetFailedCount(v) + }) +} + +// AddFailedCount adds v to the "failed_count" field. +func (u *ChannelMonitorDailyRollupUpsertOne) AddFailedCount(v int) *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.AddFailedCount(v) + }) +} + +// UpdateFailedCount sets the "failed_count" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertOne) UpdateFailedCount() *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateFailedCount() + }) +} + +// SetErrorCount sets the "error_count" field. +func (u *ChannelMonitorDailyRollupUpsertOne) SetErrorCount(v int) *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetErrorCount(v) + }) +} + +// AddErrorCount adds v to the "error_count" field. +func (u *ChannelMonitorDailyRollupUpsertOne) AddErrorCount(v int) *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.AddErrorCount(v) + }) +} + +// UpdateErrorCount sets the "error_count" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertOne) UpdateErrorCount() *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateErrorCount() + }) +} + +// SetSumLatencyMs sets the "sum_latency_ms" field. +func (u *ChannelMonitorDailyRollupUpsertOne) SetSumLatencyMs(v int64) *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetSumLatencyMs(v) + }) +} + +// AddSumLatencyMs adds v to the "sum_latency_ms" field. +func (u *ChannelMonitorDailyRollupUpsertOne) AddSumLatencyMs(v int64) *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.AddSumLatencyMs(v) + }) +} + +// UpdateSumLatencyMs sets the "sum_latency_ms" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertOne) UpdateSumLatencyMs() *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateSumLatencyMs() + }) +} + +// SetCountLatency sets the "count_latency" field. +func (u *ChannelMonitorDailyRollupUpsertOne) SetCountLatency(v int) *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetCountLatency(v) + }) +} + +// AddCountLatency adds v to the "count_latency" field. +func (u *ChannelMonitorDailyRollupUpsertOne) AddCountLatency(v int) *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.AddCountLatency(v) + }) +} + +// UpdateCountLatency sets the "count_latency" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertOne) UpdateCountLatency() *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateCountLatency() + }) +} + +// SetSumPingLatencyMs sets the "sum_ping_latency_ms" field. +func (u *ChannelMonitorDailyRollupUpsertOne) SetSumPingLatencyMs(v int64) *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetSumPingLatencyMs(v) + }) +} + +// AddSumPingLatencyMs adds v to the "sum_ping_latency_ms" field. +func (u *ChannelMonitorDailyRollupUpsertOne) AddSumPingLatencyMs(v int64) *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.AddSumPingLatencyMs(v) + }) +} + +// UpdateSumPingLatencyMs sets the "sum_ping_latency_ms" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertOne) UpdateSumPingLatencyMs() *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateSumPingLatencyMs() + }) +} + +// SetCountPingLatency sets the "count_ping_latency" field. +func (u *ChannelMonitorDailyRollupUpsertOne) SetCountPingLatency(v int) *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetCountPingLatency(v) + }) +} + +// AddCountPingLatency adds v to the "count_ping_latency" field. +func (u *ChannelMonitorDailyRollupUpsertOne) AddCountPingLatency(v int) *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.AddCountPingLatency(v) + }) +} + +// UpdateCountPingLatency sets the "count_ping_latency" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertOne) UpdateCountPingLatency() *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateCountPingLatency() + }) +} + +// SetComputedAt sets the "computed_at" field. +func (u *ChannelMonitorDailyRollupUpsertOne) SetComputedAt(v time.Time) *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetComputedAt(v) + }) +} + +// UpdateComputedAt sets the "computed_at" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertOne) UpdateComputedAt() *ChannelMonitorDailyRollupUpsertOne { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateComputedAt() + }) +} + +// Exec executes the query. +func (u *ChannelMonitorDailyRollupUpsertOne) Exec(ctx context.Context) error { + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for ChannelMonitorDailyRollupCreate.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *ChannelMonitorDailyRollupUpsertOne) ExecX(ctx context.Context) { + if err := u.create.Exec(ctx); err != nil { + panic(err) + } +} + +// Exec executes the UPSERT query and returns the inserted/updated ID. +func (u *ChannelMonitorDailyRollupUpsertOne) ID(ctx context.Context) (id int64, err error) { + node, err := u.create.Save(ctx) + if err != nil { + return id, err + } + return node.ID, nil +} + +// IDX is like ID, but panics if an error occurs. +func (u *ChannelMonitorDailyRollupUpsertOne) IDX(ctx context.Context) int64 { + id, err := u.ID(ctx) + if err != nil { + panic(err) + } + return id +} + +// ChannelMonitorDailyRollupCreateBulk is the builder for creating many ChannelMonitorDailyRollup entities in bulk. +type ChannelMonitorDailyRollupCreateBulk struct { + config + err error + builders []*ChannelMonitorDailyRollupCreate + conflict []sql.ConflictOption +} + +// Save creates the ChannelMonitorDailyRollup entities in the database. +func (_c *ChannelMonitorDailyRollupCreateBulk) Save(ctx context.Context) ([]*ChannelMonitorDailyRollup, error) { + if _c.err != nil { + return nil, _c.err + } + specs := make([]*sqlgraph.CreateSpec, len(_c.builders)) + nodes := make([]*ChannelMonitorDailyRollup, len(_c.builders)) + mutators := make([]Mutator, len(_c.builders)) + for i := range _c.builders { + func(i int, root context.Context) { + builder := _c.builders[i] + builder.defaults() + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*ChannelMonitorDailyRollupMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + if err := builder.check(); err != nil { + return nil, err + } + builder.mutation = mutation + var err error + nodes[i], specs[i] = builder.createSpec() + if i < len(mutators)-1 { + _, err = mutators[i+1].Mutate(root, _c.builders[i+1].mutation) + } else { + spec := &sqlgraph.BatchCreateSpec{Nodes: specs} + spec.OnConflict = _c.conflict + // Invoke the actual operation on the latest mutation in the chain. + if err = sqlgraph.BatchCreate(ctx, _c.driver, spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + } + } + if err != nil { + return nil, err + } + mutation.id = &nodes[i].ID + if specs[i].ID.Value != nil { + id := specs[i].ID.Value.(int64) + nodes[i].ID = int64(id) + } + mutation.done = true + return nodes[i], nil + }) + for i := len(builder.hooks) - 1; i >= 0; i-- { + mut = builder.hooks[i](mut) + } + mutators[i] = mut + }(i, ctx) + } + if len(mutators) > 0 { + if _, err := mutators[0].Mutate(ctx, _c.builders[0].mutation); err != nil { + return nil, err + } + } + return nodes, nil +} + +// SaveX is like Save, but panics if an error occurs. +func (_c *ChannelMonitorDailyRollupCreateBulk) SaveX(ctx context.Context) []*ChannelMonitorDailyRollup { + v, err := _c.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (_c *ChannelMonitorDailyRollupCreateBulk) Exec(ctx context.Context) error { + _, err := _c.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_c *ChannelMonitorDailyRollupCreateBulk) ExecX(ctx context.Context) { + if err := _c.Exec(ctx); err != nil { + panic(err) + } +} + +// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause +// of the `INSERT` statement. For example: +// +// client.ChannelMonitorDailyRollup.CreateBulk(builders...). +// OnConflict( +// // Update the row with the new values +// // the was proposed for insertion. +// sql.ResolveWithNewValues(), +// ). +// // Override some of the fields with custom +// // update values. +// Update(func(u *ent.ChannelMonitorDailyRollupUpsert) { +// SetMonitorID(v+v). +// }). +// Exec(ctx) +func (_c *ChannelMonitorDailyRollupCreateBulk) OnConflict(opts ...sql.ConflictOption) *ChannelMonitorDailyRollupUpsertBulk { + _c.conflict = opts + return &ChannelMonitorDailyRollupUpsertBulk{ + create: _c, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.ChannelMonitorDailyRollup.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (_c *ChannelMonitorDailyRollupCreateBulk) OnConflictColumns(columns ...string) *ChannelMonitorDailyRollupUpsertBulk { + _c.conflict = append(_c.conflict, sql.ConflictColumns(columns...)) + return &ChannelMonitorDailyRollupUpsertBulk{ + create: _c, + } +} + +// ChannelMonitorDailyRollupUpsertBulk is the builder for "upsert"-ing +// a bulk of ChannelMonitorDailyRollup nodes. +type ChannelMonitorDailyRollupUpsertBulk struct { + create *ChannelMonitorDailyRollupCreateBulk +} + +// UpdateNewValues updates the mutable fields using the new values that +// were set on create. Using this option is equivalent to using: +// +// client.ChannelMonitorDailyRollup.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// ). +// Exec(ctx) +func (u *ChannelMonitorDailyRollupUpsertBulk) UpdateNewValues() *ChannelMonitorDailyRollupUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues()) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.ChannelMonitorDailyRollup.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *ChannelMonitorDailyRollupUpsertBulk) Ignore() *ChannelMonitorDailyRollupUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore()) + return u +} + +// DoNothing configures the conflict_action to `DO NOTHING`. +// Supported only by SQLite and PostgreSQL. +func (u *ChannelMonitorDailyRollupUpsertBulk) DoNothing() *ChannelMonitorDailyRollupUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the ChannelMonitorDailyRollupCreateBulk.OnConflict +// documentation for more info. +func (u *ChannelMonitorDailyRollupUpsertBulk) Update(set func(*ChannelMonitorDailyRollupUpsert)) *ChannelMonitorDailyRollupUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&ChannelMonitorDailyRollupUpsert{UpdateSet: update}) + })) + return u +} + +// SetMonitorID sets the "monitor_id" field. +func (u *ChannelMonitorDailyRollupUpsertBulk) SetMonitorID(v int64) *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetMonitorID(v) + }) +} + +// UpdateMonitorID sets the "monitor_id" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertBulk) UpdateMonitorID() *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateMonitorID() + }) +} + +// SetModel sets the "model" field. +func (u *ChannelMonitorDailyRollupUpsertBulk) SetModel(v string) *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetModel(v) + }) +} + +// UpdateModel sets the "model" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertBulk) UpdateModel() *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateModel() + }) +} + +// SetBucketDate sets the "bucket_date" field. +func (u *ChannelMonitorDailyRollupUpsertBulk) SetBucketDate(v time.Time) *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetBucketDate(v) + }) +} + +// UpdateBucketDate sets the "bucket_date" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertBulk) UpdateBucketDate() *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateBucketDate() + }) +} + +// SetTotalChecks sets the "total_checks" field. +func (u *ChannelMonitorDailyRollupUpsertBulk) SetTotalChecks(v int) *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetTotalChecks(v) + }) +} + +// AddTotalChecks adds v to the "total_checks" field. +func (u *ChannelMonitorDailyRollupUpsertBulk) AddTotalChecks(v int) *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.AddTotalChecks(v) + }) +} + +// UpdateTotalChecks sets the "total_checks" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertBulk) UpdateTotalChecks() *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateTotalChecks() + }) +} + +// SetOkCount sets the "ok_count" field. +func (u *ChannelMonitorDailyRollupUpsertBulk) SetOkCount(v int) *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetOkCount(v) + }) +} + +// AddOkCount adds v to the "ok_count" field. +func (u *ChannelMonitorDailyRollupUpsertBulk) AddOkCount(v int) *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.AddOkCount(v) + }) +} + +// UpdateOkCount sets the "ok_count" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertBulk) UpdateOkCount() *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateOkCount() + }) +} + +// SetOperationalCount sets the "operational_count" field. +func (u *ChannelMonitorDailyRollupUpsertBulk) SetOperationalCount(v int) *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetOperationalCount(v) + }) +} + +// AddOperationalCount adds v to the "operational_count" field. +func (u *ChannelMonitorDailyRollupUpsertBulk) AddOperationalCount(v int) *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.AddOperationalCount(v) + }) +} + +// UpdateOperationalCount sets the "operational_count" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertBulk) UpdateOperationalCount() *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateOperationalCount() + }) +} + +// SetDegradedCount sets the "degraded_count" field. +func (u *ChannelMonitorDailyRollupUpsertBulk) SetDegradedCount(v int) *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetDegradedCount(v) + }) +} + +// AddDegradedCount adds v to the "degraded_count" field. +func (u *ChannelMonitorDailyRollupUpsertBulk) AddDegradedCount(v int) *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.AddDegradedCount(v) + }) +} + +// UpdateDegradedCount sets the "degraded_count" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertBulk) UpdateDegradedCount() *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateDegradedCount() + }) +} + +// SetFailedCount sets the "failed_count" field. +func (u *ChannelMonitorDailyRollupUpsertBulk) SetFailedCount(v int) *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetFailedCount(v) + }) +} + +// AddFailedCount adds v to the "failed_count" field. +func (u *ChannelMonitorDailyRollupUpsertBulk) AddFailedCount(v int) *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.AddFailedCount(v) + }) +} + +// UpdateFailedCount sets the "failed_count" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertBulk) UpdateFailedCount() *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateFailedCount() + }) +} + +// SetErrorCount sets the "error_count" field. +func (u *ChannelMonitorDailyRollupUpsertBulk) SetErrorCount(v int) *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetErrorCount(v) + }) +} + +// AddErrorCount adds v to the "error_count" field. +func (u *ChannelMonitorDailyRollupUpsertBulk) AddErrorCount(v int) *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.AddErrorCount(v) + }) +} + +// UpdateErrorCount sets the "error_count" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertBulk) UpdateErrorCount() *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateErrorCount() + }) +} + +// SetSumLatencyMs sets the "sum_latency_ms" field. +func (u *ChannelMonitorDailyRollupUpsertBulk) SetSumLatencyMs(v int64) *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetSumLatencyMs(v) + }) +} + +// AddSumLatencyMs adds v to the "sum_latency_ms" field. +func (u *ChannelMonitorDailyRollupUpsertBulk) AddSumLatencyMs(v int64) *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.AddSumLatencyMs(v) + }) +} + +// UpdateSumLatencyMs sets the "sum_latency_ms" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertBulk) UpdateSumLatencyMs() *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateSumLatencyMs() + }) +} + +// SetCountLatency sets the "count_latency" field. +func (u *ChannelMonitorDailyRollupUpsertBulk) SetCountLatency(v int) *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetCountLatency(v) + }) +} + +// AddCountLatency adds v to the "count_latency" field. +func (u *ChannelMonitorDailyRollupUpsertBulk) AddCountLatency(v int) *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.AddCountLatency(v) + }) +} + +// UpdateCountLatency sets the "count_latency" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertBulk) UpdateCountLatency() *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateCountLatency() + }) +} + +// SetSumPingLatencyMs sets the "sum_ping_latency_ms" field. +func (u *ChannelMonitorDailyRollupUpsertBulk) SetSumPingLatencyMs(v int64) *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetSumPingLatencyMs(v) + }) +} + +// AddSumPingLatencyMs adds v to the "sum_ping_latency_ms" field. +func (u *ChannelMonitorDailyRollupUpsertBulk) AddSumPingLatencyMs(v int64) *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.AddSumPingLatencyMs(v) + }) +} + +// UpdateSumPingLatencyMs sets the "sum_ping_latency_ms" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertBulk) UpdateSumPingLatencyMs() *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateSumPingLatencyMs() + }) +} + +// SetCountPingLatency sets the "count_ping_latency" field. +func (u *ChannelMonitorDailyRollupUpsertBulk) SetCountPingLatency(v int) *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetCountPingLatency(v) + }) +} + +// AddCountPingLatency adds v to the "count_ping_latency" field. +func (u *ChannelMonitorDailyRollupUpsertBulk) AddCountPingLatency(v int) *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.AddCountPingLatency(v) + }) +} + +// UpdateCountPingLatency sets the "count_ping_latency" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertBulk) UpdateCountPingLatency() *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateCountPingLatency() + }) +} + +// SetComputedAt sets the "computed_at" field. +func (u *ChannelMonitorDailyRollupUpsertBulk) SetComputedAt(v time.Time) *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.SetComputedAt(v) + }) +} + +// UpdateComputedAt sets the "computed_at" field to the value that was provided on create. +func (u *ChannelMonitorDailyRollupUpsertBulk) UpdateComputedAt() *ChannelMonitorDailyRollupUpsertBulk { + return u.Update(func(s *ChannelMonitorDailyRollupUpsert) { + s.UpdateComputedAt() + }) +} + +// Exec executes the query. +func (u *ChannelMonitorDailyRollupUpsertBulk) Exec(ctx context.Context) error { + if u.create.err != nil { + return u.create.err + } + for i, b := range u.create.builders { + if len(b.conflict) != 0 { + return fmt.Errorf("ent: OnConflict was set for builder %d. Set it on the ChannelMonitorDailyRollupCreateBulk instead", i) + } + } + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for ChannelMonitorDailyRollupCreateBulk.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *ChannelMonitorDailyRollupUpsertBulk) ExecX(ctx context.Context) { + if err := u.create.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/backend/ent/channelmonitordailyrollup_delete.go b/backend/ent/channelmonitordailyrollup_delete.go new file mode 100644 index 00000000..460c94f8 --- /dev/null +++ b/backend/ent/channelmonitordailyrollup_delete.go @@ -0,0 +1,88 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/Wei-Shaw/sub2api/ent/channelmonitordailyrollup" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// ChannelMonitorDailyRollupDelete is the builder for deleting a ChannelMonitorDailyRollup entity. +type ChannelMonitorDailyRollupDelete struct { + config + hooks []Hook + mutation *ChannelMonitorDailyRollupMutation +} + +// Where appends a list predicates to the ChannelMonitorDailyRollupDelete builder. +func (_d *ChannelMonitorDailyRollupDelete) Where(ps ...predicate.ChannelMonitorDailyRollup) *ChannelMonitorDailyRollupDelete { + _d.mutation.Where(ps...) + return _d +} + +// Exec executes the deletion query and returns how many vertices were deleted. +func (_d *ChannelMonitorDailyRollupDelete) Exec(ctx context.Context) (int, error) { + return withHooks(ctx, _d.sqlExec, _d.mutation, _d.hooks) +} + +// ExecX is like Exec, but panics if an error occurs. +func (_d *ChannelMonitorDailyRollupDelete) ExecX(ctx context.Context) int { + n, err := _d.Exec(ctx) + if err != nil { + panic(err) + } + return n +} + +func (_d *ChannelMonitorDailyRollupDelete) sqlExec(ctx context.Context) (int, error) { + _spec := sqlgraph.NewDeleteSpec(channelmonitordailyrollup.Table, sqlgraph.NewFieldSpec(channelmonitordailyrollup.FieldID, field.TypeInt64)) + if ps := _d.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + affected, err := sqlgraph.DeleteNodes(ctx, _d.driver, _spec) + if err != nil && sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + _d.mutation.done = true + return affected, err +} + +// ChannelMonitorDailyRollupDeleteOne is the builder for deleting a single ChannelMonitorDailyRollup entity. +type ChannelMonitorDailyRollupDeleteOne struct { + _d *ChannelMonitorDailyRollupDelete +} + +// Where appends a list predicates to the ChannelMonitorDailyRollupDelete builder. +func (_d *ChannelMonitorDailyRollupDeleteOne) Where(ps ...predicate.ChannelMonitorDailyRollup) *ChannelMonitorDailyRollupDeleteOne { + _d._d.mutation.Where(ps...) + return _d +} + +// Exec executes the deletion query. +func (_d *ChannelMonitorDailyRollupDeleteOne) Exec(ctx context.Context) error { + n, err := _d._d.Exec(ctx) + switch { + case err != nil: + return err + case n == 0: + return &NotFoundError{channelmonitordailyrollup.Label} + default: + return nil + } +} + +// ExecX is like Exec, but panics if an error occurs. +func (_d *ChannelMonitorDailyRollupDeleteOne) ExecX(ctx context.Context) { + if err := _d.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/backend/ent/channelmonitordailyrollup_query.go b/backend/ent/channelmonitordailyrollup_query.go new file mode 100644 index 00000000..e34afc61 --- /dev/null +++ b/backend/ent/channelmonitordailyrollup_query.go @@ -0,0 +1,643 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "fmt" + "math" + + "entgo.io/ent" + "entgo.io/ent/dialect" + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitordailyrollup" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// ChannelMonitorDailyRollupQuery is the builder for querying ChannelMonitorDailyRollup entities. +type ChannelMonitorDailyRollupQuery struct { + config + ctx *QueryContext + order []channelmonitordailyrollup.OrderOption + inters []Interceptor + predicates []predicate.ChannelMonitorDailyRollup + withMonitor *ChannelMonitorQuery + modifiers []func(*sql.Selector) + // intermediate query (i.e. traversal path). + sql *sql.Selector + path func(context.Context) (*sql.Selector, error) +} + +// Where adds a new predicate for the ChannelMonitorDailyRollupQuery builder. +func (_q *ChannelMonitorDailyRollupQuery) Where(ps ...predicate.ChannelMonitorDailyRollup) *ChannelMonitorDailyRollupQuery { + _q.predicates = append(_q.predicates, ps...) + return _q +} + +// Limit the number of records to be returned by this query. +func (_q *ChannelMonitorDailyRollupQuery) Limit(limit int) *ChannelMonitorDailyRollupQuery { + _q.ctx.Limit = &limit + return _q +} + +// Offset to start from. +func (_q *ChannelMonitorDailyRollupQuery) Offset(offset int) *ChannelMonitorDailyRollupQuery { + _q.ctx.Offset = &offset + return _q +} + +// Unique configures the query builder to filter duplicate records on query. +// By default, unique is set to true, and can be disabled using this method. +func (_q *ChannelMonitorDailyRollupQuery) Unique(unique bool) *ChannelMonitorDailyRollupQuery { + _q.ctx.Unique = &unique + return _q +} + +// Order specifies how the records should be ordered. +func (_q *ChannelMonitorDailyRollupQuery) Order(o ...channelmonitordailyrollup.OrderOption) *ChannelMonitorDailyRollupQuery { + _q.order = append(_q.order, o...) + return _q +} + +// QueryMonitor chains the current query on the "monitor" edge. +func (_q *ChannelMonitorDailyRollupQuery) QueryMonitor() *ChannelMonitorQuery { + query := (&ChannelMonitorClient{config: _q.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := _q.prepareQuery(ctx); err != nil { + return nil, err + } + selector := _q.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(channelmonitordailyrollup.Table, channelmonitordailyrollup.FieldID, selector), + sqlgraph.To(channelmonitor.Table, channelmonitor.FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, channelmonitordailyrollup.MonitorTable, channelmonitordailyrollup.MonitorColumn), + ) + fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step) + return fromU, nil + } + return query +} + +// First returns the first ChannelMonitorDailyRollup entity from the query. +// Returns a *NotFoundError when no ChannelMonitorDailyRollup was found. +func (_q *ChannelMonitorDailyRollupQuery) First(ctx context.Context) (*ChannelMonitorDailyRollup, error) { + nodes, err := _q.Limit(1).All(setContextOp(ctx, _q.ctx, ent.OpQueryFirst)) + if err != nil { + return nil, err + } + if len(nodes) == 0 { + return nil, &NotFoundError{channelmonitordailyrollup.Label} + } + return nodes[0], nil +} + +// FirstX is like First, but panics if an error occurs. +func (_q *ChannelMonitorDailyRollupQuery) FirstX(ctx context.Context) *ChannelMonitorDailyRollup { + node, err := _q.First(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return node +} + +// FirstID returns the first ChannelMonitorDailyRollup ID from the query. +// Returns a *NotFoundError when no ChannelMonitorDailyRollup ID was found. +func (_q *ChannelMonitorDailyRollupQuery) FirstID(ctx context.Context) (id int64, err error) { + var ids []int64 + if ids, err = _q.Limit(1).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryFirstID)); err != nil { + return + } + if len(ids) == 0 { + err = &NotFoundError{channelmonitordailyrollup.Label} + return + } + return ids[0], nil +} + +// FirstIDX is like FirstID, but panics if an error occurs. +func (_q *ChannelMonitorDailyRollupQuery) FirstIDX(ctx context.Context) int64 { + id, err := _q.FirstID(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return id +} + +// Only returns a single ChannelMonitorDailyRollup entity found by the query, ensuring it only returns one. +// Returns a *NotSingularError when more than one ChannelMonitorDailyRollup entity is found. +// Returns a *NotFoundError when no ChannelMonitorDailyRollup entities are found. +func (_q *ChannelMonitorDailyRollupQuery) Only(ctx context.Context) (*ChannelMonitorDailyRollup, error) { + nodes, err := _q.Limit(2).All(setContextOp(ctx, _q.ctx, ent.OpQueryOnly)) + if err != nil { + return nil, err + } + switch len(nodes) { + case 1: + return nodes[0], nil + case 0: + return nil, &NotFoundError{channelmonitordailyrollup.Label} + default: + return nil, &NotSingularError{channelmonitordailyrollup.Label} + } +} + +// OnlyX is like Only, but panics if an error occurs. +func (_q *ChannelMonitorDailyRollupQuery) OnlyX(ctx context.Context) *ChannelMonitorDailyRollup { + node, err := _q.Only(ctx) + if err != nil { + panic(err) + } + return node +} + +// OnlyID is like Only, but returns the only ChannelMonitorDailyRollup ID in the query. +// Returns a *NotSingularError when more than one ChannelMonitorDailyRollup ID is found. +// Returns a *NotFoundError when no entities are found. +func (_q *ChannelMonitorDailyRollupQuery) OnlyID(ctx context.Context) (id int64, err error) { + var ids []int64 + if ids, err = _q.Limit(2).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryOnlyID)); err != nil { + return + } + switch len(ids) { + case 1: + id = ids[0] + case 0: + err = &NotFoundError{channelmonitordailyrollup.Label} + default: + err = &NotSingularError{channelmonitordailyrollup.Label} + } + return +} + +// OnlyIDX is like OnlyID, but panics if an error occurs. +func (_q *ChannelMonitorDailyRollupQuery) OnlyIDX(ctx context.Context) int64 { + id, err := _q.OnlyID(ctx) + if err != nil { + panic(err) + } + return id +} + +// All executes the query and returns a list of ChannelMonitorDailyRollups. +func (_q *ChannelMonitorDailyRollupQuery) All(ctx context.Context) ([]*ChannelMonitorDailyRollup, error) { + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryAll) + if err := _q.prepareQuery(ctx); err != nil { + return nil, err + } + qr := querierAll[[]*ChannelMonitorDailyRollup, *ChannelMonitorDailyRollupQuery]() + return withInterceptors[[]*ChannelMonitorDailyRollup](ctx, _q, qr, _q.inters) +} + +// AllX is like All, but panics if an error occurs. +func (_q *ChannelMonitorDailyRollupQuery) AllX(ctx context.Context) []*ChannelMonitorDailyRollup { + nodes, err := _q.All(ctx) + if err != nil { + panic(err) + } + return nodes +} + +// IDs executes the query and returns a list of ChannelMonitorDailyRollup IDs. +func (_q *ChannelMonitorDailyRollupQuery) IDs(ctx context.Context) (ids []int64, err error) { + if _q.ctx.Unique == nil && _q.path != nil { + _q.Unique(true) + } + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryIDs) + if err = _q.Select(channelmonitordailyrollup.FieldID).Scan(ctx, &ids); err != nil { + return nil, err + } + return ids, nil +} + +// IDsX is like IDs, but panics if an error occurs. +func (_q *ChannelMonitorDailyRollupQuery) IDsX(ctx context.Context) []int64 { + ids, err := _q.IDs(ctx) + if err != nil { + panic(err) + } + return ids +} + +// Count returns the count of the given query. +func (_q *ChannelMonitorDailyRollupQuery) Count(ctx context.Context) (int, error) { + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryCount) + if err := _q.prepareQuery(ctx); err != nil { + return 0, err + } + return withInterceptors[int](ctx, _q, querierCount[*ChannelMonitorDailyRollupQuery](), _q.inters) +} + +// CountX is like Count, but panics if an error occurs. +func (_q *ChannelMonitorDailyRollupQuery) CountX(ctx context.Context) int { + count, err := _q.Count(ctx) + if err != nil { + panic(err) + } + return count +} + +// Exist returns true if the query has elements in the graph. +func (_q *ChannelMonitorDailyRollupQuery) Exist(ctx context.Context) (bool, error) { + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryExist) + switch _, err := _q.FirstID(ctx); { + case IsNotFound(err): + return false, nil + case err != nil: + return false, fmt.Errorf("ent: check existence: %w", err) + default: + return true, nil + } +} + +// ExistX is like Exist, but panics if an error occurs. +func (_q *ChannelMonitorDailyRollupQuery) ExistX(ctx context.Context) bool { + exist, err := _q.Exist(ctx) + if err != nil { + panic(err) + } + return exist +} + +// Clone returns a duplicate of the ChannelMonitorDailyRollupQuery builder, including all associated steps. It can be +// used to prepare common query builders and use them differently after the clone is made. +func (_q *ChannelMonitorDailyRollupQuery) Clone() *ChannelMonitorDailyRollupQuery { + if _q == nil { + return nil + } + return &ChannelMonitorDailyRollupQuery{ + config: _q.config, + ctx: _q.ctx.Clone(), + order: append([]channelmonitordailyrollup.OrderOption{}, _q.order...), + inters: append([]Interceptor{}, _q.inters...), + predicates: append([]predicate.ChannelMonitorDailyRollup{}, _q.predicates...), + withMonitor: _q.withMonitor.Clone(), + // clone intermediate query. + sql: _q.sql.Clone(), + path: _q.path, + } +} + +// WithMonitor tells the query-builder to eager-load the nodes that are connected to +// the "monitor" edge. The optional arguments are used to configure the query builder of the edge. +func (_q *ChannelMonitorDailyRollupQuery) WithMonitor(opts ...func(*ChannelMonitorQuery)) *ChannelMonitorDailyRollupQuery { + query := (&ChannelMonitorClient{config: _q.config}).Query() + for _, opt := range opts { + opt(query) + } + _q.withMonitor = query + return _q +} + +// GroupBy is used to group vertices by one or more fields/columns. +// It is often used with aggregate functions, like: count, max, mean, min, sum. +// +// Example: +// +// var v []struct { +// MonitorID int64 `json:"monitor_id,omitempty"` +// Count int `json:"count,omitempty"` +// } +// +// client.ChannelMonitorDailyRollup.Query(). +// GroupBy(channelmonitordailyrollup.FieldMonitorID). +// Aggregate(ent.Count()). +// Scan(ctx, &v) +func (_q *ChannelMonitorDailyRollupQuery) GroupBy(field string, fields ...string) *ChannelMonitorDailyRollupGroupBy { + _q.ctx.Fields = append([]string{field}, fields...) + grbuild := &ChannelMonitorDailyRollupGroupBy{build: _q} + grbuild.flds = &_q.ctx.Fields + grbuild.label = channelmonitordailyrollup.Label + grbuild.scan = grbuild.Scan + return grbuild +} + +// Select allows the selection one or more fields/columns for the given query, +// instead of selecting all fields in the entity. +// +// Example: +// +// var v []struct { +// MonitorID int64 `json:"monitor_id,omitempty"` +// } +// +// client.ChannelMonitorDailyRollup.Query(). +// Select(channelmonitordailyrollup.FieldMonitorID). +// Scan(ctx, &v) +func (_q *ChannelMonitorDailyRollupQuery) Select(fields ...string) *ChannelMonitorDailyRollupSelect { + _q.ctx.Fields = append(_q.ctx.Fields, fields...) + sbuild := &ChannelMonitorDailyRollupSelect{ChannelMonitorDailyRollupQuery: _q} + sbuild.label = channelmonitordailyrollup.Label + sbuild.flds, sbuild.scan = &_q.ctx.Fields, sbuild.Scan + return sbuild +} + +// Aggregate returns a ChannelMonitorDailyRollupSelect configured with the given aggregations. +func (_q *ChannelMonitorDailyRollupQuery) Aggregate(fns ...AggregateFunc) *ChannelMonitorDailyRollupSelect { + return _q.Select().Aggregate(fns...) +} + +func (_q *ChannelMonitorDailyRollupQuery) prepareQuery(ctx context.Context) error { + for _, inter := range _q.inters { + if inter == nil { + return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)") + } + if trv, ok := inter.(Traverser); ok { + if err := trv.Traverse(ctx, _q); err != nil { + return err + } + } + } + for _, f := range _q.ctx.Fields { + if !channelmonitordailyrollup.ValidColumn(f) { + return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + } + if _q.path != nil { + prev, err := _q.path(ctx) + if err != nil { + return err + } + _q.sql = prev + } + return nil +} + +func (_q *ChannelMonitorDailyRollupQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*ChannelMonitorDailyRollup, error) { + var ( + nodes = []*ChannelMonitorDailyRollup{} + _spec = _q.querySpec() + loadedTypes = [1]bool{ + _q.withMonitor != nil, + } + ) + _spec.ScanValues = func(columns []string) ([]any, error) { + return (*ChannelMonitorDailyRollup).scanValues(nil, columns) + } + _spec.Assign = func(columns []string, values []any) error { + node := &ChannelMonitorDailyRollup{config: _q.config} + nodes = append(nodes, node) + node.Edges.loadedTypes = loadedTypes + return node.assignValues(columns, values) + } + if len(_q.modifiers) > 0 { + _spec.Modifiers = _q.modifiers + } + for i := range hooks { + hooks[i](ctx, _spec) + } + if err := sqlgraph.QueryNodes(ctx, _q.driver, _spec); err != nil { + return nil, err + } + if len(nodes) == 0 { + return nodes, nil + } + if query := _q.withMonitor; query != nil { + if err := _q.loadMonitor(ctx, query, nodes, nil, + func(n *ChannelMonitorDailyRollup, e *ChannelMonitor) { n.Edges.Monitor = e }); err != nil { + return nil, err + } + } + return nodes, nil +} + +func (_q *ChannelMonitorDailyRollupQuery) loadMonitor(ctx context.Context, query *ChannelMonitorQuery, nodes []*ChannelMonitorDailyRollup, init func(*ChannelMonitorDailyRollup), assign func(*ChannelMonitorDailyRollup, *ChannelMonitor)) error { + ids := make([]int64, 0, len(nodes)) + nodeids := make(map[int64][]*ChannelMonitorDailyRollup) + for i := range nodes { + fk := nodes[i].MonitorID + if _, ok := nodeids[fk]; !ok { + ids = append(ids, fk) + } + nodeids[fk] = append(nodeids[fk], nodes[i]) + } + if len(ids) == 0 { + return nil + } + query.Where(channelmonitor.IDIn(ids...)) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + nodes, ok := nodeids[n.ID] + if !ok { + return fmt.Errorf(`unexpected foreign-key "monitor_id" returned %v`, n.ID) + } + for i := range nodes { + assign(nodes[i], n) + } + } + return nil +} + +func (_q *ChannelMonitorDailyRollupQuery) sqlCount(ctx context.Context) (int, error) { + _spec := _q.querySpec() + if len(_q.modifiers) > 0 { + _spec.Modifiers = _q.modifiers + } + _spec.Node.Columns = _q.ctx.Fields + if len(_q.ctx.Fields) > 0 { + _spec.Unique = _q.ctx.Unique != nil && *_q.ctx.Unique + } + return sqlgraph.CountNodes(ctx, _q.driver, _spec) +} + +func (_q *ChannelMonitorDailyRollupQuery) querySpec() *sqlgraph.QuerySpec { + _spec := sqlgraph.NewQuerySpec(channelmonitordailyrollup.Table, channelmonitordailyrollup.Columns, sqlgraph.NewFieldSpec(channelmonitordailyrollup.FieldID, field.TypeInt64)) + _spec.From = _q.sql + if unique := _q.ctx.Unique; unique != nil { + _spec.Unique = *unique + } else if _q.path != nil { + _spec.Unique = true + } + if fields := _q.ctx.Fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, channelmonitordailyrollup.FieldID) + for i := range fields { + if fields[i] != channelmonitordailyrollup.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) + } + } + if _q.withMonitor != nil { + _spec.Node.AddColumnOnce(channelmonitordailyrollup.FieldMonitorID) + } + } + if ps := _q.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if limit := _q.ctx.Limit; limit != nil { + _spec.Limit = *limit + } + if offset := _q.ctx.Offset; offset != nil { + _spec.Offset = *offset + } + if ps := _q.order; len(ps) > 0 { + _spec.Order = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + return _spec +} + +func (_q *ChannelMonitorDailyRollupQuery) sqlQuery(ctx context.Context) *sql.Selector { + builder := sql.Dialect(_q.driver.Dialect()) + t1 := builder.Table(channelmonitordailyrollup.Table) + columns := _q.ctx.Fields + if len(columns) == 0 { + columns = channelmonitordailyrollup.Columns + } + selector := builder.Select(t1.Columns(columns...)...).From(t1) + if _q.sql != nil { + selector = _q.sql + selector.Select(selector.Columns(columns...)...) + } + if _q.ctx.Unique != nil && *_q.ctx.Unique { + selector.Distinct() + } + for _, m := range _q.modifiers { + m(selector) + } + for _, p := range _q.predicates { + p(selector) + } + for _, p := range _q.order { + p(selector) + } + if offset := _q.ctx.Offset; offset != nil { + // limit is mandatory for offset clause. We start + // with default value, and override it below if needed. + selector.Offset(*offset).Limit(math.MaxInt32) + } + if limit := _q.ctx.Limit; limit != nil { + selector.Limit(*limit) + } + return selector +} + +// ForUpdate locks the selected rows against concurrent updates, and prevent them from being +// updated, deleted or "selected ... for update" by other sessions, until the transaction is +// either committed or rolled-back. +func (_q *ChannelMonitorDailyRollupQuery) ForUpdate(opts ...sql.LockOption) *ChannelMonitorDailyRollupQuery { + if _q.driver.Dialect() == dialect.Postgres { + _q.Unique(false) + } + _q.modifiers = append(_q.modifiers, func(s *sql.Selector) { + s.ForUpdate(opts...) + }) + return _q +} + +// ForShare behaves similarly to ForUpdate, except that it acquires a shared mode lock +// on any rows that are read. Other sessions can read the rows, but cannot modify them +// until your transaction commits. +func (_q *ChannelMonitorDailyRollupQuery) ForShare(opts ...sql.LockOption) *ChannelMonitorDailyRollupQuery { + if _q.driver.Dialect() == dialect.Postgres { + _q.Unique(false) + } + _q.modifiers = append(_q.modifiers, func(s *sql.Selector) { + s.ForShare(opts...) + }) + return _q +} + +// ChannelMonitorDailyRollupGroupBy is the group-by builder for ChannelMonitorDailyRollup entities. +type ChannelMonitorDailyRollupGroupBy struct { + selector + build *ChannelMonitorDailyRollupQuery +} + +// Aggregate adds the given aggregation functions to the group-by query. +func (_g *ChannelMonitorDailyRollupGroupBy) Aggregate(fns ...AggregateFunc) *ChannelMonitorDailyRollupGroupBy { + _g.fns = append(_g.fns, fns...) + return _g +} + +// Scan applies the selector query and scans the result into the given value. +func (_g *ChannelMonitorDailyRollupGroupBy) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, _g.build.ctx, ent.OpQueryGroupBy) + if err := _g.build.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*ChannelMonitorDailyRollupQuery, *ChannelMonitorDailyRollupGroupBy](ctx, _g.build, _g, _g.build.inters, v) +} + +func (_g *ChannelMonitorDailyRollupGroupBy) sqlScan(ctx context.Context, root *ChannelMonitorDailyRollupQuery, v any) error { + selector := root.sqlQuery(ctx).Select() + aggregation := make([]string, 0, len(_g.fns)) + for _, fn := range _g.fns { + aggregation = append(aggregation, fn(selector)) + } + if len(selector.SelectedColumns()) == 0 { + columns := make([]string, 0, len(*_g.flds)+len(_g.fns)) + for _, f := range *_g.flds { + columns = append(columns, selector.C(f)) + } + columns = append(columns, aggregation...) + selector.Select(columns...) + } + selector.GroupBy(selector.Columns(*_g.flds...)...) + if err := selector.Err(); err != nil { + return err + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := _g.build.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} + +// ChannelMonitorDailyRollupSelect is the builder for selecting fields of ChannelMonitorDailyRollup entities. +type ChannelMonitorDailyRollupSelect struct { + *ChannelMonitorDailyRollupQuery + selector +} + +// Aggregate adds the given aggregation functions to the selector query. +func (_s *ChannelMonitorDailyRollupSelect) Aggregate(fns ...AggregateFunc) *ChannelMonitorDailyRollupSelect { + _s.fns = append(_s.fns, fns...) + return _s +} + +// Scan applies the selector query and scans the result into the given value. +func (_s *ChannelMonitorDailyRollupSelect) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, _s.ctx, ent.OpQuerySelect) + if err := _s.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*ChannelMonitorDailyRollupQuery, *ChannelMonitorDailyRollupSelect](ctx, _s.ChannelMonitorDailyRollupQuery, _s, _s.inters, v) +} + +func (_s *ChannelMonitorDailyRollupSelect) sqlScan(ctx context.Context, root *ChannelMonitorDailyRollupQuery, v any) error { + selector := root.sqlQuery(ctx) + aggregation := make([]string, 0, len(_s.fns)) + for _, fn := range _s.fns { + aggregation = append(aggregation, fn(selector)) + } + switch n := len(*_s.selector.flds); { + case n == 0 && len(aggregation) > 0: + selector.Select(aggregation...) + case n != 0 && len(aggregation) > 0: + selector.AppendSelect(aggregation...) + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := _s.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} diff --git a/backend/ent/channelmonitordailyrollup_update.go b/backend/ent/channelmonitordailyrollup_update.go new file mode 100644 index 00000000..02cd86c5 --- /dev/null +++ b/backend/ent/channelmonitordailyrollup_update.go @@ -0,0 +1,961 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitordailyrollup" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// ChannelMonitorDailyRollupUpdate is the builder for updating ChannelMonitorDailyRollup entities. +type ChannelMonitorDailyRollupUpdate struct { + config + hooks []Hook + mutation *ChannelMonitorDailyRollupMutation +} + +// Where appends a list predicates to the ChannelMonitorDailyRollupUpdate builder. +func (_u *ChannelMonitorDailyRollupUpdate) Where(ps ...predicate.ChannelMonitorDailyRollup) *ChannelMonitorDailyRollupUpdate { + _u.mutation.Where(ps...) + return _u +} + +// SetMonitorID sets the "monitor_id" field. +func (_u *ChannelMonitorDailyRollupUpdate) SetMonitorID(v int64) *ChannelMonitorDailyRollupUpdate { + _u.mutation.SetMonitorID(v) + return _u +} + +// SetNillableMonitorID sets the "monitor_id" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdate) SetNillableMonitorID(v *int64) *ChannelMonitorDailyRollupUpdate { + if v != nil { + _u.SetMonitorID(*v) + } + return _u +} + +// SetModel sets the "model" field. +func (_u *ChannelMonitorDailyRollupUpdate) SetModel(v string) *ChannelMonitorDailyRollupUpdate { + _u.mutation.SetModel(v) + return _u +} + +// SetNillableModel sets the "model" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdate) SetNillableModel(v *string) *ChannelMonitorDailyRollupUpdate { + if v != nil { + _u.SetModel(*v) + } + return _u +} + +// SetBucketDate sets the "bucket_date" field. +func (_u *ChannelMonitorDailyRollupUpdate) SetBucketDate(v time.Time) *ChannelMonitorDailyRollupUpdate { + _u.mutation.SetBucketDate(v) + return _u +} + +// SetNillableBucketDate sets the "bucket_date" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdate) SetNillableBucketDate(v *time.Time) *ChannelMonitorDailyRollupUpdate { + if v != nil { + _u.SetBucketDate(*v) + } + return _u +} + +// SetTotalChecks sets the "total_checks" field. +func (_u *ChannelMonitorDailyRollupUpdate) SetTotalChecks(v int) *ChannelMonitorDailyRollupUpdate { + _u.mutation.ResetTotalChecks() + _u.mutation.SetTotalChecks(v) + return _u +} + +// SetNillableTotalChecks sets the "total_checks" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdate) SetNillableTotalChecks(v *int) *ChannelMonitorDailyRollupUpdate { + if v != nil { + _u.SetTotalChecks(*v) + } + return _u +} + +// AddTotalChecks adds value to the "total_checks" field. +func (_u *ChannelMonitorDailyRollupUpdate) AddTotalChecks(v int) *ChannelMonitorDailyRollupUpdate { + _u.mutation.AddTotalChecks(v) + return _u +} + +// SetOkCount sets the "ok_count" field. +func (_u *ChannelMonitorDailyRollupUpdate) SetOkCount(v int) *ChannelMonitorDailyRollupUpdate { + _u.mutation.ResetOkCount() + _u.mutation.SetOkCount(v) + return _u +} + +// SetNillableOkCount sets the "ok_count" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdate) SetNillableOkCount(v *int) *ChannelMonitorDailyRollupUpdate { + if v != nil { + _u.SetOkCount(*v) + } + return _u +} + +// AddOkCount adds value to the "ok_count" field. +func (_u *ChannelMonitorDailyRollupUpdate) AddOkCount(v int) *ChannelMonitorDailyRollupUpdate { + _u.mutation.AddOkCount(v) + return _u +} + +// SetOperationalCount sets the "operational_count" field. +func (_u *ChannelMonitorDailyRollupUpdate) SetOperationalCount(v int) *ChannelMonitorDailyRollupUpdate { + _u.mutation.ResetOperationalCount() + _u.mutation.SetOperationalCount(v) + return _u +} + +// SetNillableOperationalCount sets the "operational_count" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdate) SetNillableOperationalCount(v *int) *ChannelMonitorDailyRollupUpdate { + if v != nil { + _u.SetOperationalCount(*v) + } + return _u +} + +// AddOperationalCount adds value to the "operational_count" field. +func (_u *ChannelMonitorDailyRollupUpdate) AddOperationalCount(v int) *ChannelMonitorDailyRollupUpdate { + _u.mutation.AddOperationalCount(v) + return _u +} + +// SetDegradedCount sets the "degraded_count" field. +func (_u *ChannelMonitorDailyRollupUpdate) SetDegradedCount(v int) *ChannelMonitorDailyRollupUpdate { + _u.mutation.ResetDegradedCount() + _u.mutation.SetDegradedCount(v) + return _u +} + +// SetNillableDegradedCount sets the "degraded_count" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdate) SetNillableDegradedCount(v *int) *ChannelMonitorDailyRollupUpdate { + if v != nil { + _u.SetDegradedCount(*v) + } + return _u +} + +// AddDegradedCount adds value to the "degraded_count" field. +func (_u *ChannelMonitorDailyRollupUpdate) AddDegradedCount(v int) *ChannelMonitorDailyRollupUpdate { + _u.mutation.AddDegradedCount(v) + return _u +} + +// SetFailedCount sets the "failed_count" field. +func (_u *ChannelMonitorDailyRollupUpdate) SetFailedCount(v int) *ChannelMonitorDailyRollupUpdate { + _u.mutation.ResetFailedCount() + _u.mutation.SetFailedCount(v) + return _u +} + +// SetNillableFailedCount sets the "failed_count" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdate) SetNillableFailedCount(v *int) *ChannelMonitorDailyRollupUpdate { + if v != nil { + _u.SetFailedCount(*v) + } + return _u +} + +// AddFailedCount adds value to the "failed_count" field. +func (_u *ChannelMonitorDailyRollupUpdate) AddFailedCount(v int) *ChannelMonitorDailyRollupUpdate { + _u.mutation.AddFailedCount(v) + return _u +} + +// SetErrorCount sets the "error_count" field. +func (_u *ChannelMonitorDailyRollupUpdate) SetErrorCount(v int) *ChannelMonitorDailyRollupUpdate { + _u.mutation.ResetErrorCount() + _u.mutation.SetErrorCount(v) + return _u +} + +// SetNillableErrorCount sets the "error_count" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdate) SetNillableErrorCount(v *int) *ChannelMonitorDailyRollupUpdate { + if v != nil { + _u.SetErrorCount(*v) + } + return _u +} + +// AddErrorCount adds value to the "error_count" field. +func (_u *ChannelMonitorDailyRollupUpdate) AddErrorCount(v int) *ChannelMonitorDailyRollupUpdate { + _u.mutation.AddErrorCount(v) + return _u +} + +// SetSumLatencyMs sets the "sum_latency_ms" field. +func (_u *ChannelMonitorDailyRollupUpdate) SetSumLatencyMs(v int64) *ChannelMonitorDailyRollupUpdate { + _u.mutation.ResetSumLatencyMs() + _u.mutation.SetSumLatencyMs(v) + return _u +} + +// SetNillableSumLatencyMs sets the "sum_latency_ms" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdate) SetNillableSumLatencyMs(v *int64) *ChannelMonitorDailyRollupUpdate { + if v != nil { + _u.SetSumLatencyMs(*v) + } + return _u +} + +// AddSumLatencyMs adds value to the "sum_latency_ms" field. +func (_u *ChannelMonitorDailyRollupUpdate) AddSumLatencyMs(v int64) *ChannelMonitorDailyRollupUpdate { + _u.mutation.AddSumLatencyMs(v) + return _u +} + +// SetCountLatency sets the "count_latency" field. +func (_u *ChannelMonitorDailyRollupUpdate) SetCountLatency(v int) *ChannelMonitorDailyRollupUpdate { + _u.mutation.ResetCountLatency() + _u.mutation.SetCountLatency(v) + return _u +} + +// SetNillableCountLatency sets the "count_latency" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdate) SetNillableCountLatency(v *int) *ChannelMonitorDailyRollupUpdate { + if v != nil { + _u.SetCountLatency(*v) + } + return _u +} + +// AddCountLatency adds value to the "count_latency" field. +func (_u *ChannelMonitorDailyRollupUpdate) AddCountLatency(v int) *ChannelMonitorDailyRollupUpdate { + _u.mutation.AddCountLatency(v) + return _u +} + +// SetSumPingLatencyMs sets the "sum_ping_latency_ms" field. +func (_u *ChannelMonitorDailyRollupUpdate) SetSumPingLatencyMs(v int64) *ChannelMonitorDailyRollupUpdate { + _u.mutation.ResetSumPingLatencyMs() + _u.mutation.SetSumPingLatencyMs(v) + return _u +} + +// SetNillableSumPingLatencyMs sets the "sum_ping_latency_ms" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdate) SetNillableSumPingLatencyMs(v *int64) *ChannelMonitorDailyRollupUpdate { + if v != nil { + _u.SetSumPingLatencyMs(*v) + } + return _u +} + +// AddSumPingLatencyMs adds value to the "sum_ping_latency_ms" field. +func (_u *ChannelMonitorDailyRollupUpdate) AddSumPingLatencyMs(v int64) *ChannelMonitorDailyRollupUpdate { + _u.mutation.AddSumPingLatencyMs(v) + return _u +} + +// SetCountPingLatency sets the "count_ping_latency" field. +func (_u *ChannelMonitorDailyRollupUpdate) SetCountPingLatency(v int) *ChannelMonitorDailyRollupUpdate { + _u.mutation.ResetCountPingLatency() + _u.mutation.SetCountPingLatency(v) + return _u +} + +// SetNillableCountPingLatency sets the "count_ping_latency" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdate) SetNillableCountPingLatency(v *int) *ChannelMonitorDailyRollupUpdate { + if v != nil { + _u.SetCountPingLatency(*v) + } + return _u +} + +// AddCountPingLatency adds value to the "count_ping_latency" field. +func (_u *ChannelMonitorDailyRollupUpdate) AddCountPingLatency(v int) *ChannelMonitorDailyRollupUpdate { + _u.mutation.AddCountPingLatency(v) + return _u +} + +// SetComputedAt sets the "computed_at" field. +func (_u *ChannelMonitorDailyRollupUpdate) SetComputedAt(v time.Time) *ChannelMonitorDailyRollupUpdate { + _u.mutation.SetComputedAt(v) + return _u +} + +// SetMonitor sets the "monitor" edge to the ChannelMonitor entity. +func (_u *ChannelMonitorDailyRollupUpdate) SetMonitor(v *ChannelMonitor) *ChannelMonitorDailyRollupUpdate { + return _u.SetMonitorID(v.ID) +} + +// Mutation returns the ChannelMonitorDailyRollupMutation object of the builder. +func (_u *ChannelMonitorDailyRollupUpdate) Mutation() *ChannelMonitorDailyRollupMutation { + return _u.mutation +} + +// ClearMonitor clears the "monitor" edge to the ChannelMonitor entity. +func (_u *ChannelMonitorDailyRollupUpdate) ClearMonitor() *ChannelMonitorDailyRollupUpdate { + _u.mutation.ClearMonitor() + return _u +} + +// Save executes the query and returns the number of nodes affected by the update operation. +func (_u *ChannelMonitorDailyRollupUpdate) Save(ctx context.Context) (int, error) { + _u.defaults() + return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (_u *ChannelMonitorDailyRollupUpdate) SaveX(ctx context.Context) int { + affected, err := _u.Save(ctx) + if err != nil { + panic(err) + } + return affected +} + +// Exec executes the query. +func (_u *ChannelMonitorDailyRollupUpdate) Exec(ctx context.Context) error { + _, err := _u.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_u *ChannelMonitorDailyRollupUpdate) ExecX(ctx context.Context) { + if err := _u.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (_u *ChannelMonitorDailyRollupUpdate) defaults() { + if _, ok := _u.mutation.ComputedAt(); !ok { + v := channelmonitordailyrollup.UpdateDefaultComputedAt() + _u.mutation.SetComputedAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_u *ChannelMonitorDailyRollupUpdate) check() error { + if v, ok := _u.mutation.Model(); ok { + if err := channelmonitordailyrollup.ModelValidator(v); err != nil { + return &ValidationError{Name: "model", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorDailyRollup.model": %w`, err)} + } + } + if _u.mutation.MonitorCleared() && len(_u.mutation.MonitorIDs()) > 0 { + return errors.New(`ent: clearing a required unique edge "ChannelMonitorDailyRollup.monitor"`) + } + return nil +} + +func (_u *ChannelMonitorDailyRollupUpdate) sqlSave(ctx context.Context) (_node int, err error) { + if err := _u.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(channelmonitordailyrollup.Table, channelmonitordailyrollup.Columns, sqlgraph.NewFieldSpec(channelmonitordailyrollup.FieldID, field.TypeInt64)) + if ps := _u.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := _u.mutation.Model(); ok { + _spec.SetField(channelmonitordailyrollup.FieldModel, field.TypeString, value) + } + if value, ok := _u.mutation.BucketDate(); ok { + _spec.SetField(channelmonitordailyrollup.FieldBucketDate, field.TypeTime, value) + } + if value, ok := _u.mutation.TotalChecks(); ok { + _spec.SetField(channelmonitordailyrollup.FieldTotalChecks, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedTotalChecks(); ok { + _spec.AddField(channelmonitordailyrollup.FieldTotalChecks, field.TypeInt, value) + } + if value, ok := _u.mutation.OkCount(); ok { + _spec.SetField(channelmonitordailyrollup.FieldOkCount, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedOkCount(); ok { + _spec.AddField(channelmonitordailyrollup.FieldOkCount, field.TypeInt, value) + } + if value, ok := _u.mutation.OperationalCount(); ok { + _spec.SetField(channelmonitordailyrollup.FieldOperationalCount, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedOperationalCount(); ok { + _spec.AddField(channelmonitordailyrollup.FieldOperationalCount, field.TypeInt, value) + } + if value, ok := _u.mutation.DegradedCount(); ok { + _spec.SetField(channelmonitordailyrollup.FieldDegradedCount, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedDegradedCount(); ok { + _spec.AddField(channelmonitordailyrollup.FieldDegradedCount, field.TypeInt, value) + } + if value, ok := _u.mutation.FailedCount(); ok { + _spec.SetField(channelmonitordailyrollup.FieldFailedCount, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedFailedCount(); ok { + _spec.AddField(channelmonitordailyrollup.FieldFailedCount, field.TypeInt, value) + } + if value, ok := _u.mutation.ErrorCount(); ok { + _spec.SetField(channelmonitordailyrollup.FieldErrorCount, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedErrorCount(); ok { + _spec.AddField(channelmonitordailyrollup.FieldErrorCount, field.TypeInt, value) + } + if value, ok := _u.mutation.SumLatencyMs(); ok { + _spec.SetField(channelmonitordailyrollup.FieldSumLatencyMs, field.TypeInt64, value) + } + if value, ok := _u.mutation.AddedSumLatencyMs(); ok { + _spec.AddField(channelmonitordailyrollup.FieldSumLatencyMs, field.TypeInt64, value) + } + if value, ok := _u.mutation.CountLatency(); ok { + _spec.SetField(channelmonitordailyrollup.FieldCountLatency, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedCountLatency(); ok { + _spec.AddField(channelmonitordailyrollup.FieldCountLatency, field.TypeInt, value) + } + if value, ok := _u.mutation.SumPingLatencyMs(); ok { + _spec.SetField(channelmonitordailyrollup.FieldSumPingLatencyMs, field.TypeInt64, value) + } + if value, ok := _u.mutation.AddedSumPingLatencyMs(); ok { + _spec.AddField(channelmonitordailyrollup.FieldSumPingLatencyMs, field.TypeInt64, value) + } + if value, ok := _u.mutation.CountPingLatency(); ok { + _spec.SetField(channelmonitordailyrollup.FieldCountPingLatency, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedCountPingLatency(); ok { + _spec.AddField(channelmonitordailyrollup.FieldCountPingLatency, field.TypeInt, value) + } + if value, ok := _u.mutation.ComputedAt(); ok { + _spec.SetField(channelmonitordailyrollup.FieldComputedAt, field.TypeTime, value) + } + if _u.mutation.MonitorCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: channelmonitordailyrollup.MonitorTable, + Columns: []string{channelmonitordailyrollup.MonitorColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.MonitorIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: channelmonitordailyrollup.MonitorTable, + Columns: []string{channelmonitordailyrollup.MonitorColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if _node, err = sqlgraph.UpdateNodes(ctx, _u.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{channelmonitordailyrollup.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return 0, err + } + _u.mutation.done = true + return _node, nil +} + +// ChannelMonitorDailyRollupUpdateOne is the builder for updating a single ChannelMonitorDailyRollup entity. +type ChannelMonitorDailyRollupUpdateOne struct { + config + fields []string + hooks []Hook + mutation *ChannelMonitorDailyRollupMutation +} + +// SetMonitorID sets the "monitor_id" field. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetMonitorID(v int64) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.SetMonitorID(v) + return _u +} + +// SetNillableMonitorID sets the "monitor_id" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetNillableMonitorID(v *int64) *ChannelMonitorDailyRollupUpdateOne { + if v != nil { + _u.SetMonitorID(*v) + } + return _u +} + +// SetModel sets the "model" field. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetModel(v string) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.SetModel(v) + return _u +} + +// SetNillableModel sets the "model" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetNillableModel(v *string) *ChannelMonitorDailyRollupUpdateOne { + if v != nil { + _u.SetModel(*v) + } + return _u +} + +// SetBucketDate sets the "bucket_date" field. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetBucketDate(v time.Time) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.SetBucketDate(v) + return _u +} + +// SetNillableBucketDate sets the "bucket_date" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetNillableBucketDate(v *time.Time) *ChannelMonitorDailyRollupUpdateOne { + if v != nil { + _u.SetBucketDate(*v) + } + return _u +} + +// SetTotalChecks sets the "total_checks" field. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetTotalChecks(v int) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.ResetTotalChecks() + _u.mutation.SetTotalChecks(v) + return _u +} + +// SetNillableTotalChecks sets the "total_checks" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetNillableTotalChecks(v *int) *ChannelMonitorDailyRollupUpdateOne { + if v != nil { + _u.SetTotalChecks(*v) + } + return _u +} + +// AddTotalChecks adds value to the "total_checks" field. +func (_u *ChannelMonitorDailyRollupUpdateOne) AddTotalChecks(v int) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.AddTotalChecks(v) + return _u +} + +// SetOkCount sets the "ok_count" field. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetOkCount(v int) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.ResetOkCount() + _u.mutation.SetOkCount(v) + return _u +} + +// SetNillableOkCount sets the "ok_count" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetNillableOkCount(v *int) *ChannelMonitorDailyRollupUpdateOne { + if v != nil { + _u.SetOkCount(*v) + } + return _u +} + +// AddOkCount adds value to the "ok_count" field. +func (_u *ChannelMonitorDailyRollupUpdateOne) AddOkCount(v int) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.AddOkCount(v) + return _u +} + +// SetOperationalCount sets the "operational_count" field. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetOperationalCount(v int) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.ResetOperationalCount() + _u.mutation.SetOperationalCount(v) + return _u +} + +// SetNillableOperationalCount sets the "operational_count" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetNillableOperationalCount(v *int) *ChannelMonitorDailyRollupUpdateOne { + if v != nil { + _u.SetOperationalCount(*v) + } + return _u +} + +// AddOperationalCount adds value to the "operational_count" field. +func (_u *ChannelMonitorDailyRollupUpdateOne) AddOperationalCount(v int) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.AddOperationalCount(v) + return _u +} + +// SetDegradedCount sets the "degraded_count" field. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetDegradedCount(v int) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.ResetDegradedCount() + _u.mutation.SetDegradedCount(v) + return _u +} + +// SetNillableDegradedCount sets the "degraded_count" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetNillableDegradedCount(v *int) *ChannelMonitorDailyRollupUpdateOne { + if v != nil { + _u.SetDegradedCount(*v) + } + return _u +} + +// AddDegradedCount adds value to the "degraded_count" field. +func (_u *ChannelMonitorDailyRollupUpdateOne) AddDegradedCount(v int) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.AddDegradedCount(v) + return _u +} + +// SetFailedCount sets the "failed_count" field. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetFailedCount(v int) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.ResetFailedCount() + _u.mutation.SetFailedCount(v) + return _u +} + +// SetNillableFailedCount sets the "failed_count" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetNillableFailedCount(v *int) *ChannelMonitorDailyRollupUpdateOne { + if v != nil { + _u.SetFailedCount(*v) + } + return _u +} + +// AddFailedCount adds value to the "failed_count" field. +func (_u *ChannelMonitorDailyRollupUpdateOne) AddFailedCount(v int) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.AddFailedCount(v) + return _u +} + +// SetErrorCount sets the "error_count" field. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetErrorCount(v int) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.ResetErrorCount() + _u.mutation.SetErrorCount(v) + return _u +} + +// SetNillableErrorCount sets the "error_count" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetNillableErrorCount(v *int) *ChannelMonitorDailyRollupUpdateOne { + if v != nil { + _u.SetErrorCount(*v) + } + return _u +} + +// AddErrorCount adds value to the "error_count" field. +func (_u *ChannelMonitorDailyRollupUpdateOne) AddErrorCount(v int) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.AddErrorCount(v) + return _u +} + +// SetSumLatencyMs sets the "sum_latency_ms" field. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetSumLatencyMs(v int64) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.ResetSumLatencyMs() + _u.mutation.SetSumLatencyMs(v) + return _u +} + +// SetNillableSumLatencyMs sets the "sum_latency_ms" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetNillableSumLatencyMs(v *int64) *ChannelMonitorDailyRollupUpdateOne { + if v != nil { + _u.SetSumLatencyMs(*v) + } + return _u +} + +// AddSumLatencyMs adds value to the "sum_latency_ms" field. +func (_u *ChannelMonitorDailyRollupUpdateOne) AddSumLatencyMs(v int64) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.AddSumLatencyMs(v) + return _u +} + +// SetCountLatency sets the "count_latency" field. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetCountLatency(v int) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.ResetCountLatency() + _u.mutation.SetCountLatency(v) + return _u +} + +// SetNillableCountLatency sets the "count_latency" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetNillableCountLatency(v *int) *ChannelMonitorDailyRollupUpdateOne { + if v != nil { + _u.SetCountLatency(*v) + } + return _u +} + +// AddCountLatency adds value to the "count_latency" field. +func (_u *ChannelMonitorDailyRollupUpdateOne) AddCountLatency(v int) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.AddCountLatency(v) + return _u +} + +// SetSumPingLatencyMs sets the "sum_ping_latency_ms" field. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetSumPingLatencyMs(v int64) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.ResetSumPingLatencyMs() + _u.mutation.SetSumPingLatencyMs(v) + return _u +} + +// SetNillableSumPingLatencyMs sets the "sum_ping_latency_ms" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetNillableSumPingLatencyMs(v *int64) *ChannelMonitorDailyRollupUpdateOne { + if v != nil { + _u.SetSumPingLatencyMs(*v) + } + return _u +} + +// AddSumPingLatencyMs adds value to the "sum_ping_latency_ms" field. +func (_u *ChannelMonitorDailyRollupUpdateOne) AddSumPingLatencyMs(v int64) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.AddSumPingLatencyMs(v) + return _u +} + +// SetCountPingLatency sets the "count_ping_latency" field. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetCountPingLatency(v int) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.ResetCountPingLatency() + _u.mutation.SetCountPingLatency(v) + return _u +} + +// SetNillableCountPingLatency sets the "count_ping_latency" field if the given value is not nil. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetNillableCountPingLatency(v *int) *ChannelMonitorDailyRollupUpdateOne { + if v != nil { + _u.SetCountPingLatency(*v) + } + return _u +} + +// AddCountPingLatency adds value to the "count_ping_latency" field. +func (_u *ChannelMonitorDailyRollupUpdateOne) AddCountPingLatency(v int) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.AddCountPingLatency(v) + return _u +} + +// SetComputedAt sets the "computed_at" field. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetComputedAt(v time.Time) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.SetComputedAt(v) + return _u +} + +// SetMonitor sets the "monitor" edge to the ChannelMonitor entity. +func (_u *ChannelMonitorDailyRollupUpdateOne) SetMonitor(v *ChannelMonitor) *ChannelMonitorDailyRollupUpdateOne { + return _u.SetMonitorID(v.ID) +} + +// Mutation returns the ChannelMonitorDailyRollupMutation object of the builder. +func (_u *ChannelMonitorDailyRollupUpdateOne) Mutation() *ChannelMonitorDailyRollupMutation { + return _u.mutation +} + +// ClearMonitor clears the "monitor" edge to the ChannelMonitor entity. +func (_u *ChannelMonitorDailyRollupUpdateOne) ClearMonitor() *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.ClearMonitor() + return _u +} + +// Where appends a list predicates to the ChannelMonitorDailyRollupUpdate builder. +func (_u *ChannelMonitorDailyRollupUpdateOne) Where(ps ...predicate.ChannelMonitorDailyRollup) *ChannelMonitorDailyRollupUpdateOne { + _u.mutation.Where(ps...) + return _u +} + +// Select allows selecting one or more fields (columns) of the returned entity. +// The default is selecting all fields defined in the entity schema. +func (_u *ChannelMonitorDailyRollupUpdateOne) Select(field string, fields ...string) *ChannelMonitorDailyRollupUpdateOne { + _u.fields = append([]string{field}, fields...) + return _u +} + +// Save executes the query and returns the updated ChannelMonitorDailyRollup entity. +func (_u *ChannelMonitorDailyRollupUpdateOne) Save(ctx context.Context) (*ChannelMonitorDailyRollup, error) { + _u.defaults() + return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (_u *ChannelMonitorDailyRollupUpdateOne) SaveX(ctx context.Context) *ChannelMonitorDailyRollup { + node, err := _u.Save(ctx) + if err != nil { + panic(err) + } + return node +} + +// Exec executes the query on the entity. +func (_u *ChannelMonitorDailyRollupUpdateOne) Exec(ctx context.Context) error { + _, err := _u.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_u *ChannelMonitorDailyRollupUpdateOne) ExecX(ctx context.Context) { + if err := _u.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (_u *ChannelMonitorDailyRollupUpdateOne) defaults() { + if _, ok := _u.mutation.ComputedAt(); !ok { + v := channelmonitordailyrollup.UpdateDefaultComputedAt() + _u.mutation.SetComputedAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_u *ChannelMonitorDailyRollupUpdateOne) check() error { + if v, ok := _u.mutation.Model(); ok { + if err := channelmonitordailyrollup.ModelValidator(v); err != nil { + return &ValidationError{Name: "model", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorDailyRollup.model": %w`, err)} + } + } + if _u.mutation.MonitorCleared() && len(_u.mutation.MonitorIDs()) > 0 { + return errors.New(`ent: clearing a required unique edge "ChannelMonitorDailyRollup.monitor"`) + } + return nil +} + +func (_u *ChannelMonitorDailyRollupUpdateOne) sqlSave(ctx context.Context) (_node *ChannelMonitorDailyRollup, err error) { + if err := _u.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(channelmonitordailyrollup.Table, channelmonitordailyrollup.Columns, sqlgraph.NewFieldSpec(channelmonitordailyrollup.FieldID, field.TypeInt64)) + id, ok := _u.mutation.ID() + if !ok { + return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "ChannelMonitorDailyRollup.id" for update`)} + } + _spec.Node.ID.Value = id + if fields := _u.fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, channelmonitordailyrollup.FieldID) + for _, f := range fields { + if !channelmonitordailyrollup.ValidColumn(f) { + return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + if f != channelmonitordailyrollup.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, f) + } + } + } + if ps := _u.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := _u.mutation.Model(); ok { + _spec.SetField(channelmonitordailyrollup.FieldModel, field.TypeString, value) + } + if value, ok := _u.mutation.BucketDate(); ok { + _spec.SetField(channelmonitordailyrollup.FieldBucketDate, field.TypeTime, value) + } + if value, ok := _u.mutation.TotalChecks(); ok { + _spec.SetField(channelmonitordailyrollup.FieldTotalChecks, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedTotalChecks(); ok { + _spec.AddField(channelmonitordailyrollup.FieldTotalChecks, field.TypeInt, value) + } + if value, ok := _u.mutation.OkCount(); ok { + _spec.SetField(channelmonitordailyrollup.FieldOkCount, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedOkCount(); ok { + _spec.AddField(channelmonitordailyrollup.FieldOkCount, field.TypeInt, value) + } + if value, ok := _u.mutation.OperationalCount(); ok { + _spec.SetField(channelmonitordailyrollup.FieldOperationalCount, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedOperationalCount(); ok { + _spec.AddField(channelmonitordailyrollup.FieldOperationalCount, field.TypeInt, value) + } + if value, ok := _u.mutation.DegradedCount(); ok { + _spec.SetField(channelmonitordailyrollup.FieldDegradedCount, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedDegradedCount(); ok { + _spec.AddField(channelmonitordailyrollup.FieldDegradedCount, field.TypeInt, value) + } + if value, ok := _u.mutation.FailedCount(); ok { + _spec.SetField(channelmonitordailyrollup.FieldFailedCount, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedFailedCount(); ok { + _spec.AddField(channelmonitordailyrollup.FieldFailedCount, field.TypeInt, value) + } + if value, ok := _u.mutation.ErrorCount(); ok { + _spec.SetField(channelmonitordailyrollup.FieldErrorCount, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedErrorCount(); ok { + _spec.AddField(channelmonitordailyrollup.FieldErrorCount, field.TypeInt, value) + } + if value, ok := _u.mutation.SumLatencyMs(); ok { + _spec.SetField(channelmonitordailyrollup.FieldSumLatencyMs, field.TypeInt64, value) + } + if value, ok := _u.mutation.AddedSumLatencyMs(); ok { + _spec.AddField(channelmonitordailyrollup.FieldSumLatencyMs, field.TypeInt64, value) + } + if value, ok := _u.mutation.CountLatency(); ok { + _spec.SetField(channelmonitordailyrollup.FieldCountLatency, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedCountLatency(); ok { + _spec.AddField(channelmonitordailyrollup.FieldCountLatency, field.TypeInt, value) + } + if value, ok := _u.mutation.SumPingLatencyMs(); ok { + _spec.SetField(channelmonitordailyrollup.FieldSumPingLatencyMs, field.TypeInt64, value) + } + if value, ok := _u.mutation.AddedSumPingLatencyMs(); ok { + _spec.AddField(channelmonitordailyrollup.FieldSumPingLatencyMs, field.TypeInt64, value) + } + if value, ok := _u.mutation.CountPingLatency(); ok { + _spec.SetField(channelmonitordailyrollup.FieldCountPingLatency, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedCountPingLatency(); ok { + _spec.AddField(channelmonitordailyrollup.FieldCountPingLatency, field.TypeInt, value) + } + if value, ok := _u.mutation.ComputedAt(); ok { + _spec.SetField(channelmonitordailyrollup.FieldComputedAt, field.TypeTime, value) + } + if _u.mutation.MonitorCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: channelmonitordailyrollup.MonitorTable, + Columns: []string{channelmonitordailyrollup.MonitorColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.MonitorIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: channelmonitordailyrollup.MonitorTable, + Columns: []string{channelmonitordailyrollup.MonitorColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + _node = &ChannelMonitorDailyRollup{config: _u.config} + _spec.Assign = _node.assignValues + _spec.ScanValues = _node.scanValues + if err = sqlgraph.UpdateNode(ctx, _u.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{channelmonitordailyrollup.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + _u.mutation.done = true + return _node, nil +} diff --git a/backend/ent/channelmonitorhistory.go b/backend/ent/channelmonitorhistory.go new file mode 100644 index 00000000..70dde542 --- /dev/null +++ b/backend/ent/channelmonitorhistory.go @@ -0,0 +1,207 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "fmt" + "strings" + "time" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory" +) + +// ChannelMonitorHistory is the model entity for the ChannelMonitorHistory schema. +type ChannelMonitorHistory struct { + config `json:"-"` + // ID of the ent. + ID int64 `json:"id,omitempty"` + // MonitorID holds the value of the "monitor_id" field. + MonitorID int64 `json:"monitor_id,omitempty"` + // Model holds the value of the "model" field. + Model string `json:"model,omitempty"` + // Status holds the value of the "status" field. + Status channelmonitorhistory.Status `json:"status,omitempty"` + // LatencyMs holds the value of the "latency_ms" field. + LatencyMs *int `json:"latency_ms,omitempty"` + // PingLatencyMs holds the value of the "ping_latency_ms" field. + PingLatencyMs *int `json:"ping_latency_ms,omitempty"` + // Message holds the value of the "message" field. + Message string `json:"message,omitempty"` + // CheckedAt holds the value of the "checked_at" field. + CheckedAt time.Time `json:"checked_at,omitempty"` + // Edges holds the relations/edges for other nodes in the graph. + // The values are being populated by the ChannelMonitorHistoryQuery when eager-loading is set. + Edges ChannelMonitorHistoryEdges `json:"edges"` + selectValues sql.SelectValues +} + +// ChannelMonitorHistoryEdges holds the relations/edges for other nodes in the graph. +type ChannelMonitorHistoryEdges struct { + // Monitor holds the value of the monitor edge. + Monitor *ChannelMonitor `json:"monitor,omitempty"` + // loadedTypes holds the information for reporting if a + // type was loaded (or requested) in eager-loading or not. + loadedTypes [1]bool +} + +// MonitorOrErr returns the Monitor value or an error if the edge +// was not loaded in eager-loading, or loaded but was not found. +func (e ChannelMonitorHistoryEdges) MonitorOrErr() (*ChannelMonitor, error) { + if e.Monitor != nil { + return e.Monitor, nil + } else if e.loadedTypes[0] { + return nil, &NotFoundError{label: channelmonitor.Label} + } + return nil, &NotLoadedError{edge: "monitor"} +} + +// scanValues returns the types for scanning values from sql.Rows. +func (*ChannelMonitorHistory) scanValues(columns []string) ([]any, error) { + values := make([]any, len(columns)) + for i := range columns { + switch columns[i] { + case channelmonitorhistory.FieldID, channelmonitorhistory.FieldMonitorID, channelmonitorhistory.FieldLatencyMs, channelmonitorhistory.FieldPingLatencyMs: + values[i] = new(sql.NullInt64) + case channelmonitorhistory.FieldModel, channelmonitorhistory.FieldStatus, channelmonitorhistory.FieldMessage: + values[i] = new(sql.NullString) + case channelmonitorhistory.FieldCheckedAt: + values[i] = new(sql.NullTime) + default: + values[i] = new(sql.UnknownType) + } + } + return values, nil +} + +// assignValues assigns the values that were returned from sql.Rows (after scanning) +// to the ChannelMonitorHistory fields. +func (_m *ChannelMonitorHistory) assignValues(columns []string, values []any) error { + if m, n := len(values), len(columns); m < n { + return fmt.Errorf("mismatch number of scan values: %d != %d", m, n) + } + for i := range columns { + switch columns[i] { + case channelmonitorhistory.FieldID: + value, ok := values[i].(*sql.NullInt64) + if !ok { + return fmt.Errorf("unexpected type %T for field id", value) + } + _m.ID = int64(value.Int64) + case channelmonitorhistory.FieldMonitorID: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field monitor_id", values[i]) + } else if value.Valid { + _m.MonitorID = value.Int64 + } + case channelmonitorhistory.FieldModel: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field model", values[i]) + } else if value.Valid { + _m.Model = value.String + } + case channelmonitorhistory.FieldStatus: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field status", values[i]) + } else if value.Valid { + _m.Status = channelmonitorhistory.Status(value.String) + } + case channelmonitorhistory.FieldLatencyMs: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field latency_ms", values[i]) + } else if value.Valid { + _m.LatencyMs = new(int) + *_m.LatencyMs = int(value.Int64) + } + case channelmonitorhistory.FieldPingLatencyMs: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field ping_latency_ms", values[i]) + } else if value.Valid { + _m.PingLatencyMs = new(int) + *_m.PingLatencyMs = int(value.Int64) + } + case channelmonitorhistory.FieldMessage: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field message", values[i]) + } else if value.Valid { + _m.Message = value.String + } + case channelmonitorhistory.FieldCheckedAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field checked_at", values[i]) + } else if value.Valid { + _m.CheckedAt = value.Time + } + default: + _m.selectValues.Set(columns[i], values[i]) + } + } + return nil +} + +// Value returns the ent.Value that was dynamically selected and assigned to the ChannelMonitorHistory. +// This includes values selected through modifiers, order, etc. +func (_m *ChannelMonitorHistory) Value(name string) (ent.Value, error) { + return _m.selectValues.Get(name) +} + +// QueryMonitor queries the "monitor" edge of the ChannelMonitorHistory entity. +func (_m *ChannelMonitorHistory) QueryMonitor() *ChannelMonitorQuery { + return NewChannelMonitorHistoryClient(_m.config).QueryMonitor(_m) +} + +// Update returns a builder for updating this ChannelMonitorHistory. +// Note that you need to call ChannelMonitorHistory.Unwrap() before calling this method if this ChannelMonitorHistory +// was returned from a transaction, and the transaction was committed or rolled back. +func (_m *ChannelMonitorHistory) Update() *ChannelMonitorHistoryUpdateOne { + return NewChannelMonitorHistoryClient(_m.config).UpdateOne(_m) +} + +// Unwrap unwraps the ChannelMonitorHistory entity that was returned from a transaction after it was closed, +// so that all future queries will be executed through the driver which created the transaction. +func (_m *ChannelMonitorHistory) Unwrap() *ChannelMonitorHistory { + _tx, ok := _m.config.driver.(*txDriver) + if !ok { + panic("ent: ChannelMonitorHistory is not a transactional entity") + } + _m.config.driver = _tx.drv + return _m +} + +// String implements the fmt.Stringer. +func (_m *ChannelMonitorHistory) String() string { + var builder strings.Builder + builder.WriteString("ChannelMonitorHistory(") + builder.WriteString(fmt.Sprintf("id=%v, ", _m.ID)) + builder.WriteString("monitor_id=") + builder.WriteString(fmt.Sprintf("%v", _m.MonitorID)) + builder.WriteString(", ") + builder.WriteString("model=") + builder.WriteString(_m.Model) + builder.WriteString(", ") + builder.WriteString("status=") + builder.WriteString(fmt.Sprintf("%v", _m.Status)) + builder.WriteString(", ") + if v := _m.LatencyMs; v != nil { + builder.WriteString("latency_ms=") + builder.WriteString(fmt.Sprintf("%v", *v)) + } + builder.WriteString(", ") + if v := _m.PingLatencyMs; v != nil { + builder.WriteString("ping_latency_ms=") + builder.WriteString(fmt.Sprintf("%v", *v)) + } + builder.WriteString(", ") + builder.WriteString("message=") + builder.WriteString(_m.Message) + builder.WriteString(", ") + builder.WriteString("checked_at=") + builder.WriteString(_m.CheckedAt.Format(time.ANSIC)) + builder.WriteByte(')') + return builder.String() +} + +// ChannelMonitorHistories is a parsable slice of ChannelMonitorHistory. +type ChannelMonitorHistories []*ChannelMonitorHistory diff --git a/backend/ent/channelmonitorhistory/channelmonitorhistory.go b/backend/ent/channelmonitorhistory/channelmonitorhistory.go new file mode 100644 index 00000000..6a9dc006 --- /dev/null +++ b/backend/ent/channelmonitorhistory/channelmonitorhistory.go @@ -0,0 +1,158 @@ +// Code generated by ent, DO NOT EDIT. + +package channelmonitorhistory + +import ( + "fmt" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" +) + +const ( + // Label holds the string label denoting the channelmonitorhistory type in the database. + Label = "channel_monitor_history" + // FieldID holds the string denoting the id field in the database. + FieldID = "id" + // FieldMonitorID holds the string denoting the monitor_id field in the database. + FieldMonitorID = "monitor_id" + // FieldModel holds the string denoting the model field in the database. + FieldModel = "model" + // FieldStatus holds the string denoting the status field in the database. + FieldStatus = "status" + // FieldLatencyMs holds the string denoting the latency_ms field in the database. + FieldLatencyMs = "latency_ms" + // FieldPingLatencyMs holds the string denoting the ping_latency_ms field in the database. + FieldPingLatencyMs = "ping_latency_ms" + // FieldMessage holds the string denoting the message field in the database. + FieldMessage = "message" + // FieldCheckedAt holds the string denoting the checked_at field in the database. + FieldCheckedAt = "checked_at" + // EdgeMonitor holds the string denoting the monitor edge name in mutations. + EdgeMonitor = "monitor" + // Table holds the table name of the channelmonitorhistory in the database. + Table = "channel_monitor_histories" + // MonitorTable is the table that holds the monitor relation/edge. + MonitorTable = "channel_monitor_histories" + // MonitorInverseTable is the table name for the ChannelMonitor entity. + // It exists in this package in order to avoid circular dependency with the "channelmonitor" package. + MonitorInverseTable = "channel_monitors" + // MonitorColumn is the table column denoting the monitor relation/edge. + MonitorColumn = "monitor_id" +) + +// Columns holds all SQL columns for channelmonitorhistory fields. +var Columns = []string{ + FieldID, + FieldMonitorID, + FieldModel, + FieldStatus, + FieldLatencyMs, + FieldPingLatencyMs, + FieldMessage, + FieldCheckedAt, +} + +// ValidColumn reports if the column name is valid (part of the table columns). +func ValidColumn(column string) bool { + for i := range Columns { + if column == Columns[i] { + return true + } + } + return false +} + +var ( + // ModelValidator is a validator for the "model" field. It is called by the builders before save. + ModelValidator func(string) error + // DefaultMessage holds the default value on creation for the "message" field. + DefaultMessage string + // MessageValidator is a validator for the "message" field. It is called by the builders before save. + MessageValidator func(string) error + // DefaultCheckedAt holds the default value on creation for the "checked_at" field. + DefaultCheckedAt func() time.Time +) + +// Status defines the type for the "status" enum field. +type Status string + +// Status values. +const ( + StatusOperational Status = "operational" + StatusDegraded Status = "degraded" + StatusFailed Status = "failed" + StatusError Status = "error" +) + +func (s Status) String() string { + return string(s) +} + +// StatusValidator is a validator for the "status" field enum values. It is called by the builders before save. +func StatusValidator(s Status) error { + switch s { + case StatusOperational, StatusDegraded, StatusFailed, StatusError: + return nil + default: + return fmt.Errorf("channelmonitorhistory: invalid enum value for status field: %q", s) + } +} + +// OrderOption defines the ordering options for the ChannelMonitorHistory queries. +type OrderOption func(*sql.Selector) + +// ByID orders the results by the id field. +func ByID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldID, opts...).ToFunc() +} + +// ByMonitorID orders the results by the monitor_id field. +func ByMonitorID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldMonitorID, opts...).ToFunc() +} + +// ByModel orders the results by the model field. +func ByModel(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldModel, opts...).ToFunc() +} + +// ByStatus orders the results by the status field. +func ByStatus(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldStatus, opts...).ToFunc() +} + +// ByLatencyMs orders the results by the latency_ms field. +func ByLatencyMs(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldLatencyMs, opts...).ToFunc() +} + +// ByPingLatencyMs orders the results by the ping_latency_ms field. +func ByPingLatencyMs(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldPingLatencyMs, opts...).ToFunc() +} + +// ByMessage orders the results by the message field. +func ByMessage(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldMessage, opts...).ToFunc() +} + +// ByCheckedAt orders the results by the checked_at field. +func ByCheckedAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldCheckedAt, opts...).ToFunc() +} + +// ByMonitorField orders the results by monitor field. +func ByMonitorField(field string, opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newMonitorStep(), sql.OrderByField(field, opts...)) + } +} +func newMonitorStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(MonitorInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, MonitorTable, MonitorColumn), + ) +} diff --git a/backend/ent/channelmonitorhistory/where.go b/backend/ent/channelmonitorhistory/where.go new file mode 100644 index 00000000..afa73f35 --- /dev/null +++ b/backend/ent/channelmonitorhistory/where.go @@ -0,0 +1,444 @@ +// Code generated by ent, DO NOT EDIT. + +package channelmonitorhistory + +import ( + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// ID filters vertices based on their ID field. +func ID(id int64) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldEQ(FieldID, id)) +} + +// IDEQ applies the EQ predicate on the ID field. +func IDEQ(id int64) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldEQ(FieldID, id)) +} + +// IDNEQ applies the NEQ predicate on the ID field. +func IDNEQ(id int64) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldNEQ(FieldID, id)) +} + +// IDIn applies the In predicate on the ID field. +func IDIn(ids ...int64) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldIn(FieldID, ids...)) +} + +// IDNotIn applies the NotIn predicate on the ID field. +func IDNotIn(ids ...int64) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldNotIn(FieldID, ids...)) +} + +// IDGT applies the GT predicate on the ID field. +func IDGT(id int64) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldGT(FieldID, id)) +} + +// IDGTE applies the GTE predicate on the ID field. +func IDGTE(id int64) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldGTE(FieldID, id)) +} + +// IDLT applies the LT predicate on the ID field. +func IDLT(id int64) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldLT(FieldID, id)) +} + +// IDLTE applies the LTE predicate on the ID field. +func IDLTE(id int64) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldLTE(FieldID, id)) +} + +// MonitorID applies equality check predicate on the "monitor_id" field. It's identical to MonitorIDEQ. +func MonitorID(v int64) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldEQ(FieldMonitorID, v)) +} + +// Model applies equality check predicate on the "model" field. It's identical to ModelEQ. +func Model(v string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldEQ(FieldModel, v)) +} + +// LatencyMs applies equality check predicate on the "latency_ms" field. It's identical to LatencyMsEQ. +func LatencyMs(v int) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldEQ(FieldLatencyMs, v)) +} + +// PingLatencyMs applies equality check predicate on the "ping_latency_ms" field. It's identical to PingLatencyMsEQ. +func PingLatencyMs(v int) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldEQ(FieldPingLatencyMs, v)) +} + +// Message applies equality check predicate on the "message" field. It's identical to MessageEQ. +func Message(v string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldEQ(FieldMessage, v)) +} + +// CheckedAt applies equality check predicate on the "checked_at" field. It's identical to CheckedAtEQ. +func CheckedAt(v time.Time) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldEQ(FieldCheckedAt, v)) +} + +// MonitorIDEQ applies the EQ predicate on the "monitor_id" field. +func MonitorIDEQ(v int64) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldEQ(FieldMonitorID, v)) +} + +// MonitorIDNEQ applies the NEQ predicate on the "monitor_id" field. +func MonitorIDNEQ(v int64) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldNEQ(FieldMonitorID, v)) +} + +// MonitorIDIn applies the In predicate on the "monitor_id" field. +func MonitorIDIn(vs ...int64) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldIn(FieldMonitorID, vs...)) +} + +// MonitorIDNotIn applies the NotIn predicate on the "monitor_id" field. +func MonitorIDNotIn(vs ...int64) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldNotIn(FieldMonitorID, vs...)) +} + +// ModelEQ applies the EQ predicate on the "model" field. +func ModelEQ(v string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldEQ(FieldModel, v)) +} + +// ModelNEQ applies the NEQ predicate on the "model" field. +func ModelNEQ(v string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldNEQ(FieldModel, v)) +} + +// ModelIn applies the In predicate on the "model" field. +func ModelIn(vs ...string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldIn(FieldModel, vs...)) +} + +// ModelNotIn applies the NotIn predicate on the "model" field. +func ModelNotIn(vs ...string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldNotIn(FieldModel, vs...)) +} + +// ModelGT applies the GT predicate on the "model" field. +func ModelGT(v string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldGT(FieldModel, v)) +} + +// ModelGTE applies the GTE predicate on the "model" field. +func ModelGTE(v string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldGTE(FieldModel, v)) +} + +// ModelLT applies the LT predicate on the "model" field. +func ModelLT(v string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldLT(FieldModel, v)) +} + +// ModelLTE applies the LTE predicate on the "model" field. +func ModelLTE(v string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldLTE(FieldModel, v)) +} + +// ModelContains applies the Contains predicate on the "model" field. +func ModelContains(v string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldContains(FieldModel, v)) +} + +// ModelHasPrefix applies the HasPrefix predicate on the "model" field. +func ModelHasPrefix(v string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldHasPrefix(FieldModel, v)) +} + +// ModelHasSuffix applies the HasSuffix predicate on the "model" field. +func ModelHasSuffix(v string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldHasSuffix(FieldModel, v)) +} + +// ModelEqualFold applies the EqualFold predicate on the "model" field. +func ModelEqualFold(v string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldEqualFold(FieldModel, v)) +} + +// ModelContainsFold applies the ContainsFold predicate on the "model" field. +func ModelContainsFold(v string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldContainsFold(FieldModel, v)) +} + +// StatusEQ applies the EQ predicate on the "status" field. +func StatusEQ(v Status) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldEQ(FieldStatus, v)) +} + +// StatusNEQ applies the NEQ predicate on the "status" field. +func StatusNEQ(v Status) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldNEQ(FieldStatus, v)) +} + +// StatusIn applies the In predicate on the "status" field. +func StatusIn(vs ...Status) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldIn(FieldStatus, vs...)) +} + +// StatusNotIn applies the NotIn predicate on the "status" field. +func StatusNotIn(vs ...Status) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldNotIn(FieldStatus, vs...)) +} + +// LatencyMsEQ applies the EQ predicate on the "latency_ms" field. +func LatencyMsEQ(v int) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldEQ(FieldLatencyMs, v)) +} + +// LatencyMsNEQ applies the NEQ predicate on the "latency_ms" field. +func LatencyMsNEQ(v int) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldNEQ(FieldLatencyMs, v)) +} + +// LatencyMsIn applies the In predicate on the "latency_ms" field. +func LatencyMsIn(vs ...int) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldIn(FieldLatencyMs, vs...)) +} + +// LatencyMsNotIn applies the NotIn predicate on the "latency_ms" field. +func LatencyMsNotIn(vs ...int) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldNotIn(FieldLatencyMs, vs...)) +} + +// LatencyMsGT applies the GT predicate on the "latency_ms" field. +func LatencyMsGT(v int) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldGT(FieldLatencyMs, v)) +} + +// LatencyMsGTE applies the GTE predicate on the "latency_ms" field. +func LatencyMsGTE(v int) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldGTE(FieldLatencyMs, v)) +} + +// LatencyMsLT applies the LT predicate on the "latency_ms" field. +func LatencyMsLT(v int) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldLT(FieldLatencyMs, v)) +} + +// LatencyMsLTE applies the LTE predicate on the "latency_ms" field. +func LatencyMsLTE(v int) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldLTE(FieldLatencyMs, v)) +} + +// LatencyMsIsNil applies the IsNil predicate on the "latency_ms" field. +func LatencyMsIsNil() predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldIsNull(FieldLatencyMs)) +} + +// LatencyMsNotNil applies the NotNil predicate on the "latency_ms" field. +func LatencyMsNotNil() predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldNotNull(FieldLatencyMs)) +} + +// PingLatencyMsEQ applies the EQ predicate on the "ping_latency_ms" field. +func PingLatencyMsEQ(v int) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldEQ(FieldPingLatencyMs, v)) +} + +// PingLatencyMsNEQ applies the NEQ predicate on the "ping_latency_ms" field. +func PingLatencyMsNEQ(v int) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldNEQ(FieldPingLatencyMs, v)) +} + +// PingLatencyMsIn applies the In predicate on the "ping_latency_ms" field. +func PingLatencyMsIn(vs ...int) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldIn(FieldPingLatencyMs, vs...)) +} + +// PingLatencyMsNotIn applies the NotIn predicate on the "ping_latency_ms" field. +func PingLatencyMsNotIn(vs ...int) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldNotIn(FieldPingLatencyMs, vs...)) +} + +// PingLatencyMsGT applies the GT predicate on the "ping_latency_ms" field. +func PingLatencyMsGT(v int) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldGT(FieldPingLatencyMs, v)) +} + +// PingLatencyMsGTE applies the GTE predicate on the "ping_latency_ms" field. +func PingLatencyMsGTE(v int) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldGTE(FieldPingLatencyMs, v)) +} + +// PingLatencyMsLT applies the LT predicate on the "ping_latency_ms" field. +func PingLatencyMsLT(v int) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldLT(FieldPingLatencyMs, v)) +} + +// PingLatencyMsLTE applies the LTE predicate on the "ping_latency_ms" field. +func PingLatencyMsLTE(v int) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldLTE(FieldPingLatencyMs, v)) +} + +// PingLatencyMsIsNil applies the IsNil predicate on the "ping_latency_ms" field. +func PingLatencyMsIsNil() predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldIsNull(FieldPingLatencyMs)) +} + +// PingLatencyMsNotNil applies the NotNil predicate on the "ping_latency_ms" field. +func PingLatencyMsNotNil() predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldNotNull(FieldPingLatencyMs)) +} + +// MessageEQ applies the EQ predicate on the "message" field. +func MessageEQ(v string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldEQ(FieldMessage, v)) +} + +// MessageNEQ applies the NEQ predicate on the "message" field. +func MessageNEQ(v string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldNEQ(FieldMessage, v)) +} + +// MessageIn applies the In predicate on the "message" field. +func MessageIn(vs ...string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldIn(FieldMessage, vs...)) +} + +// MessageNotIn applies the NotIn predicate on the "message" field. +func MessageNotIn(vs ...string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldNotIn(FieldMessage, vs...)) +} + +// MessageGT applies the GT predicate on the "message" field. +func MessageGT(v string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldGT(FieldMessage, v)) +} + +// MessageGTE applies the GTE predicate on the "message" field. +func MessageGTE(v string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldGTE(FieldMessage, v)) +} + +// MessageLT applies the LT predicate on the "message" field. +func MessageLT(v string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldLT(FieldMessage, v)) +} + +// MessageLTE applies the LTE predicate on the "message" field. +func MessageLTE(v string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldLTE(FieldMessage, v)) +} + +// MessageContains applies the Contains predicate on the "message" field. +func MessageContains(v string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldContains(FieldMessage, v)) +} + +// MessageHasPrefix applies the HasPrefix predicate on the "message" field. +func MessageHasPrefix(v string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldHasPrefix(FieldMessage, v)) +} + +// MessageHasSuffix applies the HasSuffix predicate on the "message" field. +func MessageHasSuffix(v string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldHasSuffix(FieldMessage, v)) +} + +// MessageIsNil applies the IsNil predicate on the "message" field. +func MessageIsNil() predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldIsNull(FieldMessage)) +} + +// MessageNotNil applies the NotNil predicate on the "message" field. +func MessageNotNil() predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldNotNull(FieldMessage)) +} + +// MessageEqualFold applies the EqualFold predicate on the "message" field. +func MessageEqualFold(v string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldEqualFold(FieldMessage, v)) +} + +// MessageContainsFold applies the ContainsFold predicate on the "message" field. +func MessageContainsFold(v string) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldContainsFold(FieldMessage, v)) +} + +// CheckedAtEQ applies the EQ predicate on the "checked_at" field. +func CheckedAtEQ(v time.Time) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldEQ(FieldCheckedAt, v)) +} + +// CheckedAtNEQ applies the NEQ predicate on the "checked_at" field. +func CheckedAtNEQ(v time.Time) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldNEQ(FieldCheckedAt, v)) +} + +// CheckedAtIn applies the In predicate on the "checked_at" field. +func CheckedAtIn(vs ...time.Time) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldIn(FieldCheckedAt, vs...)) +} + +// CheckedAtNotIn applies the NotIn predicate on the "checked_at" field. +func CheckedAtNotIn(vs ...time.Time) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldNotIn(FieldCheckedAt, vs...)) +} + +// CheckedAtGT applies the GT predicate on the "checked_at" field. +func CheckedAtGT(v time.Time) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldGT(FieldCheckedAt, v)) +} + +// CheckedAtGTE applies the GTE predicate on the "checked_at" field. +func CheckedAtGTE(v time.Time) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldGTE(FieldCheckedAt, v)) +} + +// CheckedAtLT applies the LT predicate on the "checked_at" field. +func CheckedAtLT(v time.Time) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldLT(FieldCheckedAt, v)) +} + +// CheckedAtLTE applies the LTE predicate on the "checked_at" field. +func CheckedAtLTE(v time.Time) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.FieldLTE(FieldCheckedAt, v)) +} + +// HasMonitor applies the HasEdge predicate on the "monitor" edge. +func HasMonitor() predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, MonitorTable, MonitorColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasMonitorWith applies the HasEdge predicate on the "monitor" edge with a given conditions (other predicates). +func HasMonitorWith(preds ...predicate.ChannelMonitor) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(func(s *sql.Selector) { + step := newMonitorStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + +// And groups predicates with the AND operator between them. +func And(predicates ...predicate.ChannelMonitorHistory) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.AndPredicates(predicates...)) +} + +// Or groups predicates with the OR operator between them. +func Or(predicates ...predicate.ChannelMonitorHistory) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.OrPredicates(predicates...)) +} + +// Not applies the not operator on the given predicate. +func Not(p predicate.ChannelMonitorHistory) predicate.ChannelMonitorHistory { + return predicate.ChannelMonitorHistory(sql.NotPredicates(p)) +} diff --git a/backend/ent/channelmonitorhistory_create.go b/backend/ent/channelmonitorhistory_create.go new file mode 100644 index 00000000..71034865 --- /dev/null +++ b/backend/ent/channelmonitorhistory_create.go @@ -0,0 +1,947 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory" +) + +// ChannelMonitorHistoryCreate is the builder for creating a ChannelMonitorHistory entity. +type ChannelMonitorHistoryCreate struct { + config + mutation *ChannelMonitorHistoryMutation + hooks []Hook + conflict []sql.ConflictOption +} + +// SetMonitorID sets the "monitor_id" field. +func (_c *ChannelMonitorHistoryCreate) SetMonitorID(v int64) *ChannelMonitorHistoryCreate { + _c.mutation.SetMonitorID(v) + return _c +} + +// SetModel sets the "model" field. +func (_c *ChannelMonitorHistoryCreate) SetModel(v string) *ChannelMonitorHistoryCreate { + _c.mutation.SetModel(v) + return _c +} + +// SetStatus sets the "status" field. +func (_c *ChannelMonitorHistoryCreate) SetStatus(v channelmonitorhistory.Status) *ChannelMonitorHistoryCreate { + _c.mutation.SetStatus(v) + return _c +} + +// SetLatencyMs sets the "latency_ms" field. +func (_c *ChannelMonitorHistoryCreate) SetLatencyMs(v int) *ChannelMonitorHistoryCreate { + _c.mutation.SetLatencyMs(v) + return _c +} + +// SetNillableLatencyMs sets the "latency_ms" field if the given value is not nil. +func (_c *ChannelMonitorHistoryCreate) SetNillableLatencyMs(v *int) *ChannelMonitorHistoryCreate { + if v != nil { + _c.SetLatencyMs(*v) + } + return _c +} + +// SetPingLatencyMs sets the "ping_latency_ms" field. +func (_c *ChannelMonitorHistoryCreate) SetPingLatencyMs(v int) *ChannelMonitorHistoryCreate { + _c.mutation.SetPingLatencyMs(v) + return _c +} + +// SetNillablePingLatencyMs sets the "ping_latency_ms" field if the given value is not nil. +func (_c *ChannelMonitorHistoryCreate) SetNillablePingLatencyMs(v *int) *ChannelMonitorHistoryCreate { + if v != nil { + _c.SetPingLatencyMs(*v) + } + return _c +} + +// SetMessage sets the "message" field. +func (_c *ChannelMonitorHistoryCreate) SetMessage(v string) *ChannelMonitorHistoryCreate { + _c.mutation.SetMessage(v) + return _c +} + +// SetNillableMessage sets the "message" field if the given value is not nil. +func (_c *ChannelMonitorHistoryCreate) SetNillableMessage(v *string) *ChannelMonitorHistoryCreate { + if v != nil { + _c.SetMessage(*v) + } + return _c +} + +// SetCheckedAt sets the "checked_at" field. +func (_c *ChannelMonitorHistoryCreate) SetCheckedAt(v time.Time) *ChannelMonitorHistoryCreate { + _c.mutation.SetCheckedAt(v) + return _c +} + +// SetNillableCheckedAt sets the "checked_at" field if the given value is not nil. +func (_c *ChannelMonitorHistoryCreate) SetNillableCheckedAt(v *time.Time) *ChannelMonitorHistoryCreate { + if v != nil { + _c.SetCheckedAt(*v) + } + return _c +} + +// SetMonitor sets the "monitor" edge to the ChannelMonitor entity. +func (_c *ChannelMonitorHistoryCreate) SetMonitor(v *ChannelMonitor) *ChannelMonitorHistoryCreate { + return _c.SetMonitorID(v.ID) +} + +// Mutation returns the ChannelMonitorHistoryMutation object of the builder. +func (_c *ChannelMonitorHistoryCreate) Mutation() *ChannelMonitorHistoryMutation { + return _c.mutation +} + +// Save creates the ChannelMonitorHistory in the database. +func (_c *ChannelMonitorHistoryCreate) Save(ctx context.Context) (*ChannelMonitorHistory, error) { + _c.defaults() + return withHooks(ctx, _c.sqlSave, _c.mutation, _c.hooks) +} + +// SaveX calls Save and panics if Save returns an error. +func (_c *ChannelMonitorHistoryCreate) SaveX(ctx context.Context) *ChannelMonitorHistory { + v, err := _c.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (_c *ChannelMonitorHistoryCreate) Exec(ctx context.Context) error { + _, err := _c.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_c *ChannelMonitorHistoryCreate) ExecX(ctx context.Context) { + if err := _c.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (_c *ChannelMonitorHistoryCreate) defaults() { + if _, ok := _c.mutation.Message(); !ok { + v := channelmonitorhistory.DefaultMessage + _c.mutation.SetMessage(v) + } + if _, ok := _c.mutation.CheckedAt(); !ok { + v := channelmonitorhistory.DefaultCheckedAt() + _c.mutation.SetCheckedAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_c *ChannelMonitorHistoryCreate) check() error { + if _, ok := _c.mutation.MonitorID(); !ok { + return &ValidationError{Name: "monitor_id", err: errors.New(`ent: missing required field "ChannelMonitorHistory.monitor_id"`)} + } + if _, ok := _c.mutation.Model(); !ok { + return &ValidationError{Name: "model", err: errors.New(`ent: missing required field "ChannelMonitorHistory.model"`)} + } + if v, ok := _c.mutation.Model(); ok { + if err := channelmonitorhistory.ModelValidator(v); err != nil { + return &ValidationError{Name: "model", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorHistory.model": %w`, err)} + } + } + if _, ok := _c.mutation.Status(); !ok { + return &ValidationError{Name: "status", err: errors.New(`ent: missing required field "ChannelMonitorHistory.status"`)} + } + if v, ok := _c.mutation.Status(); ok { + if err := channelmonitorhistory.StatusValidator(v); err != nil { + return &ValidationError{Name: "status", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorHistory.status": %w`, err)} + } + } + if v, ok := _c.mutation.Message(); ok { + if err := channelmonitorhistory.MessageValidator(v); err != nil { + return &ValidationError{Name: "message", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorHistory.message": %w`, err)} + } + } + if _, ok := _c.mutation.CheckedAt(); !ok { + return &ValidationError{Name: "checked_at", err: errors.New(`ent: missing required field "ChannelMonitorHistory.checked_at"`)} + } + if len(_c.mutation.MonitorIDs()) == 0 { + return &ValidationError{Name: "monitor", err: errors.New(`ent: missing required edge "ChannelMonitorHistory.monitor"`)} + } + return nil +} + +func (_c *ChannelMonitorHistoryCreate) sqlSave(ctx context.Context) (*ChannelMonitorHistory, error) { + if err := _c.check(); err != nil { + return nil, err + } + _node, _spec := _c.createSpec() + if err := sqlgraph.CreateNode(ctx, _c.driver, _spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + id := _spec.ID.Value.(int64) + _node.ID = int64(id) + _c.mutation.id = &_node.ID + _c.mutation.done = true + return _node, nil +} + +func (_c *ChannelMonitorHistoryCreate) createSpec() (*ChannelMonitorHistory, *sqlgraph.CreateSpec) { + var ( + _node = &ChannelMonitorHistory{config: _c.config} + _spec = sqlgraph.NewCreateSpec(channelmonitorhistory.Table, sqlgraph.NewFieldSpec(channelmonitorhistory.FieldID, field.TypeInt64)) + ) + _spec.OnConflict = _c.conflict + if value, ok := _c.mutation.Model(); ok { + _spec.SetField(channelmonitorhistory.FieldModel, field.TypeString, value) + _node.Model = value + } + if value, ok := _c.mutation.Status(); ok { + _spec.SetField(channelmonitorhistory.FieldStatus, field.TypeEnum, value) + _node.Status = value + } + if value, ok := _c.mutation.LatencyMs(); ok { + _spec.SetField(channelmonitorhistory.FieldLatencyMs, field.TypeInt, value) + _node.LatencyMs = &value + } + if value, ok := _c.mutation.PingLatencyMs(); ok { + _spec.SetField(channelmonitorhistory.FieldPingLatencyMs, field.TypeInt, value) + _node.PingLatencyMs = &value + } + if value, ok := _c.mutation.Message(); ok { + _spec.SetField(channelmonitorhistory.FieldMessage, field.TypeString, value) + _node.Message = value + } + if value, ok := _c.mutation.CheckedAt(); ok { + _spec.SetField(channelmonitorhistory.FieldCheckedAt, field.TypeTime, value) + _node.CheckedAt = value + } + if nodes := _c.mutation.MonitorIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: channelmonitorhistory.MonitorTable, + Columns: []string{channelmonitorhistory.MonitorColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _node.MonitorID = nodes[0] + _spec.Edges = append(_spec.Edges, edge) + } + return _node, _spec +} + +// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause +// of the `INSERT` statement. For example: +// +// client.ChannelMonitorHistory.Create(). +// SetMonitorID(v). +// OnConflict( +// // Update the row with the new values +// // the was proposed for insertion. +// sql.ResolveWithNewValues(), +// ). +// // Override some of the fields with custom +// // update values. +// Update(func(u *ent.ChannelMonitorHistoryUpsert) { +// SetMonitorID(v+v). +// }). +// Exec(ctx) +func (_c *ChannelMonitorHistoryCreate) OnConflict(opts ...sql.ConflictOption) *ChannelMonitorHistoryUpsertOne { + _c.conflict = opts + return &ChannelMonitorHistoryUpsertOne{ + create: _c, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.ChannelMonitorHistory.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (_c *ChannelMonitorHistoryCreate) OnConflictColumns(columns ...string) *ChannelMonitorHistoryUpsertOne { + _c.conflict = append(_c.conflict, sql.ConflictColumns(columns...)) + return &ChannelMonitorHistoryUpsertOne{ + create: _c, + } +} + +type ( + // ChannelMonitorHistoryUpsertOne is the builder for "upsert"-ing + // one ChannelMonitorHistory node. + ChannelMonitorHistoryUpsertOne struct { + create *ChannelMonitorHistoryCreate + } + + // ChannelMonitorHistoryUpsert is the "OnConflict" setter. + ChannelMonitorHistoryUpsert struct { + *sql.UpdateSet + } +) + +// SetMonitorID sets the "monitor_id" field. +func (u *ChannelMonitorHistoryUpsert) SetMonitorID(v int64) *ChannelMonitorHistoryUpsert { + u.Set(channelmonitorhistory.FieldMonitorID, v) + return u +} + +// UpdateMonitorID sets the "monitor_id" field to the value that was provided on create. +func (u *ChannelMonitorHistoryUpsert) UpdateMonitorID() *ChannelMonitorHistoryUpsert { + u.SetExcluded(channelmonitorhistory.FieldMonitorID) + return u +} + +// SetModel sets the "model" field. +func (u *ChannelMonitorHistoryUpsert) SetModel(v string) *ChannelMonitorHistoryUpsert { + u.Set(channelmonitorhistory.FieldModel, v) + return u +} + +// UpdateModel sets the "model" field to the value that was provided on create. +func (u *ChannelMonitorHistoryUpsert) UpdateModel() *ChannelMonitorHistoryUpsert { + u.SetExcluded(channelmonitorhistory.FieldModel) + return u +} + +// SetStatus sets the "status" field. +func (u *ChannelMonitorHistoryUpsert) SetStatus(v channelmonitorhistory.Status) *ChannelMonitorHistoryUpsert { + u.Set(channelmonitorhistory.FieldStatus, v) + return u +} + +// UpdateStatus sets the "status" field to the value that was provided on create. +func (u *ChannelMonitorHistoryUpsert) UpdateStatus() *ChannelMonitorHistoryUpsert { + u.SetExcluded(channelmonitorhistory.FieldStatus) + return u +} + +// SetLatencyMs sets the "latency_ms" field. +func (u *ChannelMonitorHistoryUpsert) SetLatencyMs(v int) *ChannelMonitorHistoryUpsert { + u.Set(channelmonitorhistory.FieldLatencyMs, v) + return u +} + +// UpdateLatencyMs sets the "latency_ms" field to the value that was provided on create. +func (u *ChannelMonitorHistoryUpsert) UpdateLatencyMs() *ChannelMonitorHistoryUpsert { + u.SetExcluded(channelmonitorhistory.FieldLatencyMs) + return u +} + +// AddLatencyMs adds v to the "latency_ms" field. +func (u *ChannelMonitorHistoryUpsert) AddLatencyMs(v int) *ChannelMonitorHistoryUpsert { + u.Add(channelmonitorhistory.FieldLatencyMs, v) + return u +} + +// ClearLatencyMs clears the value of the "latency_ms" field. +func (u *ChannelMonitorHistoryUpsert) ClearLatencyMs() *ChannelMonitorHistoryUpsert { + u.SetNull(channelmonitorhistory.FieldLatencyMs) + return u +} + +// SetPingLatencyMs sets the "ping_latency_ms" field. +func (u *ChannelMonitorHistoryUpsert) SetPingLatencyMs(v int) *ChannelMonitorHistoryUpsert { + u.Set(channelmonitorhistory.FieldPingLatencyMs, v) + return u +} + +// UpdatePingLatencyMs sets the "ping_latency_ms" field to the value that was provided on create. +func (u *ChannelMonitorHistoryUpsert) UpdatePingLatencyMs() *ChannelMonitorHistoryUpsert { + u.SetExcluded(channelmonitorhistory.FieldPingLatencyMs) + return u +} + +// AddPingLatencyMs adds v to the "ping_latency_ms" field. +func (u *ChannelMonitorHistoryUpsert) AddPingLatencyMs(v int) *ChannelMonitorHistoryUpsert { + u.Add(channelmonitorhistory.FieldPingLatencyMs, v) + return u +} + +// ClearPingLatencyMs clears the value of the "ping_latency_ms" field. +func (u *ChannelMonitorHistoryUpsert) ClearPingLatencyMs() *ChannelMonitorHistoryUpsert { + u.SetNull(channelmonitorhistory.FieldPingLatencyMs) + return u +} + +// SetMessage sets the "message" field. +func (u *ChannelMonitorHistoryUpsert) SetMessage(v string) *ChannelMonitorHistoryUpsert { + u.Set(channelmonitorhistory.FieldMessage, v) + return u +} + +// UpdateMessage sets the "message" field to the value that was provided on create. +func (u *ChannelMonitorHistoryUpsert) UpdateMessage() *ChannelMonitorHistoryUpsert { + u.SetExcluded(channelmonitorhistory.FieldMessage) + return u +} + +// ClearMessage clears the value of the "message" field. +func (u *ChannelMonitorHistoryUpsert) ClearMessage() *ChannelMonitorHistoryUpsert { + u.SetNull(channelmonitorhistory.FieldMessage) + return u +} + +// SetCheckedAt sets the "checked_at" field. +func (u *ChannelMonitorHistoryUpsert) SetCheckedAt(v time.Time) *ChannelMonitorHistoryUpsert { + u.Set(channelmonitorhistory.FieldCheckedAt, v) + return u +} + +// UpdateCheckedAt sets the "checked_at" field to the value that was provided on create. +func (u *ChannelMonitorHistoryUpsert) UpdateCheckedAt() *ChannelMonitorHistoryUpsert { + u.SetExcluded(channelmonitorhistory.FieldCheckedAt) + return u +} + +// UpdateNewValues updates the mutable fields using the new values that were set on create. +// Using this option is equivalent to using: +// +// client.ChannelMonitorHistory.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// ). +// Exec(ctx) +func (u *ChannelMonitorHistoryUpsertOne) UpdateNewValues() *ChannelMonitorHistoryUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues()) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.ChannelMonitorHistory.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *ChannelMonitorHistoryUpsertOne) Ignore() *ChannelMonitorHistoryUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore()) + return u +} + +// DoNothing configures the conflict_action to `DO NOTHING`. +// Supported only by SQLite and PostgreSQL. +func (u *ChannelMonitorHistoryUpsertOne) DoNothing() *ChannelMonitorHistoryUpsertOne { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the ChannelMonitorHistoryCreate.OnConflict +// documentation for more info. +func (u *ChannelMonitorHistoryUpsertOne) Update(set func(*ChannelMonitorHistoryUpsert)) *ChannelMonitorHistoryUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&ChannelMonitorHistoryUpsert{UpdateSet: update}) + })) + return u +} + +// SetMonitorID sets the "monitor_id" field. +func (u *ChannelMonitorHistoryUpsertOne) SetMonitorID(v int64) *ChannelMonitorHistoryUpsertOne { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.SetMonitorID(v) + }) +} + +// UpdateMonitorID sets the "monitor_id" field to the value that was provided on create. +func (u *ChannelMonitorHistoryUpsertOne) UpdateMonitorID() *ChannelMonitorHistoryUpsertOne { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.UpdateMonitorID() + }) +} + +// SetModel sets the "model" field. +func (u *ChannelMonitorHistoryUpsertOne) SetModel(v string) *ChannelMonitorHistoryUpsertOne { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.SetModel(v) + }) +} + +// UpdateModel sets the "model" field to the value that was provided on create. +func (u *ChannelMonitorHistoryUpsertOne) UpdateModel() *ChannelMonitorHistoryUpsertOne { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.UpdateModel() + }) +} + +// SetStatus sets the "status" field. +func (u *ChannelMonitorHistoryUpsertOne) SetStatus(v channelmonitorhistory.Status) *ChannelMonitorHistoryUpsertOne { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.SetStatus(v) + }) +} + +// UpdateStatus sets the "status" field to the value that was provided on create. +func (u *ChannelMonitorHistoryUpsertOne) UpdateStatus() *ChannelMonitorHistoryUpsertOne { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.UpdateStatus() + }) +} + +// SetLatencyMs sets the "latency_ms" field. +func (u *ChannelMonitorHistoryUpsertOne) SetLatencyMs(v int) *ChannelMonitorHistoryUpsertOne { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.SetLatencyMs(v) + }) +} + +// AddLatencyMs adds v to the "latency_ms" field. +func (u *ChannelMonitorHistoryUpsertOne) AddLatencyMs(v int) *ChannelMonitorHistoryUpsertOne { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.AddLatencyMs(v) + }) +} + +// UpdateLatencyMs sets the "latency_ms" field to the value that was provided on create. +func (u *ChannelMonitorHistoryUpsertOne) UpdateLatencyMs() *ChannelMonitorHistoryUpsertOne { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.UpdateLatencyMs() + }) +} + +// ClearLatencyMs clears the value of the "latency_ms" field. +func (u *ChannelMonitorHistoryUpsertOne) ClearLatencyMs() *ChannelMonitorHistoryUpsertOne { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.ClearLatencyMs() + }) +} + +// SetPingLatencyMs sets the "ping_latency_ms" field. +func (u *ChannelMonitorHistoryUpsertOne) SetPingLatencyMs(v int) *ChannelMonitorHistoryUpsertOne { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.SetPingLatencyMs(v) + }) +} + +// AddPingLatencyMs adds v to the "ping_latency_ms" field. +func (u *ChannelMonitorHistoryUpsertOne) AddPingLatencyMs(v int) *ChannelMonitorHistoryUpsertOne { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.AddPingLatencyMs(v) + }) +} + +// UpdatePingLatencyMs sets the "ping_latency_ms" field to the value that was provided on create. +func (u *ChannelMonitorHistoryUpsertOne) UpdatePingLatencyMs() *ChannelMonitorHistoryUpsertOne { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.UpdatePingLatencyMs() + }) +} + +// ClearPingLatencyMs clears the value of the "ping_latency_ms" field. +func (u *ChannelMonitorHistoryUpsertOne) ClearPingLatencyMs() *ChannelMonitorHistoryUpsertOne { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.ClearPingLatencyMs() + }) +} + +// SetMessage sets the "message" field. +func (u *ChannelMonitorHistoryUpsertOne) SetMessage(v string) *ChannelMonitorHistoryUpsertOne { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.SetMessage(v) + }) +} + +// UpdateMessage sets the "message" field to the value that was provided on create. +func (u *ChannelMonitorHistoryUpsertOne) UpdateMessage() *ChannelMonitorHistoryUpsertOne { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.UpdateMessage() + }) +} + +// ClearMessage clears the value of the "message" field. +func (u *ChannelMonitorHistoryUpsertOne) ClearMessage() *ChannelMonitorHistoryUpsertOne { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.ClearMessage() + }) +} + +// SetCheckedAt sets the "checked_at" field. +func (u *ChannelMonitorHistoryUpsertOne) SetCheckedAt(v time.Time) *ChannelMonitorHistoryUpsertOne { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.SetCheckedAt(v) + }) +} + +// UpdateCheckedAt sets the "checked_at" field to the value that was provided on create. +func (u *ChannelMonitorHistoryUpsertOne) UpdateCheckedAt() *ChannelMonitorHistoryUpsertOne { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.UpdateCheckedAt() + }) +} + +// Exec executes the query. +func (u *ChannelMonitorHistoryUpsertOne) Exec(ctx context.Context) error { + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for ChannelMonitorHistoryCreate.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *ChannelMonitorHistoryUpsertOne) ExecX(ctx context.Context) { + if err := u.create.Exec(ctx); err != nil { + panic(err) + } +} + +// Exec executes the UPSERT query and returns the inserted/updated ID. +func (u *ChannelMonitorHistoryUpsertOne) ID(ctx context.Context) (id int64, err error) { + node, err := u.create.Save(ctx) + if err != nil { + return id, err + } + return node.ID, nil +} + +// IDX is like ID, but panics if an error occurs. +func (u *ChannelMonitorHistoryUpsertOne) IDX(ctx context.Context) int64 { + id, err := u.ID(ctx) + if err != nil { + panic(err) + } + return id +} + +// ChannelMonitorHistoryCreateBulk is the builder for creating many ChannelMonitorHistory entities in bulk. +type ChannelMonitorHistoryCreateBulk struct { + config + err error + builders []*ChannelMonitorHistoryCreate + conflict []sql.ConflictOption +} + +// Save creates the ChannelMonitorHistory entities in the database. +func (_c *ChannelMonitorHistoryCreateBulk) Save(ctx context.Context) ([]*ChannelMonitorHistory, error) { + if _c.err != nil { + return nil, _c.err + } + specs := make([]*sqlgraph.CreateSpec, len(_c.builders)) + nodes := make([]*ChannelMonitorHistory, len(_c.builders)) + mutators := make([]Mutator, len(_c.builders)) + for i := range _c.builders { + func(i int, root context.Context) { + builder := _c.builders[i] + builder.defaults() + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*ChannelMonitorHistoryMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + if err := builder.check(); err != nil { + return nil, err + } + builder.mutation = mutation + var err error + nodes[i], specs[i] = builder.createSpec() + if i < len(mutators)-1 { + _, err = mutators[i+1].Mutate(root, _c.builders[i+1].mutation) + } else { + spec := &sqlgraph.BatchCreateSpec{Nodes: specs} + spec.OnConflict = _c.conflict + // Invoke the actual operation on the latest mutation in the chain. + if err = sqlgraph.BatchCreate(ctx, _c.driver, spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + } + } + if err != nil { + return nil, err + } + mutation.id = &nodes[i].ID + if specs[i].ID.Value != nil { + id := specs[i].ID.Value.(int64) + nodes[i].ID = int64(id) + } + mutation.done = true + return nodes[i], nil + }) + for i := len(builder.hooks) - 1; i >= 0; i-- { + mut = builder.hooks[i](mut) + } + mutators[i] = mut + }(i, ctx) + } + if len(mutators) > 0 { + if _, err := mutators[0].Mutate(ctx, _c.builders[0].mutation); err != nil { + return nil, err + } + } + return nodes, nil +} + +// SaveX is like Save, but panics if an error occurs. +func (_c *ChannelMonitorHistoryCreateBulk) SaveX(ctx context.Context) []*ChannelMonitorHistory { + v, err := _c.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (_c *ChannelMonitorHistoryCreateBulk) Exec(ctx context.Context) error { + _, err := _c.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_c *ChannelMonitorHistoryCreateBulk) ExecX(ctx context.Context) { + if err := _c.Exec(ctx); err != nil { + panic(err) + } +} + +// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause +// of the `INSERT` statement. For example: +// +// client.ChannelMonitorHistory.CreateBulk(builders...). +// OnConflict( +// // Update the row with the new values +// // the was proposed for insertion. +// sql.ResolveWithNewValues(), +// ). +// // Override some of the fields with custom +// // update values. +// Update(func(u *ent.ChannelMonitorHistoryUpsert) { +// SetMonitorID(v+v). +// }). +// Exec(ctx) +func (_c *ChannelMonitorHistoryCreateBulk) OnConflict(opts ...sql.ConflictOption) *ChannelMonitorHistoryUpsertBulk { + _c.conflict = opts + return &ChannelMonitorHistoryUpsertBulk{ + create: _c, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.ChannelMonitorHistory.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (_c *ChannelMonitorHistoryCreateBulk) OnConflictColumns(columns ...string) *ChannelMonitorHistoryUpsertBulk { + _c.conflict = append(_c.conflict, sql.ConflictColumns(columns...)) + return &ChannelMonitorHistoryUpsertBulk{ + create: _c, + } +} + +// ChannelMonitorHistoryUpsertBulk is the builder for "upsert"-ing +// a bulk of ChannelMonitorHistory nodes. +type ChannelMonitorHistoryUpsertBulk struct { + create *ChannelMonitorHistoryCreateBulk +} + +// UpdateNewValues updates the mutable fields using the new values that +// were set on create. Using this option is equivalent to using: +// +// client.ChannelMonitorHistory.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// ). +// Exec(ctx) +func (u *ChannelMonitorHistoryUpsertBulk) UpdateNewValues() *ChannelMonitorHistoryUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues()) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.ChannelMonitorHistory.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *ChannelMonitorHistoryUpsertBulk) Ignore() *ChannelMonitorHistoryUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore()) + return u +} + +// DoNothing configures the conflict_action to `DO NOTHING`. +// Supported only by SQLite and PostgreSQL. +func (u *ChannelMonitorHistoryUpsertBulk) DoNothing() *ChannelMonitorHistoryUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the ChannelMonitorHistoryCreateBulk.OnConflict +// documentation for more info. +func (u *ChannelMonitorHistoryUpsertBulk) Update(set func(*ChannelMonitorHistoryUpsert)) *ChannelMonitorHistoryUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&ChannelMonitorHistoryUpsert{UpdateSet: update}) + })) + return u +} + +// SetMonitorID sets the "monitor_id" field. +func (u *ChannelMonitorHistoryUpsertBulk) SetMonitorID(v int64) *ChannelMonitorHistoryUpsertBulk { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.SetMonitorID(v) + }) +} + +// UpdateMonitorID sets the "monitor_id" field to the value that was provided on create. +func (u *ChannelMonitorHistoryUpsertBulk) UpdateMonitorID() *ChannelMonitorHistoryUpsertBulk { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.UpdateMonitorID() + }) +} + +// SetModel sets the "model" field. +func (u *ChannelMonitorHistoryUpsertBulk) SetModel(v string) *ChannelMonitorHistoryUpsertBulk { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.SetModel(v) + }) +} + +// UpdateModel sets the "model" field to the value that was provided on create. +func (u *ChannelMonitorHistoryUpsertBulk) UpdateModel() *ChannelMonitorHistoryUpsertBulk { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.UpdateModel() + }) +} + +// SetStatus sets the "status" field. +func (u *ChannelMonitorHistoryUpsertBulk) SetStatus(v channelmonitorhistory.Status) *ChannelMonitorHistoryUpsertBulk { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.SetStatus(v) + }) +} + +// UpdateStatus sets the "status" field to the value that was provided on create. +func (u *ChannelMonitorHistoryUpsertBulk) UpdateStatus() *ChannelMonitorHistoryUpsertBulk { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.UpdateStatus() + }) +} + +// SetLatencyMs sets the "latency_ms" field. +func (u *ChannelMonitorHistoryUpsertBulk) SetLatencyMs(v int) *ChannelMonitorHistoryUpsertBulk { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.SetLatencyMs(v) + }) +} + +// AddLatencyMs adds v to the "latency_ms" field. +func (u *ChannelMonitorHistoryUpsertBulk) AddLatencyMs(v int) *ChannelMonitorHistoryUpsertBulk { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.AddLatencyMs(v) + }) +} + +// UpdateLatencyMs sets the "latency_ms" field to the value that was provided on create. +func (u *ChannelMonitorHistoryUpsertBulk) UpdateLatencyMs() *ChannelMonitorHistoryUpsertBulk { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.UpdateLatencyMs() + }) +} + +// ClearLatencyMs clears the value of the "latency_ms" field. +func (u *ChannelMonitorHistoryUpsertBulk) ClearLatencyMs() *ChannelMonitorHistoryUpsertBulk { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.ClearLatencyMs() + }) +} + +// SetPingLatencyMs sets the "ping_latency_ms" field. +func (u *ChannelMonitorHistoryUpsertBulk) SetPingLatencyMs(v int) *ChannelMonitorHistoryUpsertBulk { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.SetPingLatencyMs(v) + }) +} + +// AddPingLatencyMs adds v to the "ping_latency_ms" field. +func (u *ChannelMonitorHistoryUpsertBulk) AddPingLatencyMs(v int) *ChannelMonitorHistoryUpsertBulk { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.AddPingLatencyMs(v) + }) +} + +// UpdatePingLatencyMs sets the "ping_latency_ms" field to the value that was provided on create. +func (u *ChannelMonitorHistoryUpsertBulk) UpdatePingLatencyMs() *ChannelMonitorHistoryUpsertBulk { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.UpdatePingLatencyMs() + }) +} + +// ClearPingLatencyMs clears the value of the "ping_latency_ms" field. +func (u *ChannelMonitorHistoryUpsertBulk) ClearPingLatencyMs() *ChannelMonitorHistoryUpsertBulk { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.ClearPingLatencyMs() + }) +} + +// SetMessage sets the "message" field. +func (u *ChannelMonitorHistoryUpsertBulk) SetMessage(v string) *ChannelMonitorHistoryUpsertBulk { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.SetMessage(v) + }) +} + +// UpdateMessage sets the "message" field to the value that was provided on create. +func (u *ChannelMonitorHistoryUpsertBulk) UpdateMessage() *ChannelMonitorHistoryUpsertBulk { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.UpdateMessage() + }) +} + +// ClearMessage clears the value of the "message" field. +func (u *ChannelMonitorHistoryUpsertBulk) ClearMessage() *ChannelMonitorHistoryUpsertBulk { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.ClearMessage() + }) +} + +// SetCheckedAt sets the "checked_at" field. +func (u *ChannelMonitorHistoryUpsertBulk) SetCheckedAt(v time.Time) *ChannelMonitorHistoryUpsertBulk { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.SetCheckedAt(v) + }) +} + +// UpdateCheckedAt sets the "checked_at" field to the value that was provided on create. +func (u *ChannelMonitorHistoryUpsertBulk) UpdateCheckedAt() *ChannelMonitorHistoryUpsertBulk { + return u.Update(func(s *ChannelMonitorHistoryUpsert) { + s.UpdateCheckedAt() + }) +} + +// Exec executes the query. +func (u *ChannelMonitorHistoryUpsertBulk) Exec(ctx context.Context) error { + if u.create.err != nil { + return u.create.err + } + for i, b := range u.create.builders { + if len(b.conflict) != 0 { + return fmt.Errorf("ent: OnConflict was set for builder %d. Set it on the ChannelMonitorHistoryCreateBulk instead", i) + } + } + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for ChannelMonitorHistoryCreateBulk.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *ChannelMonitorHistoryUpsertBulk) ExecX(ctx context.Context) { + if err := u.create.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/backend/ent/channelmonitorhistory_delete.go b/backend/ent/channelmonitorhistory_delete.go new file mode 100644 index 00000000..97110e69 --- /dev/null +++ b/backend/ent/channelmonitorhistory_delete.go @@ -0,0 +1,88 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// ChannelMonitorHistoryDelete is the builder for deleting a ChannelMonitorHistory entity. +type ChannelMonitorHistoryDelete struct { + config + hooks []Hook + mutation *ChannelMonitorHistoryMutation +} + +// Where appends a list predicates to the ChannelMonitorHistoryDelete builder. +func (_d *ChannelMonitorHistoryDelete) Where(ps ...predicate.ChannelMonitorHistory) *ChannelMonitorHistoryDelete { + _d.mutation.Where(ps...) + return _d +} + +// Exec executes the deletion query and returns how many vertices were deleted. +func (_d *ChannelMonitorHistoryDelete) Exec(ctx context.Context) (int, error) { + return withHooks(ctx, _d.sqlExec, _d.mutation, _d.hooks) +} + +// ExecX is like Exec, but panics if an error occurs. +func (_d *ChannelMonitorHistoryDelete) ExecX(ctx context.Context) int { + n, err := _d.Exec(ctx) + if err != nil { + panic(err) + } + return n +} + +func (_d *ChannelMonitorHistoryDelete) sqlExec(ctx context.Context) (int, error) { + _spec := sqlgraph.NewDeleteSpec(channelmonitorhistory.Table, sqlgraph.NewFieldSpec(channelmonitorhistory.FieldID, field.TypeInt64)) + if ps := _d.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + affected, err := sqlgraph.DeleteNodes(ctx, _d.driver, _spec) + if err != nil && sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + _d.mutation.done = true + return affected, err +} + +// ChannelMonitorHistoryDeleteOne is the builder for deleting a single ChannelMonitorHistory entity. +type ChannelMonitorHistoryDeleteOne struct { + _d *ChannelMonitorHistoryDelete +} + +// Where appends a list predicates to the ChannelMonitorHistoryDelete builder. +func (_d *ChannelMonitorHistoryDeleteOne) Where(ps ...predicate.ChannelMonitorHistory) *ChannelMonitorHistoryDeleteOne { + _d._d.mutation.Where(ps...) + return _d +} + +// Exec executes the deletion query. +func (_d *ChannelMonitorHistoryDeleteOne) Exec(ctx context.Context) error { + n, err := _d._d.Exec(ctx) + switch { + case err != nil: + return err + case n == 0: + return &NotFoundError{channelmonitorhistory.Label} + default: + return nil + } +} + +// ExecX is like Exec, but panics if an error occurs. +func (_d *ChannelMonitorHistoryDeleteOne) ExecX(ctx context.Context) { + if err := _d.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/backend/ent/channelmonitorhistory_query.go b/backend/ent/channelmonitorhistory_query.go new file mode 100644 index 00000000..1fb872ad --- /dev/null +++ b/backend/ent/channelmonitorhistory_query.go @@ -0,0 +1,643 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "fmt" + "math" + + "entgo.io/ent" + "entgo.io/ent/dialect" + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// ChannelMonitorHistoryQuery is the builder for querying ChannelMonitorHistory entities. +type ChannelMonitorHistoryQuery struct { + config + ctx *QueryContext + order []channelmonitorhistory.OrderOption + inters []Interceptor + predicates []predicate.ChannelMonitorHistory + withMonitor *ChannelMonitorQuery + modifiers []func(*sql.Selector) + // intermediate query (i.e. traversal path). + sql *sql.Selector + path func(context.Context) (*sql.Selector, error) +} + +// Where adds a new predicate for the ChannelMonitorHistoryQuery builder. +func (_q *ChannelMonitorHistoryQuery) Where(ps ...predicate.ChannelMonitorHistory) *ChannelMonitorHistoryQuery { + _q.predicates = append(_q.predicates, ps...) + return _q +} + +// Limit the number of records to be returned by this query. +func (_q *ChannelMonitorHistoryQuery) Limit(limit int) *ChannelMonitorHistoryQuery { + _q.ctx.Limit = &limit + return _q +} + +// Offset to start from. +func (_q *ChannelMonitorHistoryQuery) Offset(offset int) *ChannelMonitorHistoryQuery { + _q.ctx.Offset = &offset + return _q +} + +// Unique configures the query builder to filter duplicate records on query. +// By default, unique is set to true, and can be disabled using this method. +func (_q *ChannelMonitorHistoryQuery) Unique(unique bool) *ChannelMonitorHistoryQuery { + _q.ctx.Unique = &unique + return _q +} + +// Order specifies how the records should be ordered. +func (_q *ChannelMonitorHistoryQuery) Order(o ...channelmonitorhistory.OrderOption) *ChannelMonitorHistoryQuery { + _q.order = append(_q.order, o...) + return _q +} + +// QueryMonitor chains the current query on the "monitor" edge. +func (_q *ChannelMonitorHistoryQuery) QueryMonitor() *ChannelMonitorQuery { + query := (&ChannelMonitorClient{config: _q.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := _q.prepareQuery(ctx); err != nil { + return nil, err + } + selector := _q.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(channelmonitorhistory.Table, channelmonitorhistory.FieldID, selector), + sqlgraph.To(channelmonitor.Table, channelmonitor.FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, channelmonitorhistory.MonitorTable, channelmonitorhistory.MonitorColumn), + ) + fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step) + return fromU, nil + } + return query +} + +// First returns the first ChannelMonitorHistory entity from the query. +// Returns a *NotFoundError when no ChannelMonitorHistory was found. +func (_q *ChannelMonitorHistoryQuery) First(ctx context.Context) (*ChannelMonitorHistory, error) { + nodes, err := _q.Limit(1).All(setContextOp(ctx, _q.ctx, ent.OpQueryFirst)) + if err != nil { + return nil, err + } + if len(nodes) == 0 { + return nil, &NotFoundError{channelmonitorhistory.Label} + } + return nodes[0], nil +} + +// FirstX is like First, but panics if an error occurs. +func (_q *ChannelMonitorHistoryQuery) FirstX(ctx context.Context) *ChannelMonitorHistory { + node, err := _q.First(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return node +} + +// FirstID returns the first ChannelMonitorHistory ID from the query. +// Returns a *NotFoundError when no ChannelMonitorHistory ID was found. +func (_q *ChannelMonitorHistoryQuery) FirstID(ctx context.Context) (id int64, err error) { + var ids []int64 + if ids, err = _q.Limit(1).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryFirstID)); err != nil { + return + } + if len(ids) == 0 { + err = &NotFoundError{channelmonitorhistory.Label} + return + } + return ids[0], nil +} + +// FirstIDX is like FirstID, but panics if an error occurs. +func (_q *ChannelMonitorHistoryQuery) FirstIDX(ctx context.Context) int64 { + id, err := _q.FirstID(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return id +} + +// Only returns a single ChannelMonitorHistory entity found by the query, ensuring it only returns one. +// Returns a *NotSingularError when more than one ChannelMonitorHistory entity is found. +// Returns a *NotFoundError when no ChannelMonitorHistory entities are found. +func (_q *ChannelMonitorHistoryQuery) Only(ctx context.Context) (*ChannelMonitorHistory, error) { + nodes, err := _q.Limit(2).All(setContextOp(ctx, _q.ctx, ent.OpQueryOnly)) + if err != nil { + return nil, err + } + switch len(nodes) { + case 1: + return nodes[0], nil + case 0: + return nil, &NotFoundError{channelmonitorhistory.Label} + default: + return nil, &NotSingularError{channelmonitorhistory.Label} + } +} + +// OnlyX is like Only, but panics if an error occurs. +func (_q *ChannelMonitorHistoryQuery) OnlyX(ctx context.Context) *ChannelMonitorHistory { + node, err := _q.Only(ctx) + if err != nil { + panic(err) + } + return node +} + +// OnlyID is like Only, but returns the only ChannelMonitorHistory ID in the query. +// Returns a *NotSingularError when more than one ChannelMonitorHistory ID is found. +// Returns a *NotFoundError when no entities are found. +func (_q *ChannelMonitorHistoryQuery) OnlyID(ctx context.Context) (id int64, err error) { + var ids []int64 + if ids, err = _q.Limit(2).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryOnlyID)); err != nil { + return + } + switch len(ids) { + case 1: + id = ids[0] + case 0: + err = &NotFoundError{channelmonitorhistory.Label} + default: + err = &NotSingularError{channelmonitorhistory.Label} + } + return +} + +// OnlyIDX is like OnlyID, but panics if an error occurs. +func (_q *ChannelMonitorHistoryQuery) OnlyIDX(ctx context.Context) int64 { + id, err := _q.OnlyID(ctx) + if err != nil { + panic(err) + } + return id +} + +// All executes the query and returns a list of ChannelMonitorHistories. +func (_q *ChannelMonitorHistoryQuery) All(ctx context.Context) ([]*ChannelMonitorHistory, error) { + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryAll) + if err := _q.prepareQuery(ctx); err != nil { + return nil, err + } + qr := querierAll[[]*ChannelMonitorHistory, *ChannelMonitorHistoryQuery]() + return withInterceptors[[]*ChannelMonitorHistory](ctx, _q, qr, _q.inters) +} + +// AllX is like All, but panics if an error occurs. +func (_q *ChannelMonitorHistoryQuery) AllX(ctx context.Context) []*ChannelMonitorHistory { + nodes, err := _q.All(ctx) + if err != nil { + panic(err) + } + return nodes +} + +// IDs executes the query and returns a list of ChannelMonitorHistory IDs. +func (_q *ChannelMonitorHistoryQuery) IDs(ctx context.Context) (ids []int64, err error) { + if _q.ctx.Unique == nil && _q.path != nil { + _q.Unique(true) + } + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryIDs) + if err = _q.Select(channelmonitorhistory.FieldID).Scan(ctx, &ids); err != nil { + return nil, err + } + return ids, nil +} + +// IDsX is like IDs, but panics if an error occurs. +func (_q *ChannelMonitorHistoryQuery) IDsX(ctx context.Context) []int64 { + ids, err := _q.IDs(ctx) + if err != nil { + panic(err) + } + return ids +} + +// Count returns the count of the given query. +func (_q *ChannelMonitorHistoryQuery) Count(ctx context.Context) (int, error) { + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryCount) + if err := _q.prepareQuery(ctx); err != nil { + return 0, err + } + return withInterceptors[int](ctx, _q, querierCount[*ChannelMonitorHistoryQuery](), _q.inters) +} + +// CountX is like Count, but panics if an error occurs. +func (_q *ChannelMonitorHistoryQuery) CountX(ctx context.Context) int { + count, err := _q.Count(ctx) + if err != nil { + panic(err) + } + return count +} + +// Exist returns true if the query has elements in the graph. +func (_q *ChannelMonitorHistoryQuery) Exist(ctx context.Context) (bool, error) { + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryExist) + switch _, err := _q.FirstID(ctx); { + case IsNotFound(err): + return false, nil + case err != nil: + return false, fmt.Errorf("ent: check existence: %w", err) + default: + return true, nil + } +} + +// ExistX is like Exist, but panics if an error occurs. +func (_q *ChannelMonitorHistoryQuery) ExistX(ctx context.Context) bool { + exist, err := _q.Exist(ctx) + if err != nil { + panic(err) + } + return exist +} + +// Clone returns a duplicate of the ChannelMonitorHistoryQuery builder, including all associated steps. It can be +// used to prepare common query builders and use them differently after the clone is made. +func (_q *ChannelMonitorHistoryQuery) Clone() *ChannelMonitorHistoryQuery { + if _q == nil { + return nil + } + return &ChannelMonitorHistoryQuery{ + config: _q.config, + ctx: _q.ctx.Clone(), + order: append([]channelmonitorhistory.OrderOption{}, _q.order...), + inters: append([]Interceptor{}, _q.inters...), + predicates: append([]predicate.ChannelMonitorHistory{}, _q.predicates...), + withMonitor: _q.withMonitor.Clone(), + // clone intermediate query. + sql: _q.sql.Clone(), + path: _q.path, + } +} + +// WithMonitor tells the query-builder to eager-load the nodes that are connected to +// the "monitor" edge. The optional arguments are used to configure the query builder of the edge. +func (_q *ChannelMonitorHistoryQuery) WithMonitor(opts ...func(*ChannelMonitorQuery)) *ChannelMonitorHistoryQuery { + query := (&ChannelMonitorClient{config: _q.config}).Query() + for _, opt := range opts { + opt(query) + } + _q.withMonitor = query + return _q +} + +// GroupBy is used to group vertices by one or more fields/columns. +// It is often used with aggregate functions, like: count, max, mean, min, sum. +// +// Example: +// +// var v []struct { +// MonitorID int64 `json:"monitor_id,omitempty"` +// Count int `json:"count,omitempty"` +// } +// +// client.ChannelMonitorHistory.Query(). +// GroupBy(channelmonitorhistory.FieldMonitorID). +// Aggregate(ent.Count()). +// Scan(ctx, &v) +func (_q *ChannelMonitorHistoryQuery) GroupBy(field string, fields ...string) *ChannelMonitorHistoryGroupBy { + _q.ctx.Fields = append([]string{field}, fields...) + grbuild := &ChannelMonitorHistoryGroupBy{build: _q} + grbuild.flds = &_q.ctx.Fields + grbuild.label = channelmonitorhistory.Label + grbuild.scan = grbuild.Scan + return grbuild +} + +// Select allows the selection one or more fields/columns for the given query, +// instead of selecting all fields in the entity. +// +// Example: +// +// var v []struct { +// MonitorID int64 `json:"monitor_id,omitempty"` +// } +// +// client.ChannelMonitorHistory.Query(). +// Select(channelmonitorhistory.FieldMonitorID). +// Scan(ctx, &v) +func (_q *ChannelMonitorHistoryQuery) Select(fields ...string) *ChannelMonitorHistorySelect { + _q.ctx.Fields = append(_q.ctx.Fields, fields...) + sbuild := &ChannelMonitorHistorySelect{ChannelMonitorHistoryQuery: _q} + sbuild.label = channelmonitorhistory.Label + sbuild.flds, sbuild.scan = &_q.ctx.Fields, sbuild.Scan + return sbuild +} + +// Aggregate returns a ChannelMonitorHistorySelect configured with the given aggregations. +func (_q *ChannelMonitorHistoryQuery) Aggregate(fns ...AggregateFunc) *ChannelMonitorHistorySelect { + return _q.Select().Aggregate(fns...) +} + +func (_q *ChannelMonitorHistoryQuery) prepareQuery(ctx context.Context) error { + for _, inter := range _q.inters { + if inter == nil { + return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)") + } + if trv, ok := inter.(Traverser); ok { + if err := trv.Traverse(ctx, _q); err != nil { + return err + } + } + } + for _, f := range _q.ctx.Fields { + if !channelmonitorhistory.ValidColumn(f) { + return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + } + if _q.path != nil { + prev, err := _q.path(ctx) + if err != nil { + return err + } + _q.sql = prev + } + return nil +} + +func (_q *ChannelMonitorHistoryQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*ChannelMonitorHistory, error) { + var ( + nodes = []*ChannelMonitorHistory{} + _spec = _q.querySpec() + loadedTypes = [1]bool{ + _q.withMonitor != nil, + } + ) + _spec.ScanValues = func(columns []string) ([]any, error) { + return (*ChannelMonitorHistory).scanValues(nil, columns) + } + _spec.Assign = func(columns []string, values []any) error { + node := &ChannelMonitorHistory{config: _q.config} + nodes = append(nodes, node) + node.Edges.loadedTypes = loadedTypes + return node.assignValues(columns, values) + } + if len(_q.modifiers) > 0 { + _spec.Modifiers = _q.modifiers + } + for i := range hooks { + hooks[i](ctx, _spec) + } + if err := sqlgraph.QueryNodes(ctx, _q.driver, _spec); err != nil { + return nil, err + } + if len(nodes) == 0 { + return nodes, nil + } + if query := _q.withMonitor; query != nil { + if err := _q.loadMonitor(ctx, query, nodes, nil, + func(n *ChannelMonitorHistory, e *ChannelMonitor) { n.Edges.Monitor = e }); err != nil { + return nil, err + } + } + return nodes, nil +} + +func (_q *ChannelMonitorHistoryQuery) loadMonitor(ctx context.Context, query *ChannelMonitorQuery, nodes []*ChannelMonitorHistory, init func(*ChannelMonitorHistory), assign func(*ChannelMonitorHistory, *ChannelMonitor)) error { + ids := make([]int64, 0, len(nodes)) + nodeids := make(map[int64][]*ChannelMonitorHistory) + for i := range nodes { + fk := nodes[i].MonitorID + if _, ok := nodeids[fk]; !ok { + ids = append(ids, fk) + } + nodeids[fk] = append(nodeids[fk], nodes[i]) + } + if len(ids) == 0 { + return nil + } + query.Where(channelmonitor.IDIn(ids...)) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + nodes, ok := nodeids[n.ID] + if !ok { + return fmt.Errorf(`unexpected foreign-key "monitor_id" returned %v`, n.ID) + } + for i := range nodes { + assign(nodes[i], n) + } + } + return nil +} + +func (_q *ChannelMonitorHistoryQuery) sqlCount(ctx context.Context) (int, error) { + _spec := _q.querySpec() + if len(_q.modifiers) > 0 { + _spec.Modifiers = _q.modifiers + } + _spec.Node.Columns = _q.ctx.Fields + if len(_q.ctx.Fields) > 0 { + _spec.Unique = _q.ctx.Unique != nil && *_q.ctx.Unique + } + return sqlgraph.CountNodes(ctx, _q.driver, _spec) +} + +func (_q *ChannelMonitorHistoryQuery) querySpec() *sqlgraph.QuerySpec { + _spec := sqlgraph.NewQuerySpec(channelmonitorhistory.Table, channelmonitorhistory.Columns, sqlgraph.NewFieldSpec(channelmonitorhistory.FieldID, field.TypeInt64)) + _spec.From = _q.sql + if unique := _q.ctx.Unique; unique != nil { + _spec.Unique = *unique + } else if _q.path != nil { + _spec.Unique = true + } + if fields := _q.ctx.Fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, channelmonitorhistory.FieldID) + for i := range fields { + if fields[i] != channelmonitorhistory.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) + } + } + if _q.withMonitor != nil { + _spec.Node.AddColumnOnce(channelmonitorhistory.FieldMonitorID) + } + } + if ps := _q.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if limit := _q.ctx.Limit; limit != nil { + _spec.Limit = *limit + } + if offset := _q.ctx.Offset; offset != nil { + _spec.Offset = *offset + } + if ps := _q.order; len(ps) > 0 { + _spec.Order = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + return _spec +} + +func (_q *ChannelMonitorHistoryQuery) sqlQuery(ctx context.Context) *sql.Selector { + builder := sql.Dialect(_q.driver.Dialect()) + t1 := builder.Table(channelmonitorhistory.Table) + columns := _q.ctx.Fields + if len(columns) == 0 { + columns = channelmonitorhistory.Columns + } + selector := builder.Select(t1.Columns(columns...)...).From(t1) + if _q.sql != nil { + selector = _q.sql + selector.Select(selector.Columns(columns...)...) + } + if _q.ctx.Unique != nil && *_q.ctx.Unique { + selector.Distinct() + } + for _, m := range _q.modifiers { + m(selector) + } + for _, p := range _q.predicates { + p(selector) + } + for _, p := range _q.order { + p(selector) + } + if offset := _q.ctx.Offset; offset != nil { + // limit is mandatory for offset clause. We start + // with default value, and override it below if needed. + selector.Offset(*offset).Limit(math.MaxInt32) + } + if limit := _q.ctx.Limit; limit != nil { + selector.Limit(*limit) + } + return selector +} + +// ForUpdate locks the selected rows against concurrent updates, and prevent them from being +// updated, deleted or "selected ... for update" by other sessions, until the transaction is +// either committed or rolled-back. +func (_q *ChannelMonitorHistoryQuery) ForUpdate(opts ...sql.LockOption) *ChannelMonitorHistoryQuery { + if _q.driver.Dialect() == dialect.Postgres { + _q.Unique(false) + } + _q.modifiers = append(_q.modifiers, func(s *sql.Selector) { + s.ForUpdate(opts...) + }) + return _q +} + +// ForShare behaves similarly to ForUpdate, except that it acquires a shared mode lock +// on any rows that are read. Other sessions can read the rows, but cannot modify them +// until your transaction commits. +func (_q *ChannelMonitorHistoryQuery) ForShare(opts ...sql.LockOption) *ChannelMonitorHistoryQuery { + if _q.driver.Dialect() == dialect.Postgres { + _q.Unique(false) + } + _q.modifiers = append(_q.modifiers, func(s *sql.Selector) { + s.ForShare(opts...) + }) + return _q +} + +// ChannelMonitorHistoryGroupBy is the group-by builder for ChannelMonitorHistory entities. +type ChannelMonitorHistoryGroupBy struct { + selector + build *ChannelMonitorHistoryQuery +} + +// Aggregate adds the given aggregation functions to the group-by query. +func (_g *ChannelMonitorHistoryGroupBy) Aggregate(fns ...AggregateFunc) *ChannelMonitorHistoryGroupBy { + _g.fns = append(_g.fns, fns...) + return _g +} + +// Scan applies the selector query and scans the result into the given value. +func (_g *ChannelMonitorHistoryGroupBy) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, _g.build.ctx, ent.OpQueryGroupBy) + if err := _g.build.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*ChannelMonitorHistoryQuery, *ChannelMonitorHistoryGroupBy](ctx, _g.build, _g, _g.build.inters, v) +} + +func (_g *ChannelMonitorHistoryGroupBy) sqlScan(ctx context.Context, root *ChannelMonitorHistoryQuery, v any) error { + selector := root.sqlQuery(ctx).Select() + aggregation := make([]string, 0, len(_g.fns)) + for _, fn := range _g.fns { + aggregation = append(aggregation, fn(selector)) + } + if len(selector.SelectedColumns()) == 0 { + columns := make([]string, 0, len(*_g.flds)+len(_g.fns)) + for _, f := range *_g.flds { + columns = append(columns, selector.C(f)) + } + columns = append(columns, aggregation...) + selector.Select(columns...) + } + selector.GroupBy(selector.Columns(*_g.flds...)...) + if err := selector.Err(); err != nil { + return err + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := _g.build.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} + +// ChannelMonitorHistorySelect is the builder for selecting fields of ChannelMonitorHistory entities. +type ChannelMonitorHistorySelect struct { + *ChannelMonitorHistoryQuery + selector +} + +// Aggregate adds the given aggregation functions to the selector query. +func (_s *ChannelMonitorHistorySelect) Aggregate(fns ...AggregateFunc) *ChannelMonitorHistorySelect { + _s.fns = append(_s.fns, fns...) + return _s +} + +// Scan applies the selector query and scans the result into the given value. +func (_s *ChannelMonitorHistorySelect) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, _s.ctx, ent.OpQuerySelect) + if err := _s.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*ChannelMonitorHistoryQuery, *ChannelMonitorHistorySelect](ctx, _s.ChannelMonitorHistoryQuery, _s, _s.inters, v) +} + +func (_s *ChannelMonitorHistorySelect) sqlScan(ctx context.Context, root *ChannelMonitorHistoryQuery, v any) error { + selector := root.sqlQuery(ctx) + aggregation := make([]string, 0, len(_s.fns)) + for _, fn := range _s.fns { + aggregation = append(aggregation, fn(selector)) + } + switch n := len(*_s.selector.flds); { + case n == 0 && len(aggregation) > 0: + selector.Select(aggregation...) + case n != 0 && len(aggregation) > 0: + selector.AppendSelect(aggregation...) + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := _s.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} diff --git a/backend/ent/channelmonitorhistory_update.go b/backend/ent/channelmonitorhistory_update.go new file mode 100644 index 00000000..a85a8072 --- /dev/null +++ b/backend/ent/channelmonitorhistory_update.go @@ -0,0 +1,635 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// ChannelMonitorHistoryUpdate is the builder for updating ChannelMonitorHistory entities. +type ChannelMonitorHistoryUpdate struct { + config + hooks []Hook + mutation *ChannelMonitorHistoryMutation +} + +// Where appends a list predicates to the ChannelMonitorHistoryUpdate builder. +func (_u *ChannelMonitorHistoryUpdate) Where(ps ...predicate.ChannelMonitorHistory) *ChannelMonitorHistoryUpdate { + _u.mutation.Where(ps...) + return _u +} + +// SetMonitorID sets the "monitor_id" field. +func (_u *ChannelMonitorHistoryUpdate) SetMonitorID(v int64) *ChannelMonitorHistoryUpdate { + _u.mutation.SetMonitorID(v) + return _u +} + +// SetNillableMonitorID sets the "monitor_id" field if the given value is not nil. +func (_u *ChannelMonitorHistoryUpdate) SetNillableMonitorID(v *int64) *ChannelMonitorHistoryUpdate { + if v != nil { + _u.SetMonitorID(*v) + } + return _u +} + +// SetModel sets the "model" field. +func (_u *ChannelMonitorHistoryUpdate) SetModel(v string) *ChannelMonitorHistoryUpdate { + _u.mutation.SetModel(v) + return _u +} + +// SetNillableModel sets the "model" field if the given value is not nil. +func (_u *ChannelMonitorHistoryUpdate) SetNillableModel(v *string) *ChannelMonitorHistoryUpdate { + if v != nil { + _u.SetModel(*v) + } + return _u +} + +// SetStatus sets the "status" field. +func (_u *ChannelMonitorHistoryUpdate) SetStatus(v channelmonitorhistory.Status) *ChannelMonitorHistoryUpdate { + _u.mutation.SetStatus(v) + return _u +} + +// SetNillableStatus sets the "status" field if the given value is not nil. +func (_u *ChannelMonitorHistoryUpdate) SetNillableStatus(v *channelmonitorhistory.Status) *ChannelMonitorHistoryUpdate { + if v != nil { + _u.SetStatus(*v) + } + return _u +} + +// SetLatencyMs sets the "latency_ms" field. +func (_u *ChannelMonitorHistoryUpdate) SetLatencyMs(v int) *ChannelMonitorHistoryUpdate { + _u.mutation.ResetLatencyMs() + _u.mutation.SetLatencyMs(v) + return _u +} + +// SetNillableLatencyMs sets the "latency_ms" field if the given value is not nil. +func (_u *ChannelMonitorHistoryUpdate) SetNillableLatencyMs(v *int) *ChannelMonitorHistoryUpdate { + if v != nil { + _u.SetLatencyMs(*v) + } + return _u +} + +// AddLatencyMs adds value to the "latency_ms" field. +func (_u *ChannelMonitorHistoryUpdate) AddLatencyMs(v int) *ChannelMonitorHistoryUpdate { + _u.mutation.AddLatencyMs(v) + return _u +} + +// ClearLatencyMs clears the value of the "latency_ms" field. +func (_u *ChannelMonitorHistoryUpdate) ClearLatencyMs() *ChannelMonitorHistoryUpdate { + _u.mutation.ClearLatencyMs() + return _u +} + +// SetPingLatencyMs sets the "ping_latency_ms" field. +func (_u *ChannelMonitorHistoryUpdate) SetPingLatencyMs(v int) *ChannelMonitorHistoryUpdate { + _u.mutation.ResetPingLatencyMs() + _u.mutation.SetPingLatencyMs(v) + return _u +} + +// SetNillablePingLatencyMs sets the "ping_latency_ms" field if the given value is not nil. +func (_u *ChannelMonitorHistoryUpdate) SetNillablePingLatencyMs(v *int) *ChannelMonitorHistoryUpdate { + if v != nil { + _u.SetPingLatencyMs(*v) + } + return _u +} + +// AddPingLatencyMs adds value to the "ping_latency_ms" field. +func (_u *ChannelMonitorHistoryUpdate) AddPingLatencyMs(v int) *ChannelMonitorHistoryUpdate { + _u.mutation.AddPingLatencyMs(v) + return _u +} + +// ClearPingLatencyMs clears the value of the "ping_latency_ms" field. +func (_u *ChannelMonitorHistoryUpdate) ClearPingLatencyMs() *ChannelMonitorHistoryUpdate { + _u.mutation.ClearPingLatencyMs() + return _u +} + +// SetMessage sets the "message" field. +func (_u *ChannelMonitorHistoryUpdate) SetMessage(v string) *ChannelMonitorHistoryUpdate { + _u.mutation.SetMessage(v) + return _u +} + +// SetNillableMessage sets the "message" field if the given value is not nil. +func (_u *ChannelMonitorHistoryUpdate) SetNillableMessage(v *string) *ChannelMonitorHistoryUpdate { + if v != nil { + _u.SetMessage(*v) + } + return _u +} + +// ClearMessage clears the value of the "message" field. +func (_u *ChannelMonitorHistoryUpdate) ClearMessage() *ChannelMonitorHistoryUpdate { + _u.mutation.ClearMessage() + return _u +} + +// SetCheckedAt sets the "checked_at" field. +func (_u *ChannelMonitorHistoryUpdate) SetCheckedAt(v time.Time) *ChannelMonitorHistoryUpdate { + _u.mutation.SetCheckedAt(v) + return _u +} + +// SetNillableCheckedAt sets the "checked_at" field if the given value is not nil. +func (_u *ChannelMonitorHistoryUpdate) SetNillableCheckedAt(v *time.Time) *ChannelMonitorHistoryUpdate { + if v != nil { + _u.SetCheckedAt(*v) + } + return _u +} + +// SetMonitor sets the "monitor" edge to the ChannelMonitor entity. +func (_u *ChannelMonitorHistoryUpdate) SetMonitor(v *ChannelMonitor) *ChannelMonitorHistoryUpdate { + return _u.SetMonitorID(v.ID) +} + +// Mutation returns the ChannelMonitorHistoryMutation object of the builder. +func (_u *ChannelMonitorHistoryUpdate) Mutation() *ChannelMonitorHistoryMutation { + return _u.mutation +} + +// ClearMonitor clears the "monitor" edge to the ChannelMonitor entity. +func (_u *ChannelMonitorHistoryUpdate) ClearMonitor() *ChannelMonitorHistoryUpdate { + _u.mutation.ClearMonitor() + return _u +} + +// Save executes the query and returns the number of nodes affected by the update operation. +func (_u *ChannelMonitorHistoryUpdate) Save(ctx context.Context) (int, error) { + return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (_u *ChannelMonitorHistoryUpdate) SaveX(ctx context.Context) int { + affected, err := _u.Save(ctx) + if err != nil { + panic(err) + } + return affected +} + +// Exec executes the query. +func (_u *ChannelMonitorHistoryUpdate) Exec(ctx context.Context) error { + _, err := _u.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_u *ChannelMonitorHistoryUpdate) ExecX(ctx context.Context) { + if err := _u.Exec(ctx); err != nil { + panic(err) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_u *ChannelMonitorHistoryUpdate) check() error { + if v, ok := _u.mutation.Model(); ok { + if err := channelmonitorhistory.ModelValidator(v); err != nil { + return &ValidationError{Name: "model", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorHistory.model": %w`, err)} + } + } + if v, ok := _u.mutation.Status(); ok { + if err := channelmonitorhistory.StatusValidator(v); err != nil { + return &ValidationError{Name: "status", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorHistory.status": %w`, err)} + } + } + if v, ok := _u.mutation.Message(); ok { + if err := channelmonitorhistory.MessageValidator(v); err != nil { + return &ValidationError{Name: "message", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorHistory.message": %w`, err)} + } + } + if _u.mutation.MonitorCleared() && len(_u.mutation.MonitorIDs()) > 0 { + return errors.New(`ent: clearing a required unique edge "ChannelMonitorHistory.monitor"`) + } + return nil +} + +func (_u *ChannelMonitorHistoryUpdate) sqlSave(ctx context.Context) (_node int, err error) { + if err := _u.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(channelmonitorhistory.Table, channelmonitorhistory.Columns, sqlgraph.NewFieldSpec(channelmonitorhistory.FieldID, field.TypeInt64)) + if ps := _u.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := _u.mutation.Model(); ok { + _spec.SetField(channelmonitorhistory.FieldModel, field.TypeString, value) + } + if value, ok := _u.mutation.Status(); ok { + _spec.SetField(channelmonitorhistory.FieldStatus, field.TypeEnum, value) + } + if value, ok := _u.mutation.LatencyMs(); ok { + _spec.SetField(channelmonitorhistory.FieldLatencyMs, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedLatencyMs(); ok { + _spec.AddField(channelmonitorhistory.FieldLatencyMs, field.TypeInt, value) + } + if _u.mutation.LatencyMsCleared() { + _spec.ClearField(channelmonitorhistory.FieldLatencyMs, field.TypeInt) + } + if value, ok := _u.mutation.PingLatencyMs(); ok { + _spec.SetField(channelmonitorhistory.FieldPingLatencyMs, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedPingLatencyMs(); ok { + _spec.AddField(channelmonitorhistory.FieldPingLatencyMs, field.TypeInt, value) + } + if _u.mutation.PingLatencyMsCleared() { + _spec.ClearField(channelmonitorhistory.FieldPingLatencyMs, field.TypeInt) + } + if value, ok := _u.mutation.Message(); ok { + _spec.SetField(channelmonitorhistory.FieldMessage, field.TypeString, value) + } + if _u.mutation.MessageCleared() { + _spec.ClearField(channelmonitorhistory.FieldMessage, field.TypeString) + } + if value, ok := _u.mutation.CheckedAt(); ok { + _spec.SetField(channelmonitorhistory.FieldCheckedAt, field.TypeTime, value) + } + if _u.mutation.MonitorCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: channelmonitorhistory.MonitorTable, + Columns: []string{channelmonitorhistory.MonitorColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.MonitorIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: channelmonitorhistory.MonitorTable, + Columns: []string{channelmonitorhistory.MonitorColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if _node, err = sqlgraph.UpdateNodes(ctx, _u.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{channelmonitorhistory.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return 0, err + } + _u.mutation.done = true + return _node, nil +} + +// ChannelMonitorHistoryUpdateOne is the builder for updating a single ChannelMonitorHistory entity. +type ChannelMonitorHistoryUpdateOne struct { + config + fields []string + hooks []Hook + mutation *ChannelMonitorHistoryMutation +} + +// SetMonitorID sets the "monitor_id" field. +func (_u *ChannelMonitorHistoryUpdateOne) SetMonitorID(v int64) *ChannelMonitorHistoryUpdateOne { + _u.mutation.SetMonitorID(v) + return _u +} + +// SetNillableMonitorID sets the "monitor_id" field if the given value is not nil. +func (_u *ChannelMonitorHistoryUpdateOne) SetNillableMonitorID(v *int64) *ChannelMonitorHistoryUpdateOne { + if v != nil { + _u.SetMonitorID(*v) + } + return _u +} + +// SetModel sets the "model" field. +func (_u *ChannelMonitorHistoryUpdateOne) SetModel(v string) *ChannelMonitorHistoryUpdateOne { + _u.mutation.SetModel(v) + return _u +} + +// SetNillableModel sets the "model" field if the given value is not nil. +func (_u *ChannelMonitorHistoryUpdateOne) SetNillableModel(v *string) *ChannelMonitorHistoryUpdateOne { + if v != nil { + _u.SetModel(*v) + } + return _u +} + +// SetStatus sets the "status" field. +func (_u *ChannelMonitorHistoryUpdateOne) SetStatus(v channelmonitorhistory.Status) *ChannelMonitorHistoryUpdateOne { + _u.mutation.SetStatus(v) + return _u +} + +// SetNillableStatus sets the "status" field if the given value is not nil. +func (_u *ChannelMonitorHistoryUpdateOne) SetNillableStatus(v *channelmonitorhistory.Status) *ChannelMonitorHistoryUpdateOne { + if v != nil { + _u.SetStatus(*v) + } + return _u +} + +// SetLatencyMs sets the "latency_ms" field. +func (_u *ChannelMonitorHistoryUpdateOne) SetLatencyMs(v int) *ChannelMonitorHistoryUpdateOne { + _u.mutation.ResetLatencyMs() + _u.mutation.SetLatencyMs(v) + return _u +} + +// SetNillableLatencyMs sets the "latency_ms" field if the given value is not nil. +func (_u *ChannelMonitorHistoryUpdateOne) SetNillableLatencyMs(v *int) *ChannelMonitorHistoryUpdateOne { + if v != nil { + _u.SetLatencyMs(*v) + } + return _u +} + +// AddLatencyMs adds value to the "latency_ms" field. +func (_u *ChannelMonitorHistoryUpdateOne) AddLatencyMs(v int) *ChannelMonitorHistoryUpdateOne { + _u.mutation.AddLatencyMs(v) + return _u +} + +// ClearLatencyMs clears the value of the "latency_ms" field. +func (_u *ChannelMonitorHistoryUpdateOne) ClearLatencyMs() *ChannelMonitorHistoryUpdateOne { + _u.mutation.ClearLatencyMs() + return _u +} + +// SetPingLatencyMs sets the "ping_latency_ms" field. +func (_u *ChannelMonitorHistoryUpdateOne) SetPingLatencyMs(v int) *ChannelMonitorHistoryUpdateOne { + _u.mutation.ResetPingLatencyMs() + _u.mutation.SetPingLatencyMs(v) + return _u +} + +// SetNillablePingLatencyMs sets the "ping_latency_ms" field if the given value is not nil. +func (_u *ChannelMonitorHistoryUpdateOne) SetNillablePingLatencyMs(v *int) *ChannelMonitorHistoryUpdateOne { + if v != nil { + _u.SetPingLatencyMs(*v) + } + return _u +} + +// AddPingLatencyMs adds value to the "ping_latency_ms" field. +func (_u *ChannelMonitorHistoryUpdateOne) AddPingLatencyMs(v int) *ChannelMonitorHistoryUpdateOne { + _u.mutation.AddPingLatencyMs(v) + return _u +} + +// ClearPingLatencyMs clears the value of the "ping_latency_ms" field. +func (_u *ChannelMonitorHistoryUpdateOne) ClearPingLatencyMs() *ChannelMonitorHistoryUpdateOne { + _u.mutation.ClearPingLatencyMs() + return _u +} + +// SetMessage sets the "message" field. +func (_u *ChannelMonitorHistoryUpdateOne) SetMessage(v string) *ChannelMonitorHistoryUpdateOne { + _u.mutation.SetMessage(v) + return _u +} + +// SetNillableMessage sets the "message" field if the given value is not nil. +func (_u *ChannelMonitorHistoryUpdateOne) SetNillableMessage(v *string) *ChannelMonitorHistoryUpdateOne { + if v != nil { + _u.SetMessage(*v) + } + return _u +} + +// ClearMessage clears the value of the "message" field. +func (_u *ChannelMonitorHistoryUpdateOne) ClearMessage() *ChannelMonitorHistoryUpdateOne { + _u.mutation.ClearMessage() + return _u +} + +// SetCheckedAt sets the "checked_at" field. +func (_u *ChannelMonitorHistoryUpdateOne) SetCheckedAt(v time.Time) *ChannelMonitorHistoryUpdateOne { + _u.mutation.SetCheckedAt(v) + return _u +} + +// SetNillableCheckedAt sets the "checked_at" field if the given value is not nil. +func (_u *ChannelMonitorHistoryUpdateOne) SetNillableCheckedAt(v *time.Time) *ChannelMonitorHistoryUpdateOne { + if v != nil { + _u.SetCheckedAt(*v) + } + return _u +} + +// SetMonitor sets the "monitor" edge to the ChannelMonitor entity. +func (_u *ChannelMonitorHistoryUpdateOne) SetMonitor(v *ChannelMonitor) *ChannelMonitorHistoryUpdateOne { + return _u.SetMonitorID(v.ID) +} + +// Mutation returns the ChannelMonitorHistoryMutation object of the builder. +func (_u *ChannelMonitorHistoryUpdateOne) Mutation() *ChannelMonitorHistoryMutation { + return _u.mutation +} + +// ClearMonitor clears the "monitor" edge to the ChannelMonitor entity. +func (_u *ChannelMonitorHistoryUpdateOne) ClearMonitor() *ChannelMonitorHistoryUpdateOne { + _u.mutation.ClearMonitor() + return _u +} + +// Where appends a list predicates to the ChannelMonitorHistoryUpdate builder. +func (_u *ChannelMonitorHistoryUpdateOne) Where(ps ...predicate.ChannelMonitorHistory) *ChannelMonitorHistoryUpdateOne { + _u.mutation.Where(ps...) + return _u +} + +// Select allows selecting one or more fields (columns) of the returned entity. +// The default is selecting all fields defined in the entity schema. +func (_u *ChannelMonitorHistoryUpdateOne) Select(field string, fields ...string) *ChannelMonitorHistoryUpdateOne { + _u.fields = append([]string{field}, fields...) + return _u +} + +// Save executes the query and returns the updated ChannelMonitorHistory entity. +func (_u *ChannelMonitorHistoryUpdateOne) Save(ctx context.Context) (*ChannelMonitorHistory, error) { + return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (_u *ChannelMonitorHistoryUpdateOne) SaveX(ctx context.Context) *ChannelMonitorHistory { + node, err := _u.Save(ctx) + if err != nil { + panic(err) + } + return node +} + +// Exec executes the query on the entity. +func (_u *ChannelMonitorHistoryUpdateOne) Exec(ctx context.Context) error { + _, err := _u.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_u *ChannelMonitorHistoryUpdateOne) ExecX(ctx context.Context) { + if err := _u.Exec(ctx); err != nil { + panic(err) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_u *ChannelMonitorHistoryUpdateOne) check() error { + if v, ok := _u.mutation.Model(); ok { + if err := channelmonitorhistory.ModelValidator(v); err != nil { + return &ValidationError{Name: "model", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorHistory.model": %w`, err)} + } + } + if v, ok := _u.mutation.Status(); ok { + if err := channelmonitorhistory.StatusValidator(v); err != nil { + return &ValidationError{Name: "status", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorHistory.status": %w`, err)} + } + } + if v, ok := _u.mutation.Message(); ok { + if err := channelmonitorhistory.MessageValidator(v); err != nil { + return &ValidationError{Name: "message", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorHistory.message": %w`, err)} + } + } + if _u.mutation.MonitorCleared() && len(_u.mutation.MonitorIDs()) > 0 { + return errors.New(`ent: clearing a required unique edge "ChannelMonitorHistory.monitor"`) + } + return nil +} + +func (_u *ChannelMonitorHistoryUpdateOne) sqlSave(ctx context.Context) (_node *ChannelMonitorHistory, err error) { + if err := _u.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(channelmonitorhistory.Table, channelmonitorhistory.Columns, sqlgraph.NewFieldSpec(channelmonitorhistory.FieldID, field.TypeInt64)) + id, ok := _u.mutation.ID() + if !ok { + return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "ChannelMonitorHistory.id" for update`)} + } + _spec.Node.ID.Value = id + if fields := _u.fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, channelmonitorhistory.FieldID) + for _, f := range fields { + if !channelmonitorhistory.ValidColumn(f) { + return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + if f != channelmonitorhistory.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, f) + } + } + } + if ps := _u.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := _u.mutation.Model(); ok { + _spec.SetField(channelmonitorhistory.FieldModel, field.TypeString, value) + } + if value, ok := _u.mutation.Status(); ok { + _spec.SetField(channelmonitorhistory.FieldStatus, field.TypeEnum, value) + } + if value, ok := _u.mutation.LatencyMs(); ok { + _spec.SetField(channelmonitorhistory.FieldLatencyMs, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedLatencyMs(); ok { + _spec.AddField(channelmonitorhistory.FieldLatencyMs, field.TypeInt, value) + } + if _u.mutation.LatencyMsCleared() { + _spec.ClearField(channelmonitorhistory.FieldLatencyMs, field.TypeInt) + } + if value, ok := _u.mutation.PingLatencyMs(); ok { + _spec.SetField(channelmonitorhistory.FieldPingLatencyMs, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedPingLatencyMs(); ok { + _spec.AddField(channelmonitorhistory.FieldPingLatencyMs, field.TypeInt, value) + } + if _u.mutation.PingLatencyMsCleared() { + _spec.ClearField(channelmonitorhistory.FieldPingLatencyMs, field.TypeInt) + } + if value, ok := _u.mutation.Message(); ok { + _spec.SetField(channelmonitorhistory.FieldMessage, field.TypeString, value) + } + if _u.mutation.MessageCleared() { + _spec.ClearField(channelmonitorhistory.FieldMessage, field.TypeString) + } + if value, ok := _u.mutation.CheckedAt(); ok { + _spec.SetField(channelmonitorhistory.FieldCheckedAt, field.TypeTime, value) + } + if _u.mutation.MonitorCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: channelmonitorhistory.MonitorTable, + Columns: []string{channelmonitorhistory.MonitorColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.MonitorIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: channelmonitorhistory.MonitorTable, + Columns: []string{channelmonitorhistory.MonitorColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + _node = &ChannelMonitorHistory{config: _u.config} + _spec.Assign = _node.assignValues + _spec.ScanValues = _node.scanValues + if err = sqlgraph.UpdateNode(ctx, _u.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{channelmonitorhistory.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + _u.mutation.done = true + return _node, nil +} diff --git a/backend/ent/channelmonitorrequesttemplate.go b/backend/ent/channelmonitorrequesttemplate.go new file mode 100644 index 00000000..b8429a4d --- /dev/null +++ b/backend/ent/channelmonitorrequesttemplate.go @@ -0,0 +1,216 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "encoding/json" + "fmt" + "strings" + "time" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" +) + +// ChannelMonitorRequestTemplate is the model entity for the ChannelMonitorRequestTemplate schema. +type ChannelMonitorRequestTemplate struct { + config `json:"-"` + // ID of the ent. + ID int64 `json:"id,omitempty"` + // CreatedAt holds the value of the "created_at" field. + CreatedAt time.Time `json:"created_at,omitempty"` + // UpdatedAt holds the value of the "updated_at" field. + UpdatedAt time.Time `json:"updated_at,omitempty"` + // Name holds the value of the "name" field. + Name string `json:"name,omitempty"` + // Provider holds the value of the "provider" field. + Provider channelmonitorrequesttemplate.Provider `json:"provider,omitempty"` + // Description holds the value of the "description" field. + Description string `json:"description,omitempty"` + // ExtraHeaders holds the value of the "extra_headers" field. + ExtraHeaders map[string]string `json:"extra_headers,omitempty"` + // BodyOverrideMode holds the value of the "body_override_mode" field. + BodyOverrideMode string `json:"body_override_mode,omitempty"` + // BodyOverride holds the value of the "body_override" field. + BodyOverride map[string]interface{} `json:"body_override,omitempty"` + // Edges holds the relations/edges for other nodes in the graph. + // The values are being populated by the ChannelMonitorRequestTemplateQuery when eager-loading is set. + Edges ChannelMonitorRequestTemplateEdges `json:"edges"` + selectValues sql.SelectValues +} + +// ChannelMonitorRequestTemplateEdges holds the relations/edges for other nodes in the graph. +type ChannelMonitorRequestTemplateEdges struct { + // Monitors holds the value of the monitors edge. + Monitors []*ChannelMonitor `json:"monitors,omitempty"` + // loadedTypes holds the information for reporting if a + // type was loaded (or requested) in eager-loading or not. + loadedTypes [1]bool +} + +// MonitorsOrErr returns the Monitors value or an error if the edge +// was not loaded in eager-loading. +func (e ChannelMonitorRequestTemplateEdges) MonitorsOrErr() ([]*ChannelMonitor, error) { + if e.loadedTypes[0] { + return e.Monitors, nil + } + return nil, &NotLoadedError{edge: "monitors"} +} + +// scanValues returns the types for scanning values from sql.Rows. +func (*ChannelMonitorRequestTemplate) scanValues(columns []string) ([]any, error) { + values := make([]any, len(columns)) + for i := range columns { + switch columns[i] { + case channelmonitorrequesttemplate.FieldExtraHeaders, channelmonitorrequesttemplate.FieldBodyOverride: + values[i] = new([]byte) + case channelmonitorrequesttemplate.FieldID: + values[i] = new(sql.NullInt64) + case channelmonitorrequesttemplate.FieldName, channelmonitorrequesttemplate.FieldProvider, channelmonitorrequesttemplate.FieldDescription, channelmonitorrequesttemplate.FieldBodyOverrideMode: + values[i] = new(sql.NullString) + case channelmonitorrequesttemplate.FieldCreatedAt, channelmonitorrequesttemplate.FieldUpdatedAt: + values[i] = new(sql.NullTime) + default: + values[i] = new(sql.UnknownType) + } + } + return values, nil +} + +// assignValues assigns the values that were returned from sql.Rows (after scanning) +// to the ChannelMonitorRequestTemplate fields. +func (_m *ChannelMonitorRequestTemplate) assignValues(columns []string, values []any) error { + if m, n := len(values), len(columns); m < n { + return fmt.Errorf("mismatch number of scan values: %d != %d", m, n) + } + for i := range columns { + switch columns[i] { + case channelmonitorrequesttemplate.FieldID: + value, ok := values[i].(*sql.NullInt64) + if !ok { + return fmt.Errorf("unexpected type %T for field id", value) + } + _m.ID = int64(value.Int64) + case channelmonitorrequesttemplate.FieldCreatedAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field created_at", values[i]) + } else if value.Valid { + _m.CreatedAt = value.Time + } + case channelmonitorrequesttemplate.FieldUpdatedAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field updated_at", values[i]) + } else if value.Valid { + _m.UpdatedAt = value.Time + } + case channelmonitorrequesttemplate.FieldName: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field name", values[i]) + } else if value.Valid { + _m.Name = value.String + } + case channelmonitorrequesttemplate.FieldProvider: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field provider", values[i]) + } else if value.Valid { + _m.Provider = channelmonitorrequesttemplate.Provider(value.String) + } + case channelmonitorrequesttemplate.FieldDescription: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field description", values[i]) + } else if value.Valid { + _m.Description = value.String + } + case channelmonitorrequesttemplate.FieldExtraHeaders: + if value, ok := values[i].(*[]byte); !ok { + return fmt.Errorf("unexpected type %T for field extra_headers", values[i]) + } else if value != nil && len(*value) > 0 { + if err := json.Unmarshal(*value, &_m.ExtraHeaders); err != nil { + return fmt.Errorf("unmarshal field extra_headers: %w", err) + } + } + case channelmonitorrequesttemplate.FieldBodyOverrideMode: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field body_override_mode", values[i]) + } else if value.Valid { + _m.BodyOverrideMode = value.String + } + case channelmonitorrequesttemplate.FieldBodyOverride: + if value, ok := values[i].(*[]byte); !ok { + return fmt.Errorf("unexpected type %T for field body_override", values[i]) + } else if value != nil && len(*value) > 0 { + if err := json.Unmarshal(*value, &_m.BodyOverride); err != nil { + return fmt.Errorf("unmarshal field body_override: %w", err) + } + } + default: + _m.selectValues.Set(columns[i], values[i]) + } + } + return nil +} + +// Value returns the ent.Value that was dynamically selected and assigned to the ChannelMonitorRequestTemplate. +// This includes values selected through modifiers, order, etc. +func (_m *ChannelMonitorRequestTemplate) Value(name string) (ent.Value, error) { + return _m.selectValues.Get(name) +} + +// QueryMonitors queries the "monitors" edge of the ChannelMonitorRequestTemplate entity. +func (_m *ChannelMonitorRequestTemplate) QueryMonitors() *ChannelMonitorQuery { + return NewChannelMonitorRequestTemplateClient(_m.config).QueryMonitors(_m) +} + +// Update returns a builder for updating this ChannelMonitorRequestTemplate. +// Note that you need to call ChannelMonitorRequestTemplate.Unwrap() before calling this method if this ChannelMonitorRequestTemplate +// was returned from a transaction, and the transaction was committed or rolled back. +func (_m *ChannelMonitorRequestTemplate) Update() *ChannelMonitorRequestTemplateUpdateOne { + return NewChannelMonitorRequestTemplateClient(_m.config).UpdateOne(_m) +} + +// Unwrap unwraps the ChannelMonitorRequestTemplate entity that was returned from a transaction after it was closed, +// so that all future queries will be executed through the driver which created the transaction. +func (_m *ChannelMonitorRequestTemplate) Unwrap() *ChannelMonitorRequestTemplate { + _tx, ok := _m.config.driver.(*txDriver) + if !ok { + panic("ent: ChannelMonitorRequestTemplate is not a transactional entity") + } + _m.config.driver = _tx.drv + return _m +} + +// String implements the fmt.Stringer. +func (_m *ChannelMonitorRequestTemplate) String() string { + var builder strings.Builder + builder.WriteString("ChannelMonitorRequestTemplate(") + builder.WriteString(fmt.Sprintf("id=%v, ", _m.ID)) + builder.WriteString("created_at=") + builder.WriteString(_m.CreatedAt.Format(time.ANSIC)) + builder.WriteString(", ") + builder.WriteString("updated_at=") + builder.WriteString(_m.UpdatedAt.Format(time.ANSIC)) + builder.WriteString(", ") + builder.WriteString("name=") + builder.WriteString(_m.Name) + builder.WriteString(", ") + builder.WriteString("provider=") + builder.WriteString(fmt.Sprintf("%v", _m.Provider)) + builder.WriteString(", ") + builder.WriteString("description=") + builder.WriteString(_m.Description) + builder.WriteString(", ") + builder.WriteString("extra_headers=") + builder.WriteString(fmt.Sprintf("%v", _m.ExtraHeaders)) + builder.WriteString(", ") + builder.WriteString("body_override_mode=") + builder.WriteString(_m.BodyOverrideMode) + builder.WriteString(", ") + builder.WriteString("body_override=") + builder.WriteString(fmt.Sprintf("%v", _m.BodyOverride)) + builder.WriteByte(')') + return builder.String() +} + +// ChannelMonitorRequestTemplates is a parsable slice of ChannelMonitorRequestTemplate. +type ChannelMonitorRequestTemplates []*ChannelMonitorRequestTemplate diff --git a/backend/ent/channelmonitorrequesttemplate/channelmonitorrequesttemplate.go b/backend/ent/channelmonitorrequesttemplate/channelmonitorrequesttemplate.go new file mode 100644 index 00000000..65b8d641 --- /dev/null +++ b/backend/ent/channelmonitorrequesttemplate/channelmonitorrequesttemplate.go @@ -0,0 +1,172 @@ +// Code generated by ent, DO NOT EDIT. + +package channelmonitorrequesttemplate + +import ( + "fmt" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" +) + +const ( + // Label holds the string label denoting the channelmonitorrequesttemplate type in the database. + Label = "channel_monitor_request_template" + // FieldID holds the string denoting the id field in the database. + FieldID = "id" + // FieldCreatedAt holds the string denoting the created_at field in the database. + FieldCreatedAt = "created_at" + // FieldUpdatedAt holds the string denoting the updated_at field in the database. + FieldUpdatedAt = "updated_at" + // FieldName holds the string denoting the name field in the database. + FieldName = "name" + // FieldProvider holds the string denoting the provider field in the database. + FieldProvider = "provider" + // FieldDescription holds the string denoting the description field in the database. + FieldDescription = "description" + // FieldExtraHeaders holds the string denoting the extra_headers field in the database. + FieldExtraHeaders = "extra_headers" + // FieldBodyOverrideMode holds the string denoting the body_override_mode field in the database. + FieldBodyOverrideMode = "body_override_mode" + // FieldBodyOverride holds the string denoting the body_override field in the database. + FieldBodyOverride = "body_override" + // EdgeMonitors holds the string denoting the monitors edge name in mutations. + EdgeMonitors = "monitors" + // Table holds the table name of the channelmonitorrequesttemplate in the database. + Table = "channel_monitor_request_templates" + // MonitorsTable is the table that holds the monitors relation/edge. + MonitorsTable = "channel_monitors" + // MonitorsInverseTable is the table name for the ChannelMonitor entity. + // It exists in this package in order to avoid circular dependency with the "channelmonitor" package. + MonitorsInverseTable = "channel_monitors" + // MonitorsColumn is the table column denoting the monitors relation/edge. + MonitorsColumn = "template_id" +) + +// Columns holds all SQL columns for channelmonitorrequesttemplate fields. +var Columns = []string{ + FieldID, + FieldCreatedAt, + FieldUpdatedAt, + FieldName, + FieldProvider, + FieldDescription, + FieldExtraHeaders, + FieldBodyOverrideMode, + FieldBodyOverride, +} + +// ValidColumn reports if the column name is valid (part of the table columns). +func ValidColumn(column string) bool { + for i := range Columns { + if column == Columns[i] { + return true + } + } + return false +} + +var ( + // DefaultCreatedAt holds the default value on creation for the "created_at" field. + DefaultCreatedAt func() time.Time + // DefaultUpdatedAt holds the default value on creation for the "updated_at" field. + DefaultUpdatedAt func() time.Time + // UpdateDefaultUpdatedAt holds the default value on update for the "updated_at" field. + UpdateDefaultUpdatedAt func() time.Time + // NameValidator is a validator for the "name" field. It is called by the builders before save. + NameValidator func(string) error + // DefaultDescription holds the default value on creation for the "description" field. + DefaultDescription string + // DescriptionValidator is a validator for the "description" field. It is called by the builders before save. + DescriptionValidator func(string) error + // DefaultExtraHeaders holds the default value on creation for the "extra_headers" field. + DefaultExtraHeaders map[string]string + // DefaultBodyOverrideMode holds the default value on creation for the "body_override_mode" field. + DefaultBodyOverrideMode string + // BodyOverrideModeValidator is a validator for the "body_override_mode" field. It is called by the builders before save. + BodyOverrideModeValidator func(string) error +) + +// Provider defines the type for the "provider" enum field. +type Provider string + +// Provider values. +const ( + ProviderOpenai Provider = "openai" + ProviderAnthropic Provider = "anthropic" + ProviderGemini Provider = "gemini" +) + +func (pr Provider) String() string { + return string(pr) +} + +// ProviderValidator is a validator for the "provider" field enum values. It is called by the builders before save. +func ProviderValidator(pr Provider) error { + switch pr { + case ProviderOpenai, ProviderAnthropic, ProviderGemini: + return nil + default: + return fmt.Errorf("channelmonitorrequesttemplate: invalid enum value for provider field: %q", pr) + } +} + +// OrderOption defines the ordering options for the ChannelMonitorRequestTemplate queries. +type OrderOption func(*sql.Selector) + +// ByID orders the results by the id field. +func ByID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldID, opts...).ToFunc() +} + +// ByCreatedAt orders the results by the created_at field. +func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldCreatedAt, opts...).ToFunc() +} + +// ByUpdatedAt orders the results by the updated_at field. +func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc() +} + +// ByName orders the results by the name field. +func ByName(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldName, opts...).ToFunc() +} + +// ByProvider orders the results by the provider field. +func ByProvider(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldProvider, opts...).ToFunc() +} + +// ByDescription orders the results by the description field. +func ByDescription(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldDescription, opts...).ToFunc() +} + +// ByBodyOverrideMode orders the results by the body_override_mode field. +func ByBodyOverrideMode(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldBodyOverrideMode, opts...).ToFunc() +} + +// ByMonitorsCount orders the results by monitors count. +func ByMonitorsCount(opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborsCount(s, newMonitorsStep(), opts...) + } +} + +// ByMonitors orders the results by monitors terms. +func ByMonitors(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newMonitorsStep(), append([]sql.OrderTerm{term}, terms...)...) + } +} +func newMonitorsStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(MonitorsInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, true, MonitorsTable, MonitorsColumn), + ) +} diff --git a/backend/ent/channelmonitorrequesttemplate/where.go b/backend/ent/channelmonitorrequesttemplate/where.go new file mode 100644 index 00000000..b95e5df0 --- /dev/null +++ b/backend/ent/channelmonitorrequesttemplate/where.go @@ -0,0 +1,434 @@ +// Code generated by ent, DO NOT EDIT. + +package channelmonitorrequesttemplate + +import ( + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// ID filters vertices based on their ID field. +func ID(id int64) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldID, id)) +} + +// IDEQ applies the EQ predicate on the ID field. +func IDEQ(id int64) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldID, id)) +} + +// IDNEQ applies the NEQ predicate on the ID field. +func IDNEQ(id int64) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNEQ(FieldID, id)) +} + +// IDIn applies the In predicate on the ID field. +func IDIn(ids ...int64) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldIn(FieldID, ids...)) +} + +// IDNotIn applies the NotIn predicate on the ID field. +func IDNotIn(ids ...int64) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNotIn(FieldID, ids...)) +} + +// IDGT applies the GT predicate on the ID field. +func IDGT(id int64) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldGT(FieldID, id)) +} + +// IDGTE applies the GTE predicate on the ID field. +func IDGTE(id int64) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldGTE(FieldID, id)) +} + +// IDLT applies the LT predicate on the ID field. +func IDLT(id int64) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldLT(FieldID, id)) +} + +// IDLTE applies the LTE predicate on the ID field. +func IDLTE(id int64) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldLTE(FieldID, id)) +} + +// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ. +func CreatedAt(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldCreatedAt, v)) +} + +// UpdatedAt applies equality check predicate on the "updated_at" field. It's identical to UpdatedAtEQ. +func UpdatedAt(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldUpdatedAt, v)) +} + +// Name applies equality check predicate on the "name" field. It's identical to NameEQ. +func Name(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldName, v)) +} + +// Description applies equality check predicate on the "description" field. It's identical to DescriptionEQ. +func Description(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldDescription, v)) +} + +// BodyOverrideMode applies equality check predicate on the "body_override_mode" field. It's identical to BodyOverrideModeEQ. +func BodyOverrideMode(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldBodyOverrideMode, v)) +} + +// CreatedAtEQ applies the EQ predicate on the "created_at" field. +func CreatedAtEQ(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldCreatedAt, v)) +} + +// CreatedAtNEQ applies the NEQ predicate on the "created_at" field. +func CreatedAtNEQ(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNEQ(FieldCreatedAt, v)) +} + +// CreatedAtIn applies the In predicate on the "created_at" field. +func CreatedAtIn(vs ...time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldIn(FieldCreatedAt, vs...)) +} + +// CreatedAtNotIn applies the NotIn predicate on the "created_at" field. +func CreatedAtNotIn(vs ...time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNotIn(FieldCreatedAt, vs...)) +} + +// CreatedAtGT applies the GT predicate on the "created_at" field. +func CreatedAtGT(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldGT(FieldCreatedAt, v)) +} + +// CreatedAtGTE applies the GTE predicate on the "created_at" field. +func CreatedAtGTE(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldGTE(FieldCreatedAt, v)) +} + +// CreatedAtLT applies the LT predicate on the "created_at" field. +func CreatedAtLT(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldLT(FieldCreatedAt, v)) +} + +// CreatedAtLTE applies the LTE predicate on the "created_at" field. +func CreatedAtLTE(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldLTE(FieldCreatedAt, v)) +} + +// UpdatedAtEQ applies the EQ predicate on the "updated_at" field. +func UpdatedAtEQ(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldUpdatedAt, v)) +} + +// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field. +func UpdatedAtNEQ(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNEQ(FieldUpdatedAt, v)) +} + +// UpdatedAtIn applies the In predicate on the "updated_at" field. +func UpdatedAtIn(vs ...time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldIn(FieldUpdatedAt, vs...)) +} + +// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field. +func UpdatedAtNotIn(vs ...time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNotIn(FieldUpdatedAt, vs...)) +} + +// UpdatedAtGT applies the GT predicate on the "updated_at" field. +func UpdatedAtGT(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldGT(FieldUpdatedAt, v)) +} + +// UpdatedAtGTE applies the GTE predicate on the "updated_at" field. +func UpdatedAtGTE(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldGTE(FieldUpdatedAt, v)) +} + +// UpdatedAtLT applies the LT predicate on the "updated_at" field. +func UpdatedAtLT(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldLT(FieldUpdatedAt, v)) +} + +// UpdatedAtLTE applies the LTE predicate on the "updated_at" field. +func UpdatedAtLTE(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldLTE(FieldUpdatedAt, v)) +} + +// NameEQ applies the EQ predicate on the "name" field. +func NameEQ(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldName, v)) +} + +// NameNEQ applies the NEQ predicate on the "name" field. +func NameNEQ(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNEQ(FieldName, v)) +} + +// NameIn applies the In predicate on the "name" field. +func NameIn(vs ...string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldIn(FieldName, vs...)) +} + +// NameNotIn applies the NotIn predicate on the "name" field. +func NameNotIn(vs ...string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNotIn(FieldName, vs...)) +} + +// NameGT applies the GT predicate on the "name" field. +func NameGT(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldGT(FieldName, v)) +} + +// NameGTE applies the GTE predicate on the "name" field. +func NameGTE(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldGTE(FieldName, v)) +} + +// NameLT applies the LT predicate on the "name" field. +func NameLT(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldLT(FieldName, v)) +} + +// NameLTE applies the LTE predicate on the "name" field. +func NameLTE(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldLTE(FieldName, v)) +} + +// NameContains applies the Contains predicate on the "name" field. +func NameContains(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldContains(FieldName, v)) +} + +// NameHasPrefix applies the HasPrefix predicate on the "name" field. +func NameHasPrefix(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldHasPrefix(FieldName, v)) +} + +// NameHasSuffix applies the HasSuffix predicate on the "name" field. +func NameHasSuffix(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldHasSuffix(FieldName, v)) +} + +// NameEqualFold applies the EqualFold predicate on the "name" field. +func NameEqualFold(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEqualFold(FieldName, v)) +} + +// NameContainsFold applies the ContainsFold predicate on the "name" field. +func NameContainsFold(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldContainsFold(FieldName, v)) +} + +// ProviderEQ applies the EQ predicate on the "provider" field. +func ProviderEQ(v Provider) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldProvider, v)) +} + +// ProviderNEQ applies the NEQ predicate on the "provider" field. +func ProviderNEQ(v Provider) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNEQ(FieldProvider, v)) +} + +// ProviderIn applies the In predicate on the "provider" field. +func ProviderIn(vs ...Provider) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldIn(FieldProvider, vs...)) +} + +// ProviderNotIn applies the NotIn predicate on the "provider" field. +func ProviderNotIn(vs ...Provider) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNotIn(FieldProvider, vs...)) +} + +// DescriptionEQ applies the EQ predicate on the "description" field. +func DescriptionEQ(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldDescription, v)) +} + +// DescriptionNEQ applies the NEQ predicate on the "description" field. +func DescriptionNEQ(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNEQ(FieldDescription, v)) +} + +// DescriptionIn applies the In predicate on the "description" field. +func DescriptionIn(vs ...string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldIn(FieldDescription, vs...)) +} + +// DescriptionNotIn applies the NotIn predicate on the "description" field. +func DescriptionNotIn(vs ...string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNotIn(FieldDescription, vs...)) +} + +// DescriptionGT applies the GT predicate on the "description" field. +func DescriptionGT(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldGT(FieldDescription, v)) +} + +// DescriptionGTE applies the GTE predicate on the "description" field. +func DescriptionGTE(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldGTE(FieldDescription, v)) +} + +// DescriptionLT applies the LT predicate on the "description" field. +func DescriptionLT(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldLT(FieldDescription, v)) +} + +// DescriptionLTE applies the LTE predicate on the "description" field. +func DescriptionLTE(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldLTE(FieldDescription, v)) +} + +// DescriptionContains applies the Contains predicate on the "description" field. +func DescriptionContains(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldContains(FieldDescription, v)) +} + +// DescriptionHasPrefix applies the HasPrefix predicate on the "description" field. +func DescriptionHasPrefix(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldHasPrefix(FieldDescription, v)) +} + +// DescriptionHasSuffix applies the HasSuffix predicate on the "description" field. +func DescriptionHasSuffix(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldHasSuffix(FieldDescription, v)) +} + +// DescriptionIsNil applies the IsNil predicate on the "description" field. +func DescriptionIsNil() predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldIsNull(FieldDescription)) +} + +// DescriptionNotNil applies the NotNil predicate on the "description" field. +func DescriptionNotNil() predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNotNull(FieldDescription)) +} + +// DescriptionEqualFold applies the EqualFold predicate on the "description" field. +func DescriptionEqualFold(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEqualFold(FieldDescription, v)) +} + +// DescriptionContainsFold applies the ContainsFold predicate on the "description" field. +func DescriptionContainsFold(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldContainsFold(FieldDescription, v)) +} + +// BodyOverrideModeEQ applies the EQ predicate on the "body_override_mode" field. +func BodyOverrideModeEQ(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeNEQ applies the NEQ predicate on the "body_override_mode" field. +func BodyOverrideModeNEQ(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNEQ(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeIn applies the In predicate on the "body_override_mode" field. +func BodyOverrideModeIn(vs ...string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldIn(FieldBodyOverrideMode, vs...)) +} + +// BodyOverrideModeNotIn applies the NotIn predicate on the "body_override_mode" field. +func BodyOverrideModeNotIn(vs ...string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNotIn(FieldBodyOverrideMode, vs...)) +} + +// BodyOverrideModeGT applies the GT predicate on the "body_override_mode" field. +func BodyOverrideModeGT(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldGT(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeGTE applies the GTE predicate on the "body_override_mode" field. +func BodyOverrideModeGTE(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldGTE(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeLT applies the LT predicate on the "body_override_mode" field. +func BodyOverrideModeLT(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldLT(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeLTE applies the LTE predicate on the "body_override_mode" field. +func BodyOverrideModeLTE(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldLTE(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeContains applies the Contains predicate on the "body_override_mode" field. +func BodyOverrideModeContains(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldContains(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeHasPrefix applies the HasPrefix predicate on the "body_override_mode" field. +func BodyOverrideModeHasPrefix(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldHasPrefix(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeHasSuffix applies the HasSuffix predicate on the "body_override_mode" field. +func BodyOverrideModeHasSuffix(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldHasSuffix(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeEqualFold applies the EqualFold predicate on the "body_override_mode" field. +func BodyOverrideModeEqualFold(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEqualFold(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeContainsFold applies the ContainsFold predicate on the "body_override_mode" field. +func BodyOverrideModeContainsFold(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldContainsFold(FieldBodyOverrideMode, v)) +} + +// BodyOverrideIsNil applies the IsNil predicate on the "body_override" field. +func BodyOverrideIsNil() predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldIsNull(FieldBodyOverride)) +} + +// BodyOverrideNotNil applies the NotNil predicate on the "body_override" field. +func BodyOverrideNotNil() predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNotNull(FieldBodyOverride)) +} + +// HasMonitors applies the HasEdge predicate on the "monitors" edge. +func HasMonitors() predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.O2M, true, MonitorsTable, MonitorsColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasMonitorsWith applies the HasEdge predicate on the "monitors" edge with a given conditions (other predicates). +func HasMonitorsWith(preds ...predicate.ChannelMonitor) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(func(s *sql.Selector) { + step := newMonitorsStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + +// And groups predicates with the AND operator between them. +func And(predicates ...predicate.ChannelMonitorRequestTemplate) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.AndPredicates(predicates...)) +} + +// Or groups predicates with the OR operator between them. +func Or(predicates ...predicate.ChannelMonitorRequestTemplate) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.OrPredicates(predicates...)) +} + +// Not applies the not operator on the given predicate. +func Not(p predicate.ChannelMonitorRequestTemplate) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.NotPredicates(p)) +} diff --git a/backend/ent/channelmonitorrequesttemplate_create.go b/backend/ent/channelmonitorrequesttemplate_create.go new file mode 100644 index 00000000..1ba842cd --- /dev/null +++ b/backend/ent/channelmonitorrequesttemplate_create.go @@ -0,0 +1,942 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" +) + +// ChannelMonitorRequestTemplateCreate is the builder for creating a ChannelMonitorRequestTemplate entity. +type ChannelMonitorRequestTemplateCreate struct { + config + mutation *ChannelMonitorRequestTemplateMutation + hooks []Hook + conflict []sql.ConflictOption +} + +// SetCreatedAt sets the "created_at" field. +func (_c *ChannelMonitorRequestTemplateCreate) SetCreatedAt(v time.Time) *ChannelMonitorRequestTemplateCreate { + _c.mutation.SetCreatedAt(v) + return _c +} + +// SetNillableCreatedAt sets the "created_at" field if the given value is not nil. +func (_c *ChannelMonitorRequestTemplateCreate) SetNillableCreatedAt(v *time.Time) *ChannelMonitorRequestTemplateCreate { + if v != nil { + _c.SetCreatedAt(*v) + } + return _c +} + +// SetUpdatedAt sets the "updated_at" field. +func (_c *ChannelMonitorRequestTemplateCreate) SetUpdatedAt(v time.Time) *ChannelMonitorRequestTemplateCreate { + _c.mutation.SetUpdatedAt(v) + return _c +} + +// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil. +func (_c *ChannelMonitorRequestTemplateCreate) SetNillableUpdatedAt(v *time.Time) *ChannelMonitorRequestTemplateCreate { + if v != nil { + _c.SetUpdatedAt(*v) + } + return _c +} + +// SetName sets the "name" field. +func (_c *ChannelMonitorRequestTemplateCreate) SetName(v string) *ChannelMonitorRequestTemplateCreate { + _c.mutation.SetName(v) + return _c +} + +// SetProvider sets the "provider" field. +func (_c *ChannelMonitorRequestTemplateCreate) SetProvider(v channelmonitorrequesttemplate.Provider) *ChannelMonitorRequestTemplateCreate { + _c.mutation.SetProvider(v) + return _c +} + +// SetDescription sets the "description" field. +func (_c *ChannelMonitorRequestTemplateCreate) SetDescription(v string) *ChannelMonitorRequestTemplateCreate { + _c.mutation.SetDescription(v) + return _c +} + +// SetNillableDescription sets the "description" field if the given value is not nil. +func (_c *ChannelMonitorRequestTemplateCreate) SetNillableDescription(v *string) *ChannelMonitorRequestTemplateCreate { + if v != nil { + _c.SetDescription(*v) + } + return _c +} + +// SetExtraHeaders sets the "extra_headers" field. +func (_c *ChannelMonitorRequestTemplateCreate) SetExtraHeaders(v map[string]string) *ChannelMonitorRequestTemplateCreate { + _c.mutation.SetExtraHeaders(v) + return _c +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (_c *ChannelMonitorRequestTemplateCreate) SetBodyOverrideMode(v string) *ChannelMonitorRequestTemplateCreate { + _c.mutation.SetBodyOverrideMode(v) + return _c +} + +// SetNillableBodyOverrideMode sets the "body_override_mode" field if the given value is not nil. +func (_c *ChannelMonitorRequestTemplateCreate) SetNillableBodyOverrideMode(v *string) *ChannelMonitorRequestTemplateCreate { + if v != nil { + _c.SetBodyOverrideMode(*v) + } + return _c +} + +// SetBodyOverride sets the "body_override" field. +func (_c *ChannelMonitorRequestTemplateCreate) SetBodyOverride(v map[string]interface{}) *ChannelMonitorRequestTemplateCreate { + _c.mutation.SetBodyOverride(v) + return _c +} + +// AddMonitorIDs adds the "monitors" edge to the ChannelMonitor entity by IDs. +func (_c *ChannelMonitorRequestTemplateCreate) AddMonitorIDs(ids ...int64) *ChannelMonitorRequestTemplateCreate { + _c.mutation.AddMonitorIDs(ids...) + return _c +} + +// AddMonitors adds the "monitors" edges to the ChannelMonitor entity. +func (_c *ChannelMonitorRequestTemplateCreate) AddMonitors(v ...*ChannelMonitor) *ChannelMonitorRequestTemplateCreate { + ids := make([]int64, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _c.AddMonitorIDs(ids...) +} + +// Mutation returns the ChannelMonitorRequestTemplateMutation object of the builder. +func (_c *ChannelMonitorRequestTemplateCreate) Mutation() *ChannelMonitorRequestTemplateMutation { + return _c.mutation +} + +// Save creates the ChannelMonitorRequestTemplate in the database. +func (_c *ChannelMonitorRequestTemplateCreate) Save(ctx context.Context) (*ChannelMonitorRequestTemplate, error) { + _c.defaults() + return withHooks(ctx, _c.sqlSave, _c.mutation, _c.hooks) +} + +// SaveX calls Save and panics if Save returns an error. +func (_c *ChannelMonitorRequestTemplateCreate) SaveX(ctx context.Context) *ChannelMonitorRequestTemplate { + v, err := _c.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (_c *ChannelMonitorRequestTemplateCreate) Exec(ctx context.Context) error { + _, err := _c.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_c *ChannelMonitorRequestTemplateCreate) ExecX(ctx context.Context) { + if err := _c.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (_c *ChannelMonitorRequestTemplateCreate) defaults() { + if _, ok := _c.mutation.CreatedAt(); !ok { + v := channelmonitorrequesttemplate.DefaultCreatedAt() + _c.mutation.SetCreatedAt(v) + } + if _, ok := _c.mutation.UpdatedAt(); !ok { + v := channelmonitorrequesttemplate.DefaultUpdatedAt() + _c.mutation.SetUpdatedAt(v) + } + if _, ok := _c.mutation.Description(); !ok { + v := channelmonitorrequesttemplate.DefaultDescription + _c.mutation.SetDescription(v) + } + if _, ok := _c.mutation.ExtraHeaders(); !ok { + v := channelmonitorrequesttemplate.DefaultExtraHeaders + _c.mutation.SetExtraHeaders(v) + } + if _, ok := _c.mutation.BodyOverrideMode(); !ok { + v := channelmonitorrequesttemplate.DefaultBodyOverrideMode + _c.mutation.SetBodyOverrideMode(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_c *ChannelMonitorRequestTemplateCreate) check() error { + if _, ok := _c.mutation.CreatedAt(); !ok { + return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "ChannelMonitorRequestTemplate.created_at"`)} + } + if _, ok := _c.mutation.UpdatedAt(); !ok { + return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "ChannelMonitorRequestTemplate.updated_at"`)} + } + if _, ok := _c.mutation.Name(); !ok { + return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "ChannelMonitorRequestTemplate.name"`)} + } + if v, ok := _c.mutation.Name(); ok { + if err := channelmonitorrequesttemplate.NameValidator(v); err != nil { + return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorRequestTemplate.name": %w`, err)} + } + } + if _, ok := _c.mutation.Provider(); !ok { + return &ValidationError{Name: "provider", err: errors.New(`ent: missing required field "ChannelMonitorRequestTemplate.provider"`)} + } + if v, ok := _c.mutation.Provider(); ok { + if err := channelmonitorrequesttemplate.ProviderValidator(v); err != nil { + return &ValidationError{Name: "provider", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorRequestTemplate.provider": %w`, err)} + } + } + if v, ok := _c.mutation.Description(); ok { + if err := channelmonitorrequesttemplate.DescriptionValidator(v); err != nil { + return &ValidationError{Name: "description", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorRequestTemplate.description": %w`, err)} + } + } + if _, ok := _c.mutation.ExtraHeaders(); !ok { + return &ValidationError{Name: "extra_headers", err: errors.New(`ent: missing required field "ChannelMonitorRequestTemplate.extra_headers"`)} + } + if _, ok := _c.mutation.BodyOverrideMode(); !ok { + return &ValidationError{Name: "body_override_mode", err: errors.New(`ent: missing required field "ChannelMonitorRequestTemplate.body_override_mode"`)} + } + if v, ok := _c.mutation.BodyOverrideMode(); ok { + if err := channelmonitorrequesttemplate.BodyOverrideModeValidator(v); err != nil { + return &ValidationError{Name: "body_override_mode", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorRequestTemplate.body_override_mode": %w`, err)} + } + } + return nil +} + +func (_c *ChannelMonitorRequestTemplateCreate) sqlSave(ctx context.Context) (*ChannelMonitorRequestTemplate, error) { + if err := _c.check(); err != nil { + return nil, err + } + _node, _spec := _c.createSpec() + if err := sqlgraph.CreateNode(ctx, _c.driver, _spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + id := _spec.ID.Value.(int64) + _node.ID = int64(id) + _c.mutation.id = &_node.ID + _c.mutation.done = true + return _node, nil +} + +func (_c *ChannelMonitorRequestTemplateCreate) createSpec() (*ChannelMonitorRequestTemplate, *sqlgraph.CreateSpec) { + var ( + _node = &ChannelMonitorRequestTemplate{config: _c.config} + _spec = sqlgraph.NewCreateSpec(channelmonitorrequesttemplate.Table, sqlgraph.NewFieldSpec(channelmonitorrequesttemplate.FieldID, field.TypeInt64)) + ) + _spec.OnConflict = _c.conflict + if value, ok := _c.mutation.CreatedAt(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldCreatedAt, field.TypeTime, value) + _node.CreatedAt = value + } + if value, ok := _c.mutation.UpdatedAt(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldUpdatedAt, field.TypeTime, value) + _node.UpdatedAt = value + } + if value, ok := _c.mutation.Name(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldName, field.TypeString, value) + _node.Name = value + } + if value, ok := _c.mutation.Provider(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldProvider, field.TypeEnum, value) + _node.Provider = value + } + if value, ok := _c.mutation.Description(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldDescription, field.TypeString, value) + _node.Description = value + } + if value, ok := _c.mutation.ExtraHeaders(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldExtraHeaders, field.TypeJSON, value) + _node.ExtraHeaders = value + } + if value, ok := _c.mutation.BodyOverrideMode(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldBodyOverrideMode, field.TypeString, value) + _node.BodyOverrideMode = value + } + if value, ok := _c.mutation.BodyOverride(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldBodyOverride, field.TypeJSON, value) + _node.BodyOverride = value + } + if nodes := _c.mutation.MonitorsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: true, + Table: channelmonitorrequesttemplate.MonitorsTable, + Columns: []string{channelmonitorrequesttemplate.MonitorsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges = append(_spec.Edges, edge) + } + return _node, _spec +} + +// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause +// of the `INSERT` statement. For example: +// +// client.ChannelMonitorRequestTemplate.Create(). +// SetCreatedAt(v). +// OnConflict( +// // Update the row with the new values +// // the was proposed for insertion. +// sql.ResolveWithNewValues(), +// ). +// // Override some of the fields with custom +// // update values. +// Update(func(u *ent.ChannelMonitorRequestTemplateUpsert) { +// SetCreatedAt(v+v). +// }). +// Exec(ctx) +func (_c *ChannelMonitorRequestTemplateCreate) OnConflict(opts ...sql.ConflictOption) *ChannelMonitorRequestTemplateUpsertOne { + _c.conflict = opts + return &ChannelMonitorRequestTemplateUpsertOne{ + create: _c, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.ChannelMonitorRequestTemplate.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (_c *ChannelMonitorRequestTemplateCreate) OnConflictColumns(columns ...string) *ChannelMonitorRequestTemplateUpsertOne { + _c.conflict = append(_c.conflict, sql.ConflictColumns(columns...)) + return &ChannelMonitorRequestTemplateUpsertOne{ + create: _c, + } +} + +type ( + // ChannelMonitorRequestTemplateUpsertOne is the builder for "upsert"-ing + // one ChannelMonitorRequestTemplate node. + ChannelMonitorRequestTemplateUpsertOne struct { + create *ChannelMonitorRequestTemplateCreate + } + + // ChannelMonitorRequestTemplateUpsert is the "OnConflict" setter. + ChannelMonitorRequestTemplateUpsert struct { + *sql.UpdateSet + } +) + +// SetUpdatedAt sets the "updated_at" field. +func (u *ChannelMonitorRequestTemplateUpsert) SetUpdatedAt(v time.Time) *ChannelMonitorRequestTemplateUpsert { + u.Set(channelmonitorrequesttemplate.FieldUpdatedAt, v) + return u +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsert) UpdateUpdatedAt() *ChannelMonitorRequestTemplateUpsert { + u.SetExcluded(channelmonitorrequesttemplate.FieldUpdatedAt) + return u +} + +// SetName sets the "name" field. +func (u *ChannelMonitorRequestTemplateUpsert) SetName(v string) *ChannelMonitorRequestTemplateUpsert { + u.Set(channelmonitorrequesttemplate.FieldName, v) + return u +} + +// UpdateName sets the "name" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsert) UpdateName() *ChannelMonitorRequestTemplateUpsert { + u.SetExcluded(channelmonitorrequesttemplate.FieldName) + return u +} + +// SetProvider sets the "provider" field. +func (u *ChannelMonitorRequestTemplateUpsert) SetProvider(v channelmonitorrequesttemplate.Provider) *ChannelMonitorRequestTemplateUpsert { + u.Set(channelmonitorrequesttemplate.FieldProvider, v) + return u +} + +// UpdateProvider sets the "provider" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsert) UpdateProvider() *ChannelMonitorRequestTemplateUpsert { + u.SetExcluded(channelmonitorrequesttemplate.FieldProvider) + return u +} + +// SetDescription sets the "description" field. +func (u *ChannelMonitorRequestTemplateUpsert) SetDescription(v string) *ChannelMonitorRequestTemplateUpsert { + u.Set(channelmonitorrequesttemplate.FieldDescription, v) + return u +} + +// UpdateDescription sets the "description" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsert) UpdateDescription() *ChannelMonitorRequestTemplateUpsert { + u.SetExcluded(channelmonitorrequesttemplate.FieldDescription) + return u +} + +// ClearDescription clears the value of the "description" field. +func (u *ChannelMonitorRequestTemplateUpsert) ClearDescription() *ChannelMonitorRequestTemplateUpsert { + u.SetNull(channelmonitorrequesttemplate.FieldDescription) + return u +} + +// SetExtraHeaders sets the "extra_headers" field. +func (u *ChannelMonitorRequestTemplateUpsert) SetExtraHeaders(v map[string]string) *ChannelMonitorRequestTemplateUpsert { + u.Set(channelmonitorrequesttemplate.FieldExtraHeaders, v) + return u +} + +// UpdateExtraHeaders sets the "extra_headers" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsert) UpdateExtraHeaders() *ChannelMonitorRequestTemplateUpsert { + u.SetExcluded(channelmonitorrequesttemplate.FieldExtraHeaders) + return u +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (u *ChannelMonitorRequestTemplateUpsert) SetBodyOverrideMode(v string) *ChannelMonitorRequestTemplateUpsert { + u.Set(channelmonitorrequesttemplate.FieldBodyOverrideMode, v) + return u +} + +// UpdateBodyOverrideMode sets the "body_override_mode" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsert) UpdateBodyOverrideMode() *ChannelMonitorRequestTemplateUpsert { + u.SetExcluded(channelmonitorrequesttemplate.FieldBodyOverrideMode) + return u +} + +// SetBodyOverride sets the "body_override" field. +func (u *ChannelMonitorRequestTemplateUpsert) SetBodyOverride(v map[string]interface{}) *ChannelMonitorRequestTemplateUpsert { + u.Set(channelmonitorrequesttemplate.FieldBodyOverride, v) + return u +} + +// UpdateBodyOverride sets the "body_override" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsert) UpdateBodyOverride() *ChannelMonitorRequestTemplateUpsert { + u.SetExcluded(channelmonitorrequesttemplate.FieldBodyOverride) + return u +} + +// ClearBodyOverride clears the value of the "body_override" field. +func (u *ChannelMonitorRequestTemplateUpsert) ClearBodyOverride() *ChannelMonitorRequestTemplateUpsert { + u.SetNull(channelmonitorrequesttemplate.FieldBodyOverride) + return u +} + +// UpdateNewValues updates the mutable fields using the new values that were set on create. +// Using this option is equivalent to using: +// +// client.ChannelMonitorRequestTemplate.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// ). +// Exec(ctx) +func (u *ChannelMonitorRequestTemplateUpsertOne) UpdateNewValues() *ChannelMonitorRequestTemplateUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues()) + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) { + if _, exists := u.create.mutation.CreatedAt(); exists { + s.SetIgnore(channelmonitorrequesttemplate.FieldCreatedAt) + } + })) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.ChannelMonitorRequestTemplate.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *ChannelMonitorRequestTemplateUpsertOne) Ignore() *ChannelMonitorRequestTemplateUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore()) + return u +} + +// DoNothing configures the conflict_action to `DO NOTHING`. +// Supported only by SQLite and PostgreSQL. +func (u *ChannelMonitorRequestTemplateUpsertOne) DoNothing() *ChannelMonitorRequestTemplateUpsertOne { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the ChannelMonitorRequestTemplateCreate.OnConflict +// documentation for more info. +func (u *ChannelMonitorRequestTemplateUpsertOne) Update(set func(*ChannelMonitorRequestTemplateUpsert)) *ChannelMonitorRequestTemplateUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&ChannelMonitorRequestTemplateUpsert{UpdateSet: update}) + })) + return u +} + +// SetUpdatedAt sets the "updated_at" field. +func (u *ChannelMonitorRequestTemplateUpsertOne) SetUpdatedAt(v time.Time) *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetUpdatedAt(v) + }) +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertOne) UpdateUpdatedAt() *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateUpdatedAt() + }) +} + +// SetName sets the "name" field. +func (u *ChannelMonitorRequestTemplateUpsertOne) SetName(v string) *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetName(v) + }) +} + +// UpdateName sets the "name" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertOne) UpdateName() *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateName() + }) +} + +// SetProvider sets the "provider" field. +func (u *ChannelMonitorRequestTemplateUpsertOne) SetProvider(v channelmonitorrequesttemplate.Provider) *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetProvider(v) + }) +} + +// UpdateProvider sets the "provider" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertOne) UpdateProvider() *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateProvider() + }) +} + +// SetDescription sets the "description" field. +func (u *ChannelMonitorRequestTemplateUpsertOne) SetDescription(v string) *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetDescription(v) + }) +} + +// UpdateDescription sets the "description" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertOne) UpdateDescription() *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateDescription() + }) +} + +// ClearDescription clears the value of the "description" field. +func (u *ChannelMonitorRequestTemplateUpsertOne) ClearDescription() *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.ClearDescription() + }) +} + +// SetExtraHeaders sets the "extra_headers" field. +func (u *ChannelMonitorRequestTemplateUpsertOne) SetExtraHeaders(v map[string]string) *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetExtraHeaders(v) + }) +} + +// UpdateExtraHeaders sets the "extra_headers" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertOne) UpdateExtraHeaders() *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateExtraHeaders() + }) +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (u *ChannelMonitorRequestTemplateUpsertOne) SetBodyOverrideMode(v string) *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetBodyOverrideMode(v) + }) +} + +// UpdateBodyOverrideMode sets the "body_override_mode" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertOne) UpdateBodyOverrideMode() *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateBodyOverrideMode() + }) +} + +// SetBodyOverride sets the "body_override" field. +func (u *ChannelMonitorRequestTemplateUpsertOne) SetBodyOverride(v map[string]interface{}) *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetBodyOverride(v) + }) +} + +// UpdateBodyOverride sets the "body_override" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertOne) UpdateBodyOverride() *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateBodyOverride() + }) +} + +// ClearBodyOverride clears the value of the "body_override" field. +func (u *ChannelMonitorRequestTemplateUpsertOne) ClearBodyOverride() *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.ClearBodyOverride() + }) +} + +// Exec executes the query. +func (u *ChannelMonitorRequestTemplateUpsertOne) Exec(ctx context.Context) error { + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for ChannelMonitorRequestTemplateCreate.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *ChannelMonitorRequestTemplateUpsertOne) ExecX(ctx context.Context) { + if err := u.create.Exec(ctx); err != nil { + panic(err) + } +} + +// Exec executes the UPSERT query and returns the inserted/updated ID. +func (u *ChannelMonitorRequestTemplateUpsertOne) ID(ctx context.Context) (id int64, err error) { + node, err := u.create.Save(ctx) + if err != nil { + return id, err + } + return node.ID, nil +} + +// IDX is like ID, but panics if an error occurs. +func (u *ChannelMonitorRequestTemplateUpsertOne) IDX(ctx context.Context) int64 { + id, err := u.ID(ctx) + if err != nil { + panic(err) + } + return id +} + +// ChannelMonitorRequestTemplateCreateBulk is the builder for creating many ChannelMonitorRequestTemplate entities in bulk. +type ChannelMonitorRequestTemplateCreateBulk struct { + config + err error + builders []*ChannelMonitorRequestTemplateCreate + conflict []sql.ConflictOption +} + +// Save creates the ChannelMonitorRequestTemplate entities in the database. +func (_c *ChannelMonitorRequestTemplateCreateBulk) Save(ctx context.Context) ([]*ChannelMonitorRequestTemplate, error) { + if _c.err != nil { + return nil, _c.err + } + specs := make([]*sqlgraph.CreateSpec, len(_c.builders)) + nodes := make([]*ChannelMonitorRequestTemplate, len(_c.builders)) + mutators := make([]Mutator, len(_c.builders)) + for i := range _c.builders { + func(i int, root context.Context) { + builder := _c.builders[i] + builder.defaults() + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*ChannelMonitorRequestTemplateMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + if err := builder.check(); err != nil { + return nil, err + } + builder.mutation = mutation + var err error + nodes[i], specs[i] = builder.createSpec() + if i < len(mutators)-1 { + _, err = mutators[i+1].Mutate(root, _c.builders[i+1].mutation) + } else { + spec := &sqlgraph.BatchCreateSpec{Nodes: specs} + spec.OnConflict = _c.conflict + // Invoke the actual operation on the latest mutation in the chain. + if err = sqlgraph.BatchCreate(ctx, _c.driver, spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + } + } + if err != nil { + return nil, err + } + mutation.id = &nodes[i].ID + if specs[i].ID.Value != nil { + id := specs[i].ID.Value.(int64) + nodes[i].ID = int64(id) + } + mutation.done = true + return nodes[i], nil + }) + for i := len(builder.hooks) - 1; i >= 0; i-- { + mut = builder.hooks[i](mut) + } + mutators[i] = mut + }(i, ctx) + } + if len(mutators) > 0 { + if _, err := mutators[0].Mutate(ctx, _c.builders[0].mutation); err != nil { + return nil, err + } + } + return nodes, nil +} + +// SaveX is like Save, but panics if an error occurs. +func (_c *ChannelMonitorRequestTemplateCreateBulk) SaveX(ctx context.Context) []*ChannelMonitorRequestTemplate { + v, err := _c.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (_c *ChannelMonitorRequestTemplateCreateBulk) Exec(ctx context.Context) error { + _, err := _c.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_c *ChannelMonitorRequestTemplateCreateBulk) ExecX(ctx context.Context) { + if err := _c.Exec(ctx); err != nil { + panic(err) + } +} + +// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause +// of the `INSERT` statement. For example: +// +// client.ChannelMonitorRequestTemplate.CreateBulk(builders...). +// OnConflict( +// // Update the row with the new values +// // the was proposed for insertion. +// sql.ResolveWithNewValues(), +// ). +// // Override some of the fields with custom +// // update values. +// Update(func(u *ent.ChannelMonitorRequestTemplateUpsert) { +// SetCreatedAt(v+v). +// }). +// Exec(ctx) +func (_c *ChannelMonitorRequestTemplateCreateBulk) OnConflict(opts ...sql.ConflictOption) *ChannelMonitorRequestTemplateUpsertBulk { + _c.conflict = opts + return &ChannelMonitorRequestTemplateUpsertBulk{ + create: _c, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.ChannelMonitorRequestTemplate.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (_c *ChannelMonitorRequestTemplateCreateBulk) OnConflictColumns(columns ...string) *ChannelMonitorRequestTemplateUpsertBulk { + _c.conflict = append(_c.conflict, sql.ConflictColumns(columns...)) + return &ChannelMonitorRequestTemplateUpsertBulk{ + create: _c, + } +} + +// ChannelMonitorRequestTemplateUpsertBulk is the builder for "upsert"-ing +// a bulk of ChannelMonitorRequestTemplate nodes. +type ChannelMonitorRequestTemplateUpsertBulk struct { + create *ChannelMonitorRequestTemplateCreateBulk +} + +// UpdateNewValues updates the mutable fields using the new values that +// were set on create. Using this option is equivalent to using: +// +// client.ChannelMonitorRequestTemplate.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// ). +// Exec(ctx) +func (u *ChannelMonitorRequestTemplateUpsertBulk) UpdateNewValues() *ChannelMonitorRequestTemplateUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues()) + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) { + for _, b := range u.create.builders { + if _, exists := b.mutation.CreatedAt(); exists { + s.SetIgnore(channelmonitorrequesttemplate.FieldCreatedAt) + } + } + })) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.ChannelMonitorRequestTemplate.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *ChannelMonitorRequestTemplateUpsertBulk) Ignore() *ChannelMonitorRequestTemplateUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore()) + return u +} + +// DoNothing configures the conflict_action to `DO NOTHING`. +// Supported only by SQLite and PostgreSQL. +func (u *ChannelMonitorRequestTemplateUpsertBulk) DoNothing() *ChannelMonitorRequestTemplateUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the ChannelMonitorRequestTemplateCreateBulk.OnConflict +// documentation for more info. +func (u *ChannelMonitorRequestTemplateUpsertBulk) Update(set func(*ChannelMonitorRequestTemplateUpsert)) *ChannelMonitorRequestTemplateUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&ChannelMonitorRequestTemplateUpsert{UpdateSet: update}) + })) + return u +} + +// SetUpdatedAt sets the "updated_at" field. +func (u *ChannelMonitorRequestTemplateUpsertBulk) SetUpdatedAt(v time.Time) *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetUpdatedAt(v) + }) +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertBulk) UpdateUpdatedAt() *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateUpdatedAt() + }) +} + +// SetName sets the "name" field. +func (u *ChannelMonitorRequestTemplateUpsertBulk) SetName(v string) *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetName(v) + }) +} + +// UpdateName sets the "name" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertBulk) UpdateName() *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateName() + }) +} + +// SetProvider sets the "provider" field. +func (u *ChannelMonitorRequestTemplateUpsertBulk) SetProvider(v channelmonitorrequesttemplate.Provider) *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetProvider(v) + }) +} + +// UpdateProvider sets the "provider" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertBulk) UpdateProvider() *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateProvider() + }) +} + +// SetDescription sets the "description" field. +func (u *ChannelMonitorRequestTemplateUpsertBulk) SetDescription(v string) *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetDescription(v) + }) +} + +// UpdateDescription sets the "description" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertBulk) UpdateDescription() *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateDescription() + }) +} + +// ClearDescription clears the value of the "description" field. +func (u *ChannelMonitorRequestTemplateUpsertBulk) ClearDescription() *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.ClearDescription() + }) +} + +// SetExtraHeaders sets the "extra_headers" field. +func (u *ChannelMonitorRequestTemplateUpsertBulk) SetExtraHeaders(v map[string]string) *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetExtraHeaders(v) + }) +} + +// UpdateExtraHeaders sets the "extra_headers" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertBulk) UpdateExtraHeaders() *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateExtraHeaders() + }) +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (u *ChannelMonitorRequestTemplateUpsertBulk) SetBodyOverrideMode(v string) *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetBodyOverrideMode(v) + }) +} + +// UpdateBodyOverrideMode sets the "body_override_mode" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertBulk) UpdateBodyOverrideMode() *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateBodyOverrideMode() + }) +} + +// SetBodyOverride sets the "body_override" field. +func (u *ChannelMonitorRequestTemplateUpsertBulk) SetBodyOverride(v map[string]interface{}) *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetBodyOverride(v) + }) +} + +// UpdateBodyOverride sets the "body_override" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertBulk) UpdateBodyOverride() *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateBodyOverride() + }) +} + +// ClearBodyOverride clears the value of the "body_override" field. +func (u *ChannelMonitorRequestTemplateUpsertBulk) ClearBodyOverride() *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.ClearBodyOverride() + }) +} + +// Exec executes the query. +func (u *ChannelMonitorRequestTemplateUpsertBulk) Exec(ctx context.Context) error { + if u.create.err != nil { + return u.create.err + } + for i, b := range u.create.builders { + if len(b.conflict) != 0 { + return fmt.Errorf("ent: OnConflict was set for builder %d. Set it on the ChannelMonitorRequestTemplateCreateBulk instead", i) + } + } + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for ChannelMonitorRequestTemplateCreateBulk.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *ChannelMonitorRequestTemplateUpsertBulk) ExecX(ctx context.Context) { + if err := u.create.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/backend/ent/channelmonitorrequesttemplate_delete.go b/backend/ent/channelmonitorrequesttemplate_delete.go new file mode 100644 index 00000000..98d365c8 --- /dev/null +++ b/backend/ent/channelmonitorrequesttemplate_delete.go @@ -0,0 +1,88 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// ChannelMonitorRequestTemplateDelete is the builder for deleting a ChannelMonitorRequestTemplate entity. +type ChannelMonitorRequestTemplateDelete struct { + config + hooks []Hook + mutation *ChannelMonitorRequestTemplateMutation +} + +// Where appends a list predicates to the ChannelMonitorRequestTemplateDelete builder. +func (_d *ChannelMonitorRequestTemplateDelete) Where(ps ...predicate.ChannelMonitorRequestTemplate) *ChannelMonitorRequestTemplateDelete { + _d.mutation.Where(ps...) + return _d +} + +// Exec executes the deletion query and returns how many vertices were deleted. +func (_d *ChannelMonitorRequestTemplateDelete) Exec(ctx context.Context) (int, error) { + return withHooks(ctx, _d.sqlExec, _d.mutation, _d.hooks) +} + +// ExecX is like Exec, but panics if an error occurs. +func (_d *ChannelMonitorRequestTemplateDelete) ExecX(ctx context.Context) int { + n, err := _d.Exec(ctx) + if err != nil { + panic(err) + } + return n +} + +func (_d *ChannelMonitorRequestTemplateDelete) sqlExec(ctx context.Context) (int, error) { + _spec := sqlgraph.NewDeleteSpec(channelmonitorrequesttemplate.Table, sqlgraph.NewFieldSpec(channelmonitorrequesttemplate.FieldID, field.TypeInt64)) + if ps := _d.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + affected, err := sqlgraph.DeleteNodes(ctx, _d.driver, _spec) + if err != nil && sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + _d.mutation.done = true + return affected, err +} + +// ChannelMonitorRequestTemplateDeleteOne is the builder for deleting a single ChannelMonitorRequestTemplate entity. +type ChannelMonitorRequestTemplateDeleteOne struct { + _d *ChannelMonitorRequestTemplateDelete +} + +// Where appends a list predicates to the ChannelMonitorRequestTemplateDelete builder. +func (_d *ChannelMonitorRequestTemplateDeleteOne) Where(ps ...predicate.ChannelMonitorRequestTemplate) *ChannelMonitorRequestTemplateDeleteOne { + _d._d.mutation.Where(ps...) + return _d +} + +// Exec executes the deletion query. +func (_d *ChannelMonitorRequestTemplateDeleteOne) Exec(ctx context.Context) error { + n, err := _d._d.Exec(ctx) + switch { + case err != nil: + return err + case n == 0: + return &NotFoundError{channelmonitorrequesttemplate.Label} + default: + return nil + } +} + +// ExecX is like Exec, but panics if an error occurs. +func (_d *ChannelMonitorRequestTemplateDeleteOne) ExecX(ctx context.Context) { + if err := _d.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/backend/ent/channelmonitorrequesttemplate_query.go b/backend/ent/channelmonitorrequesttemplate_query.go new file mode 100644 index 00000000..6491ea60 --- /dev/null +++ b/backend/ent/channelmonitorrequesttemplate_query.go @@ -0,0 +1,648 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "database/sql/driver" + "fmt" + "math" + + "entgo.io/ent" + "entgo.io/ent/dialect" + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// ChannelMonitorRequestTemplateQuery is the builder for querying ChannelMonitorRequestTemplate entities. +type ChannelMonitorRequestTemplateQuery struct { + config + ctx *QueryContext + order []channelmonitorrequesttemplate.OrderOption + inters []Interceptor + predicates []predicate.ChannelMonitorRequestTemplate + withMonitors *ChannelMonitorQuery + modifiers []func(*sql.Selector) + // intermediate query (i.e. traversal path). + sql *sql.Selector + path func(context.Context) (*sql.Selector, error) +} + +// Where adds a new predicate for the ChannelMonitorRequestTemplateQuery builder. +func (_q *ChannelMonitorRequestTemplateQuery) Where(ps ...predicate.ChannelMonitorRequestTemplate) *ChannelMonitorRequestTemplateQuery { + _q.predicates = append(_q.predicates, ps...) + return _q +} + +// Limit the number of records to be returned by this query. +func (_q *ChannelMonitorRequestTemplateQuery) Limit(limit int) *ChannelMonitorRequestTemplateQuery { + _q.ctx.Limit = &limit + return _q +} + +// Offset to start from. +func (_q *ChannelMonitorRequestTemplateQuery) Offset(offset int) *ChannelMonitorRequestTemplateQuery { + _q.ctx.Offset = &offset + return _q +} + +// Unique configures the query builder to filter duplicate records on query. +// By default, unique is set to true, and can be disabled using this method. +func (_q *ChannelMonitorRequestTemplateQuery) Unique(unique bool) *ChannelMonitorRequestTemplateQuery { + _q.ctx.Unique = &unique + return _q +} + +// Order specifies how the records should be ordered. +func (_q *ChannelMonitorRequestTemplateQuery) Order(o ...channelmonitorrequesttemplate.OrderOption) *ChannelMonitorRequestTemplateQuery { + _q.order = append(_q.order, o...) + return _q +} + +// QueryMonitors chains the current query on the "monitors" edge. +func (_q *ChannelMonitorRequestTemplateQuery) QueryMonitors() *ChannelMonitorQuery { + query := (&ChannelMonitorClient{config: _q.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := _q.prepareQuery(ctx); err != nil { + return nil, err + } + selector := _q.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(channelmonitorrequesttemplate.Table, channelmonitorrequesttemplate.FieldID, selector), + sqlgraph.To(channelmonitor.Table, channelmonitor.FieldID), + sqlgraph.Edge(sqlgraph.O2M, true, channelmonitorrequesttemplate.MonitorsTable, channelmonitorrequesttemplate.MonitorsColumn), + ) + fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step) + return fromU, nil + } + return query +} + +// First returns the first ChannelMonitorRequestTemplate entity from the query. +// Returns a *NotFoundError when no ChannelMonitorRequestTemplate was found. +func (_q *ChannelMonitorRequestTemplateQuery) First(ctx context.Context) (*ChannelMonitorRequestTemplate, error) { + nodes, err := _q.Limit(1).All(setContextOp(ctx, _q.ctx, ent.OpQueryFirst)) + if err != nil { + return nil, err + } + if len(nodes) == 0 { + return nil, &NotFoundError{channelmonitorrequesttemplate.Label} + } + return nodes[0], nil +} + +// FirstX is like First, but panics if an error occurs. +func (_q *ChannelMonitorRequestTemplateQuery) FirstX(ctx context.Context) *ChannelMonitorRequestTemplate { + node, err := _q.First(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return node +} + +// FirstID returns the first ChannelMonitorRequestTemplate ID from the query. +// Returns a *NotFoundError when no ChannelMonitorRequestTemplate ID was found. +func (_q *ChannelMonitorRequestTemplateQuery) FirstID(ctx context.Context) (id int64, err error) { + var ids []int64 + if ids, err = _q.Limit(1).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryFirstID)); err != nil { + return + } + if len(ids) == 0 { + err = &NotFoundError{channelmonitorrequesttemplate.Label} + return + } + return ids[0], nil +} + +// FirstIDX is like FirstID, but panics if an error occurs. +func (_q *ChannelMonitorRequestTemplateQuery) FirstIDX(ctx context.Context) int64 { + id, err := _q.FirstID(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return id +} + +// Only returns a single ChannelMonitorRequestTemplate entity found by the query, ensuring it only returns one. +// Returns a *NotSingularError when more than one ChannelMonitorRequestTemplate entity is found. +// Returns a *NotFoundError when no ChannelMonitorRequestTemplate entities are found. +func (_q *ChannelMonitorRequestTemplateQuery) Only(ctx context.Context) (*ChannelMonitorRequestTemplate, error) { + nodes, err := _q.Limit(2).All(setContextOp(ctx, _q.ctx, ent.OpQueryOnly)) + if err != nil { + return nil, err + } + switch len(nodes) { + case 1: + return nodes[0], nil + case 0: + return nil, &NotFoundError{channelmonitorrequesttemplate.Label} + default: + return nil, &NotSingularError{channelmonitorrequesttemplate.Label} + } +} + +// OnlyX is like Only, but panics if an error occurs. +func (_q *ChannelMonitorRequestTemplateQuery) OnlyX(ctx context.Context) *ChannelMonitorRequestTemplate { + node, err := _q.Only(ctx) + if err != nil { + panic(err) + } + return node +} + +// OnlyID is like Only, but returns the only ChannelMonitorRequestTemplate ID in the query. +// Returns a *NotSingularError when more than one ChannelMonitorRequestTemplate ID is found. +// Returns a *NotFoundError when no entities are found. +func (_q *ChannelMonitorRequestTemplateQuery) OnlyID(ctx context.Context) (id int64, err error) { + var ids []int64 + if ids, err = _q.Limit(2).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryOnlyID)); err != nil { + return + } + switch len(ids) { + case 1: + id = ids[0] + case 0: + err = &NotFoundError{channelmonitorrequesttemplate.Label} + default: + err = &NotSingularError{channelmonitorrequesttemplate.Label} + } + return +} + +// OnlyIDX is like OnlyID, but panics if an error occurs. +func (_q *ChannelMonitorRequestTemplateQuery) OnlyIDX(ctx context.Context) int64 { + id, err := _q.OnlyID(ctx) + if err != nil { + panic(err) + } + return id +} + +// All executes the query and returns a list of ChannelMonitorRequestTemplates. +func (_q *ChannelMonitorRequestTemplateQuery) All(ctx context.Context) ([]*ChannelMonitorRequestTemplate, error) { + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryAll) + if err := _q.prepareQuery(ctx); err != nil { + return nil, err + } + qr := querierAll[[]*ChannelMonitorRequestTemplate, *ChannelMonitorRequestTemplateQuery]() + return withInterceptors[[]*ChannelMonitorRequestTemplate](ctx, _q, qr, _q.inters) +} + +// AllX is like All, but panics if an error occurs. +func (_q *ChannelMonitorRequestTemplateQuery) AllX(ctx context.Context) []*ChannelMonitorRequestTemplate { + nodes, err := _q.All(ctx) + if err != nil { + panic(err) + } + return nodes +} + +// IDs executes the query and returns a list of ChannelMonitorRequestTemplate IDs. +func (_q *ChannelMonitorRequestTemplateQuery) IDs(ctx context.Context) (ids []int64, err error) { + if _q.ctx.Unique == nil && _q.path != nil { + _q.Unique(true) + } + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryIDs) + if err = _q.Select(channelmonitorrequesttemplate.FieldID).Scan(ctx, &ids); err != nil { + return nil, err + } + return ids, nil +} + +// IDsX is like IDs, but panics if an error occurs. +func (_q *ChannelMonitorRequestTemplateQuery) IDsX(ctx context.Context) []int64 { + ids, err := _q.IDs(ctx) + if err != nil { + panic(err) + } + return ids +} + +// Count returns the count of the given query. +func (_q *ChannelMonitorRequestTemplateQuery) Count(ctx context.Context) (int, error) { + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryCount) + if err := _q.prepareQuery(ctx); err != nil { + return 0, err + } + return withInterceptors[int](ctx, _q, querierCount[*ChannelMonitorRequestTemplateQuery](), _q.inters) +} + +// CountX is like Count, but panics if an error occurs. +func (_q *ChannelMonitorRequestTemplateQuery) CountX(ctx context.Context) int { + count, err := _q.Count(ctx) + if err != nil { + panic(err) + } + return count +} + +// Exist returns true if the query has elements in the graph. +func (_q *ChannelMonitorRequestTemplateQuery) Exist(ctx context.Context) (bool, error) { + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryExist) + switch _, err := _q.FirstID(ctx); { + case IsNotFound(err): + return false, nil + case err != nil: + return false, fmt.Errorf("ent: check existence: %w", err) + default: + return true, nil + } +} + +// ExistX is like Exist, but panics if an error occurs. +func (_q *ChannelMonitorRequestTemplateQuery) ExistX(ctx context.Context) bool { + exist, err := _q.Exist(ctx) + if err != nil { + panic(err) + } + return exist +} + +// Clone returns a duplicate of the ChannelMonitorRequestTemplateQuery builder, including all associated steps. It can be +// used to prepare common query builders and use them differently after the clone is made. +func (_q *ChannelMonitorRequestTemplateQuery) Clone() *ChannelMonitorRequestTemplateQuery { + if _q == nil { + return nil + } + return &ChannelMonitorRequestTemplateQuery{ + config: _q.config, + ctx: _q.ctx.Clone(), + order: append([]channelmonitorrequesttemplate.OrderOption{}, _q.order...), + inters: append([]Interceptor{}, _q.inters...), + predicates: append([]predicate.ChannelMonitorRequestTemplate{}, _q.predicates...), + withMonitors: _q.withMonitors.Clone(), + // clone intermediate query. + sql: _q.sql.Clone(), + path: _q.path, + } +} + +// WithMonitors tells the query-builder to eager-load the nodes that are connected to +// the "monitors" edge. The optional arguments are used to configure the query builder of the edge. +func (_q *ChannelMonitorRequestTemplateQuery) WithMonitors(opts ...func(*ChannelMonitorQuery)) *ChannelMonitorRequestTemplateQuery { + query := (&ChannelMonitorClient{config: _q.config}).Query() + for _, opt := range opts { + opt(query) + } + _q.withMonitors = query + return _q +} + +// GroupBy is used to group vertices by one or more fields/columns. +// It is often used with aggregate functions, like: count, max, mean, min, sum. +// +// Example: +// +// var v []struct { +// CreatedAt time.Time `json:"created_at,omitempty"` +// Count int `json:"count,omitempty"` +// } +// +// client.ChannelMonitorRequestTemplate.Query(). +// GroupBy(channelmonitorrequesttemplate.FieldCreatedAt). +// Aggregate(ent.Count()). +// Scan(ctx, &v) +func (_q *ChannelMonitorRequestTemplateQuery) GroupBy(field string, fields ...string) *ChannelMonitorRequestTemplateGroupBy { + _q.ctx.Fields = append([]string{field}, fields...) + grbuild := &ChannelMonitorRequestTemplateGroupBy{build: _q} + grbuild.flds = &_q.ctx.Fields + grbuild.label = channelmonitorrequesttemplate.Label + grbuild.scan = grbuild.Scan + return grbuild +} + +// Select allows the selection one or more fields/columns for the given query, +// instead of selecting all fields in the entity. +// +// Example: +// +// var v []struct { +// CreatedAt time.Time `json:"created_at,omitempty"` +// } +// +// client.ChannelMonitorRequestTemplate.Query(). +// Select(channelmonitorrequesttemplate.FieldCreatedAt). +// Scan(ctx, &v) +func (_q *ChannelMonitorRequestTemplateQuery) Select(fields ...string) *ChannelMonitorRequestTemplateSelect { + _q.ctx.Fields = append(_q.ctx.Fields, fields...) + sbuild := &ChannelMonitorRequestTemplateSelect{ChannelMonitorRequestTemplateQuery: _q} + sbuild.label = channelmonitorrequesttemplate.Label + sbuild.flds, sbuild.scan = &_q.ctx.Fields, sbuild.Scan + return sbuild +} + +// Aggregate returns a ChannelMonitorRequestTemplateSelect configured with the given aggregations. +func (_q *ChannelMonitorRequestTemplateQuery) Aggregate(fns ...AggregateFunc) *ChannelMonitorRequestTemplateSelect { + return _q.Select().Aggregate(fns...) +} + +func (_q *ChannelMonitorRequestTemplateQuery) prepareQuery(ctx context.Context) error { + for _, inter := range _q.inters { + if inter == nil { + return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)") + } + if trv, ok := inter.(Traverser); ok { + if err := trv.Traverse(ctx, _q); err != nil { + return err + } + } + } + for _, f := range _q.ctx.Fields { + if !channelmonitorrequesttemplate.ValidColumn(f) { + return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + } + if _q.path != nil { + prev, err := _q.path(ctx) + if err != nil { + return err + } + _q.sql = prev + } + return nil +} + +func (_q *ChannelMonitorRequestTemplateQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*ChannelMonitorRequestTemplate, error) { + var ( + nodes = []*ChannelMonitorRequestTemplate{} + _spec = _q.querySpec() + loadedTypes = [1]bool{ + _q.withMonitors != nil, + } + ) + _spec.ScanValues = func(columns []string) ([]any, error) { + return (*ChannelMonitorRequestTemplate).scanValues(nil, columns) + } + _spec.Assign = func(columns []string, values []any) error { + node := &ChannelMonitorRequestTemplate{config: _q.config} + nodes = append(nodes, node) + node.Edges.loadedTypes = loadedTypes + return node.assignValues(columns, values) + } + if len(_q.modifiers) > 0 { + _spec.Modifiers = _q.modifiers + } + for i := range hooks { + hooks[i](ctx, _spec) + } + if err := sqlgraph.QueryNodes(ctx, _q.driver, _spec); err != nil { + return nil, err + } + if len(nodes) == 0 { + return nodes, nil + } + if query := _q.withMonitors; query != nil { + if err := _q.loadMonitors(ctx, query, nodes, + func(n *ChannelMonitorRequestTemplate) { n.Edges.Monitors = []*ChannelMonitor{} }, + func(n *ChannelMonitorRequestTemplate, e *ChannelMonitor) { + n.Edges.Monitors = append(n.Edges.Monitors, e) + }); err != nil { + return nil, err + } + } + return nodes, nil +} + +func (_q *ChannelMonitorRequestTemplateQuery) loadMonitors(ctx context.Context, query *ChannelMonitorQuery, nodes []*ChannelMonitorRequestTemplate, init func(*ChannelMonitorRequestTemplate), assign func(*ChannelMonitorRequestTemplate, *ChannelMonitor)) error { + fks := make([]driver.Value, 0, len(nodes)) + nodeids := make(map[int64]*ChannelMonitorRequestTemplate) + for i := range nodes { + fks = append(fks, nodes[i].ID) + nodeids[nodes[i].ID] = nodes[i] + if init != nil { + init(nodes[i]) + } + } + if len(query.ctx.Fields) > 0 { + query.ctx.AppendFieldOnce(channelmonitor.FieldTemplateID) + } + query.Where(predicate.ChannelMonitor(func(s *sql.Selector) { + s.Where(sql.InValues(s.C(channelmonitorrequesttemplate.MonitorsColumn), fks...)) + })) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + fk := n.TemplateID + if fk == nil { + return fmt.Errorf(`foreign-key "template_id" is nil for node %v`, n.ID) + } + node, ok := nodeids[*fk] + if !ok { + return fmt.Errorf(`unexpected referenced foreign-key "template_id" returned %v for node %v`, *fk, n.ID) + } + assign(node, n) + } + return nil +} + +func (_q *ChannelMonitorRequestTemplateQuery) sqlCount(ctx context.Context) (int, error) { + _spec := _q.querySpec() + if len(_q.modifiers) > 0 { + _spec.Modifiers = _q.modifiers + } + _spec.Node.Columns = _q.ctx.Fields + if len(_q.ctx.Fields) > 0 { + _spec.Unique = _q.ctx.Unique != nil && *_q.ctx.Unique + } + return sqlgraph.CountNodes(ctx, _q.driver, _spec) +} + +func (_q *ChannelMonitorRequestTemplateQuery) querySpec() *sqlgraph.QuerySpec { + _spec := sqlgraph.NewQuerySpec(channelmonitorrequesttemplate.Table, channelmonitorrequesttemplate.Columns, sqlgraph.NewFieldSpec(channelmonitorrequesttemplate.FieldID, field.TypeInt64)) + _spec.From = _q.sql + if unique := _q.ctx.Unique; unique != nil { + _spec.Unique = *unique + } else if _q.path != nil { + _spec.Unique = true + } + if fields := _q.ctx.Fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, channelmonitorrequesttemplate.FieldID) + for i := range fields { + if fields[i] != channelmonitorrequesttemplate.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) + } + } + } + if ps := _q.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if limit := _q.ctx.Limit; limit != nil { + _spec.Limit = *limit + } + if offset := _q.ctx.Offset; offset != nil { + _spec.Offset = *offset + } + if ps := _q.order; len(ps) > 0 { + _spec.Order = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + return _spec +} + +func (_q *ChannelMonitorRequestTemplateQuery) sqlQuery(ctx context.Context) *sql.Selector { + builder := sql.Dialect(_q.driver.Dialect()) + t1 := builder.Table(channelmonitorrequesttemplate.Table) + columns := _q.ctx.Fields + if len(columns) == 0 { + columns = channelmonitorrequesttemplate.Columns + } + selector := builder.Select(t1.Columns(columns...)...).From(t1) + if _q.sql != nil { + selector = _q.sql + selector.Select(selector.Columns(columns...)...) + } + if _q.ctx.Unique != nil && *_q.ctx.Unique { + selector.Distinct() + } + for _, m := range _q.modifiers { + m(selector) + } + for _, p := range _q.predicates { + p(selector) + } + for _, p := range _q.order { + p(selector) + } + if offset := _q.ctx.Offset; offset != nil { + // limit is mandatory for offset clause. We start + // with default value, and override it below if needed. + selector.Offset(*offset).Limit(math.MaxInt32) + } + if limit := _q.ctx.Limit; limit != nil { + selector.Limit(*limit) + } + return selector +} + +// ForUpdate locks the selected rows against concurrent updates, and prevent them from being +// updated, deleted or "selected ... for update" by other sessions, until the transaction is +// either committed or rolled-back. +func (_q *ChannelMonitorRequestTemplateQuery) ForUpdate(opts ...sql.LockOption) *ChannelMonitorRequestTemplateQuery { + if _q.driver.Dialect() == dialect.Postgres { + _q.Unique(false) + } + _q.modifiers = append(_q.modifiers, func(s *sql.Selector) { + s.ForUpdate(opts...) + }) + return _q +} + +// ForShare behaves similarly to ForUpdate, except that it acquires a shared mode lock +// on any rows that are read. Other sessions can read the rows, but cannot modify them +// until your transaction commits. +func (_q *ChannelMonitorRequestTemplateQuery) ForShare(opts ...sql.LockOption) *ChannelMonitorRequestTemplateQuery { + if _q.driver.Dialect() == dialect.Postgres { + _q.Unique(false) + } + _q.modifiers = append(_q.modifiers, func(s *sql.Selector) { + s.ForShare(opts...) + }) + return _q +} + +// ChannelMonitorRequestTemplateGroupBy is the group-by builder for ChannelMonitorRequestTemplate entities. +type ChannelMonitorRequestTemplateGroupBy struct { + selector + build *ChannelMonitorRequestTemplateQuery +} + +// Aggregate adds the given aggregation functions to the group-by query. +func (_g *ChannelMonitorRequestTemplateGroupBy) Aggregate(fns ...AggregateFunc) *ChannelMonitorRequestTemplateGroupBy { + _g.fns = append(_g.fns, fns...) + return _g +} + +// Scan applies the selector query and scans the result into the given value. +func (_g *ChannelMonitorRequestTemplateGroupBy) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, _g.build.ctx, ent.OpQueryGroupBy) + if err := _g.build.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*ChannelMonitorRequestTemplateQuery, *ChannelMonitorRequestTemplateGroupBy](ctx, _g.build, _g, _g.build.inters, v) +} + +func (_g *ChannelMonitorRequestTemplateGroupBy) sqlScan(ctx context.Context, root *ChannelMonitorRequestTemplateQuery, v any) error { + selector := root.sqlQuery(ctx).Select() + aggregation := make([]string, 0, len(_g.fns)) + for _, fn := range _g.fns { + aggregation = append(aggregation, fn(selector)) + } + if len(selector.SelectedColumns()) == 0 { + columns := make([]string, 0, len(*_g.flds)+len(_g.fns)) + for _, f := range *_g.flds { + columns = append(columns, selector.C(f)) + } + columns = append(columns, aggregation...) + selector.Select(columns...) + } + selector.GroupBy(selector.Columns(*_g.flds...)...) + if err := selector.Err(); err != nil { + return err + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := _g.build.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} + +// ChannelMonitorRequestTemplateSelect is the builder for selecting fields of ChannelMonitorRequestTemplate entities. +type ChannelMonitorRequestTemplateSelect struct { + *ChannelMonitorRequestTemplateQuery + selector +} + +// Aggregate adds the given aggregation functions to the selector query. +func (_s *ChannelMonitorRequestTemplateSelect) Aggregate(fns ...AggregateFunc) *ChannelMonitorRequestTemplateSelect { + _s.fns = append(_s.fns, fns...) + return _s +} + +// Scan applies the selector query and scans the result into the given value. +func (_s *ChannelMonitorRequestTemplateSelect) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, _s.ctx, ent.OpQuerySelect) + if err := _s.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*ChannelMonitorRequestTemplateQuery, *ChannelMonitorRequestTemplateSelect](ctx, _s.ChannelMonitorRequestTemplateQuery, _s, _s.inters, v) +} + +func (_s *ChannelMonitorRequestTemplateSelect) sqlScan(ctx context.Context, root *ChannelMonitorRequestTemplateQuery, v any) error { + selector := root.sqlQuery(ctx) + aggregation := make([]string, 0, len(_s.fns)) + for _, fn := range _s.fns { + aggregation = append(aggregation, fn(selector)) + } + switch n := len(*_s.selector.flds); { + case n == 0 && len(aggregation) > 0: + selector.Select(aggregation...) + case n != 0 && len(aggregation) > 0: + selector.AppendSelect(aggregation...) + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := _s.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} diff --git a/backend/ent/channelmonitorrequesttemplate_update.go b/backend/ent/channelmonitorrequesttemplate_update.go new file mode 100644 index 00000000..8f55ba04 --- /dev/null +++ b/backend/ent/channelmonitorrequesttemplate_update.go @@ -0,0 +1,639 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// ChannelMonitorRequestTemplateUpdate is the builder for updating ChannelMonitorRequestTemplate entities. +type ChannelMonitorRequestTemplateUpdate struct { + config + hooks []Hook + mutation *ChannelMonitorRequestTemplateMutation +} + +// Where appends a list predicates to the ChannelMonitorRequestTemplateUpdate builder. +func (_u *ChannelMonitorRequestTemplateUpdate) Where(ps ...predicate.ChannelMonitorRequestTemplate) *ChannelMonitorRequestTemplateUpdate { + _u.mutation.Where(ps...) + return _u +} + +// SetUpdatedAt sets the "updated_at" field. +func (_u *ChannelMonitorRequestTemplateUpdate) SetUpdatedAt(v time.Time) *ChannelMonitorRequestTemplateUpdate { + _u.mutation.SetUpdatedAt(v) + return _u +} + +// SetName sets the "name" field. +func (_u *ChannelMonitorRequestTemplateUpdate) SetName(v string) *ChannelMonitorRequestTemplateUpdate { + _u.mutation.SetName(v) + return _u +} + +// SetNillableName sets the "name" field if the given value is not nil. +func (_u *ChannelMonitorRequestTemplateUpdate) SetNillableName(v *string) *ChannelMonitorRequestTemplateUpdate { + if v != nil { + _u.SetName(*v) + } + return _u +} + +// SetProvider sets the "provider" field. +func (_u *ChannelMonitorRequestTemplateUpdate) SetProvider(v channelmonitorrequesttemplate.Provider) *ChannelMonitorRequestTemplateUpdate { + _u.mutation.SetProvider(v) + return _u +} + +// SetNillableProvider sets the "provider" field if the given value is not nil. +func (_u *ChannelMonitorRequestTemplateUpdate) SetNillableProvider(v *channelmonitorrequesttemplate.Provider) *ChannelMonitorRequestTemplateUpdate { + if v != nil { + _u.SetProvider(*v) + } + return _u +} + +// SetDescription sets the "description" field. +func (_u *ChannelMonitorRequestTemplateUpdate) SetDescription(v string) *ChannelMonitorRequestTemplateUpdate { + _u.mutation.SetDescription(v) + return _u +} + +// SetNillableDescription sets the "description" field if the given value is not nil. +func (_u *ChannelMonitorRequestTemplateUpdate) SetNillableDescription(v *string) *ChannelMonitorRequestTemplateUpdate { + if v != nil { + _u.SetDescription(*v) + } + return _u +} + +// ClearDescription clears the value of the "description" field. +func (_u *ChannelMonitorRequestTemplateUpdate) ClearDescription() *ChannelMonitorRequestTemplateUpdate { + _u.mutation.ClearDescription() + return _u +} + +// SetExtraHeaders sets the "extra_headers" field. +func (_u *ChannelMonitorRequestTemplateUpdate) SetExtraHeaders(v map[string]string) *ChannelMonitorRequestTemplateUpdate { + _u.mutation.SetExtraHeaders(v) + return _u +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (_u *ChannelMonitorRequestTemplateUpdate) SetBodyOverrideMode(v string) *ChannelMonitorRequestTemplateUpdate { + _u.mutation.SetBodyOverrideMode(v) + return _u +} + +// SetNillableBodyOverrideMode sets the "body_override_mode" field if the given value is not nil. +func (_u *ChannelMonitorRequestTemplateUpdate) SetNillableBodyOverrideMode(v *string) *ChannelMonitorRequestTemplateUpdate { + if v != nil { + _u.SetBodyOverrideMode(*v) + } + return _u +} + +// SetBodyOverride sets the "body_override" field. +func (_u *ChannelMonitorRequestTemplateUpdate) SetBodyOverride(v map[string]interface{}) *ChannelMonitorRequestTemplateUpdate { + _u.mutation.SetBodyOverride(v) + return _u +} + +// ClearBodyOverride clears the value of the "body_override" field. +func (_u *ChannelMonitorRequestTemplateUpdate) ClearBodyOverride() *ChannelMonitorRequestTemplateUpdate { + _u.mutation.ClearBodyOverride() + return _u +} + +// AddMonitorIDs adds the "monitors" edge to the ChannelMonitor entity by IDs. +func (_u *ChannelMonitorRequestTemplateUpdate) AddMonitorIDs(ids ...int64) *ChannelMonitorRequestTemplateUpdate { + _u.mutation.AddMonitorIDs(ids...) + return _u +} + +// AddMonitors adds the "monitors" edges to the ChannelMonitor entity. +func (_u *ChannelMonitorRequestTemplateUpdate) AddMonitors(v ...*ChannelMonitor) *ChannelMonitorRequestTemplateUpdate { + ids := make([]int64, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _u.AddMonitorIDs(ids...) +} + +// Mutation returns the ChannelMonitorRequestTemplateMutation object of the builder. +func (_u *ChannelMonitorRequestTemplateUpdate) Mutation() *ChannelMonitorRequestTemplateMutation { + return _u.mutation +} + +// ClearMonitors clears all "monitors" edges to the ChannelMonitor entity. +func (_u *ChannelMonitorRequestTemplateUpdate) ClearMonitors() *ChannelMonitorRequestTemplateUpdate { + _u.mutation.ClearMonitors() + return _u +} + +// RemoveMonitorIDs removes the "monitors" edge to ChannelMonitor entities by IDs. +func (_u *ChannelMonitorRequestTemplateUpdate) RemoveMonitorIDs(ids ...int64) *ChannelMonitorRequestTemplateUpdate { + _u.mutation.RemoveMonitorIDs(ids...) + return _u +} + +// RemoveMonitors removes "monitors" edges to ChannelMonitor entities. +func (_u *ChannelMonitorRequestTemplateUpdate) RemoveMonitors(v ...*ChannelMonitor) *ChannelMonitorRequestTemplateUpdate { + ids := make([]int64, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _u.RemoveMonitorIDs(ids...) +} + +// Save executes the query and returns the number of nodes affected by the update operation. +func (_u *ChannelMonitorRequestTemplateUpdate) Save(ctx context.Context) (int, error) { + _u.defaults() + return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (_u *ChannelMonitorRequestTemplateUpdate) SaveX(ctx context.Context) int { + affected, err := _u.Save(ctx) + if err != nil { + panic(err) + } + return affected +} + +// Exec executes the query. +func (_u *ChannelMonitorRequestTemplateUpdate) Exec(ctx context.Context) error { + _, err := _u.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_u *ChannelMonitorRequestTemplateUpdate) ExecX(ctx context.Context) { + if err := _u.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (_u *ChannelMonitorRequestTemplateUpdate) defaults() { + if _, ok := _u.mutation.UpdatedAt(); !ok { + v := channelmonitorrequesttemplate.UpdateDefaultUpdatedAt() + _u.mutation.SetUpdatedAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_u *ChannelMonitorRequestTemplateUpdate) check() error { + if v, ok := _u.mutation.Name(); ok { + if err := channelmonitorrequesttemplate.NameValidator(v); err != nil { + return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorRequestTemplate.name": %w`, err)} + } + } + if v, ok := _u.mutation.Provider(); ok { + if err := channelmonitorrequesttemplate.ProviderValidator(v); err != nil { + return &ValidationError{Name: "provider", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorRequestTemplate.provider": %w`, err)} + } + } + if v, ok := _u.mutation.Description(); ok { + if err := channelmonitorrequesttemplate.DescriptionValidator(v); err != nil { + return &ValidationError{Name: "description", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorRequestTemplate.description": %w`, err)} + } + } + if v, ok := _u.mutation.BodyOverrideMode(); ok { + if err := channelmonitorrequesttemplate.BodyOverrideModeValidator(v); err != nil { + return &ValidationError{Name: "body_override_mode", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorRequestTemplate.body_override_mode": %w`, err)} + } + } + return nil +} + +func (_u *ChannelMonitorRequestTemplateUpdate) sqlSave(ctx context.Context) (_node int, err error) { + if err := _u.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(channelmonitorrequesttemplate.Table, channelmonitorrequesttemplate.Columns, sqlgraph.NewFieldSpec(channelmonitorrequesttemplate.FieldID, field.TypeInt64)) + if ps := _u.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := _u.mutation.UpdatedAt(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldUpdatedAt, field.TypeTime, value) + } + if value, ok := _u.mutation.Name(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldName, field.TypeString, value) + } + if value, ok := _u.mutation.Provider(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldProvider, field.TypeEnum, value) + } + if value, ok := _u.mutation.Description(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldDescription, field.TypeString, value) + } + if _u.mutation.DescriptionCleared() { + _spec.ClearField(channelmonitorrequesttemplate.FieldDescription, field.TypeString) + } + if value, ok := _u.mutation.ExtraHeaders(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldExtraHeaders, field.TypeJSON, value) + } + if value, ok := _u.mutation.BodyOverrideMode(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldBodyOverrideMode, field.TypeString, value) + } + if value, ok := _u.mutation.BodyOverride(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldBodyOverride, field.TypeJSON, value) + } + if _u.mutation.BodyOverrideCleared() { + _spec.ClearField(channelmonitorrequesttemplate.FieldBodyOverride, field.TypeJSON) + } + if _u.mutation.MonitorsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: true, + Table: channelmonitorrequesttemplate.MonitorsTable, + Columns: []string{channelmonitorrequesttemplate.MonitorsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.RemovedMonitorsIDs(); len(nodes) > 0 && !_u.mutation.MonitorsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: true, + Table: channelmonitorrequesttemplate.MonitorsTable, + Columns: []string{channelmonitorrequesttemplate.MonitorsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.MonitorsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: true, + Table: channelmonitorrequesttemplate.MonitorsTable, + Columns: []string{channelmonitorrequesttemplate.MonitorsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if _node, err = sqlgraph.UpdateNodes(ctx, _u.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{channelmonitorrequesttemplate.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return 0, err + } + _u.mutation.done = true + return _node, nil +} + +// ChannelMonitorRequestTemplateUpdateOne is the builder for updating a single ChannelMonitorRequestTemplate entity. +type ChannelMonitorRequestTemplateUpdateOne struct { + config + fields []string + hooks []Hook + mutation *ChannelMonitorRequestTemplateMutation +} + +// SetUpdatedAt sets the "updated_at" field. +func (_u *ChannelMonitorRequestTemplateUpdateOne) SetUpdatedAt(v time.Time) *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.SetUpdatedAt(v) + return _u +} + +// SetName sets the "name" field. +func (_u *ChannelMonitorRequestTemplateUpdateOne) SetName(v string) *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.SetName(v) + return _u +} + +// SetNillableName sets the "name" field if the given value is not nil. +func (_u *ChannelMonitorRequestTemplateUpdateOne) SetNillableName(v *string) *ChannelMonitorRequestTemplateUpdateOne { + if v != nil { + _u.SetName(*v) + } + return _u +} + +// SetProvider sets the "provider" field. +func (_u *ChannelMonitorRequestTemplateUpdateOne) SetProvider(v channelmonitorrequesttemplate.Provider) *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.SetProvider(v) + return _u +} + +// SetNillableProvider sets the "provider" field if the given value is not nil. +func (_u *ChannelMonitorRequestTemplateUpdateOne) SetNillableProvider(v *channelmonitorrequesttemplate.Provider) *ChannelMonitorRequestTemplateUpdateOne { + if v != nil { + _u.SetProvider(*v) + } + return _u +} + +// SetDescription sets the "description" field. +func (_u *ChannelMonitorRequestTemplateUpdateOne) SetDescription(v string) *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.SetDescription(v) + return _u +} + +// SetNillableDescription sets the "description" field if the given value is not nil. +func (_u *ChannelMonitorRequestTemplateUpdateOne) SetNillableDescription(v *string) *ChannelMonitorRequestTemplateUpdateOne { + if v != nil { + _u.SetDescription(*v) + } + return _u +} + +// ClearDescription clears the value of the "description" field. +func (_u *ChannelMonitorRequestTemplateUpdateOne) ClearDescription() *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.ClearDescription() + return _u +} + +// SetExtraHeaders sets the "extra_headers" field. +func (_u *ChannelMonitorRequestTemplateUpdateOne) SetExtraHeaders(v map[string]string) *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.SetExtraHeaders(v) + return _u +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (_u *ChannelMonitorRequestTemplateUpdateOne) SetBodyOverrideMode(v string) *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.SetBodyOverrideMode(v) + return _u +} + +// SetNillableBodyOverrideMode sets the "body_override_mode" field if the given value is not nil. +func (_u *ChannelMonitorRequestTemplateUpdateOne) SetNillableBodyOverrideMode(v *string) *ChannelMonitorRequestTemplateUpdateOne { + if v != nil { + _u.SetBodyOverrideMode(*v) + } + return _u +} + +// SetBodyOverride sets the "body_override" field. +func (_u *ChannelMonitorRequestTemplateUpdateOne) SetBodyOverride(v map[string]interface{}) *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.SetBodyOverride(v) + return _u +} + +// ClearBodyOverride clears the value of the "body_override" field. +func (_u *ChannelMonitorRequestTemplateUpdateOne) ClearBodyOverride() *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.ClearBodyOverride() + return _u +} + +// AddMonitorIDs adds the "monitors" edge to the ChannelMonitor entity by IDs. +func (_u *ChannelMonitorRequestTemplateUpdateOne) AddMonitorIDs(ids ...int64) *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.AddMonitorIDs(ids...) + return _u +} + +// AddMonitors adds the "monitors" edges to the ChannelMonitor entity. +func (_u *ChannelMonitorRequestTemplateUpdateOne) AddMonitors(v ...*ChannelMonitor) *ChannelMonitorRequestTemplateUpdateOne { + ids := make([]int64, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _u.AddMonitorIDs(ids...) +} + +// Mutation returns the ChannelMonitorRequestTemplateMutation object of the builder. +func (_u *ChannelMonitorRequestTemplateUpdateOne) Mutation() *ChannelMonitorRequestTemplateMutation { + return _u.mutation +} + +// ClearMonitors clears all "monitors" edges to the ChannelMonitor entity. +func (_u *ChannelMonitorRequestTemplateUpdateOne) ClearMonitors() *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.ClearMonitors() + return _u +} + +// RemoveMonitorIDs removes the "monitors" edge to ChannelMonitor entities by IDs. +func (_u *ChannelMonitorRequestTemplateUpdateOne) RemoveMonitorIDs(ids ...int64) *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.RemoveMonitorIDs(ids...) + return _u +} + +// RemoveMonitors removes "monitors" edges to ChannelMonitor entities. +func (_u *ChannelMonitorRequestTemplateUpdateOne) RemoveMonitors(v ...*ChannelMonitor) *ChannelMonitorRequestTemplateUpdateOne { + ids := make([]int64, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _u.RemoveMonitorIDs(ids...) +} + +// Where appends a list predicates to the ChannelMonitorRequestTemplateUpdate builder. +func (_u *ChannelMonitorRequestTemplateUpdateOne) Where(ps ...predicate.ChannelMonitorRequestTemplate) *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.Where(ps...) + return _u +} + +// Select allows selecting one or more fields (columns) of the returned entity. +// The default is selecting all fields defined in the entity schema. +func (_u *ChannelMonitorRequestTemplateUpdateOne) Select(field string, fields ...string) *ChannelMonitorRequestTemplateUpdateOne { + _u.fields = append([]string{field}, fields...) + return _u +} + +// Save executes the query and returns the updated ChannelMonitorRequestTemplate entity. +func (_u *ChannelMonitorRequestTemplateUpdateOne) Save(ctx context.Context) (*ChannelMonitorRequestTemplate, error) { + _u.defaults() + return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (_u *ChannelMonitorRequestTemplateUpdateOne) SaveX(ctx context.Context) *ChannelMonitorRequestTemplate { + node, err := _u.Save(ctx) + if err != nil { + panic(err) + } + return node +} + +// Exec executes the query on the entity. +func (_u *ChannelMonitorRequestTemplateUpdateOne) Exec(ctx context.Context) error { + _, err := _u.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_u *ChannelMonitorRequestTemplateUpdateOne) ExecX(ctx context.Context) { + if err := _u.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (_u *ChannelMonitorRequestTemplateUpdateOne) defaults() { + if _, ok := _u.mutation.UpdatedAt(); !ok { + v := channelmonitorrequesttemplate.UpdateDefaultUpdatedAt() + _u.mutation.SetUpdatedAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_u *ChannelMonitorRequestTemplateUpdateOne) check() error { + if v, ok := _u.mutation.Name(); ok { + if err := channelmonitorrequesttemplate.NameValidator(v); err != nil { + return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorRequestTemplate.name": %w`, err)} + } + } + if v, ok := _u.mutation.Provider(); ok { + if err := channelmonitorrequesttemplate.ProviderValidator(v); err != nil { + return &ValidationError{Name: "provider", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorRequestTemplate.provider": %w`, err)} + } + } + if v, ok := _u.mutation.Description(); ok { + if err := channelmonitorrequesttemplate.DescriptionValidator(v); err != nil { + return &ValidationError{Name: "description", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorRequestTemplate.description": %w`, err)} + } + } + if v, ok := _u.mutation.BodyOverrideMode(); ok { + if err := channelmonitorrequesttemplate.BodyOverrideModeValidator(v); err != nil { + return &ValidationError{Name: "body_override_mode", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorRequestTemplate.body_override_mode": %w`, err)} + } + } + return nil +} + +func (_u *ChannelMonitorRequestTemplateUpdateOne) sqlSave(ctx context.Context) (_node *ChannelMonitorRequestTemplate, err error) { + if err := _u.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(channelmonitorrequesttemplate.Table, channelmonitorrequesttemplate.Columns, sqlgraph.NewFieldSpec(channelmonitorrequesttemplate.FieldID, field.TypeInt64)) + id, ok := _u.mutation.ID() + if !ok { + return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "ChannelMonitorRequestTemplate.id" for update`)} + } + _spec.Node.ID.Value = id + if fields := _u.fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, channelmonitorrequesttemplate.FieldID) + for _, f := range fields { + if !channelmonitorrequesttemplate.ValidColumn(f) { + return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + if f != channelmonitorrequesttemplate.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, f) + } + } + } + if ps := _u.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := _u.mutation.UpdatedAt(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldUpdatedAt, field.TypeTime, value) + } + if value, ok := _u.mutation.Name(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldName, field.TypeString, value) + } + if value, ok := _u.mutation.Provider(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldProvider, field.TypeEnum, value) + } + if value, ok := _u.mutation.Description(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldDescription, field.TypeString, value) + } + if _u.mutation.DescriptionCleared() { + _spec.ClearField(channelmonitorrequesttemplate.FieldDescription, field.TypeString) + } + if value, ok := _u.mutation.ExtraHeaders(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldExtraHeaders, field.TypeJSON, value) + } + if value, ok := _u.mutation.BodyOverrideMode(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldBodyOverrideMode, field.TypeString, value) + } + if value, ok := _u.mutation.BodyOverride(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldBodyOverride, field.TypeJSON, value) + } + if _u.mutation.BodyOverrideCleared() { + _spec.ClearField(channelmonitorrequesttemplate.FieldBodyOverride, field.TypeJSON) + } + if _u.mutation.MonitorsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: true, + Table: channelmonitorrequesttemplate.MonitorsTable, + Columns: []string{channelmonitorrequesttemplate.MonitorsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.RemovedMonitorsIDs(); len(nodes) > 0 && !_u.mutation.MonitorsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: true, + Table: channelmonitorrequesttemplate.MonitorsTable, + Columns: []string{channelmonitorrequesttemplate.MonitorsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.MonitorsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: true, + Table: channelmonitorrequesttemplate.MonitorsTable, + Columns: []string{channelmonitorrequesttemplate.MonitorsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + _node = &ChannelMonitorRequestTemplate{config: _u.config} + _spec.Assign = _node.assignValues + _spec.ScanValues = _node.scanValues + if err = sqlgraph.UpdateNode(ctx, _u.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{channelmonitorrequesttemplate.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + _u.mutation.done = true + return _node, nil +} diff --git a/backend/ent/client.go b/backend/ent/client.go index b02f519b..df20ddfa 100644 --- a/backend/ent/client.go +++ b/backend/ent/client.go @@ -22,6 +22,10 @@ import ( "github.com/Wei-Shaw/sub2api/ent/apikey" "github.com/Wei-Shaw/sub2api/ent/authidentity" "github.com/Wei-Shaw/sub2api/ent/authidentitychannel" + "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitordailyrollup" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" "github.com/Wei-Shaw/sub2api/ent/errorpassthroughrule" "github.com/Wei-Shaw/sub2api/ent/group" "github.com/Wei-Shaw/sub2api/ent/idempotencyrecord" @@ -68,6 +72,14 @@ type Client struct { AuthIdentity *AuthIdentityClient // AuthIdentityChannel is the client for interacting with the AuthIdentityChannel builders. AuthIdentityChannel *AuthIdentityChannelClient + // ChannelMonitor is the client for interacting with the ChannelMonitor builders. + ChannelMonitor *ChannelMonitorClient + // ChannelMonitorDailyRollup is the client for interacting with the ChannelMonitorDailyRollup builders. + ChannelMonitorDailyRollup *ChannelMonitorDailyRollupClient + // ChannelMonitorHistory is the client for interacting with the ChannelMonitorHistory builders. + ChannelMonitorHistory *ChannelMonitorHistoryClient + // ChannelMonitorRequestTemplate is the client for interacting with the ChannelMonitorRequestTemplate builders. + ChannelMonitorRequestTemplate *ChannelMonitorRequestTemplateClient // ErrorPassthroughRule is the client for interacting with the ErrorPassthroughRule builders. ErrorPassthroughRule *ErrorPassthroughRuleClient // Group is the client for interacting with the Group builders. @@ -132,6 +144,10 @@ func (c *Client) init() { c.AnnouncementRead = NewAnnouncementReadClient(c.config) c.AuthIdentity = NewAuthIdentityClient(c.config) c.AuthIdentityChannel = NewAuthIdentityChannelClient(c.config) + c.ChannelMonitor = NewChannelMonitorClient(c.config) + c.ChannelMonitorDailyRollup = NewChannelMonitorDailyRollupClient(c.config) + c.ChannelMonitorHistory = NewChannelMonitorHistoryClient(c.config) + c.ChannelMonitorRequestTemplate = NewChannelMonitorRequestTemplateClient(c.config) c.ErrorPassthroughRule = NewErrorPassthroughRuleClient(c.config) c.Group = NewGroupClient(c.config) c.IdempotencyRecord = NewIdempotencyRecordClient(c.config) @@ -245,38 +261,42 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) { cfg := c.config cfg.driver = tx return &Tx{ - ctx: ctx, - config: cfg, - APIKey: NewAPIKeyClient(cfg), - Account: NewAccountClient(cfg), - AccountGroup: NewAccountGroupClient(cfg), - Announcement: NewAnnouncementClient(cfg), - AnnouncementRead: NewAnnouncementReadClient(cfg), - AuthIdentity: NewAuthIdentityClient(cfg), - AuthIdentityChannel: NewAuthIdentityChannelClient(cfg), - ErrorPassthroughRule: NewErrorPassthroughRuleClient(cfg), - Group: NewGroupClient(cfg), - IdempotencyRecord: NewIdempotencyRecordClient(cfg), - IdentityAdoptionDecision: NewIdentityAdoptionDecisionClient(cfg), - PaymentAuditLog: NewPaymentAuditLogClient(cfg), - PaymentOrder: NewPaymentOrderClient(cfg), - PaymentProviderInstance: NewPaymentProviderInstanceClient(cfg), - PendingAuthSession: NewPendingAuthSessionClient(cfg), - PromoCode: NewPromoCodeClient(cfg), - PromoCodeUsage: NewPromoCodeUsageClient(cfg), - Proxy: NewProxyClient(cfg), - RedeemCode: NewRedeemCodeClient(cfg), - SecuritySecret: NewSecuritySecretClient(cfg), - Setting: NewSettingClient(cfg), - SubscriptionPlan: NewSubscriptionPlanClient(cfg), - TLSFingerprintProfile: NewTLSFingerprintProfileClient(cfg), - UsageCleanupTask: NewUsageCleanupTaskClient(cfg), - UsageLog: NewUsageLogClient(cfg), - User: NewUserClient(cfg), - UserAllowedGroup: NewUserAllowedGroupClient(cfg), - UserAttributeDefinition: NewUserAttributeDefinitionClient(cfg), - UserAttributeValue: NewUserAttributeValueClient(cfg), - UserSubscription: NewUserSubscriptionClient(cfg), + ctx: ctx, + config: cfg, + APIKey: NewAPIKeyClient(cfg), + Account: NewAccountClient(cfg), + AccountGroup: NewAccountGroupClient(cfg), + Announcement: NewAnnouncementClient(cfg), + AnnouncementRead: NewAnnouncementReadClient(cfg), + AuthIdentity: NewAuthIdentityClient(cfg), + AuthIdentityChannel: NewAuthIdentityChannelClient(cfg), + ChannelMonitor: NewChannelMonitorClient(cfg), + ChannelMonitorDailyRollup: NewChannelMonitorDailyRollupClient(cfg), + ChannelMonitorHistory: NewChannelMonitorHistoryClient(cfg), + ChannelMonitorRequestTemplate: NewChannelMonitorRequestTemplateClient(cfg), + ErrorPassthroughRule: NewErrorPassthroughRuleClient(cfg), + Group: NewGroupClient(cfg), + IdempotencyRecord: NewIdempotencyRecordClient(cfg), + IdentityAdoptionDecision: NewIdentityAdoptionDecisionClient(cfg), + PaymentAuditLog: NewPaymentAuditLogClient(cfg), + PaymentOrder: NewPaymentOrderClient(cfg), + PaymentProviderInstance: NewPaymentProviderInstanceClient(cfg), + PendingAuthSession: NewPendingAuthSessionClient(cfg), + PromoCode: NewPromoCodeClient(cfg), + PromoCodeUsage: NewPromoCodeUsageClient(cfg), + Proxy: NewProxyClient(cfg), + RedeemCode: NewRedeemCodeClient(cfg), + SecuritySecret: NewSecuritySecretClient(cfg), + Setting: NewSettingClient(cfg), + SubscriptionPlan: NewSubscriptionPlanClient(cfg), + TLSFingerprintProfile: NewTLSFingerprintProfileClient(cfg), + UsageCleanupTask: NewUsageCleanupTaskClient(cfg), + UsageLog: NewUsageLogClient(cfg), + User: NewUserClient(cfg), + UserAllowedGroup: NewUserAllowedGroupClient(cfg), + UserAttributeDefinition: NewUserAttributeDefinitionClient(cfg), + UserAttributeValue: NewUserAttributeValueClient(cfg), + UserSubscription: NewUserSubscriptionClient(cfg), }, nil } @@ -294,38 +314,42 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) cfg := c.config cfg.driver = &txDriver{tx: tx, drv: c.driver} return &Tx{ - ctx: ctx, - config: cfg, - APIKey: NewAPIKeyClient(cfg), - Account: NewAccountClient(cfg), - AccountGroup: NewAccountGroupClient(cfg), - Announcement: NewAnnouncementClient(cfg), - AnnouncementRead: NewAnnouncementReadClient(cfg), - AuthIdentity: NewAuthIdentityClient(cfg), - AuthIdentityChannel: NewAuthIdentityChannelClient(cfg), - ErrorPassthroughRule: NewErrorPassthroughRuleClient(cfg), - Group: NewGroupClient(cfg), - IdempotencyRecord: NewIdempotencyRecordClient(cfg), - IdentityAdoptionDecision: NewIdentityAdoptionDecisionClient(cfg), - PaymentAuditLog: NewPaymentAuditLogClient(cfg), - PaymentOrder: NewPaymentOrderClient(cfg), - PaymentProviderInstance: NewPaymentProviderInstanceClient(cfg), - PendingAuthSession: NewPendingAuthSessionClient(cfg), - PromoCode: NewPromoCodeClient(cfg), - PromoCodeUsage: NewPromoCodeUsageClient(cfg), - Proxy: NewProxyClient(cfg), - RedeemCode: NewRedeemCodeClient(cfg), - SecuritySecret: NewSecuritySecretClient(cfg), - Setting: NewSettingClient(cfg), - SubscriptionPlan: NewSubscriptionPlanClient(cfg), - TLSFingerprintProfile: NewTLSFingerprintProfileClient(cfg), - UsageCleanupTask: NewUsageCleanupTaskClient(cfg), - UsageLog: NewUsageLogClient(cfg), - User: NewUserClient(cfg), - UserAllowedGroup: NewUserAllowedGroupClient(cfg), - UserAttributeDefinition: NewUserAttributeDefinitionClient(cfg), - UserAttributeValue: NewUserAttributeValueClient(cfg), - UserSubscription: NewUserSubscriptionClient(cfg), + ctx: ctx, + config: cfg, + APIKey: NewAPIKeyClient(cfg), + Account: NewAccountClient(cfg), + AccountGroup: NewAccountGroupClient(cfg), + Announcement: NewAnnouncementClient(cfg), + AnnouncementRead: NewAnnouncementReadClient(cfg), + AuthIdentity: NewAuthIdentityClient(cfg), + AuthIdentityChannel: NewAuthIdentityChannelClient(cfg), + ChannelMonitor: NewChannelMonitorClient(cfg), + ChannelMonitorDailyRollup: NewChannelMonitorDailyRollupClient(cfg), + ChannelMonitorHistory: NewChannelMonitorHistoryClient(cfg), + ChannelMonitorRequestTemplate: NewChannelMonitorRequestTemplateClient(cfg), + ErrorPassthroughRule: NewErrorPassthroughRuleClient(cfg), + Group: NewGroupClient(cfg), + IdempotencyRecord: NewIdempotencyRecordClient(cfg), + IdentityAdoptionDecision: NewIdentityAdoptionDecisionClient(cfg), + PaymentAuditLog: NewPaymentAuditLogClient(cfg), + PaymentOrder: NewPaymentOrderClient(cfg), + PaymentProviderInstance: NewPaymentProviderInstanceClient(cfg), + PendingAuthSession: NewPendingAuthSessionClient(cfg), + PromoCode: NewPromoCodeClient(cfg), + PromoCodeUsage: NewPromoCodeUsageClient(cfg), + Proxy: NewProxyClient(cfg), + RedeemCode: NewRedeemCodeClient(cfg), + SecuritySecret: NewSecuritySecretClient(cfg), + Setting: NewSettingClient(cfg), + SubscriptionPlan: NewSubscriptionPlanClient(cfg), + TLSFingerprintProfile: NewTLSFingerprintProfileClient(cfg), + UsageCleanupTask: NewUsageCleanupTaskClient(cfg), + UsageLog: NewUsageLogClient(cfg), + User: NewUserClient(cfg), + UserAllowedGroup: NewUserAllowedGroupClient(cfg), + UserAttributeDefinition: NewUserAttributeDefinitionClient(cfg), + UserAttributeValue: NewUserAttributeValueClient(cfg), + UserSubscription: NewUserSubscriptionClient(cfg), }, nil } @@ -356,7 +380,9 @@ func (c *Client) Close() error { func (c *Client) Use(hooks ...Hook) { for _, n := range []interface{ Use(...Hook) }{ c.APIKey, c.Account, c.AccountGroup, c.Announcement, c.AnnouncementRead, - c.AuthIdentity, c.AuthIdentityChannel, c.ErrorPassthroughRule, c.Group, + c.AuthIdentity, c.AuthIdentityChannel, c.ChannelMonitor, + c.ChannelMonitorDailyRollup, c.ChannelMonitorHistory, + c.ChannelMonitorRequestTemplate, c.ErrorPassthroughRule, c.Group, c.IdempotencyRecord, c.IdentityAdoptionDecision, c.PaymentAuditLog, c.PaymentOrder, c.PaymentProviderInstance, c.PendingAuthSession, c.PromoCode, c.PromoCodeUsage, c.Proxy, c.RedeemCode, c.SecuritySecret, c.Setting, @@ -373,7 +399,9 @@ func (c *Client) Use(hooks ...Hook) { func (c *Client) Intercept(interceptors ...Interceptor) { for _, n := range []interface{ Intercept(...Interceptor) }{ c.APIKey, c.Account, c.AccountGroup, c.Announcement, c.AnnouncementRead, - c.AuthIdentity, c.AuthIdentityChannel, c.ErrorPassthroughRule, c.Group, + c.AuthIdentity, c.AuthIdentityChannel, c.ChannelMonitor, + c.ChannelMonitorDailyRollup, c.ChannelMonitorHistory, + c.ChannelMonitorRequestTemplate, c.ErrorPassthroughRule, c.Group, c.IdempotencyRecord, c.IdentityAdoptionDecision, c.PaymentAuditLog, c.PaymentOrder, c.PaymentProviderInstance, c.PendingAuthSession, c.PromoCode, c.PromoCodeUsage, c.Proxy, c.RedeemCode, c.SecuritySecret, c.Setting, @@ -402,6 +430,14 @@ func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) { return c.AuthIdentity.mutate(ctx, m) case *AuthIdentityChannelMutation: return c.AuthIdentityChannel.mutate(ctx, m) + case *ChannelMonitorMutation: + return c.ChannelMonitor.mutate(ctx, m) + case *ChannelMonitorDailyRollupMutation: + return c.ChannelMonitorDailyRollup.mutate(ctx, m) + case *ChannelMonitorHistoryMutation: + return c.ChannelMonitorHistory.mutate(ctx, m) + case *ChannelMonitorRequestTemplateMutation: + return c.ChannelMonitorRequestTemplate.mutate(ctx, m) case *ErrorPassthroughRuleMutation: return c.ErrorPassthroughRule.mutate(ctx, m) case *GroupMutation: @@ -1595,6 +1631,634 @@ func (c *AuthIdentityChannelClient) mutate(ctx context.Context, m *AuthIdentityC } } +// ChannelMonitorClient is a client for the ChannelMonitor schema. +type ChannelMonitorClient struct { + config +} + +// NewChannelMonitorClient returns a client for the ChannelMonitor from the given config. +func NewChannelMonitorClient(c config) *ChannelMonitorClient { + return &ChannelMonitorClient{config: c} +} + +// Use adds a list of mutation hooks to the hooks stack. +// A call to `Use(f, g, h)` equals to `channelmonitor.Hooks(f(g(h())))`. +func (c *ChannelMonitorClient) Use(hooks ...Hook) { + c.hooks.ChannelMonitor = append(c.hooks.ChannelMonitor, hooks...) +} + +// Intercept adds a list of query interceptors to the interceptors stack. +// A call to `Intercept(f, g, h)` equals to `channelmonitor.Intercept(f(g(h())))`. +func (c *ChannelMonitorClient) Intercept(interceptors ...Interceptor) { + c.inters.ChannelMonitor = append(c.inters.ChannelMonitor, interceptors...) +} + +// Create returns a builder for creating a ChannelMonitor entity. +func (c *ChannelMonitorClient) Create() *ChannelMonitorCreate { + mutation := newChannelMonitorMutation(c.config, OpCreate) + return &ChannelMonitorCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// CreateBulk returns a builder for creating a bulk of ChannelMonitor entities. +func (c *ChannelMonitorClient) CreateBulk(builders ...*ChannelMonitorCreate) *ChannelMonitorCreateBulk { + return &ChannelMonitorCreateBulk{config: c.config, builders: builders} +} + +// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates +// a builder and applies setFunc on it. +func (c *ChannelMonitorClient) MapCreateBulk(slice any, setFunc func(*ChannelMonitorCreate, int)) *ChannelMonitorCreateBulk { + rv := reflect.ValueOf(slice) + if rv.Kind() != reflect.Slice { + return &ChannelMonitorCreateBulk{err: fmt.Errorf("calling to ChannelMonitorClient.MapCreateBulk with wrong type %T, need slice", slice)} + } + builders := make([]*ChannelMonitorCreate, rv.Len()) + for i := 0; i < rv.Len(); i++ { + builders[i] = c.Create() + setFunc(builders[i], i) + } + return &ChannelMonitorCreateBulk{config: c.config, builders: builders} +} + +// Update returns an update builder for ChannelMonitor. +func (c *ChannelMonitorClient) Update() *ChannelMonitorUpdate { + mutation := newChannelMonitorMutation(c.config, OpUpdate) + return &ChannelMonitorUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOne returns an update builder for the given entity. +func (c *ChannelMonitorClient) UpdateOne(_m *ChannelMonitor) *ChannelMonitorUpdateOne { + mutation := newChannelMonitorMutation(c.config, OpUpdateOne, withChannelMonitor(_m)) + return &ChannelMonitorUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOneID returns an update builder for the given id. +func (c *ChannelMonitorClient) UpdateOneID(id int64) *ChannelMonitorUpdateOne { + mutation := newChannelMonitorMutation(c.config, OpUpdateOne, withChannelMonitorID(id)) + return &ChannelMonitorUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// Delete returns a delete builder for ChannelMonitor. +func (c *ChannelMonitorClient) Delete() *ChannelMonitorDelete { + mutation := newChannelMonitorMutation(c.config, OpDelete) + return &ChannelMonitorDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// DeleteOne returns a builder for deleting the given entity. +func (c *ChannelMonitorClient) DeleteOne(_m *ChannelMonitor) *ChannelMonitorDeleteOne { + return c.DeleteOneID(_m.ID) +} + +// DeleteOneID returns a builder for deleting the given entity by its id. +func (c *ChannelMonitorClient) DeleteOneID(id int64) *ChannelMonitorDeleteOne { + builder := c.Delete().Where(channelmonitor.ID(id)) + builder.mutation.id = &id + builder.mutation.op = OpDeleteOne + return &ChannelMonitorDeleteOne{builder} +} + +// Query returns a query builder for ChannelMonitor. +func (c *ChannelMonitorClient) Query() *ChannelMonitorQuery { + return &ChannelMonitorQuery{ + config: c.config, + ctx: &QueryContext{Type: TypeChannelMonitor}, + inters: c.Interceptors(), + } +} + +// Get returns a ChannelMonitor entity by its id. +func (c *ChannelMonitorClient) Get(ctx context.Context, id int64) (*ChannelMonitor, error) { + return c.Query().Where(channelmonitor.ID(id)).Only(ctx) +} + +// GetX is like Get, but panics if an error occurs. +func (c *ChannelMonitorClient) GetX(ctx context.Context, id int64) *ChannelMonitor { + obj, err := c.Get(ctx, id) + if err != nil { + panic(err) + } + return obj +} + +// QueryHistory queries the history edge of a ChannelMonitor. +func (c *ChannelMonitorClient) QueryHistory(_m *ChannelMonitor) *ChannelMonitorHistoryQuery { + query := (&ChannelMonitorHistoryClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := _m.ID + step := sqlgraph.NewStep( + sqlgraph.From(channelmonitor.Table, channelmonitor.FieldID, id), + sqlgraph.To(channelmonitorhistory.Table, channelmonitorhistory.FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, channelmonitor.HistoryTable, channelmonitor.HistoryColumn), + ) + fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step) + return fromV, nil + } + return query +} + +// QueryDailyRollups queries the daily_rollups edge of a ChannelMonitor. +func (c *ChannelMonitorClient) QueryDailyRollups(_m *ChannelMonitor) *ChannelMonitorDailyRollupQuery { + query := (&ChannelMonitorDailyRollupClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := _m.ID + step := sqlgraph.NewStep( + sqlgraph.From(channelmonitor.Table, channelmonitor.FieldID, id), + sqlgraph.To(channelmonitordailyrollup.Table, channelmonitordailyrollup.FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, channelmonitor.DailyRollupsTable, channelmonitor.DailyRollupsColumn), + ) + fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step) + return fromV, nil + } + return query +} + +// QueryRequestTemplate queries the request_template edge of a ChannelMonitor. +func (c *ChannelMonitorClient) QueryRequestTemplate(_m *ChannelMonitor) *ChannelMonitorRequestTemplateQuery { + query := (&ChannelMonitorRequestTemplateClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := _m.ID + step := sqlgraph.NewStep( + sqlgraph.From(channelmonitor.Table, channelmonitor.FieldID, id), + sqlgraph.To(channelmonitorrequesttemplate.Table, channelmonitorrequesttemplate.FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, channelmonitor.RequestTemplateTable, channelmonitor.RequestTemplateColumn), + ) + fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step) + return fromV, nil + } + return query +} + +// Hooks returns the client hooks. +func (c *ChannelMonitorClient) Hooks() []Hook { + return c.hooks.ChannelMonitor +} + +// Interceptors returns the client interceptors. +func (c *ChannelMonitorClient) Interceptors() []Interceptor { + return c.inters.ChannelMonitor +} + +func (c *ChannelMonitorClient) mutate(ctx context.Context, m *ChannelMonitorMutation) (Value, error) { + switch m.Op() { + case OpCreate: + return (&ChannelMonitorCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdate: + return (&ChannelMonitorUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdateOne: + return (&ChannelMonitorUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpDelete, OpDeleteOne: + return (&ChannelMonitorDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx) + default: + return nil, fmt.Errorf("ent: unknown ChannelMonitor mutation op: %q", m.Op()) + } +} + +// ChannelMonitorDailyRollupClient is a client for the ChannelMonitorDailyRollup schema. +type ChannelMonitorDailyRollupClient struct { + config +} + +// NewChannelMonitorDailyRollupClient returns a client for the ChannelMonitorDailyRollup from the given config. +func NewChannelMonitorDailyRollupClient(c config) *ChannelMonitorDailyRollupClient { + return &ChannelMonitorDailyRollupClient{config: c} +} + +// Use adds a list of mutation hooks to the hooks stack. +// A call to `Use(f, g, h)` equals to `channelmonitordailyrollup.Hooks(f(g(h())))`. +func (c *ChannelMonitorDailyRollupClient) Use(hooks ...Hook) { + c.hooks.ChannelMonitorDailyRollup = append(c.hooks.ChannelMonitorDailyRollup, hooks...) +} + +// Intercept adds a list of query interceptors to the interceptors stack. +// A call to `Intercept(f, g, h)` equals to `channelmonitordailyrollup.Intercept(f(g(h())))`. +func (c *ChannelMonitorDailyRollupClient) Intercept(interceptors ...Interceptor) { + c.inters.ChannelMonitorDailyRollup = append(c.inters.ChannelMonitorDailyRollup, interceptors...) +} + +// Create returns a builder for creating a ChannelMonitorDailyRollup entity. +func (c *ChannelMonitorDailyRollupClient) Create() *ChannelMonitorDailyRollupCreate { + mutation := newChannelMonitorDailyRollupMutation(c.config, OpCreate) + return &ChannelMonitorDailyRollupCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// CreateBulk returns a builder for creating a bulk of ChannelMonitorDailyRollup entities. +func (c *ChannelMonitorDailyRollupClient) CreateBulk(builders ...*ChannelMonitorDailyRollupCreate) *ChannelMonitorDailyRollupCreateBulk { + return &ChannelMonitorDailyRollupCreateBulk{config: c.config, builders: builders} +} + +// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates +// a builder and applies setFunc on it. +func (c *ChannelMonitorDailyRollupClient) MapCreateBulk(slice any, setFunc func(*ChannelMonitorDailyRollupCreate, int)) *ChannelMonitorDailyRollupCreateBulk { + rv := reflect.ValueOf(slice) + if rv.Kind() != reflect.Slice { + return &ChannelMonitorDailyRollupCreateBulk{err: fmt.Errorf("calling to ChannelMonitorDailyRollupClient.MapCreateBulk with wrong type %T, need slice", slice)} + } + builders := make([]*ChannelMonitorDailyRollupCreate, rv.Len()) + for i := 0; i < rv.Len(); i++ { + builders[i] = c.Create() + setFunc(builders[i], i) + } + return &ChannelMonitorDailyRollupCreateBulk{config: c.config, builders: builders} +} + +// Update returns an update builder for ChannelMonitorDailyRollup. +func (c *ChannelMonitorDailyRollupClient) Update() *ChannelMonitorDailyRollupUpdate { + mutation := newChannelMonitorDailyRollupMutation(c.config, OpUpdate) + return &ChannelMonitorDailyRollupUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOne returns an update builder for the given entity. +func (c *ChannelMonitorDailyRollupClient) UpdateOne(_m *ChannelMonitorDailyRollup) *ChannelMonitorDailyRollupUpdateOne { + mutation := newChannelMonitorDailyRollupMutation(c.config, OpUpdateOne, withChannelMonitorDailyRollup(_m)) + return &ChannelMonitorDailyRollupUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOneID returns an update builder for the given id. +func (c *ChannelMonitorDailyRollupClient) UpdateOneID(id int64) *ChannelMonitorDailyRollupUpdateOne { + mutation := newChannelMonitorDailyRollupMutation(c.config, OpUpdateOne, withChannelMonitorDailyRollupID(id)) + return &ChannelMonitorDailyRollupUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// Delete returns a delete builder for ChannelMonitorDailyRollup. +func (c *ChannelMonitorDailyRollupClient) Delete() *ChannelMonitorDailyRollupDelete { + mutation := newChannelMonitorDailyRollupMutation(c.config, OpDelete) + return &ChannelMonitorDailyRollupDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// DeleteOne returns a builder for deleting the given entity. +func (c *ChannelMonitorDailyRollupClient) DeleteOne(_m *ChannelMonitorDailyRollup) *ChannelMonitorDailyRollupDeleteOne { + return c.DeleteOneID(_m.ID) +} + +// DeleteOneID returns a builder for deleting the given entity by its id. +func (c *ChannelMonitorDailyRollupClient) DeleteOneID(id int64) *ChannelMonitorDailyRollupDeleteOne { + builder := c.Delete().Where(channelmonitordailyrollup.ID(id)) + builder.mutation.id = &id + builder.mutation.op = OpDeleteOne + return &ChannelMonitorDailyRollupDeleteOne{builder} +} + +// Query returns a query builder for ChannelMonitorDailyRollup. +func (c *ChannelMonitorDailyRollupClient) Query() *ChannelMonitorDailyRollupQuery { + return &ChannelMonitorDailyRollupQuery{ + config: c.config, + ctx: &QueryContext{Type: TypeChannelMonitorDailyRollup}, + inters: c.Interceptors(), + } +} + +// Get returns a ChannelMonitorDailyRollup entity by its id. +func (c *ChannelMonitorDailyRollupClient) Get(ctx context.Context, id int64) (*ChannelMonitorDailyRollup, error) { + return c.Query().Where(channelmonitordailyrollup.ID(id)).Only(ctx) +} + +// GetX is like Get, but panics if an error occurs. +func (c *ChannelMonitorDailyRollupClient) GetX(ctx context.Context, id int64) *ChannelMonitorDailyRollup { + obj, err := c.Get(ctx, id) + if err != nil { + panic(err) + } + return obj +} + +// QueryMonitor queries the monitor edge of a ChannelMonitorDailyRollup. +func (c *ChannelMonitorDailyRollupClient) QueryMonitor(_m *ChannelMonitorDailyRollup) *ChannelMonitorQuery { + query := (&ChannelMonitorClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := _m.ID + step := sqlgraph.NewStep( + sqlgraph.From(channelmonitordailyrollup.Table, channelmonitordailyrollup.FieldID, id), + sqlgraph.To(channelmonitor.Table, channelmonitor.FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, channelmonitordailyrollup.MonitorTable, channelmonitordailyrollup.MonitorColumn), + ) + fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step) + return fromV, nil + } + return query +} + +// Hooks returns the client hooks. +func (c *ChannelMonitorDailyRollupClient) Hooks() []Hook { + return c.hooks.ChannelMonitorDailyRollup +} + +// Interceptors returns the client interceptors. +func (c *ChannelMonitorDailyRollupClient) Interceptors() []Interceptor { + return c.inters.ChannelMonitorDailyRollup +} + +func (c *ChannelMonitorDailyRollupClient) mutate(ctx context.Context, m *ChannelMonitorDailyRollupMutation) (Value, error) { + switch m.Op() { + case OpCreate: + return (&ChannelMonitorDailyRollupCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdate: + return (&ChannelMonitorDailyRollupUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdateOne: + return (&ChannelMonitorDailyRollupUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpDelete, OpDeleteOne: + return (&ChannelMonitorDailyRollupDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx) + default: + return nil, fmt.Errorf("ent: unknown ChannelMonitorDailyRollup mutation op: %q", m.Op()) + } +} + +// ChannelMonitorHistoryClient is a client for the ChannelMonitorHistory schema. +type ChannelMonitorHistoryClient struct { + config +} + +// NewChannelMonitorHistoryClient returns a client for the ChannelMonitorHistory from the given config. +func NewChannelMonitorHistoryClient(c config) *ChannelMonitorHistoryClient { + return &ChannelMonitorHistoryClient{config: c} +} + +// Use adds a list of mutation hooks to the hooks stack. +// A call to `Use(f, g, h)` equals to `channelmonitorhistory.Hooks(f(g(h())))`. +func (c *ChannelMonitorHistoryClient) Use(hooks ...Hook) { + c.hooks.ChannelMonitorHistory = append(c.hooks.ChannelMonitorHistory, hooks...) +} + +// Intercept adds a list of query interceptors to the interceptors stack. +// A call to `Intercept(f, g, h)` equals to `channelmonitorhistory.Intercept(f(g(h())))`. +func (c *ChannelMonitorHistoryClient) Intercept(interceptors ...Interceptor) { + c.inters.ChannelMonitorHistory = append(c.inters.ChannelMonitorHistory, interceptors...) +} + +// Create returns a builder for creating a ChannelMonitorHistory entity. +func (c *ChannelMonitorHistoryClient) Create() *ChannelMonitorHistoryCreate { + mutation := newChannelMonitorHistoryMutation(c.config, OpCreate) + return &ChannelMonitorHistoryCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// CreateBulk returns a builder for creating a bulk of ChannelMonitorHistory entities. +func (c *ChannelMonitorHistoryClient) CreateBulk(builders ...*ChannelMonitorHistoryCreate) *ChannelMonitorHistoryCreateBulk { + return &ChannelMonitorHistoryCreateBulk{config: c.config, builders: builders} +} + +// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates +// a builder and applies setFunc on it. +func (c *ChannelMonitorHistoryClient) MapCreateBulk(slice any, setFunc func(*ChannelMonitorHistoryCreate, int)) *ChannelMonitorHistoryCreateBulk { + rv := reflect.ValueOf(slice) + if rv.Kind() != reflect.Slice { + return &ChannelMonitorHistoryCreateBulk{err: fmt.Errorf("calling to ChannelMonitorHistoryClient.MapCreateBulk with wrong type %T, need slice", slice)} + } + builders := make([]*ChannelMonitorHistoryCreate, rv.Len()) + for i := 0; i < rv.Len(); i++ { + builders[i] = c.Create() + setFunc(builders[i], i) + } + return &ChannelMonitorHistoryCreateBulk{config: c.config, builders: builders} +} + +// Update returns an update builder for ChannelMonitorHistory. +func (c *ChannelMonitorHistoryClient) Update() *ChannelMonitorHistoryUpdate { + mutation := newChannelMonitorHistoryMutation(c.config, OpUpdate) + return &ChannelMonitorHistoryUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOne returns an update builder for the given entity. +func (c *ChannelMonitorHistoryClient) UpdateOne(_m *ChannelMonitorHistory) *ChannelMonitorHistoryUpdateOne { + mutation := newChannelMonitorHistoryMutation(c.config, OpUpdateOne, withChannelMonitorHistory(_m)) + return &ChannelMonitorHistoryUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOneID returns an update builder for the given id. +func (c *ChannelMonitorHistoryClient) UpdateOneID(id int64) *ChannelMonitorHistoryUpdateOne { + mutation := newChannelMonitorHistoryMutation(c.config, OpUpdateOne, withChannelMonitorHistoryID(id)) + return &ChannelMonitorHistoryUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// Delete returns a delete builder for ChannelMonitorHistory. +func (c *ChannelMonitorHistoryClient) Delete() *ChannelMonitorHistoryDelete { + mutation := newChannelMonitorHistoryMutation(c.config, OpDelete) + return &ChannelMonitorHistoryDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// DeleteOne returns a builder for deleting the given entity. +func (c *ChannelMonitorHistoryClient) DeleteOne(_m *ChannelMonitorHistory) *ChannelMonitorHistoryDeleteOne { + return c.DeleteOneID(_m.ID) +} + +// DeleteOneID returns a builder for deleting the given entity by its id. +func (c *ChannelMonitorHistoryClient) DeleteOneID(id int64) *ChannelMonitorHistoryDeleteOne { + builder := c.Delete().Where(channelmonitorhistory.ID(id)) + builder.mutation.id = &id + builder.mutation.op = OpDeleteOne + return &ChannelMonitorHistoryDeleteOne{builder} +} + +// Query returns a query builder for ChannelMonitorHistory. +func (c *ChannelMonitorHistoryClient) Query() *ChannelMonitorHistoryQuery { + return &ChannelMonitorHistoryQuery{ + config: c.config, + ctx: &QueryContext{Type: TypeChannelMonitorHistory}, + inters: c.Interceptors(), + } +} + +// Get returns a ChannelMonitorHistory entity by its id. +func (c *ChannelMonitorHistoryClient) Get(ctx context.Context, id int64) (*ChannelMonitorHistory, error) { + return c.Query().Where(channelmonitorhistory.ID(id)).Only(ctx) +} + +// GetX is like Get, but panics if an error occurs. +func (c *ChannelMonitorHistoryClient) GetX(ctx context.Context, id int64) *ChannelMonitorHistory { + obj, err := c.Get(ctx, id) + if err != nil { + panic(err) + } + return obj +} + +// QueryMonitor queries the monitor edge of a ChannelMonitorHistory. +func (c *ChannelMonitorHistoryClient) QueryMonitor(_m *ChannelMonitorHistory) *ChannelMonitorQuery { + query := (&ChannelMonitorClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := _m.ID + step := sqlgraph.NewStep( + sqlgraph.From(channelmonitorhistory.Table, channelmonitorhistory.FieldID, id), + sqlgraph.To(channelmonitor.Table, channelmonitor.FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, channelmonitorhistory.MonitorTable, channelmonitorhistory.MonitorColumn), + ) + fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step) + return fromV, nil + } + return query +} + +// Hooks returns the client hooks. +func (c *ChannelMonitorHistoryClient) Hooks() []Hook { + return c.hooks.ChannelMonitorHistory +} + +// Interceptors returns the client interceptors. +func (c *ChannelMonitorHistoryClient) Interceptors() []Interceptor { + return c.inters.ChannelMonitorHistory +} + +func (c *ChannelMonitorHistoryClient) mutate(ctx context.Context, m *ChannelMonitorHistoryMutation) (Value, error) { + switch m.Op() { + case OpCreate: + return (&ChannelMonitorHistoryCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdate: + return (&ChannelMonitorHistoryUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdateOne: + return (&ChannelMonitorHistoryUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpDelete, OpDeleteOne: + return (&ChannelMonitorHistoryDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx) + default: + return nil, fmt.Errorf("ent: unknown ChannelMonitorHistory mutation op: %q", m.Op()) + } +} + +// ChannelMonitorRequestTemplateClient is a client for the ChannelMonitorRequestTemplate schema. +type ChannelMonitorRequestTemplateClient struct { + config +} + +// NewChannelMonitorRequestTemplateClient returns a client for the ChannelMonitorRequestTemplate from the given config. +func NewChannelMonitorRequestTemplateClient(c config) *ChannelMonitorRequestTemplateClient { + return &ChannelMonitorRequestTemplateClient{config: c} +} + +// Use adds a list of mutation hooks to the hooks stack. +// A call to `Use(f, g, h)` equals to `channelmonitorrequesttemplate.Hooks(f(g(h())))`. +func (c *ChannelMonitorRequestTemplateClient) Use(hooks ...Hook) { + c.hooks.ChannelMonitorRequestTemplate = append(c.hooks.ChannelMonitorRequestTemplate, hooks...) +} + +// Intercept adds a list of query interceptors to the interceptors stack. +// A call to `Intercept(f, g, h)` equals to `channelmonitorrequesttemplate.Intercept(f(g(h())))`. +func (c *ChannelMonitorRequestTemplateClient) Intercept(interceptors ...Interceptor) { + c.inters.ChannelMonitorRequestTemplate = append(c.inters.ChannelMonitorRequestTemplate, interceptors...) +} + +// Create returns a builder for creating a ChannelMonitorRequestTemplate entity. +func (c *ChannelMonitorRequestTemplateClient) Create() *ChannelMonitorRequestTemplateCreate { + mutation := newChannelMonitorRequestTemplateMutation(c.config, OpCreate) + return &ChannelMonitorRequestTemplateCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// CreateBulk returns a builder for creating a bulk of ChannelMonitorRequestTemplate entities. +func (c *ChannelMonitorRequestTemplateClient) CreateBulk(builders ...*ChannelMonitorRequestTemplateCreate) *ChannelMonitorRequestTemplateCreateBulk { + return &ChannelMonitorRequestTemplateCreateBulk{config: c.config, builders: builders} +} + +// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates +// a builder and applies setFunc on it. +func (c *ChannelMonitorRequestTemplateClient) MapCreateBulk(slice any, setFunc func(*ChannelMonitorRequestTemplateCreate, int)) *ChannelMonitorRequestTemplateCreateBulk { + rv := reflect.ValueOf(slice) + if rv.Kind() != reflect.Slice { + return &ChannelMonitorRequestTemplateCreateBulk{err: fmt.Errorf("calling to ChannelMonitorRequestTemplateClient.MapCreateBulk with wrong type %T, need slice", slice)} + } + builders := make([]*ChannelMonitorRequestTemplateCreate, rv.Len()) + for i := 0; i < rv.Len(); i++ { + builders[i] = c.Create() + setFunc(builders[i], i) + } + return &ChannelMonitorRequestTemplateCreateBulk{config: c.config, builders: builders} +} + +// Update returns an update builder for ChannelMonitorRequestTemplate. +func (c *ChannelMonitorRequestTemplateClient) Update() *ChannelMonitorRequestTemplateUpdate { + mutation := newChannelMonitorRequestTemplateMutation(c.config, OpUpdate) + return &ChannelMonitorRequestTemplateUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOne returns an update builder for the given entity. +func (c *ChannelMonitorRequestTemplateClient) UpdateOne(_m *ChannelMonitorRequestTemplate) *ChannelMonitorRequestTemplateUpdateOne { + mutation := newChannelMonitorRequestTemplateMutation(c.config, OpUpdateOne, withChannelMonitorRequestTemplate(_m)) + return &ChannelMonitorRequestTemplateUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOneID returns an update builder for the given id. +func (c *ChannelMonitorRequestTemplateClient) UpdateOneID(id int64) *ChannelMonitorRequestTemplateUpdateOne { + mutation := newChannelMonitorRequestTemplateMutation(c.config, OpUpdateOne, withChannelMonitorRequestTemplateID(id)) + return &ChannelMonitorRequestTemplateUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// Delete returns a delete builder for ChannelMonitorRequestTemplate. +func (c *ChannelMonitorRequestTemplateClient) Delete() *ChannelMonitorRequestTemplateDelete { + mutation := newChannelMonitorRequestTemplateMutation(c.config, OpDelete) + return &ChannelMonitorRequestTemplateDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// DeleteOne returns a builder for deleting the given entity. +func (c *ChannelMonitorRequestTemplateClient) DeleteOne(_m *ChannelMonitorRequestTemplate) *ChannelMonitorRequestTemplateDeleteOne { + return c.DeleteOneID(_m.ID) +} + +// DeleteOneID returns a builder for deleting the given entity by its id. +func (c *ChannelMonitorRequestTemplateClient) DeleteOneID(id int64) *ChannelMonitorRequestTemplateDeleteOne { + builder := c.Delete().Where(channelmonitorrequesttemplate.ID(id)) + builder.mutation.id = &id + builder.mutation.op = OpDeleteOne + return &ChannelMonitorRequestTemplateDeleteOne{builder} +} + +// Query returns a query builder for ChannelMonitorRequestTemplate. +func (c *ChannelMonitorRequestTemplateClient) Query() *ChannelMonitorRequestTemplateQuery { + return &ChannelMonitorRequestTemplateQuery{ + config: c.config, + ctx: &QueryContext{Type: TypeChannelMonitorRequestTemplate}, + inters: c.Interceptors(), + } +} + +// Get returns a ChannelMonitorRequestTemplate entity by its id. +func (c *ChannelMonitorRequestTemplateClient) Get(ctx context.Context, id int64) (*ChannelMonitorRequestTemplate, error) { + return c.Query().Where(channelmonitorrequesttemplate.ID(id)).Only(ctx) +} + +// GetX is like Get, but panics if an error occurs. +func (c *ChannelMonitorRequestTemplateClient) GetX(ctx context.Context, id int64) *ChannelMonitorRequestTemplate { + obj, err := c.Get(ctx, id) + if err != nil { + panic(err) + } + return obj +} + +// QueryMonitors queries the monitors edge of a ChannelMonitorRequestTemplate. +func (c *ChannelMonitorRequestTemplateClient) QueryMonitors(_m *ChannelMonitorRequestTemplate) *ChannelMonitorQuery { + query := (&ChannelMonitorClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := _m.ID + step := sqlgraph.NewStep( + sqlgraph.From(channelmonitorrequesttemplate.Table, channelmonitorrequesttemplate.FieldID, id), + sqlgraph.To(channelmonitor.Table, channelmonitor.FieldID), + sqlgraph.Edge(sqlgraph.O2M, true, channelmonitorrequesttemplate.MonitorsTable, channelmonitorrequesttemplate.MonitorsColumn), + ) + fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step) + return fromV, nil + } + return query +} + +// Hooks returns the client hooks. +func (c *ChannelMonitorRequestTemplateClient) Hooks() []Hook { + return c.hooks.ChannelMonitorRequestTemplate +} + +// Interceptors returns the client interceptors. +func (c *ChannelMonitorRequestTemplateClient) Interceptors() []Interceptor { + return c.inters.ChannelMonitorRequestTemplate +} + +func (c *ChannelMonitorRequestTemplateClient) mutate(ctx context.Context, m *ChannelMonitorRequestTemplateMutation) (Value, error) { + switch m.Op() { + case OpCreate: + return (&ChannelMonitorRequestTemplateCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdate: + return (&ChannelMonitorRequestTemplateUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdateOne: + return (&ChannelMonitorRequestTemplateUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpDelete, OpDeleteOne: + return (&ChannelMonitorRequestTemplateDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx) + default: + return nil, fmt.Errorf("ent: unknown ChannelMonitorRequestTemplate mutation op: %q", m.Op()) + } +} + // ErrorPassthroughRuleClient is a client for the ErrorPassthroughRule schema. type ErrorPassthroughRuleClient struct { config @@ -5355,21 +6019,23 @@ func (c *UserSubscriptionClient) mutate(ctx context.Context, m *UserSubscription type ( hooks struct { APIKey, Account, AccountGroup, Announcement, AnnouncementRead, AuthIdentity, - AuthIdentityChannel, ErrorPassthroughRule, Group, IdempotencyRecord, - IdentityAdoptionDecision, PaymentAuditLog, PaymentOrder, - PaymentProviderInstance, PendingAuthSession, PromoCode, PromoCodeUsage, Proxy, - RedeemCode, SecuritySecret, Setting, SubscriptionPlan, TLSFingerprintProfile, - UsageCleanupTask, UsageLog, User, UserAllowedGroup, UserAttributeDefinition, - UserAttributeValue, UserSubscription []ent.Hook + AuthIdentityChannel, ChannelMonitor, ChannelMonitorDailyRollup, + ChannelMonitorHistory, ChannelMonitorRequestTemplate, ErrorPassthroughRule, + Group, IdempotencyRecord, IdentityAdoptionDecision, PaymentAuditLog, + PaymentOrder, PaymentProviderInstance, PendingAuthSession, PromoCode, + PromoCodeUsage, Proxy, RedeemCode, SecuritySecret, Setting, SubscriptionPlan, + TLSFingerprintProfile, UsageCleanupTask, UsageLog, User, UserAllowedGroup, + UserAttributeDefinition, UserAttributeValue, UserSubscription []ent.Hook } inters struct { APIKey, Account, AccountGroup, Announcement, AnnouncementRead, AuthIdentity, - AuthIdentityChannel, ErrorPassthroughRule, Group, IdempotencyRecord, - IdentityAdoptionDecision, PaymentAuditLog, PaymentOrder, - PaymentProviderInstance, PendingAuthSession, PromoCode, PromoCodeUsage, Proxy, - RedeemCode, SecuritySecret, Setting, SubscriptionPlan, TLSFingerprintProfile, - UsageCleanupTask, UsageLog, User, UserAllowedGroup, UserAttributeDefinition, - UserAttributeValue, UserSubscription []ent.Interceptor + AuthIdentityChannel, ChannelMonitor, ChannelMonitorDailyRollup, + ChannelMonitorHistory, ChannelMonitorRequestTemplate, ErrorPassthroughRule, + Group, IdempotencyRecord, IdentityAdoptionDecision, PaymentAuditLog, + PaymentOrder, PaymentProviderInstance, PendingAuthSession, PromoCode, + PromoCodeUsage, Proxy, RedeemCode, SecuritySecret, Setting, SubscriptionPlan, + TLSFingerprintProfile, UsageCleanupTask, UsageLog, User, UserAllowedGroup, + UserAttributeDefinition, UserAttributeValue, UserSubscription []ent.Interceptor } ) diff --git a/backend/ent/ent.go b/backend/ent/ent.go index 339e5369..c9fcc314 100644 --- a/backend/ent/ent.go +++ b/backend/ent/ent.go @@ -19,6 +19,10 @@ import ( "github.com/Wei-Shaw/sub2api/ent/apikey" "github.com/Wei-Shaw/sub2api/ent/authidentity" "github.com/Wei-Shaw/sub2api/ent/authidentitychannel" + "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitordailyrollup" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" "github.com/Wei-Shaw/sub2api/ent/errorpassthroughrule" "github.com/Wei-Shaw/sub2api/ent/group" "github.com/Wei-Shaw/sub2api/ent/idempotencyrecord" @@ -102,36 +106,40 @@ var ( func checkColumn(t, c string) error { initCheck.Do(func() { columnCheck = sql.NewColumnCheck(map[string]func(string) bool{ - apikey.Table: apikey.ValidColumn, - account.Table: account.ValidColumn, - accountgroup.Table: accountgroup.ValidColumn, - announcement.Table: announcement.ValidColumn, - announcementread.Table: announcementread.ValidColumn, - authidentity.Table: authidentity.ValidColumn, - authidentitychannel.Table: authidentitychannel.ValidColumn, - errorpassthroughrule.Table: errorpassthroughrule.ValidColumn, - group.Table: group.ValidColumn, - idempotencyrecord.Table: idempotencyrecord.ValidColumn, - identityadoptiondecision.Table: identityadoptiondecision.ValidColumn, - paymentauditlog.Table: paymentauditlog.ValidColumn, - paymentorder.Table: paymentorder.ValidColumn, - paymentproviderinstance.Table: paymentproviderinstance.ValidColumn, - pendingauthsession.Table: pendingauthsession.ValidColumn, - promocode.Table: promocode.ValidColumn, - promocodeusage.Table: promocodeusage.ValidColumn, - proxy.Table: proxy.ValidColumn, - redeemcode.Table: redeemcode.ValidColumn, - securitysecret.Table: securitysecret.ValidColumn, - setting.Table: setting.ValidColumn, - subscriptionplan.Table: subscriptionplan.ValidColumn, - tlsfingerprintprofile.Table: tlsfingerprintprofile.ValidColumn, - usagecleanuptask.Table: usagecleanuptask.ValidColumn, - usagelog.Table: usagelog.ValidColumn, - user.Table: user.ValidColumn, - userallowedgroup.Table: userallowedgroup.ValidColumn, - userattributedefinition.Table: userattributedefinition.ValidColumn, - userattributevalue.Table: userattributevalue.ValidColumn, - usersubscription.Table: usersubscription.ValidColumn, + apikey.Table: apikey.ValidColumn, + account.Table: account.ValidColumn, + accountgroup.Table: accountgroup.ValidColumn, + announcement.Table: announcement.ValidColumn, + announcementread.Table: announcementread.ValidColumn, + authidentity.Table: authidentity.ValidColumn, + authidentitychannel.Table: authidentitychannel.ValidColumn, + channelmonitor.Table: channelmonitor.ValidColumn, + channelmonitordailyrollup.Table: channelmonitordailyrollup.ValidColumn, + channelmonitorhistory.Table: channelmonitorhistory.ValidColumn, + channelmonitorrequesttemplate.Table: channelmonitorrequesttemplate.ValidColumn, + errorpassthroughrule.Table: errorpassthroughrule.ValidColumn, + group.Table: group.ValidColumn, + idempotencyrecord.Table: idempotencyrecord.ValidColumn, + identityadoptiondecision.Table: identityadoptiondecision.ValidColumn, + paymentauditlog.Table: paymentauditlog.ValidColumn, + paymentorder.Table: paymentorder.ValidColumn, + paymentproviderinstance.Table: paymentproviderinstance.ValidColumn, + pendingauthsession.Table: pendingauthsession.ValidColumn, + promocode.Table: promocode.ValidColumn, + promocodeusage.Table: promocodeusage.ValidColumn, + proxy.Table: proxy.ValidColumn, + redeemcode.Table: redeemcode.ValidColumn, + securitysecret.Table: securitysecret.ValidColumn, + setting.Table: setting.ValidColumn, + subscriptionplan.Table: subscriptionplan.ValidColumn, + tlsfingerprintprofile.Table: tlsfingerprintprofile.ValidColumn, + usagecleanuptask.Table: usagecleanuptask.ValidColumn, + usagelog.Table: usagelog.ValidColumn, + user.Table: user.ValidColumn, + userallowedgroup.Table: userallowedgroup.ValidColumn, + userattributedefinition.Table: userattributedefinition.ValidColumn, + userattributevalue.Table: userattributevalue.ValidColumn, + usersubscription.Table: usersubscription.ValidColumn, }) }) return columnCheck(t, c) diff --git a/backend/ent/hook/hook.go b/backend/ent/hook/hook.go index 46ac02bc..414eba24 100644 --- a/backend/ent/hook/hook.go +++ b/backend/ent/hook/hook.go @@ -93,6 +93,54 @@ func (f AuthIdentityChannelFunc) Mutate(ctx context.Context, m ent.Mutation) (en return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.AuthIdentityChannelMutation", m) } +// The ChannelMonitorFunc type is an adapter to allow the use of ordinary +// function as ChannelMonitor mutator. +type ChannelMonitorFunc func(context.Context, *ent.ChannelMonitorMutation) (ent.Value, error) + +// Mutate calls f(ctx, m). +func (f ChannelMonitorFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { + if mv, ok := m.(*ent.ChannelMonitorMutation); ok { + return f(ctx, mv) + } + return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.ChannelMonitorMutation", m) +} + +// The ChannelMonitorDailyRollupFunc type is an adapter to allow the use of ordinary +// function as ChannelMonitorDailyRollup mutator. +type ChannelMonitorDailyRollupFunc func(context.Context, *ent.ChannelMonitorDailyRollupMutation) (ent.Value, error) + +// Mutate calls f(ctx, m). +func (f ChannelMonitorDailyRollupFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { + if mv, ok := m.(*ent.ChannelMonitorDailyRollupMutation); ok { + return f(ctx, mv) + } + return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.ChannelMonitorDailyRollupMutation", m) +} + +// The ChannelMonitorHistoryFunc type is an adapter to allow the use of ordinary +// function as ChannelMonitorHistory mutator. +type ChannelMonitorHistoryFunc func(context.Context, *ent.ChannelMonitorHistoryMutation) (ent.Value, error) + +// Mutate calls f(ctx, m). +func (f ChannelMonitorHistoryFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { + if mv, ok := m.(*ent.ChannelMonitorHistoryMutation); ok { + return f(ctx, mv) + } + return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.ChannelMonitorHistoryMutation", m) +} + +// The ChannelMonitorRequestTemplateFunc type is an adapter to allow the use of ordinary +// function as ChannelMonitorRequestTemplate mutator. +type ChannelMonitorRequestTemplateFunc func(context.Context, *ent.ChannelMonitorRequestTemplateMutation) (ent.Value, error) + +// Mutate calls f(ctx, m). +func (f ChannelMonitorRequestTemplateFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { + if mv, ok := m.(*ent.ChannelMonitorRequestTemplateMutation); ok { + return f(ctx, mv) + } + return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.ChannelMonitorRequestTemplateMutation", m) +} + // The ErrorPassthroughRuleFunc type is an adapter to allow the use of ordinary // function as ErrorPassthroughRule mutator. type ErrorPassthroughRuleFunc func(context.Context, *ent.ErrorPassthroughRuleMutation) (ent.Value, error) diff --git a/backend/ent/intercept/intercept.go b/backend/ent/intercept/intercept.go index 157c5122..95b68e09 100644 --- a/backend/ent/intercept/intercept.go +++ b/backend/ent/intercept/intercept.go @@ -15,6 +15,10 @@ import ( "github.com/Wei-Shaw/sub2api/ent/apikey" "github.com/Wei-Shaw/sub2api/ent/authidentity" "github.com/Wei-Shaw/sub2api/ent/authidentitychannel" + "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitordailyrollup" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" "github.com/Wei-Shaw/sub2api/ent/errorpassthroughrule" "github.com/Wei-Shaw/sub2api/ent/group" "github.com/Wei-Shaw/sub2api/ent/idempotencyrecord" @@ -286,6 +290,114 @@ func (f TraverseAuthIdentityChannel) Traverse(ctx context.Context, q ent.Query) return fmt.Errorf("unexpected query type %T. expect *ent.AuthIdentityChannelQuery", q) } +// The ChannelMonitorFunc type is an adapter to allow the use of ordinary function as a Querier. +type ChannelMonitorFunc func(context.Context, *ent.ChannelMonitorQuery) (ent.Value, error) + +// Query calls f(ctx, q). +func (f ChannelMonitorFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) { + if q, ok := q.(*ent.ChannelMonitorQuery); ok { + return f(ctx, q) + } + return nil, fmt.Errorf("unexpected query type %T. expect *ent.ChannelMonitorQuery", q) +} + +// The TraverseChannelMonitor type is an adapter to allow the use of ordinary function as Traverser. +type TraverseChannelMonitor func(context.Context, *ent.ChannelMonitorQuery) error + +// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline. +func (f TraverseChannelMonitor) Intercept(next ent.Querier) ent.Querier { + return next +} + +// Traverse calls f(ctx, q). +func (f TraverseChannelMonitor) Traverse(ctx context.Context, q ent.Query) error { + if q, ok := q.(*ent.ChannelMonitorQuery); ok { + return f(ctx, q) + } + return fmt.Errorf("unexpected query type %T. expect *ent.ChannelMonitorQuery", q) +} + +// The ChannelMonitorDailyRollupFunc type is an adapter to allow the use of ordinary function as a Querier. +type ChannelMonitorDailyRollupFunc func(context.Context, *ent.ChannelMonitorDailyRollupQuery) (ent.Value, error) + +// Query calls f(ctx, q). +func (f ChannelMonitorDailyRollupFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) { + if q, ok := q.(*ent.ChannelMonitorDailyRollupQuery); ok { + return f(ctx, q) + } + return nil, fmt.Errorf("unexpected query type %T. expect *ent.ChannelMonitorDailyRollupQuery", q) +} + +// The TraverseChannelMonitorDailyRollup type is an adapter to allow the use of ordinary function as Traverser. +type TraverseChannelMonitorDailyRollup func(context.Context, *ent.ChannelMonitorDailyRollupQuery) error + +// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline. +func (f TraverseChannelMonitorDailyRollup) Intercept(next ent.Querier) ent.Querier { + return next +} + +// Traverse calls f(ctx, q). +func (f TraverseChannelMonitorDailyRollup) Traverse(ctx context.Context, q ent.Query) error { + if q, ok := q.(*ent.ChannelMonitorDailyRollupQuery); ok { + return f(ctx, q) + } + return fmt.Errorf("unexpected query type %T. expect *ent.ChannelMonitorDailyRollupQuery", q) +} + +// The ChannelMonitorHistoryFunc type is an adapter to allow the use of ordinary function as a Querier. +type ChannelMonitorHistoryFunc func(context.Context, *ent.ChannelMonitorHistoryQuery) (ent.Value, error) + +// Query calls f(ctx, q). +func (f ChannelMonitorHistoryFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) { + if q, ok := q.(*ent.ChannelMonitorHistoryQuery); ok { + return f(ctx, q) + } + return nil, fmt.Errorf("unexpected query type %T. expect *ent.ChannelMonitorHistoryQuery", q) +} + +// The TraverseChannelMonitorHistory type is an adapter to allow the use of ordinary function as Traverser. +type TraverseChannelMonitorHistory func(context.Context, *ent.ChannelMonitorHistoryQuery) error + +// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline. +func (f TraverseChannelMonitorHistory) Intercept(next ent.Querier) ent.Querier { + return next +} + +// Traverse calls f(ctx, q). +func (f TraverseChannelMonitorHistory) Traverse(ctx context.Context, q ent.Query) error { + if q, ok := q.(*ent.ChannelMonitorHistoryQuery); ok { + return f(ctx, q) + } + return fmt.Errorf("unexpected query type %T. expect *ent.ChannelMonitorHistoryQuery", q) +} + +// The ChannelMonitorRequestTemplateFunc type is an adapter to allow the use of ordinary function as a Querier. +type ChannelMonitorRequestTemplateFunc func(context.Context, *ent.ChannelMonitorRequestTemplateQuery) (ent.Value, error) + +// Query calls f(ctx, q). +func (f ChannelMonitorRequestTemplateFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) { + if q, ok := q.(*ent.ChannelMonitorRequestTemplateQuery); ok { + return f(ctx, q) + } + return nil, fmt.Errorf("unexpected query type %T. expect *ent.ChannelMonitorRequestTemplateQuery", q) +} + +// The TraverseChannelMonitorRequestTemplate type is an adapter to allow the use of ordinary function as Traverser. +type TraverseChannelMonitorRequestTemplate func(context.Context, *ent.ChannelMonitorRequestTemplateQuery) error + +// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline. +func (f TraverseChannelMonitorRequestTemplate) Intercept(next ent.Querier) ent.Querier { + return next +} + +// Traverse calls f(ctx, q). +func (f TraverseChannelMonitorRequestTemplate) Traverse(ctx context.Context, q ent.Query) error { + if q, ok := q.(*ent.ChannelMonitorRequestTemplateQuery); ok { + return f(ctx, q) + } + return fmt.Errorf("unexpected query type %T. expect *ent.ChannelMonitorRequestTemplateQuery", q) +} + // The ErrorPassthroughRuleFunc type is an adapter to allow the use of ordinary function as a Querier. type ErrorPassthroughRuleFunc func(context.Context, *ent.ErrorPassthroughRuleQuery) (ent.Value, error) @@ -924,6 +1036,14 @@ func NewQuery(q ent.Query) (Query, error) { return &query[*ent.AuthIdentityQuery, predicate.AuthIdentity, authidentity.OrderOption]{typ: ent.TypeAuthIdentity, tq: q}, nil case *ent.AuthIdentityChannelQuery: return &query[*ent.AuthIdentityChannelQuery, predicate.AuthIdentityChannel, authidentitychannel.OrderOption]{typ: ent.TypeAuthIdentityChannel, tq: q}, nil + case *ent.ChannelMonitorQuery: + return &query[*ent.ChannelMonitorQuery, predicate.ChannelMonitor, channelmonitor.OrderOption]{typ: ent.TypeChannelMonitor, tq: q}, nil + case *ent.ChannelMonitorDailyRollupQuery: + return &query[*ent.ChannelMonitorDailyRollupQuery, predicate.ChannelMonitorDailyRollup, channelmonitordailyrollup.OrderOption]{typ: ent.TypeChannelMonitorDailyRollup, tq: q}, nil + case *ent.ChannelMonitorHistoryQuery: + return &query[*ent.ChannelMonitorHistoryQuery, predicate.ChannelMonitorHistory, channelmonitorhistory.OrderOption]{typ: ent.TypeChannelMonitorHistory, tq: q}, nil + case *ent.ChannelMonitorRequestTemplateQuery: + return &query[*ent.ChannelMonitorRequestTemplateQuery, predicate.ChannelMonitorRequestTemplate, channelmonitorrequesttemplate.OrderOption]{typ: ent.TypeChannelMonitorRequestTemplate, tq: q}, nil case *ent.ErrorPassthroughRuleQuery: return &query[*ent.ErrorPassthroughRuleQuery, predicate.ErrorPassthroughRule, errorpassthroughrule.OrderOption]{typ: ent.TypeErrorPassthroughRule, tq: q}, nil case *ent.GroupQuery: diff --git a/backend/ent/migrate/schema.go b/backend/ent/migrate/schema.go index c3e43eed..178ae170 100644 --- a/backend/ent/migrate/schema.go +++ b/backend/ent/migrate/schema.go @@ -421,6 +421,169 @@ var ( }, }, } + // ChannelMonitorsColumns holds the columns for the "channel_monitors" table. + ChannelMonitorsColumns = []*schema.Column{ + {Name: "id", Type: field.TypeInt64, Increment: true}, + {Name: "created_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}}, + {Name: "updated_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}}, + {Name: "name", Type: field.TypeString, Size: 100}, + {Name: "provider", Type: field.TypeEnum, Enums: []string{"openai", "anthropic", "gemini"}}, + {Name: "endpoint", Type: field.TypeString, Size: 500}, + {Name: "api_key_encrypted", Type: field.TypeString}, + {Name: "primary_model", Type: field.TypeString, Size: 200}, + {Name: "extra_models", Type: field.TypeJSON}, + {Name: "group_name", Type: field.TypeString, Nullable: true, Size: 100, Default: ""}, + {Name: "enabled", Type: field.TypeBool, Default: true}, + {Name: "interval_seconds", Type: field.TypeInt}, + {Name: "last_checked_at", Type: field.TypeTime, Nullable: true}, + {Name: "created_by", Type: field.TypeInt64}, + {Name: "extra_headers", Type: field.TypeJSON}, + {Name: "body_override_mode", Type: field.TypeString, Size: 10, Default: "off"}, + {Name: "body_override", Type: field.TypeJSON, Nullable: true}, + {Name: "template_id", Type: field.TypeInt64, Nullable: true}, + } + // ChannelMonitorsTable holds the schema information for the "channel_monitors" table. + ChannelMonitorsTable = &schema.Table{ + Name: "channel_monitors", + Columns: ChannelMonitorsColumns, + PrimaryKey: []*schema.Column{ChannelMonitorsColumns[0]}, + ForeignKeys: []*schema.ForeignKey{ + { + Symbol: "channel_monitors_channel_monitor_request_templates_request_template", + Columns: []*schema.Column{ChannelMonitorsColumns[17]}, + RefColumns: []*schema.Column{ChannelMonitorRequestTemplatesColumns[0]}, + OnDelete: schema.SetNull, + }, + }, + Indexes: []*schema.Index{ + { + Name: "channelmonitor_enabled_last_checked_at", + Unique: false, + Columns: []*schema.Column{ChannelMonitorsColumns[10], ChannelMonitorsColumns[12]}, + }, + { + Name: "channelmonitor_provider", + Unique: false, + Columns: []*schema.Column{ChannelMonitorsColumns[4]}, + }, + { + Name: "channelmonitor_group_name", + Unique: false, + Columns: []*schema.Column{ChannelMonitorsColumns[9]}, + }, + { + Name: "channelmonitor_template_id", + Unique: false, + Columns: []*schema.Column{ChannelMonitorsColumns[17]}, + }, + }, + } + // ChannelMonitorDailyRollupsColumns holds the columns for the "channel_monitor_daily_rollups" table. + ChannelMonitorDailyRollupsColumns = []*schema.Column{ + {Name: "id", Type: field.TypeInt64, Increment: true}, + {Name: "model", Type: field.TypeString, Size: 200}, + {Name: "bucket_date", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "date"}}, + {Name: "total_checks", Type: field.TypeInt, Default: 0}, + {Name: "ok_count", Type: field.TypeInt, Default: 0}, + {Name: "operational_count", Type: field.TypeInt, Default: 0}, + {Name: "degraded_count", Type: field.TypeInt, Default: 0}, + {Name: "failed_count", Type: field.TypeInt, Default: 0}, + {Name: "error_count", Type: field.TypeInt, Default: 0}, + {Name: "sum_latency_ms", Type: field.TypeInt64, Default: 0}, + {Name: "count_latency", Type: field.TypeInt, Default: 0}, + {Name: "sum_ping_latency_ms", Type: field.TypeInt64, Default: 0}, + {Name: "count_ping_latency", Type: field.TypeInt, Default: 0}, + {Name: "computed_at", Type: field.TypeTime}, + {Name: "monitor_id", Type: field.TypeInt64}, + } + // ChannelMonitorDailyRollupsTable holds the schema information for the "channel_monitor_daily_rollups" table. + ChannelMonitorDailyRollupsTable = &schema.Table{ + Name: "channel_monitor_daily_rollups", + Columns: ChannelMonitorDailyRollupsColumns, + PrimaryKey: []*schema.Column{ChannelMonitorDailyRollupsColumns[0]}, + ForeignKeys: []*schema.ForeignKey{ + { + Symbol: "channel_monitor_daily_rollups_channel_monitors_daily_rollups", + Columns: []*schema.Column{ChannelMonitorDailyRollupsColumns[14]}, + RefColumns: []*schema.Column{ChannelMonitorsColumns[0]}, + OnDelete: schema.Cascade, + }, + }, + Indexes: []*schema.Index{ + { + Name: "channelmonitordailyrollup_monitor_id_model_bucket_date", + Unique: true, + Columns: []*schema.Column{ChannelMonitorDailyRollupsColumns[14], ChannelMonitorDailyRollupsColumns[1], ChannelMonitorDailyRollupsColumns[2]}, + }, + { + Name: "channelmonitordailyrollup_bucket_date", + Unique: false, + Columns: []*schema.Column{ChannelMonitorDailyRollupsColumns[2]}, + }, + }, + } + // ChannelMonitorHistoriesColumns holds the columns for the "channel_monitor_histories" table. + ChannelMonitorHistoriesColumns = []*schema.Column{ + {Name: "id", Type: field.TypeInt64, Increment: true}, + {Name: "model", Type: field.TypeString, Size: 200}, + {Name: "status", Type: field.TypeEnum, Enums: []string{"operational", "degraded", "failed", "error"}}, + {Name: "latency_ms", Type: field.TypeInt, Nullable: true}, + {Name: "ping_latency_ms", Type: field.TypeInt, Nullable: true}, + {Name: "message", Type: field.TypeString, Nullable: true, Size: 500, Default: ""}, + {Name: "checked_at", Type: field.TypeTime}, + {Name: "monitor_id", Type: field.TypeInt64}, + } + // ChannelMonitorHistoriesTable holds the schema information for the "channel_monitor_histories" table. + ChannelMonitorHistoriesTable = &schema.Table{ + Name: "channel_monitor_histories", + Columns: ChannelMonitorHistoriesColumns, + PrimaryKey: []*schema.Column{ChannelMonitorHistoriesColumns[0]}, + ForeignKeys: []*schema.ForeignKey{ + { + Symbol: "channel_monitor_histories_channel_monitors_history", + Columns: []*schema.Column{ChannelMonitorHistoriesColumns[7]}, + RefColumns: []*schema.Column{ChannelMonitorsColumns[0]}, + OnDelete: schema.Cascade, + }, + }, + Indexes: []*schema.Index{ + { + Name: "channelmonitorhistory_monitor_id_model_checked_at", + Unique: false, + Columns: []*schema.Column{ChannelMonitorHistoriesColumns[7], ChannelMonitorHistoriesColumns[1], ChannelMonitorHistoriesColumns[6]}, + }, + { + Name: "channelmonitorhistory_checked_at", + Unique: false, + Columns: []*schema.Column{ChannelMonitorHistoriesColumns[6]}, + }, + }, + } + // ChannelMonitorRequestTemplatesColumns holds the columns for the "channel_monitor_request_templates" table. + ChannelMonitorRequestTemplatesColumns = []*schema.Column{ + {Name: "id", Type: field.TypeInt64, Increment: true}, + {Name: "created_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}}, + {Name: "updated_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}}, + {Name: "name", Type: field.TypeString, Size: 100}, + {Name: "provider", Type: field.TypeEnum, Enums: []string{"openai", "anthropic", "gemini"}}, + {Name: "description", Type: field.TypeString, Nullable: true, Size: 500, Default: ""}, + {Name: "extra_headers", Type: field.TypeJSON}, + {Name: "body_override_mode", Type: field.TypeString, Size: 10, Default: "off"}, + {Name: "body_override", Type: field.TypeJSON, Nullable: true}, + } + // ChannelMonitorRequestTemplatesTable holds the schema information for the "channel_monitor_request_templates" table. + ChannelMonitorRequestTemplatesTable = &schema.Table{ + Name: "channel_monitor_request_templates", + Columns: ChannelMonitorRequestTemplatesColumns, + PrimaryKey: []*schema.Column{ChannelMonitorRequestTemplatesColumns[0]}, + Indexes: []*schema.Index{ + { + Name: "channelmonitorrequesttemplate_provider_name", + Unique: true, + Columns: []*schema.Column{ChannelMonitorRequestTemplatesColumns[4], ChannelMonitorRequestTemplatesColumns[3]}, + }, + }, + } // ErrorPassthroughRulesColumns holds the columns for the "error_passthrough_rules" table. ErrorPassthroughRulesColumns = []*schema.Column{ {Name: "id", Type: field.TypeInt64, Increment: true}, @@ -1522,6 +1685,10 @@ var ( AnnouncementReadsTable, AuthIdentitiesTable, AuthIdentityChannelsTable, + ChannelMonitorsTable, + ChannelMonitorDailyRollupsTable, + ChannelMonitorHistoriesTable, + ChannelMonitorRequestTemplatesTable, ErrorPassthroughRulesTable, GroupsTable, IdempotencyRecordsTable, @@ -1579,6 +1746,21 @@ func init() { AuthIdentityChannelsTable.Annotation = &entsql.Annotation{ Table: "auth_identity_channels", } + ChannelMonitorsTable.ForeignKeys[0].RefTable = ChannelMonitorRequestTemplatesTable + ChannelMonitorsTable.Annotation = &entsql.Annotation{ + Table: "channel_monitors", + } + ChannelMonitorDailyRollupsTable.ForeignKeys[0].RefTable = ChannelMonitorsTable + ChannelMonitorDailyRollupsTable.Annotation = &entsql.Annotation{ + Table: "channel_monitor_daily_rollups", + } + ChannelMonitorHistoriesTable.ForeignKeys[0].RefTable = ChannelMonitorsTable + ChannelMonitorHistoriesTable.Annotation = &entsql.Annotation{ + Table: "channel_monitor_histories", + } + ChannelMonitorRequestTemplatesTable.Annotation = &entsql.Annotation{ + Table: "channel_monitor_request_templates", + } ErrorPassthroughRulesTable.Annotation = &entsql.Annotation{ Table: "error_passthrough_rules", } diff --git a/backend/ent/mutation.go b/backend/ent/mutation.go index 80c845c3..d616e4ae 100644 --- a/backend/ent/mutation.go +++ b/backend/ent/mutation.go @@ -19,6 +19,10 @@ import ( "github.com/Wei-Shaw/sub2api/ent/apikey" "github.com/Wei-Shaw/sub2api/ent/authidentity" "github.com/Wei-Shaw/sub2api/ent/authidentitychannel" + "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitordailyrollup" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" "github.com/Wei-Shaw/sub2api/ent/errorpassthroughrule" "github.com/Wei-Shaw/sub2api/ent/group" "github.com/Wei-Shaw/sub2api/ent/idempotencyrecord" @@ -55,36 +59,40 @@ const ( OpUpdateOne = ent.OpUpdateOne // Node types. - TypeAPIKey = "APIKey" - TypeAccount = "Account" - TypeAccountGroup = "AccountGroup" - TypeAnnouncement = "Announcement" - TypeAnnouncementRead = "AnnouncementRead" - TypeAuthIdentity = "AuthIdentity" - TypeAuthIdentityChannel = "AuthIdentityChannel" - TypeErrorPassthroughRule = "ErrorPassthroughRule" - TypeGroup = "Group" - TypeIdempotencyRecord = "IdempotencyRecord" - TypeIdentityAdoptionDecision = "IdentityAdoptionDecision" - TypePaymentAuditLog = "PaymentAuditLog" - TypePaymentOrder = "PaymentOrder" - TypePaymentProviderInstance = "PaymentProviderInstance" - TypePendingAuthSession = "PendingAuthSession" - TypePromoCode = "PromoCode" - TypePromoCodeUsage = "PromoCodeUsage" - TypeProxy = "Proxy" - TypeRedeemCode = "RedeemCode" - TypeSecuritySecret = "SecuritySecret" - TypeSetting = "Setting" - TypeSubscriptionPlan = "SubscriptionPlan" - TypeTLSFingerprintProfile = "TLSFingerprintProfile" - TypeUsageCleanupTask = "UsageCleanupTask" - TypeUsageLog = "UsageLog" - TypeUser = "User" - TypeUserAllowedGroup = "UserAllowedGroup" - TypeUserAttributeDefinition = "UserAttributeDefinition" - TypeUserAttributeValue = "UserAttributeValue" - TypeUserSubscription = "UserSubscription" + TypeAPIKey = "APIKey" + TypeAccount = "Account" + TypeAccountGroup = "AccountGroup" + TypeAnnouncement = "Announcement" + TypeAnnouncementRead = "AnnouncementRead" + TypeAuthIdentity = "AuthIdentity" + TypeAuthIdentityChannel = "AuthIdentityChannel" + TypeChannelMonitor = "ChannelMonitor" + TypeChannelMonitorDailyRollup = "ChannelMonitorDailyRollup" + TypeChannelMonitorHistory = "ChannelMonitorHistory" + TypeChannelMonitorRequestTemplate = "ChannelMonitorRequestTemplate" + TypeErrorPassthroughRule = "ErrorPassthroughRule" + TypeGroup = "Group" + TypeIdempotencyRecord = "IdempotencyRecord" + TypeIdentityAdoptionDecision = "IdentityAdoptionDecision" + TypePaymentAuditLog = "PaymentAuditLog" + TypePaymentOrder = "PaymentOrder" + TypePaymentProviderInstance = "PaymentProviderInstance" + TypePendingAuthSession = "PendingAuthSession" + TypePromoCode = "PromoCode" + TypePromoCodeUsage = "PromoCodeUsage" + TypeProxy = "Proxy" + TypeRedeemCode = "RedeemCode" + TypeSecuritySecret = "SecuritySecret" + TypeSetting = "Setting" + TypeSubscriptionPlan = "SubscriptionPlan" + TypeTLSFingerprintProfile = "TLSFingerprintProfile" + TypeUsageCleanupTask = "UsageCleanupTask" + TypeUsageLog = "UsageLog" + TypeUser = "User" + TypeUserAllowedGroup = "UserAllowedGroup" + TypeUserAttributeDefinition = "UserAttributeDefinition" + TypeUserAttributeValue = "UserAttributeValue" + TypeUserSubscription = "UserSubscription" ) // APIKeyMutation represents an operation that mutates the APIKey nodes in the graph. @@ -8734,6 +8742,4683 @@ func (m *AuthIdentityChannelMutation) ResetEdge(name string) error { return fmt.Errorf("unknown AuthIdentityChannel edge %s", name) } +// ChannelMonitorMutation represents an operation that mutates the ChannelMonitor nodes in the graph. +type ChannelMonitorMutation struct { + config + op Op + typ string + id *int64 + created_at *time.Time + updated_at *time.Time + name *string + provider *channelmonitor.Provider + endpoint *string + api_key_encrypted *string + primary_model *string + extra_models *[]string + appendextra_models []string + group_name *string + enabled *bool + interval_seconds *int + addinterval_seconds *int + last_checked_at *time.Time + created_by *int64 + addcreated_by *int64 + extra_headers *map[string]string + body_override_mode *string + body_override *map[string]interface{} + clearedFields map[string]struct{} + history map[int64]struct{} + removedhistory map[int64]struct{} + clearedhistory bool + daily_rollups map[int64]struct{} + removeddaily_rollups map[int64]struct{} + cleareddaily_rollups bool + request_template *int64 + clearedrequest_template bool + done bool + oldValue func(context.Context) (*ChannelMonitor, error) + predicates []predicate.ChannelMonitor +} + +var _ ent.Mutation = (*ChannelMonitorMutation)(nil) + +// channelmonitorOption allows management of the mutation configuration using functional options. +type channelmonitorOption func(*ChannelMonitorMutation) + +// newChannelMonitorMutation creates new mutation for the ChannelMonitor entity. +func newChannelMonitorMutation(c config, op Op, opts ...channelmonitorOption) *ChannelMonitorMutation { + m := &ChannelMonitorMutation{ + config: c, + op: op, + typ: TypeChannelMonitor, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withChannelMonitorID sets the ID field of the mutation. +func withChannelMonitorID(id int64) channelmonitorOption { + return func(m *ChannelMonitorMutation) { + var ( + err error + once sync.Once + value *ChannelMonitor + ) + m.oldValue = func(ctx context.Context) (*ChannelMonitor, error) { + once.Do(func() { + if m.done { + err = errors.New("querying old values post mutation is not allowed") + } else { + value, err = m.Client().ChannelMonitor.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withChannelMonitor sets the old ChannelMonitor of the mutation. +func withChannelMonitor(node *ChannelMonitor) channelmonitorOption { + return func(m *ChannelMonitorMutation) { + m.oldValue = func(context.Context) (*ChannelMonitor, error) { + return node, nil + } + m.id = &node.ID + } +} + +// Client returns a new `ent.Client` from the mutation. If the mutation was +// executed in a transaction (ent.Tx), a transactional client is returned. +func (m ChannelMonitorMutation) Client() *Client { + client := &Client{config: m.config} + client.init() + return client +} + +// Tx returns an `ent.Tx` for mutations that were executed in transactions; +// it returns an error otherwise. +func (m ChannelMonitorMutation) Tx() (*Tx, error) { + if _, ok := m.driver.(*txDriver); !ok { + return nil, errors.New("ent: mutation is not running in a transaction") + } + tx := &Tx{config: m.config} + tx.init() + return tx, nil +} + +// ID returns the ID value in the mutation. Note that the ID is only available +// if it was provided to the builder or after it was returned from the database. +func (m *ChannelMonitorMutation) ID() (id int64, exists bool) { + if m.id == nil { + return + } + return *m.id, true +} + +// IDs queries the database and returns the entity ids that match the mutation's predicate. +// That means, if the mutation is applied within a transaction with an isolation level such +// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated +// or updated by the mutation. +func (m *ChannelMonitorMutation) IDs(ctx context.Context) ([]int64, error) { + switch { + case m.op.Is(OpUpdateOne | OpDeleteOne): + id, exists := m.ID() + if exists { + return []int64{id}, nil + } + fallthrough + case m.op.Is(OpUpdate | OpDelete): + return m.Client().ChannelMonitor.Query().Where(m.predicates...).IDs(ctx) + default: + return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op) + } +} + +// SetCreatedAt sets the "created_at" field. +func (m *ChannelMonitorMutation) SetCreatedAt(t time.Time) { + m.created_at = &t +} + +// CreatedAt returns the value of the "created_at" field in the mutation. +func (m *ChannelMonitorMutation) CreatedAt() (r time.Time, exists bool) { + v := m.created_at + if v == nil { + return + } + return *v, true +} + +// OldCreatedAt returns the old "created_at" field's value of the ChannelMonitor entity. +// If the ChannelMonitor object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorMutation) OldCreatedAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldCreatedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldCreatedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCreatedAt: %w", err) + } + return oldValue.CreatedAt, nil +} + +// ResetCreatedAt resets all changes to the "created_at" field. +func (m *ChannelMonitorMutation) ResetCreatedAt() { + m.created_at = nil +} + +// SetUpdatedAt sets the "updated_at" field. +func (m *ChannelMonitorMutation) SetUpdatedAt(t time.Time) { + m.updated_at = &t +} + +// UpdatedAt returns the value of the "updated_at" field in the mutation. +func (m *ChannelMonitorMutation) UpdatedAt() (r time.Time, exists bool) { + v := m.updated_at + if v == nil { + return + } + return *v, true +} + +// OldUpdatedAt returns the old "updated_at" field's value of the ChannelMonitor entity. +// If the ChannelMonitor object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorMutation) OldUpdatedAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldUpdatedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldUpdatedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldUpdatedAt: %w", err) + } + return oldValue.UpdatedAt, nil +} + +// ResetUpdatedAt resets all changes to the "updated_at" field. +func (m *ChannelMonitorMutation) ResetUpdatedAt() { + m.updated_at = nil +} + +// SetName sets the "name" field. +func (m *ChannelMonitorMutation) SetName(s string) { + m.name = &s +} + +// Name returns the value of the "name" field in the mutation. +func (m *ChannelMonitorMutation) Name() (r string, exists bool) { + v := m.name + if v == nil { + return + } + return *v, true +} + +// OldName returns the old "name" field's value of the ChannelMonitor entity. +// If the ChannelMonitor object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorMutation) OldName(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldName is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldName requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldName: %w", err) + } + return oldValue.Name, nil +} + +// ResetName resets all changes to the "name" field. +func (m *ChannelMonitorMutation) ResetName() { + m.name = nil +} + +// SetProvider sets the "provider" field. +func (m *ChannelMonitorMutation) SetProvider(c channelmonitor.Provider) { + m.provider = &c +} + +// Provider returns the value of the "provider" field in the mutation. +func (m *ChannelMonitorMutation) Provider() (r channelmonitor.Provider, exists bool) { + v := m.provider + if v == nil { + return + } + return *v, true +} + +// OldProvider returns the old "provider" field's value of the ChannelMonitor entity. +// If the ChannelMonitor object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorMutation) OldProvider(ctx context.Context) (v channelmonitor.Provider, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldProvider is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldProvider requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldProvider: %w", err) + } + return oldValue.Provider, nil +} + +// ResetProvider resets all changes to the "provider" field. +func (m *ChannelMonitorMutation) ResetProvider() { + m.provider = nil +} + +// SetEndpoint sets the "endpoint" field. +func (m *ChannelMonitorMutation) SetEndpoint(s string) { + m.endpoint = &s +} + +// Endpoint returns the value of the "endpoint" field in the mutation. +func (m *ChannelMonitorMutation) Endpoint() (r string, exists bool) { + v := m.endpoint + if v == nil { + return + } + return *v, true +} + +// OldEndpoint returns the old "endpoint" field's value of the ChannelMonitor entity. +// If the ChannelMonitor object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorMutation) OldEndpoint(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldEndpoint is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldEndpoint requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldEndpoint: %w", err) + } + return oldValue.Endpoint, nil +} + +// ResetEndpoint resets all changes to the "endpoint" field. +func (m *ChannelMonitorMutation) ResetEndpoint() { + m.endpoint = nil +} + +// SetAPIKeyEncrypted sets the "api_key_encrypted" field. +func (m *ChannelMonitorMutation) SetAPIKeyEncrypted(s string) { + m.api_key_encrypted = &s +} + +// APIKeyEncrypted returns the value of the "api_key_encrypted" field in the mutation. +func (m *ChannelMonitorMutation) APIKeyEncrypted() (r string, exists bool) { + v := m.api_key_encrypted + if v == nil { + return + } + return *v, true +} + +// OldAPIKeyEncrypted returns the old "api_key_encrypted" field's value of the ChannelMonitor entity. +// If the ChannelMonitor object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorMutation) OldAPIKeyEncrypted(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldAPIKeyEncrypted is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldAPIKeyEncrypted requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldAPIKeyEncrypted: %w", err) + } + return oldValue.APIKeyEncrypted, nil +} + +// ResetAPIKeyEncrypted resets all changes to the "api_key_encrypted" field. +func (m *ChannelMonitorMutation) ResetAPIKeyEncrypted() { + m.api_key_encrypted = nil +} + +// SetPrimaryModel sets the "primary_model" field. +func (m *ChannelMonitorMutation) SetPrimaryModel(s string) { + m.primary_model = &s +} + +// PrimaryModel returns the value of the "primary_model" field in the mutation. +func (m *ChannelMonitorMutation) PrimaryModel() (r string, exists bool) { + v := m.primary_model + if v == nil { + return + } + return *v, true +} + +// OldPrimaryModel returns the old "primary_model" field's value of the ChannelMonitor entity. +// If the ChannelMonitor object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorMutation) OldPrimaryModel(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldPrimaryModel is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldPrimaryModel requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldPrimaryModel: %w", err) + } + return oldValue.PrimaryModel, nil +} + +// ResetPrimaryModel resets all changes to the "primary_model" field. +func (m *ChannelMonitorMutation) ResetPrimaryModel() { + m.primary_model = nil +} + +// SetExtraModels sets the "extra_models" field. +func (m *ChannelMonitorMutation) SetExtraModels(s []string) { + m.extra_models = &s + m.appendextra_models = nil +} + +// ExtraModels returns the value of the "extra_models" field in the mutation. +func (m *ChannelMonitorMutation) ExtraModels() (r []string, exists bool) { + v := m.extra_models + if v == nil { + return + } + return *v, true +} + +// OldExtraModels returns the old "extra_models" field's value of the ChannelMonitor entity. +// If the ChannelMonitor object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorMutation) OldExtraModels(ctx context.Context) (v []string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldExtraModels is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldExtraModels requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldExtraModels: %w", err) + } + return oldValue.ExtraModels, nil +} + +// AppendExtraModels adds s to the "extra_models" field. +func (m *ChannelMonitorMutation) AppendExtraModels(s []string) { + m.appendextra_models = append(m.appendextra_models, s...) +} + +// AppendedExtraModels returns the list of values that were appended to the "extra_models" field in this mutation. +func (m *ChannelMonitorMutation) AppendedExtraModels() ([]string, bool) { + if len(m.appendextra_models) == 0 { + return nil, false + } + return m.appendextra_models, true +} + +// ResetExtraModels resets all changes to the "extra_models" field. +func (m *ChannelMonitorMutation) ResetExtraModels() { + m.extra_models = nil + m.appendextra_models = nil +} + +// SetGroupName sets the "group_name" field. +func (m *ChannelMonitorMutation) SetGroupName(s string) { + m.group_name = &s +} + +// GroupName returns the value of the "group_name" field in the mutation. +func (m *ChannelMonitorMutation) GroupName() (r string, exists bool) { + v := m.group_name + if v == nil { + return + } + return *v, true +} + +// OldGroupName returns the old "group_name" field's value of the ChannelMonitor entity. +// If the ChannelMonitor object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorMutation) OldGroupName(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldGroupName is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldGroupName requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldGroupName: %w", err) + } + return oldValue.GroupName, nil +} + +// ClearGroupName clears the value of the "group_name" field. +func (m *ChannelMonitorMutation) ClearGroupName() { + m.group_name = nil + m.clearedFields[channelmonitor.FieldGroupName] = struct{}{} +} + +// GroupNameCleared returns if the "group_name" field was cleared in this mutation. +func (m *ChannelMonitorMutation) GroupNameCleared() bool { + _, ok := m.clearedFields[channelmonitor.FieldGroupName] + return ok +} + +// ResetGroupName resets all changes to the "group_name" field. +func (m *ChannelMonitorMutation) ResetGroupName() { + m.group_name = nil + delete(m.clearedFields, channelmonitor.FieldGroupName) +} + +// SetEnabled sets the "enabled" field. +func (m *ChannelMonitorMutation) SetEnabled(b bool) { + m.enabled = &b +} + +// Enabled returns the value of the "enabled" field in the mutation. +func (m *ChannelMonitorMutation) Enabled() (r bool, exists bool) { + v := m.enabled + if v == nil { + return + } + return *v, true +} + +// OldEnabled returns the old "enabled" field's value of the ChannelMonitor entity. +// If the ChannelMonitor object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorMutation) OldEnabled(ctx context.Context) (v bool, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldEnabled is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldEnabled requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldEnabled: %w", err) + } + return oldValue.Enabled, nil +} + +// ResetEnabled resets all changes to the "enabled" field. +func (m *ChannelMonitorMutation) ResetEnabled() { + m.enabled = nil +} + +// SetIntervalSeconds sets the "interval_seconds" field. +func (m *ChannelMonitorMutation) SetIntervalSeconds(i int) { + m.interval_seconds = &i + m.addinterval_seconds = nil +} + +// IntervalSeconds returns the value of the "interval_seconds" field in the mutation. +func (m *ChannelMonitorMutation) IntervalSeconds() (r int, exists bool) { + v := m.interval_seconds + if v == nil { + return + } + return *v, true +} + +// OldIntervalSeconds returns the old "interval_seconds" field's value of the ChannelMonitor entity. +// If the ChannelMonitor object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorMutation) OldIntervalSeconds(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldIntervalSeconds is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldIntervalSeconds requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldIntervalSeconds: %w", err) + } + return oldValue.IntervalSeconds, nil +} + +// AddIntervalSeconds adds i to the "interval_seconds" field. +func (m *ChannelMonitorMutation) AddIntervalSeconds(i int) { + if m.addinterval_seconds != nil { + *m.addinterval_seconds += i + } else { + m.addinterval_seconds = &i + } +} + +// AddedIntervalSeconds returns the value that was added to the "interval_seconds" field in this mutation. +func (m *ChannelMonitorMutation) AddedIntervalSeconds() (r int, exists bool) { + v := m.addinterval_seconds + if v == nil { + return + } + return *v, true +} + +// ResetIntervalSeconds resets all changes to the "interval_seconds" field. +func (m *ChannelMonitorMutation) ResetIntervalSeconds() { + m.interval_seconds = nil + m.addinterval_seconds = nil +} + +// SetLastCheckedAt sets the "last_checked_at" field. +func (m *ChannelMonitorMutation) SetLastCheckedAt(t time.Time) { + m.last_checked_at = &t +} + +// LastCheckedAt returns the value of the "last_checked_at" field in the mutation. +func (m *ChannelMonitorMutation) LastCheckedAt() (r time.Time, exists bool) { + v := m.last_checked_at + if v == nil { + return + } + return *v, true +} + +// OldLastCheckedAt returns the old "last_checked_at" field's value of the ChannelMonitor entity. +// If the ChannelMonitor object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorMutation) OldLastCheckedAt(ctx context.Context) (v *time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldLastCheckedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldLastCheckedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldLastCheckedAt: %w", err) + } + return oldValue.LastCheckedAt, nil +} + +// ClearLastCheckedAt clears the value of the "last_checked_at" field. +func (m *ChannelMonitorMutation) ClearLastCheckedAt() { + m.last_checked_at = nil + m.clearedFields[channelmonitor.FieldLastCheckedAt] = struct{}{} +} + +// LastCheckedAtCleared returns if the "last_checked_at" field was cleared in this mutation. +func (m *ChannelMonitorMutation) LastCheckedAtCleared() bool { + _, ok := m.clearedFields[channelmonitor.FieldLastCheckedAt] + return ok +} + +// ResetLastCheckedAt resets all changes to the "last_checked_at" field. +func (m *ChannelMonitorMutation) ResetLastCheckedAt() { + m.last_checked_at = nil + delete(m.clearedFields, channelmonitor.FieldLastCheckedAt) +} + +// SetCreatedBy sets the "created_by" field. +func (m *ChannelMonitorMutation) SetCreatedBy(i int64) { + m.created_by = &i + m.addcreated_by = nil +} + +// CreatedBy returns the value of the "created_by" field in the mutation. +func (m *ChannelMonitorMutation) CreatedBy() (r int64, exists bool) { + v := m.created_by + if v == nil { + return + } + return *v, true +} + +// OldCreatedBy returns the old "created_by" field's value of the ChannelMonitor entity. +// If the ChannelMonitor object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorMutation) OldCreatedBy(ctx context.Context) (v int64, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldCreatedBy is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldCreatedBy requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCreatedBy: %w", err) + } + return oldValue.CreatedBy, nil +} + +// AddCreatedBy adds i to the "created_by" field. +func (m *ChannelMonitorMutation) AddCreatedBy(i int64) { + if m.addcreated_by != nil { + *m.addcreated_by += i + } else { + m.addcreated_by = &i + } +} + +// AddedCreatedBy returns the value that was added to the "created_by" field in this mutation. +func (m *ChannelMonitorMutation) AddedCreatedBy() (r int64, exists bool) { + v := m.addcreated_by + if v == nil { + return + } + return *v, true +} + +// ResetCreatedBy resets all changes to the "created_by" field. +func (m *ChannelMonitorMutation) ResetCreatedBy() { + m.created_by = nil + m.addcreated_by = nil +} + +// SetTemplateID sets the "template_id" field. +func (m *ChannelMonitorMutation) SetTemplateID(i int64) { + m.request_template = &i +} + +// TemplateID returns the value of the "template_id" field in the mutation. +func (m *ChannelMonitorMutation) TemplateID() (r int64, exists bool) { + v := m.request_template + if v == nil { + return + } + return *v, true +} + +// OldTemplateID returns the old "template_id" field's value of the ChannelMonitor entity. +// If the ChannelMonitor object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorMutation) OldTemplateID(ctx context.Context) (v *int64, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldTemplateID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldTemplateID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldTemplateID: %w", err) + } + return oldValue.TemplateID, nil +} + +// ClearTemplateID clears the value of the "template_id" field. +func (m *ChannelMonitorMutation) ClearTemplateID() { + m.request_template = nil + m.clearedFields[channelmonitor.FieldTemplateID] = struct{}{} +} + +// TemplateIDCleared returns if the "template_id" field was cleared in this mutation. +func (m *ChannelMonitorMutation) TemplateIDCleared() bool { + _, ok := m.clearedFields[channelmonitor.FieldTemplateID] + return ok +} + +// ResetTemplateID resets all changes to the "template_id" field. +func (m *ChannelMonitorMutation) ResetTemplateID() { + m.request_template = nil + delete(m.clearedFields, channelmonitor.FieldTemplateID) +} + +// SetExtraHeaders sets the "extra_headers" field. +func (m *ChannelMonitorMutation) SetExtraHeaders(value map[string]string) { + m.extra_headers = &value +} + +// ExtraHeaders returns the value of the "extra_headers" field in the mutation. +func (m *ChannelMonitorMutation) ExtraHeaders() (r map[string]string, exists bool) { + v := m.extra_headers + if v == nil { + return + } + return *v, true +} + +// OldExtraHeaders returns the old "extra_headers" field's value of the ChannelMonitor entity. +// If the ChannelMonitor object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorMutation) OldExtraHeaders(ctx context.Context) (v map[string]string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldExtraHeaders is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldExtraHeaders requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldExtraHeaders: %w", err) + } + return oldValue.ExtraHeaders, nil +} + +// ResetExtraHeaders resets all changes to the "extra_headers" field. +func (m *ChannelMonitorMutation) ResetExtraHeaders() { + m.extra_headers = nil +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (m *ChannelMonitorMutation) SetBodyOverrideMode(s string) { + m.body_override_mode = &s +} + +// BodyOverrideMode returns the value of the "body_override_mode" field in the mutation. +func (m *ChannelMonitorMutation) BodyOverrideMode() (r string, exists bool) { + v := m.body_override_mode + if v == nil { + return + } + return *v, true +} + +// OldBodyOverrideMode returns the old "body_override_mode" field's value of the ChannelMonitor entity. +// If the ChannelMonitor object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorMutation) OldBodyOverrideMode(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldBodyOverrideMode is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldBodyOverrideMode requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldBodyOverrideMode: %w", err) + } + return oldValue.BodyOverrideMode, nil +} + +// ResetBodyOverrideMode resets all changes to the "body_override_mode" field. +func (m *ChannelMonitorMutation) ResetBodyOverrideMode() { + m.body_override_mode = nil +} + +// SetBodyOverride sets the "body_override" field. +func (m *ChannelMonitorMutation) SetBodyOverride(value map[string]interface{}) { + m.body_override = &value +} + +// BodyOverride returns the value of the "body_override" field in the mutation. +func (m *ChannelMonitorMutation) BodyOverride() (r map[string]interface{}, exists bool) { + v := m.body_override + if v == nil { + return + } + return *v, true +} + +// OldBodyOverride returns the old "body_override" field's value of the ChannelMonitor entity. +// If the ChannelMonitor object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorMutation) OldBodyOverride(ctx context.Context) (v map[string]interface{}, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldBodyOverride is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldBodyOverride requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldBodyOverride: %w", err) + } + return oldValue.BodyOverride, nil +} + +// ClearBodyOverride clears the value of the "body_override" field. +func (m *ChannelMonitorMutation) ClearBodyOverride() { + m.body_override = nil + m.clearedFields[channelmonitor.FieldBodyOverride] = struct{}{} +} + +// BodyOverrideCleared returns if the "body_override" field was cleared in this mutation. +func (m *ChannelMonitorMutation) BodyOverrideCleared() bool { + _, ok := m.clearedFields[channelmonitor.FieldBodyOverride] + return ok +} + +// ResetBodyOverride resets all changes to the "body_override" field. +func (m *ChannelMonitorMutation) ResetBodyOverride() { + m.body_override = nil + delete(m.clearedFields, channelmonitor.FieldBodyOverride) +} + +// AddHistoryIDs adds the "history" edge to the ChannelMonitorHistory entity by ids. +func (m *ChannelMonitorMutation) AddHistoryIDs(ids ...int64) { + if m.history == nil { + m.history = make(map[int64]struct{}) + } + for i := range ids { + m.history[ids[i]] = struct{}{} + } +} + +// ClearHistory clears the "history" edge to the ChannelMonitorHistory entity. +func (m *ChannelMonitorMutation) ClearHistory() { + m.clearedhistory = true +} + +// HistoryCleared reports if the "history" edge to the ChannelMonitorHistory entity was cleared. +func (m *ChannelMonitorMutation) HistoryCleared() bool { + return m.clearedhistory +} + +// RemoveHistoryIDs removes the "history" edge to the ChannelMonitorHistory entity by IDs. +func (m *ChannelMonitorMutation) RemoveHistoryIDs(ids ...int64) { + if m.removedhistory == nil { + m.removedhistory = make(map[int64]struct{}) + } + for i := range ids { + delete(m.history, ids[i]) + m.removedhistory[ids[i]] = struct{}{} + } +} + +// RemovedHistory returns the removed IDs of the "history" edge to the ChannelMonitorHistory entity. +func (m *ChannelMonitorMutation) RemovedHistoryIDs() (ids []int64) { + for id := range m.removedhistory { + ids = append(ids, id) + } + return +} + +// HistoryIDs returns the "history" edge IDs in the mutation. +func (m *ChannelMonitorMutation) HistoryIDs() (ids []int64) { + for id := range m.history { + ids = append(ids, id) + } + return +} + +// ResetHistory resets all changes to the "history" edge. +func (m *ChannelMonitorMutation) ResetHistory() { + m.history = nil + m.clearedhistory = false + m.removedhistory = nil +} + +// AddDailyRollupIDs adds the "daily_rollups" edge to the ChannelMonitorDailyRollup entity by ids. +func (m *ChannelMonitorMutation) AddDailyRollupIDs(ids ...int64) { + if m.daily_rollups == nil { + m.daily_rollups = make(map[int64]struct{}) + } + for i := range ids { + m.daily_rollups[ids[i]] = struct{}{} + } +} + +// ClearDailyRollups clears the "daily_rollups" edge to the ChannelMonitorDailyRollup entity. +func (m *ChannelMonitorMutation) ClearDailyRollups() { + m.cleareddaily_rollups = true +} + +// DailyRollupsCleared reports if the "daily_rollups" edge to the ChannelMonitorDailyRollup entity was cleared. +func (m *ChannelMonitorMutation) DailyRollupsCleared() bool { + return m.cleareddaily_rollups +} + +// RemoveDailyRollupIDs removes the "daily_rollups" edge to the ChannelMonitorDailyRollup entity by IDs. +func (m *ChannelMonitorMutation) RemoveDailyRollupIDs(ids ...int64) { + if m.removeddaily_rollups == nil { + m.removeddaily_rollups = make(map[int64]struct{}) + } + for i := range ids { + delete(m.daily_rollups, ids[i]) + m.removeddaily_rollups[ids[i]] = struct{}{} + } +} + +// RemovedDailyRollups returns the removed IDs of the "daily_rollups" edge to the ChannelMonitorDailyRollup entity. +func (m *ChannelMonitorMutation) RemovedDailyRollupsIDs() (ids []int64) { + for id := range m.removeddaily_rollups { + ids = append(ids, id) + } + return +} + +// DailyRollupsIDs returns the "daily_rollups" edge IDs in the mutation. +func (m *ChannelMonitorMutation) DailyRollupsIDs() (ids []int64) { + for id := range m.daily_rollups { + ids = append(ids, id) + } + return +} + +// ResetDailyRollups resets all changes to the "daily_rollups" edge. +func (m *ChannelMonitorMutation) ResetDailyRollups() { + m.daily_rollups = nil + m.cleareddaily_rollups = false + m.removeddaily_rollups = nil +} + +// SetRequestTemplateID sets the "request_template" edge to the ChannelMonitorRequestTemplate entity by id. +func (m *ChannelMonitorMutation) SetRequestTemplateID(id int64) { + m.request_template = &id +} + +// ClearRequestTemplate clears the "request_template" edge to the ChannelMonitorRequestTemplate entity. +func (m *ChannelMonitorMutation) ClearRequestTemplate() { + m.clearedrequest_template = true + m.clearedFields[channelmonitor.FieldTemplateID] = struct{}{} +} + +// RequestTemplateCleared reports if the "request_template" edge to the ChannelMonitorRequestTemplate entity was cleared. +func (m *ChannelMonitorMutation) RequestTemplateCleared() bool { + return m.TemplateIDCleared() || m.clearedrequest_template +} + +// RequestTemplateID returns the "request_template" edge ID in the mutation. +func (m *ChannelMonitorMutation) RequestTemplateID() (id int64, exists bool) { + if m.request_template != nil { + return *m.request_template, true + } + return +} + +// RequestTemplateIDs returns the "request_template" edge IDs in the mutation. +// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use +// RequestTemplateID instead. It exists only for internal usage by the builders. +func (m *ChannelMonitorMutation) RequestTemplateIDs() (ids []int64) { + if id := m.request_template; id != nil { + ids = append(ids, *id) + } + return +} + +// ResetRequestTemplate resets all changes to the "request_template" edge. +func (m *ChannelMonitorMutation) ResetRequestTemplate() { + m.request_template = nil + m.clearedrequest_template = false +} + +// Where appends a list predicates to the ChannelMonitorMutation builder. +func (m *ChannelMonitorMutation) Where(ps ...predicate.ChannelMonitor) { + m.predicates = append(m.predicates, ps...) +} + +// WhereP appends storage-level predicates to the ChannelMonitorMutation builder. Using this method, +// users can use type-assertion to append predicates that do not depend on any generated package. +func (m *ChannelMonitorMutation) WhereP(ps ...func(*sql.Selector)) { + p := make([]predicate.ChannelMonitor, len(ps)) + for i := range ps { + p[i] = ps[i] + } + m.Where(p...) +} + +// Op returns the operation name. +func (m *ChannelMonitorMutation) Op() Op { + return m.op +} + +// SetOp allows setting the mutation operation. +func (m *ChannelMonitorMutation) SetOp(op Op) { + m.op = op +} + +// Type returns the node type of this mutation (ChannelMonitor). +func (m *ChannelMonitorMutation) Type() string { + return m.typ +} + +// Fields returns all fields that were changed during this mutation. Note that in +// order to get all numeric fields that were incremented/decremented, call +// AddedFields(). +func (m *ChannelMonitorMutation) Fields() []string { + fields := make([]string, 0, 17) + if m.created_at != nil { + fields = append(fields, channelmonitor.FieldCreatedAt) + } + if m.updated_at != nil { + fields = append(fields, channelmonitor.FieldUpdatedAt) + } + if m.name != nil { + fields = append(fields, channelmonitor.FieldName) + } + if m.provider != nil { + fields = append(fields, channelmonitor.FieldProvider) + } + if m.endpoint != nil { + fields = append(fields, channelmonitor.FieldEndpoint) + } + if m.api_key_encrypted != nil { + fields = append(fields, channelmonitor.FieldAPIKeyEncrypted) + } + if m.primary_model != nil { + fields = append(fields, channelmonitor.FieldPrimaryModel) + } + if m.extra_models != nil { + fields = append(fields, channelmonitor.FieldExtraModels) + } + if m.group_name != nil { + fields = append(fields, channelmonitor.FieldGroupName) + } + if m.enabled != nil { + fields = append(fields, channelmonitor.FieldEnabled) + } + if m.interval_seconds != nil { + fields = append(fields, channelmonitor.FieldIntervalSeconds) + } + if m.last_checked_at != nil { + fields = append(fields, channelmonitor.FieldLastCheckedAt) + } + if m.created_by != nil { + fields = append(fields, channelmonitor.FieldCreatedBy) + } + if m.request_template != nil { + fields = append(fields, channelmonitor.FieldTemplateID) + } + if m.extra_headers != nil { + fields = append(fields, channelmonitor.FieldExtraHeaders) + } + if m.body_override_mode != nil { + fields = append(fields, channelmonitor.FieldBodyOverrideMode) + } + if m.body_override != nil { + fields = append(fields, channelmonitor.FieldBodyOverride) + } + return fields +} + +// Field returns the value of a field with the given name. The second boolean +// return value indicates that this field was not set, or was not defined in the +// schema. +func (m *ChannelMonitorMutation) Field(name string) (ent.Value, bool) { + switch name { + case channelmonitor.FieldCreatedAt: + return m.CreatedAt() + case channelmonitor.FieldUpdatedAt: + return m.UpdatedAt() + case channelmonitor.FieldName: + return m.Name() + case channelmonitor.FieldProvider: + return m.Provider() + case channelmonitor.FieldEndpoint: + return m.Endpoint() + case channelmonitor.FieldAPIKeyEncrypted: + return m.APIKeyEncrypted() + case channelmonitor.FieldPrimaryModel: + return m.PrimaryModel() + case channelmonitor.FieldExtraModels: + return m.ExtraModels() + case channelmonitor.FieldGroupName: + return m.GroupName() + case channelmonitor.FieldEnabled: + return m.Enabled() + case channelmonitor.FieldIntervalSeconds: + return m.IntervalSeconds() + case channelmonitor.FieldLastCheckedAt: + return m.LastCheckedAt() + case channelmonitor.FieldCreatedBy: + return m.CreatedBy() + case channelmonitor.FieldTemplateID: + return m.TemplateID() + case channelmonitor.FieldExtraHeaders: + return m.ExtraHeaders() + case channelmonitor.FieldBodyOverrideMode: + return m.BodyOverrideMode() + case channelmonitor.FieldBodyOverride: + return m.BodyOverride() + } + return nil, false +} + +// OldField returns the old value of the field from the database. An error is +// returned if the mutation operation is not UpdateOne, or the query to the +// database failed. +func (m *ChannelMonitorMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case channelmonitor.FieldCreatedAt: + return m.OldCreatedAt(ctx) + case channelmonitor.FieldUpdatedAt: + return m.OldUpdatedAt(ctx) + case channelmonitor.FieldName: + return m.OldName(ctx) + case channelmonitor.FieldProvider: + return m.OldProvider(ctx) + case channelmonitor.FieldEndpoint: + return m.OldEndpoint(ctx) + case channelmonitor.FieldAPIKeyEncrypted: + return m.OldAPIKeyEncrypted(ctx) + case channelmonitor.FieldPrimaryModel: + return m.OldPrimaryModel(ctx) + case channelmonitor.FieldExtraModels: + return m.OldExtraModels(ctx) + case channelmonitor.FieldGroupName: + return m.OldGroupName(ctx) + case channelmonitor.FieldEnabled: + return m.OldEnabled(ctx) + case channelmonitor.FieldIntervalSeconds: + return m.OldIntervalSeconds(ctx) + case channelmonitor.FieldLastCheckedAt: + return m.OldLastCheckedAt(ctx) + case channelmonitor.FieldCreatedBy: + return m.OldCreatedBy(ctx) + case channelmonitor.FieldTemplateID: + return m.OldTemplateID(ctx) + case channelmonitor.FieldExtraHeaders: + return m.OldExtraHeaders(ctx) + case channelmonitor.FieldBodyOverrideMode: + return m.OldBodyOverrideMode(ctx) + case channelmonitor.FieldBodyOverride: + return m.OldBodyOverride(ctx) + } + return nil, fmt.Errorf("unknown ChannelMonitor field %s", name) +} + +// SetField sets the value of a field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *ChannelMonitorMutation) SetField(name string, value ent.Value) error { + switch name { + case channelmonitor.FieldCreatedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCreatedAt(v) + return nil + case channelmonitor.FieldUpdatedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetUpdatedAt(v) + return nil + case channelmonitor.FieldName: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetName(v) + return nil + case channelmonitor.FieldProvider: + v, ok := value.(channelmonitor.Provider) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetProvider(v) + return nil + case channelmonitor.FieldEndpoint: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetEndpoint(v) + return nil + case channelmonitor.FieldAPIKeyEncrypted: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetAPIKeyEncrypted(v) + return nil + case channelmonitor.FieldPrimaryModel: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetPrimaryModel(v) + return nil + case channelmonitor.FieldExtraModels: + v, ok := value.([]string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetExtraModels(v) + return nil + case channelmonitor.FieldGroupName: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetGroupName(v) + return nil + case channelmonitor.FieldEnabled: + v, ok := value.(bool) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetEnabled(v) + return nil + case channelmonitor.FieldIntervalSeconds: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetIntervalSeconds(v) + return nil + case channelmonitor.FieldLastCheckedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetLastCheckedAt(v) + return nil + case channelmonitor.FieldCreatedBy: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCreatedBy(v) + return nil + case channelmonitor.FieldTemplateID: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetTemplateID(v) + return nil + case channelmonitor.FieldExtraHeaders: + v, ok := value.(map[string]string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetExtraHeaders(v) + return nil + case channelmonitor.FieldBodyOverrideMode: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetBodyOverrideMode(v) + return nil + case channelmonitor.FieldBodyOverride: + v, ok := value.(map[string]interface{}) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetBodyOverride(v) + return nil + } + return fmt.Errorf("unknown ChannelMonitor field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *ChannelMonitorMutation) AddedFields() []string { + var fields []string + if m.addinterval_seconds != nil { + fields = append(fields, channelmonitor.FieldIntervalSeconds) + } + if m.addcreated_by != nil { + fields = append(fields, channelmonitor.FieldCreatedBy) + } + return fields +} + +// AddedField returns the numeric value that was incremented/decremented on a field +// with the given name. The second boolean return value indicates that this field +// was not set, or was not defined in the schema. +func (m *ChannelMonitorMutation) AddedField(name string) (ent.Value, bool) { + switch name { + case channelmonitor.FieldIntervalSeconds: + return m.AddedIntervalSeconds() + case channelmonitor.FieldCreatedBy: + return m.AddedCreatedBy() + } + return nil, false +} + +// AddField adds the value to the field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *ChannelMonitorMutation) AddField(name string, value ent.Value) error { + switch name { + case channelmonitor.FieldIntervalSeconds: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddIntervalSeconds(v) + return nil + case channelmonitor.FieldCreatedBy: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddCreatedBy(v) + return nil + } + return fmt.Errorf("unknown ChannelMonitor numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *ChannelMonitorMutation) ClearedFields() []string { + var fields []string + if m.FieldCleared(channelmonitor.FieldGroupName) { + fields = append(fields, channelmonitor.FieldGroupName) + } + if m.FieldCleared(channelmonitor.FieldLastCheckedAt) { + fields = append(fields, channelmonitor.FieldLastCheckedAt) + } + if m.FieldCleared(channelmonitor.FieldTemplateID) { + fields = append(fields, channelmonitor.FieldTemplateID) + } + if m.FieldCleared(channelmonitor.FieldBodyOverride) { + fields = append(fields, channelmonitor.FieldBodyOverride) + } + return fields +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *ChannelMonitorMutation) FieldCleared(name string) bool { + _, ok := m.clearedFields[name] + return ok +} + +// ClearField clears the value of the field with the given name. It returns an +// error if the field is not defined in the schema. +func (m *ChannelMonitorMutation) ClearField(name string) error { + switch name { + case channelmonitor.FieldGroupName: + m.ClearGroupName() + return nil + case channelmonitor.FieldLastCheckedAt: + m.ClearLastCheckedAt() + return nil + case channelmonitor.FieldTemplateID: + m.ClearTemplateID() + return nil + case channelmonitor.FieldBodyOverride: + m.ClearBodyOverride() + return nil + } + return fmt.Errorf("unknown ChannelMonitor nullable field %s", name) +} + +// ResetField resets all changes in the mutation for the field with the given name. +// It returns an error if the field is not defined in the schema. +func (m *ChannelMonitorMutation) ResetField(name string) error { + switch name { + case channelmonitor.FieldCreatedAt: + m.ResetCreatedAt() + return nil + case channelmonitor.FieldUpdatedAt: + m.ResetUpdatedAt() + return nil + case channelmonitor.FieldName: + m.ResetName() + return nil + case channelmonitor.FieldProvider: + m.ResetProvider() + return nil + case channelmonitor.FieldEndpoint: + m.ResetEndpoint() + return nil + case channelmonitor.FieldAPIKeyEncrypted: + m.ResetAPIKeyEncrypted() + return nil + case channelmonitor.FieldPrimaryModel: + m.ResetPrimaryModel() + return nil + case channelmonitor.FieldExtraModels: + m.ResetExtraModels() + return nil + case channelmonitor.FieldGroupName: + m.ResetGroupName() + return nil + case channelmonitor.FieldEnabled: + m.ResetEnabled() + return nil + case channelmonitor.FieldIntervalSeconds: + m.ResetIntervalSeconds() + return nil + case channelmonitor.FieldLastCheckedAt: + m.ResetLastCheckedAt() + return nil + case channelmonitor.FieldCreatedBy: + m.ResetCreatedBy() + return nil + case channelmonitor.FieldTemplateID: + m.ResetTemplateID() + return nil + case channelmonitor.FieldExtraHeaders: + m.ResetExtraHeaders() + return nil + case channelmonitor.FieldBodyOverrideMode: + m.ResetBodyOverrideMode() + return nil + case channelmonitor.FieldBodyOverride: + m.ResetBodyOverride() + return nil + } + return fmt.Errorf("unknown ChannelMonitor field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *ChannelMonitorMutation) AddedEdges() []string { + edges := make([]string, 0, 3) + if m.history != nil { + edges = append(edges, channelmonitor.EdgeHistory) + } + if m.daily_rollups != nil { + edges = append(edges, channelmonitor.EdgeDailyRollups) + } + if m.request_template != nil { + edges = append(edges, channelmonitor.EdgeRequestTemplate) + } + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *ChannelMonitorMutation) AddedIDs(name string) []ent.Value { + switch name { + case channelmonitor.EdgeHistory: + ids := make([]ent.Value, 0, len(m.history)) + for id := range m.history { + ids = append(ids, id) + } + return ids + case channelmonitor.EdgeDailyRollups: + ids := make([]ent.Value, 0, len(m.daily_rollups)) + for id := range m.daily_rollups { + ids = append(ids, id) + } + return ids + case channelmonitor.EdgeRequestTemplate: + if id := m.request_template; id != nil { + return []ent.Value{*id} + } + } + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *ChannelMonitorMutation) RemovedEdges() []string { + edges := make([]string, 0, 3) + if m.removedhistory != nil { + edges = append(edges, channelmonitor.EdgeHistory) + } + if m.removeddaily_rollups != nil { + edges = append(edges, channelmonitor.EdgeDailyRollups) + } + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *ChannelMonitorMutation) RemovedIDs(name string) []ent.Value { + switch name { + case channelmonitor.EdgeHistory: + ids := make([]ent.Value, 0, len(m.removedhistory)) + for id := range m.removedhistory { + ids = append(ids, id) + } + return ids + case channelmonitor.EdgeDailyRollups: + ids := make([]ent.Value, 0, len(m.removeddaily_rollups)) + for id := range m.removeddaily_rollups { + ids = append(ids, id) + } + return ids + } + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *ChannelMonitorMutation) ClearedEdges() []string { + edges := make([]string, 0, 3) + if m.clearedhistory { + edges = append(edges, channelmonitor.EdgeHistory) + } + if m.cleareddaily_rollups { + edges = append(edges, channelmonitor.EdgeDailyRollups) + } + if m.clearedrequest_template { + edges = append(edges, channelmonitor.EdgeRequestTemplate) + } + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *ChannelMonitorMutation) EdgeCleared(name string) bool { + switch name { + case channelmonitor.EdgeHistory: + return m.clearedhistory + case channelmonitor.EdgeDailyRollups: + return m.cleareddaily_rollups + case channelmonitor.EdgeRequestTemplate: + return m.clearedrequest_template + } + return false +} + +// ClearEdge clears the value of the edge with the given name. It returns an error +// if that edge is not defined in the schema. +func (m *ChannelMonitorMutation) ClearEdge(name string) error { + switch name { + case channelmonitor.EdgeRequestTemplate: + m.ClearRequestTemplate() + return nil + } + return fmt.Errorf("unknown ChannelMonitor unique edge %s", name) +} + +// ResetEdge resets all changes to the edge with the given name in this mutation. +// It returns an error if the edge is not defined in the schema. +func (m *ChannelMonitorMutation) ResetEdge(name string) error { + switch name { + case channelmonitor.EdgeHistory: + m.ResetHistory() + return nil + case channelmonitor.EdgeDailyRollups: + m.ResetDailyRollups() + return nil + case channelmonitor.EdgeRequestTemplate: + m.ResetRequestTemplate() + return nil + } + return fmt.Errorf("unknown ChannelMonitor edge %s", name) +} + +// ChannelMonitorDailyRollupMutation represents an operation that mutates the ChannelMonitorDailyRollup nodes in the graph. +type ChannelMonitorDailyRollupMutation struct { + config + op Op + typ string + id *int64 + model *string + bucket_date *time.Time + total_checks *int + addtotal_checks *int + ok_count *int + addok_count *int + operational_count *int + addoperational_count *int + degraded_count *int + adddegraded_count *int + failed_count *int + addfailed_count *int + error_count *int + adderror_count *int + sum_latency_ms *int64 + addsum_latency_ms *int64 + count_latency *int + addcount_latency *int + sum_ping_latency_ms *int64 + addsum_ping_latency_ms *int64 + count_ping_latency *int + addcount_ping_latency *int + computed_at *time.Time + clearedFields map[string]struct{} + monitor *int64 + clearedmonitor bool + done bool + oldValue func(context.Context) (*ChannelMonitorDailyRollup, error) + predicates []predicate.ChannelMonitorDailyRollup +} + +var _ ent.Mutation = (*ChannelMonitorDailyRollupMutation)(nil) + +// channelmonitordailyrollupOption allows management of the mutation configuration using functional options. +type channelmonitordailyrollupOption func(*ChannelMonitorDailyRollupMutation) + +// newChannelMonitorDailyRollupMutation creates new mutation for the ChannelMonitorDailyRollup entity. +func newChannelMonitorDailyRollupMutation(c config, op Op, opts ...channelmonitordailyrollupOption) *ChannelMonitorDailyRollupMutation { + m := &ChannelMonitorDailyRollupMutation{ + config: c, + op: op, + typ: TypeChannelMonitorDailyRollup, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withChannelMonitorDailyRollupID sets the ID field of the mutation. +func withChannelMonitorDailyRollupID(id int64) channelmonitordailyrollupOption { + return func(m *ChannelMonitorDailyRollupMutation) { + var ( + err error + once sync.Once + value *ChannelMonitorDailyRollup + ) + m.oldValue = func(ctx context.Context) (*ChannelMonitorDailyRollup, error) { + once.Do(func() { + if m.done { + err = errors.New("querying old values post mutation is not allowed") + } else { + value, err = m.Client().ChannelMonitorDailyRollup.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withChannelMonitorDailyRollup sets the old ChannelMonitorDailyRollup of the mutation. +func withChannelMonitorDailyRollup(node *ChannelMonitorDailyRollup) channelmonitordailyrollupOption { + return func(m *ChannelMonitorDailyRollupMutation) { + m.oldValue = func(context.Context) (*ChannelMonitorDailyRollup, error) { + return node, nil + } + m.id = &node.ID + } +} + +// Client returns a new `ent.Client` from the mutation. If the mutation was +// executed in a transaction (ent.Tx), a transactional client is returned. +func (m ChannelMonitorDailyRollupMutation) Client() *Client { + client := &Client{config: m.config} + client.init() + return client +} + +// Tx returns an `ent.Tx` for mutations that were executed in transactions; +// it returns an error otherwise. +func (m ChannelMonitorDailyRollupMutation) Tx() (*Tx, error) { + if _, ok := m.driver.(*txDriver); !ok { + return nil, errors.New("ent: mutation is not running in a transaction") + } + tx := &Tx{config: m.config} + tx.init() + return tx, nil +} + +// ID returns the ID value in the mutation. Note that the ID is only available +// if it was provided to the builder or after it was returned from the database. +func (m *ChannelMonitorDailyRollupMutation) ID() (id int64, exists bool) { + if m.id == nil { + return + } + return *m.id, true +} + +// IDs queries the database and returns the entity ids that match the mutation's predicate. +// That means, if the mutation is applied within a transaction with an isolation level such +// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated +// or updated by the mutation. +func (m *ChannelMonitorDailyRollupMutation) IDs(ctx context.Context) ([]int64, error) { + switch { + case m.op.Is(OpUpdateOne | OpDeleteOne): + id, exists := m.ID() + if exists { + return []int64{id}, nil + } + fallthrough + case m.op.Is(OpUpdate | OpDelete): + return m.Client().ChannelMonitorDailyRollup.Query().Where(m.predicates...).IDs(ctx) + default: + return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op) + } +} + +// SetMonitorID sets the "monitor_id" field. +func (m *ChannelMonitorDailyRollupMutation) SetMonitorID(i int64) { + m.monitor = &i +} + +// MonitorID returns the value of the "monitor_id" field in the mutation. +func (m *ChannelMonitorDailyRollupMutation) MonitorID() (r int64, exists bool) { + v := m.monitor + if v == nil { + return + } + return *v, true +} + +// OldMonitorID returns the old "monitor_id" field's value of the ChannelMonitorDailyRollup entity. +// If the ChannelMonitorDailyRollup object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorDailyRollupMutation) OldMonitorID(ctx context.Context) (v int64, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldMonitorID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldMonitorID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldMonitorID: %w", err) + } + return oldValue.MonitorID, nil +} + +// ResetMonitorID resets all changes to the "monitor_id" field. +func (m *ChannelMonitorDailyRollupMutation) ResetMonitorID() { + m.monitor = nil +} + +// SetModel sets the "model" field. +func (m *ChannelMonitorDailyRollupMutation) SetModel(s string) { + m.model = &s +} + +// Model returns the value of the "model" field in the mutation. +func (m *ChannelMonitorDailyRollupMutation) Model() (r string, exists bool) { + v := m.model + if v == nil { + return + } + return *v, true +} + +// OldModel returns the old "model" field's value of the ChannelMonitorDailyRollup entity. +// If the ChannelMonitorDailyRollup object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorDailyRollupMutation) OldModel(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldModel is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldModel requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldModel: %w", err) + } + return oldValue.Model, nil +} + +// ResetModel resets all changes to the "model" field. +func (m *ChannelMonitorDailyRollupMutation) ResetModel() { + m.model = nil +} + +// SetBucketDate sets the "bucket_date" field. +func (m *ChannelMonitorDailyRollupMutation) SetBucketDate(t time.Time) { + m.bucket_date = &t +} + +// BucketDate returns the value of the "bucket_date" field in the mutation. +func (m *ChannelMonitorDailyRollupMutation) BucketDate() (r time.Time, exists bool) { + v := m.bucket_date + if v == nil { + return + } + return *v, true +} + +// OldBucketDate returns the old "bucket_date" field's value of the ChannelMonitorDailyRollup entity. +// If the ChannelMonitorDailyRollup object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorDailyRollupMutation) OldBucketDate(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldBucketDate is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldBucketDate requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldBucketDate: %w", err) + } + return oldValue.BucketDate, nil +} + +// ResetBucketDate resets all changes to the "bucket_date" field. +func (m *ChannelMonitorDailyRollupMutation) ResetBucketDate() { + m.bucket_date = nil +} + +// SetTotalChecks sets the "total_checks" field. +func (m *ChannelMonitorDailyRollupMutation) SetTotalChecks(i int) { + m.total_checks = &i + m.addtotal_checks = nil +} + +// TotalChecks returns the value of the "total_checks" field in the mutation. +func (m *ChannelMonitorDailyRollupMutation) TotalChecks() (r int, exists bool) { + v := m.total_checks + if v == nil { + return + } + return *v, true +} + +// OldTotalChecks returns the old "total_checks" field's value of the ChannelMonitorDailyRollup entity. +// If the ChannelMonitorDailyRollup object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorDailyRollupMutation) OldTotalChecks(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldTotalChecks is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldTotalChecks requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldTotalChecks: %w", err) + } + return oldValue.TotalChecks, nil +} + +// AddTotalChecks adds i to the "total_checks" field. +func (m *ChannelMonitorDailyRollupMutation) AddTotalChecks(i int) { + if m.addtotal_checks != nil { + *m.addtotal_checks += i + } else { + m.addtotal_checks = &i + } +} + +// AddedTotalChecks returns the value that was added to the "total_checks" field in this mutation. +func (m *ChannelMonitorDailyRollupMutation) AddedTotalChecks() (r int, exists bool) { + v := m.addtotal_checks + if v == nil { + return + } + return *v, true +} + +// ResetTotalChecks resets all changes to the "total_checks" field. +func (m *ChannelMonitorDailyRollupMutation) ResetTotalChecks() { + m.total_checks = nil + m.addtotal_checks = nil +} + +// SetOkCount sets the "ok_count" field. +func (m *ChannelMonitorDailyRollupMutation) SetOkCount(i int) { + m.ok_count = &i + m.addok_count = nil +} + +// OkCount returns the value of the "ok_count" field in the mutation. +func (m *ChannelMonitorDailyRollupMutation) OkCount() (r int, exists bool) { + v := m.ok_count + if v == nil { + return + } + return *v, true +} + +// OldOkCount returns the old "ok_count" field's value of the ChannelMonitorDailyRollup entity. +// If the ChannelMonitorDailyRollup object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorDailyRollupMutation) OldOkCount(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldOkCount is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldOkCount requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldOkCount: %w", err) + } + return oldValue.OkCount, nil +} + +// AddOkCount adds i to the "ok_count" field. +func (m *ChannelMonitorDailyRollupMutation) AddOkCount(i int) { + if m.addok_count != nil { + *m.addok_count += i + } else { + m.addok_count = &i + } +} + +// AddedOkCount returns the value that was added to the "ok_count" field in this mutation. +func (m *ChannelMonitorDailyRollupMutation) AddedOkCount() (r int, exists bool) { + v := m.addok_count + if v == nil { + return + } + return *v, true +} + +// ResetOkCount resets all changes to the "ok_count" field. +func (m *ChannelMonitorDailyRollupMutation) ResetOkCount() { + m.ok_count = nil + m.addok_count = nil +} + +// SetOperationalCount sets the "operational_count" field. +func (m *ChannelMonitorDailyRollupMutation) SetOperationalCount(i int) { + m.operational_count = &i + m.addoperational_count = nil +} + +// OperationalCount returns the value of the "operational_count" field in the mutation. +func (m *ChannelMonitorDailyRollupMutation) OperationalCount() (r int, exists bool) { + v := m.operational_count + if v == nil { + return + } + return *v, true +} + +// OldOperationalCount returns the old "operational_count" field's value of the ChannelMonitorDailyRollup entity. +// If the ChannelMonitorDailyRollup object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorDailyRollupMutation) OldOperationalCount(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldOperationalCount is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldOperationalCount requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldOperationalCount: %w", err) + } + return oldValue.OperationalCount, nil +} + +// AddOperationalCount adds i to the "operational_count" field. +func (m *ChannelMonitorDailyRollupMutation) AddOperationalCount(i int) { + if m.addoperational_count != nil { + *m.addoperational_count += i + } else { + m.addoperational_count = &i + } +} + +// AddedOperationalCount returns the value that was added to the "operational_count" field in this mutation. +func (m *ChannelMonitorDailyRollupMutation) AddedOperationalCount() (r int, exists bool) { + v := m.addoperational_count + if v == nil { + return + } + return *v, true +} + +// ResetOperationalCount resets all changes to the "operational_count" field. +func (m *ChannelMonitorDailyRollupMutation) ResetOperationalCount() { + m.operational_count = nil + m.addoperational_count = nil +} + +// SetDegradedCount sets the "degraded_count" field. +func (m *ChannelMonitorDailyRollupMutation) SetDegradedCount(i int) { + m.degraded_count = &i + m.adddegraded_count = nil +} + +// DegradedCount returns the value of the "degraded_count" field in the mutation. +func (m *ChannelMonitorDailyRollupMutation) DegradedCount() (r int, exists bool) { + v := m.degraded_count + if v == nil { + return + } + return *v, true +} + +// OldDegradedCount returns the old "degraded_count" field's value of the ChannelMonitorDailyRollup entity. +// If the ChannelMonitorDailyRollup object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorDailyRollupMutation) OldDegradedCount(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldDegradedCount is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldDegradedCount requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldDegradedCount: %w", err) + } + return oldValue.DegradedCount, nil +} + +// AddDegradedCount adds i to the "degraded_count" field. +func (m *ChannelMonitorDailyRollupMutation) AddDegradedCount(i int) { + if m.adddegraded_count != nil { + *m.adddegraded_count += i + } else { + m.adddegraded_count = &i + } +} + +// AddedDegradedCount returns the value that was added to the "degraded_count" field in this mutation. +func (m *ChannelMonitorDailyRollupMutation) AddedDegradedCount() (r int, exists bool) { + v := m.adddegraded_count + if v == nil { + return + } + return *v, true +} + +// ResetDegradedCount resets all changes to the "degraded_count" field. +func (m *ChannelMonitorDailyRollupMutation) ResetDegradedCount() { + m.degraded_count = nil + m.adddegraded_count = nil +} + +// SetFailedCount sets the "failed_count" field. +func (m *ChannelMonitorDailyRollupMutation) SetFailedCount(i int) { + m.failed_count = &i + m.addfailed_count = nil +} + +// FailedCount returns the value of the "failed_count" field in the mutation. +func (m *ChannelMonitorDailyRollupMutation) FailedCount() (r int, exists bool) { + v := m.failed_count + if v == nil { + return + } + return *v, true +} + +// OldFailedCount returns the old "failed_count" field's value of the ChannelMonitorDailyRollup entity. +// If the ChannelMonitorDailyRollup object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorDailyRollupMutation) OldFailedCount(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldFailedCount is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldFailedCount requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldFailedCount: %w", err) + } + return oldValue.FailedCount, nil +} + +// AddFailedCount adds i to the "failed_count" field. +func (m *ChannelMonitorDailyRollupMutation) AddFailedCount(i int) { + if m.addfailed_count != nil { + *m.addfailed_count += i + } else { + m.addfailed_count = &i + } +} + +// AddedFailedCount returns the value that was added to the "failed_count" field in this mutation. +func (m *ChannelMonitorDailyRollupMutation) AddedFailedCount() (r int, exists bool) { + v := m.addfailed_count + if v == nil { + return + } + return *v, true +} + +// ResetFailedCount resets all changes to the "failed_count" field. +func (m *ChannelMonitorDailyRollupMutation) ResetFailedCount() { + m.failed_count = nil + m.addfailed_count = nil +} + +// SetErrorCount sets the "error_count" field. +func (m *ChannelMonitorDailyRollupMutation) SetErrorCount(i int) { + m.error_count = &i + m.adderror_count = nil +} + +// ErrorCount returns the value of the "error_count" field in the mutation. +func (m *ChannelMonitorDailyRollupMutation) ErrorCount() (r int, exists bool) { + v := m.error_count + if v == nil { + return + } + return *v, true +} + +// OldErrorCount returns the old "error_count" field's value of the ChannelMonitorDailyRollup entity. +// If the ChannelMonitorDailyRollup object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorDailyRollupMutation) OldErrorCount(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldErrorCount is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldErrorCount requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldErrorCount: %w", err) + } + return oldValue.ErrorCount, nil +} + +// AddErrorCount adds i to the "error_count" field. +func (m *ChannelMonitorDailyRollupMutation) AddErrorCount(i int) { + if m.adderror_count != nil { + *m.adderror_count += i + } else { + m.adderror_count = &i + } +} + +// AddedErrorCount returns the value that was added to the "error_count" field in this mutation. +func (m *ChannelMonitorDailyRollupMutation) AddedErrorCount() (r int, exists bool) { + v := m.adderror_count + if v == nil { + return + } + return *v, true +} + +// ResetErrorCount resets all changes to the "error_count" field. +func (m *ChannelMonitorDailyRollupMutation) ResetErrorCount() { + m.error_count = nil + m.adderror_count = nil +} + +// SetSumLatencyMs sets the "sum_latency_ms" field. +func (m *ChannelMonitorDailyRollupMutation) SetSumLatencyMs(i int64) { + m.sum_latency_ms = &i + m.addsum_latency_ms = nil +} + +// SumLatencyMs returns the value of the "sum_latency_ms" field in the mutation. +func (m *ChannelMonitorDailyRollupMutation) SumLatencyMs() (r int64, exists bool) { + v := m.sum_latency_ms + if v == nil { + return + } + return *v, true +} + +// OldSumLatencyMs returns the old "sum_latency_ms" field's value of the ChannelMonitorDailyRollup entity. +// If the ChannelMonitorDailyRollup object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorDailyRollupMutation) OldSumLatencyMs(ctx context.Context) (v int64, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldSumLatencyMs is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldSumLatencyMs requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldSumLatencyMs: %w", err) + } + return oldValue.SumLatencyMs, nil +} + +// AddSumLatencyMs adds i to the "sum_latency_ms" field. +func (m *ChannelMonitorDailyRollupMutation) AddSumLatencyMs(i int64) { + if m.addsum_latency_ms != nil { + *m.addsum_latency_ms += i + } else { + m.addsum_latency_ms = &i + } +} + +// AddedSumLatencyMs returns the value that was added to the "sum_latency_ms" field in this mutation. +func (m *ChannelMonitorDailyRollupMutation) AddedSumLatencyMs() (r int64, exists bool) { + v := m.addsum_latency_ms + if v == nil { + return + } + return *v, true +} + +// ResetSumLatencyMs resets all changes to the "sum_latency_ms" field. +func (m *ChannelMonitorDailyRollupMutation) ResetSumLatencyMs() { + m.sum_latency_ms = nil + m.addsum_latency_ms = nil +} + +// SetCountLatency sets the "count_latency" field. +func (m *ChannelMonitorDailyRollupMutation) SetCountLatency(i int) { + m.count_latency = &i + m.addcount_latency = nil +} + +// CountLatency returns the value of the "count_latency" field in the mutation. +func (m *ChannelMonitorDailyRollupMutation) CountLatency() (r int, exists bool) { + v := m.count_latency + if v == nil { + return + } + return *v, true +} + +// OldCountLatency returns the old "count_latency" field's value of the ChannelMonitorDailyRollup entity. +// If the ChannelMonitorDailyRollup object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorDailyRollupMutation) OldCountLatency(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldCountLatency is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldCountLatency requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCountLatency: %w", err) + } + return oldValue.CountLatency, nil +} + +// AddCountLatency adds i to the "count_latency" field. +func (m *ChannelMonitorDailyRollupMutation) AddCountLatency(i int) { + if m.addcount_latency != nil { + *m.addcount_latency += i + } else { + m.addcount_latency = &i + } +} + +// AddedCountLatency returns the value that was added to the "count_latency" field in this mutation. +func (m *ChannelMonitorDailyRollupMutation) AddedCountLatency() (r int, exists bool) { + v := m.addcount_latency + if v == nil { + return + } + return *v, true +} + +// ResetCountLatency resets all changes to the "count_latency" field. +func (m *ChannelMonitorDailyRollupMutation) ResetCountLatency() { + m.count_latency = nil + m.addcount_latency = nil +} + +// SetSumPingLatencyMs sets the "sum_ping_latency_ms" field. +func (m *ChannelMonitorDailyRollupMutation) SetSumPingLatencyMs(i int64) { + m.sum_ping_latency_ms = &i + m.addsum_ping_latency_ms = nil +} + +// SumPingLatencyMs returns the value of the "sum_ping_latency_ms" field in the mutation. +func (m *ChannelMonitorDailyRollupMutation) SumPingLatencyMs() (r int64, exists bool) { + v := m.sum_ping_latency_ms + if v == nil { + return + } + return *v, true +} + +// OldSumPingLatencyMs returns the old "sum_ping_latency_ms" field's value of the ChannelMonitorDailyRollup entity. +// If the ChannelMonitorDailyRollup object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorDailyRollupMutation) OldSumPingLatencyMs(ctx context.Context) (v int64, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldSumPingLatencyMs is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldSumPingLatencyMs requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldSumPingLatencyMs: %w", err) + } + return oldValue.SumPingLatencyMs, nil +} + +// AddSumPingLatencyMs adds i to the "sum_ping_latency_ms" field. +func (m *ChannelMonitorDailyRollupMutation) AddSumPingLatencyMs(i int64) { + if m.addsum_ping_latency_ms != nil { + *m.addsum_ping_latency_ms += i + } else { + m.addsum_ping_latency_ms = &i + } +} + +// AddedSumPingLatencyMs returns the value that was added to the "sum_ping_latency_ms" field in this mutation. +func (m *ChannelMonitorDailyRollupMutation) AddedSumPingLatencyMs() (r int64, exists bool) { + v := m.addsum_ping_latency_ms + if v == nil { + return + } + return *v, true +} + +// ResetSumPingLatencyMs resets all changes to the "sum_ping_latency_ms" field. +func (m *ChannelMonitorDailyRollupMutation) ResetSumPingLatencyMs() { + m.sum_ping_latency_ms = nil + m.addsum_ping_latency_ms = nil +} + +// SetCountPingLatency sets the "count_ping_latency" field. +func (m *ChannelMonitorDailyRollupMutation) SetCountPingLatency(i int) { + m.count_ping_latency = &i + m.addcount_ping_latency = nil +} + +// CountPingLatency returns the value of the "count_ping_latency" field in the mutation. +func (m *ChannelMonitorDailyRollupMutation) CountPingLatency() (r int, exists bool) { + v := m.count_ping_latency + if v == nil { + return + } + return *v, true +} + +// OldCountPingLatency returns the old "count_ping_latency" field's value of the ChannelMonitorDailyRollup entity. +// If the ChannelMonitorDailyRollup object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorDailyRollupMutation) OldCountPingLatency(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldCountPingLatency is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldCountPingLatency requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCountPingLatency: %w", err) + } + return oldValue.CountPingLatency, nil +} + +// AddCountPingLatency adds i to the "count_ping_latency" field. +func (m *ChannelMonitorDailyRollupMutation) AddCountPingLatency(i int) { + if m.addcount_ping_latency != nil { + *m.addcount_ping_latency += i + } else { + m.addcount_ping_latency = &i + } +} + +// AddedCountPingLatency returns the value that was added to the "count_ping_latency" field in this mutation. +func (m *ChannelMonitorDailyRollupMutation) AddedCountPingLatency() (r int, exists bool) { + v := m.addcount_ping_latency + if v == nil { + return + } + return *v, true +} + +// ResetCountPingLatency resets all changes to the "count_ping_latency" field. +func (m *ChannelMonitorDailyRollupMutation) ResetCountPingLatency() { + m.count_ping_latency = nil + m.addcount_ping_latency = nil +} + +// SetComputedAt sets the "computed_at" field. +func (m *ChannelMonitorDailyRollupMutation) SetComputedAt(t time.Time) { + m.computed_at = &t +} + +// ComputedAt returns the value of the "computed_at" field in the mutation. +func (m *ChannelMonitorDailyRollupMutation) ComputedAt() (r time.Time, exists bool) { + v := m.computed_at + if v == nil { + return + } + return *v, true +} + +// OldComputedAt returns the old "computed_at" field's value of the ChannelMonitorDailyRollup entity. +// If the ChannelMonitorDailyRollup object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorDailyRollupMutation) OldComputedAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldComputedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldComputedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldComputedAt: %w", err) + } + return oldValue.ComputedAt, nil +} + +// ResetComputedAt resets all changes to the "computed_at" field. +func (m *ChannelMonitorDailyRollupMutation) ResetComputedAt() { + m.computed_at = nil +} + +// ClearMonitor clears the "monitor" edge to the ChannelMonitor entity. +func (m *ChannelMonitorDailyRollupMutation) ClearMonitor() { + m.clearedmonitor = true + m.clearedFields[channelmonitordailyrollup.FieldMonitorID] = struct{}{} +} + +// MonitorCleared reports if the "monitor" edge to the ChannelMonitor entity was cleared. +func (m *ChannelMonitorDailyRollupMutation) MonitorCleared() bool { + return m.clearedmonitor +} + +// MonitorIDs returns the "monitor" edge IDs in the mutation. +// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use +// MonitorID instead. It exists only for internal usage by the builders. +func (m *ChannelMonitorDailyRollupMutation) MonitorIDs() (ids []int64) { + if id := m.monitor; id != nil { + ids = append(ids, *id) + } + return +} + +// ResetMonitor resets all changes to the "monitor" edge. +func (m *ChannelMonitorDailyRollupMutation) ResetMonitor() { + m.monitor = nil + m.clearedmonitor = false +} + +// Where appends a list predicates to the ChannelMonitorDailyRollupMutation builder. +func (m *ChannelMonitorDailyRollupMutation) Where(ps ...predicate.ChannelMonitorDailyRollup) { + m.predicates = append(m.predicates, ps...) +} + +// WhereP appends storage-level predicates to the ChannelMonitorDailyRollupMutation builder. Using this method, +// users can use type-assertion to append predicates that do not depend on any generated package. +func (m *ChannelMonitorDailyRollupMutation) WhereP(ps ...func(*sql.Selector)) { + p := make([]predicate.ChannelMonitorDailyRollup, len(ps)) + for i := range ps { + p[i] = ps[i] + } + m.Where(p...) +} + +// Op returns the operation name. +func (m *ChannelMonitorDailyRollupMutation) Op() Op { + return m.op +} + +// SetOp allows setting the mutation operation. +func (m *ChannelMonitorDailyRollupMutation) SetOp(op Op) { + m.op = op +} + +// Type returns the node type of this mutation (ChannelMonitorDailyRollup). +func (m *ChannelMonitorDailyRollupMutation) Type() string { + return m.typ +} + +// Fields returns all fields that were changed during this mutation. Note that in +// order to get all numeric fields that were incremented/decremented, call +// AddedFields(). +func (m *ChannelMonitorDailyRollupMutation) Fields() []string { + fields := make([]string, 0, 14) + if m.monitor != nil { + fields = append(fields, channelmonitordailyrollup.FieldMonitorID) + } + if m.model != nil { + fields = append(fields, channelmonitordailyrollup.FieldModel) + } + if m.bucket_date != nil { + fields = append(fields, channelmonitordailyrollup.FieldBucketDate) + } + if m.total_checks != nil { + fields = append(fields, channelmonitordailyrollup.FieldTotalChecks) + } + if m.ok_count != nil { + fields = append(fields, channelmonitordailyrollup.FieldOkCount) + } + if m.operational_count != nil { + fields = append(fields, channelmonitordailyrollup.FieldOperationalCount) + } + if m.degraded_count != nil { + fields = append(fields, channelmonitordailyrollup.FieldDegradedCount) + } + if m.failed_count != nil { + fields = append(fields, channelmonitordailyrollup.FieldFailedCount) + } + if m.error_count != nil { + fields = append(fields, channelmonitordailyrollup.FieldErrorCount) + } + if m.sum_latency_ms != nil { + fields = append(fields, channelmonitordailyrollup.FieldSumLatencyMs) + } + if m.count_latency != nil { + fields = append(fields, channelmonitordailyrollup.FieldCountLatency) + } + if m.sum_ping_latency_ms != nil { + fields = append(fields, channelmonitordailyrollup.FieldSumPingLatencyMs) + } + if m.count_ping_latency != nil { + fields = append(fields, channelmonitordailyrollup.FieldCountPingLatency) + } + if m.computed_at != nil { + fields = append(fields, channelmonitordailyrollup.FieldComputedAt) + } + return fields +} + +// Field returns the value of a field with the given name. The second boolean +// return value indicates that this field was not set, or was not defined in the +// schema. +func (m *ChannelMonitorDailyRollupMutation) Field(name string) (ent.Value, bool) { + switch name { + case channelmonitordailyrollup.FieldMonitorID: + return m.MonitorID() + case channelmonitordailyrollup.FieldModel: + return m.Model() + case channelmonitordailyrollup.FieldBucketDate: + return m.BucketDate() + case channelmonitordailyrollup.FieldTotalChecks: + return m.TotalChecks() + case channelmonitordailyrollup.FieldOkCount: + return m.OkCount() + case channelmonitordailyrollup.FieldOperationalCount: + return m.OperationalCount() + case channelmonitordailyrollup.FieldDegradedCount: + return m.DegradedCount() + case channelmonitordailyrollup.FieldFailedCount: + return m.FailedCount() + case channelmonitordailyrollup.FieldErrorCount: + return m.ErrorCount() + case channelmonitordailyrollup.FieldSumLatencyMs: + return m.SumLatencyMs() + case channelmonitordailyrollup.FieldCountLatency: + return m.CountLatency() + case channelmonitordailyrollup.FieldSumPingLatencyMs: + return m.SumPingLatencyMs() + case channelmonitordailyrollup.FieldCountPingLatency: + return m.CountPingLatency() + case channelmonitordailyrollup.FieldComputedAt: + return m.ComputedAt() + } + return nil, false +} + +// OldField returns the old value of the field from the database. An error is +// returned if the mutation operation is not UpdateOne, or the query to the +// database failed. +func (m *ChannelMonitorDailyRollupMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case channelmonitordailyrollup.FieldMonitorID: + return m.OldMonitorID(ctx) + case channelmonitordailyrollup.FieldModel: + return m.OldModel(ctx) + case channelmonitordailyrollup.FieldBucketDate: + return m.OldBucketDate(ctx) + case channelmonitordailyrollup.FieldTotalChecks: + return m.OldTotalChecks(ctx) + case channelmonitordailyrollup.FieldOkCount: + return m.OldOkCount(ctx) + case channelmonitordailyrollup.FieldOperationalCount: + return m.OldOperationalCount(ctx) + case channelmonitordailyrollup.FieldDegradedCount: + return m.OldDegradedCount(ctx) + case channelmonitordailyrollup.FieldFailedCount: + return m.OldFailedCount(ctx) + case channelmonitordailyrollup.FieldErrorCount: + return m.OldErrorCount(ctx) + case channelmonitordailyrollup.FieldSumLatencyMs: + return m.OldSumLatencyMs(ctx) + case channelmonitordailyrollup.FieldCountLatency: + return m.OldCountLatency(ctx) + case channelmonitordailyrollup.FieldSumPingLatencyMs: + return m.OldSumPingLatencyMs(ctx) + case channelmonitordailyrollup.FieldCountPingLatency: + return m.OldCountPingLatency(ctx) + case channelmonitordailyrollup.FieldComputedAt: + return m.OldComputedAt(ctx) + } + return nil, fmt.Errorf("unknown ChannelMonitorDailyRollup field %s", name) +} + +// SetField sets the value of a field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *ChannelMonitorDailyRollupMutation) SetField(name string, value ent.Value) error { + switch name { + case channelmonitordailyrollup.FieldMonitorID: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetMonitorID(v) + return nil + case channelmonitordailyrollup.FieldModel: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetModel(v) + return nil + case channelmonitordailyrollup.FieldBucketDate: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetBucketDate(v) + return nil + case channelmonitordailyrollup.FieldTotalChecks: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetTotalChecks(v) + return nil + case channelmonitordailyrollup.FieldOkCount: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetOkCount(v) + return nil + case channelmonitordailyrollup.FieldOperationalCount: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetOperationalCount(v) + return nil + case channelmonitordailyrollup.FieldDegradedCount: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetDegradedCount(v) + return nil + case channelmonitordailyrollup.FieldFailedCount: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetFailedCount(v) + return nil + case channelmonitordailyrollup.FieldErrorCount: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetErrorCount(v) + return nil + case channelmonitordailyrollup.FieldSumLatencyMs: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetSumLatencyMs(v) + return nil + case channelmonitordailyrollup.FieldCountLatency: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCountLatency(v) + return nil + case channelmonitordailyrollup.FieldSumPingLatencyMs: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetSumPingLatencyMs(v) + return nil + case channelmonitordailyrollup.FieldCountPingLatency: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCountPingLatency(v) + return nil + case channelmonitordailyrollup.FieldComputedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetComputedAt(v) + return nil + } + return fmt.Errorf("unknown ChannelMonitorDailyRollup field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *ChannelMonitorDailyRollupMutation) AddedFields() []string { + var fields []string + if m.addtotal_checks != nil { + fields = append(fields, channelmonitordailyrollup.FieldTotalChecks) + } + if m.addok_count != nil { + fields = append(fields, channelmonitordailyrollup.FieldOkCount) + } + if m.addoperational_count != nil { + fields = append(fields, channelmonitordailyrollup.FieldOperationalCount) + } + if m.adddegraded_count != nil { + fields = append(fields, channelmonitordailyrollup.FieldDegradedCount) + } + if m.addfailed_count != nil { + fields = append(fields, channelmonitordailyrollup.FieldFailedCount) + } + if m.adderror_count != nil { + fields = append(fields, channelmonitordailyrollup.FieldErrorCount) + } + if m.addsum_latency_ms != nil { + fields = append(fields, channelmonitordailyrollup.FieldSumLatencyMs) + } + if m.addcount_latency != nil { + fields = append(fields, channelmonitordailyrollup.FieldCountLatency) + } + if m.addsum_ping_latency_ms != nil { + fields = append(fields, channelmonitordailyrollup.FieldSumPingLatencyMs) + } + if m.addcount_ping_latency != nil { + fields = append(fields, channelmonitordailyrollup.FieldCountPingLatency) + } + return fields +} + +// AddedField returns the numeric value that was incremented/decremented on a field +// with the given name. The second boolean return value indicates that this field +// was not set, or was not defined in the schema. +func (m *ChannelMonitorDailyRollupMutation) AddedField(name string) (ent.Value, bool) { + switch name { + case channelmonitordailyrollup.FieldTotalChecks: + return m.AddedTotalChecks() + case channelmonitordailyrollup.FieldOkCount: + return m.AddedOkCount() + case channelmonitordailyrollup.FieldOperationalCount: + return m.AddedOperationalCount() + case channelmonitordailyrollup.FieldDegradedCount: + return m.AddedDegradedCount() + case channelmonitordailyrollup.FieldFailedCount: + return m.AddedFailedCount() + case channelmonitordailyrollup.FieldErrorCount: + return m.AddedErrorCount() + case channelmonitordailyrollup.FieldSumLatencyMs: + return m.AddedSumLatencyMs() + case channelmonitordailyrollup.FieldCountLatency: + return m.AddedCountLatency() + case channelmonitordailyrollup.FieldSumPingLatencyMs: + return m.AddedSumPingLatencyMs() + case channelmonitordailyrollup.FieldCountPingLatency: + return m.AddedCountPingLatency() + } + return nil, false +} + +// AddField adds the value to the field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *ChannelMonitorDailyRollupMutation) AddField(name string, value ent.Value) error { + switch name { + case channelmonitordailyrollup.FieldTotalChecks: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddTotalChecks(v) + return nil + case channelmonitordailyrollup.FieldOkCount: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddOkCount(v) + return nil + case channelmonitordailyrollup.FieldOperationalCount: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddOperationalCount(v) + return nil + case channelmonitordailyrollup.FieldDegradedCount: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddDegradedCount(v) + return nil + case channelmonitordailyrollup.FieldFailedCount: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddFailedCount(v) + return nil + case channelmonitordailyrollup.FieldErrorCount: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddErrorCount(v) + return nil + case channelmonitordailyrollup.FieldSumLatencyMs: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddSumLatencyMs(v) + return nil + case channelmonitordailyrollup.FieldCountLatency: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddCountLatency(v) + return nil + case channelmonitordailyrollup.FieldSumPingLatencyMs: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddSumPingLatencyMs(v) + return nil + case channelmonitordailyrollup.FieldCountPingLatency: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddCountPingLatency(v) + return nil + } + return fmt.Errorf("unknown ChannelMonitorDailyRollup numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *ChannelMonitorDailyRollupMutation) ClearedFields() []string { + return nil +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *ChannelMonitorDailyRollupMutation) FieldCleared(name string) bool { + _, ok := m.clearedFields[name] + return ok +} + +// ClearField clears the value of the field with the given name. It returns an +// error if the field is not defined in the schema. +func (m *ChannelMonitorDailyRollupMutation) ClearField(name string) error { + return fmt.Errorf("unknown ChannelMonitorDailyRollup nullable field %s", name) +} + +// ResetField resets all changes in the mutation for the field with the given name. +// It returns an error if the field is not defined in the schema. +func (m *ChannelMonitorDailyRollupMutation) ResetField(name string) error { + switch name { + case channelmonitordailyrollup.FieldMonitorID: + m.ResetMonitorID() + return nil + case channelmonitordailyrollup.FieldModel: + m.ResetModel() + return nil + case channelmonitordailyrollup.FieldBucketDate: + m.ResetBucketDate() + return nil + case channelmonitordailyrollup.FieldTotalChecks: + m.ResetTotalChecks() + return nil + case channelmonitordailyrollup.FieldOkCount: + m.ResetOkCount() + return nil + case channelmonitordailyrollup.FieldOperationalCount: + m.ResetOperationalCount() + return nil + case channelmonitordailyrollup.FieldDegradedCount: + m.ResetDegradedCount() + return nil + case channelmonitordailyrollup.FieldFailedCount: + m.ResetFailedCount() + return nil + case channelmonitordailyrollup.FieldErrorCount: + m.ResetErrorCount() + return nil + case channelmonitordailyrollup.FieldSumLatencyMs: + m.ResetSumLatencyMs() + return nil + case channelmonitordailyrollup.FieldCountLatency: + m.ResetCountLatency() + return nil + case channelmonitordailyrollup.FieldSumPingLatencyMs: + m.ResetSumPingLatencyMs() + return nil + case channelmonitordailyrollup.FieldCountPingLatency: + m.ResetCountPingLatency() + return nil + case channelmonitordailyrollup.FieldComputedAt: + m.ResetComputedAt() + return nil + } + return fmt.Errorf("unknown ChannelMonitorDailyRollup field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *ChannelMonitorDailyRollupMutation) AddedEdges() []string { + edges := make([]string, 0, 1) + if m.monitor != nil { + edges = append(edges, channelmonitordailyrollup.EdgeMonitor) + } + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *ChannelMonitorDailyRollupMutation) AddedIDs(name string) []ent.Value { + switch name { + case channelmonitordailyrollup.EdgeMonitor: + if id := m.monitor; id != nil { + return []ent.Value{*id} + } + } + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *ChannelMonitorDailyRollupMutation) RemovedEdges() []string { + edges := make([]string, 0, 1) + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *ChannelMonitorDailyRollupMutation) RemovedIDs(name string) []ent.Value { + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *ChannelMonitorDailyRollupMutation) ClearedEdges() []string { + edges := make([]string, 0, 1) + if m.clearedmonitor { + edges = append(edges, channelmonitordailyrollup.EdgeMonitor) + } + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *ChannelMonitorDailyRollupMutation) EdgeCleared(name string) bool { + switch name { + case channelmonitordailyrollup.EdgeMonitor: + return m.clearedmonitor + } + return false +} + +// ClearEdge clears the value of the edge with the given name. It returns an error +// if that edge is not defined in the schema. +func (m *ChannelMonitorDailyRollupMutation) ClearEdge(name string) error { + switch name { + case channelmonitordailyrollup.EdgeMonitor: + m.ClearMonitor() + return nil + } + return fmt.Errorf("unknown ChannelMonitorDailyRollup unique edge %s", name) +} + +// ResetEdge resets all changes to the edge with the given name in this mutation. +// It returns an error if the edge is not defined in the schema. +func (m *ChannelMonitorDailyRollupMutation) ResetEdge(name string) error { + switch name { + case channelmonitordailyrollup.EdgeMonitor: + m.ResetMonitor() + return nil + } + return fmt.Errorf("unknown ChannelMonitorDailyRollup edge %s", name) +} + +// ChannelMonitorHistoryMutation represents an operation that mutates the ChannelMonitorHistory nodes in the graph. +type ChannelMonitorHistoryMutation struct { + config + op Op + typ string + id *int64 + model *string + status *channelmonitorhistory.Status + latency_ms *int + addlatency_ms *int + ping_latency_ms *int + addping_latency_ms *int + message *string + checked_at *time.Time + clearedFields map[string]struct{} + monitor *int64 + clearedmonitor bool + done bool + oldValue func(context.Context) (*ChannelMonitorHistory, error) + predicates []predicate.ChannelMonitorHistory +} + +var _ ent.Mutation = (*ChannelMonitorHistoryMutation)(nil) + +// channelmonitorhistoryOption allows management of the mutation configuration using functional options. +type channelmonitorhistoryOption func(*ChannelMonitorHistoryMutation) + +// newChannelMonitorHistoryMutation creates new mutation for the ChannelMonitorHistory entity. +func newChannelMonitorHistoryMutation(c config, op Op, opts ...channelmonitorhistoryOption) *ChannelMonitorHistoryMutation { + m := &ChannelMonitorHistoryMutation{ + config: c, + op: op, + typ: TypeChannelMonitorHistory, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withChannelMonitorHistoryID sets the ID field of the mutation. +func withChannelMonitorHistoryID(id int64) channelmonitorhistoryOption { + return func(m *ChannelMonitorHistoryMutation) { + var ( + err error + once sync.Once + value *ChannelMonitorHistory + ) + m.oldValue = func(ctx context.Context) (*ChannelMonitorHistory, error) { + once.Do(func() { + if m.done { + err = errors.New("querying old values post mutation is not allowed") + } else { + value, err = m.Client().ChannelMonitorHistory.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withChannelMonitorHistory sets the old ChannelMonitorHistory of the mutation. +func withChannelMonitorHistory(node *ChannelMonitorHistory) channelmonitorhistoryOption { + return func(m *ChannelMonitorHistoryMutation) { + m.oldValue = func(context.Context) (*ChannelMonitorHistory, error) { + return node, nil + } + m.id = &node.ID + } +} + +// Client returns a new `ent.Client` from the mutation. If the mutation was +// executed in a transaction (ent.Tx), a transactional client is returned. +func (m ChannelMonitorHistoryMutation) Client() *Client { + client := &Client{config: m.config} + client.init() + return client +} + +// Tx returns an `ent.Tx` for mutations that were executed in transactions; +// it returns an error otherwise. +func (m ChannelMonitorHistoryMutation) Tx() (*Tx, error) { + if _, ok := m.driver.(*txDriver); !ok { + return nil, errors.New("ent: mutation is not running in a transaction") + } + tx := &Tx{config: m.config} + tx.init() + return tx, nil +} + +// ID returns the ID value in the mutation. Note that the ID is only available +// if it was provided to the builder or after it was returned from the database. +func (m *ChannelMonitorHistoryMutation) ID() (id int64, exists bool) { + if m.id == nil { + return + } + return *m.id, true +} + +// IDs queries the database and returns the entity ids that match the mutation's predicate. +// That means, if the mutation is applied within a transaction with an isolation level such +// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated +// or updated by the mutation. +func (m *ChannelMonitorHistoryMutation) IDs(ctx context.Context) ([]int64, error) { + switch { + case m.op.Is(OpUpdateOne | OpDeleteOne): + id, exists := m.ID() + if exists { + return []int64{id}, nil + } + fallthrough + case m.op.Is(OpUpdate | OpDelete): + return m.Client().ChannelMonitorHistory.Query().Where(m.predicates...).IDs(ctx) + default: + return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op) + } +} + +// SetMonitorID sets the "monitor_id" field. +func (m *ChannelMonitorHistoryMutation) SetMonitorID(i int64) { + m.monitor = &i +} + +// MonitorID returns the value of the "monitor_id" field in the mutation. +func (m *ChannelMonitorHistoryMutation) MonitorID() (r int64, exists bool) { + v := m.monitor + if v == nil { + return + } + return *v, true +} + +// OldMonitorID returns the old "monitor_id" field's value of the ChannelMonitorHistory entity. +// If the ChannelMonitorHistory object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorHistoryMutation) OldMonitorID(ctx context.Context) (v int64, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldMonitorID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldMonitorID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldMonitorID: %w", err) + } + return oldValue.MonitorID, nil +} + +// ResetMonitorID resets all changes to the "monitor_id" field. +func (m *ChannelMonitorHistoryMutation) ResetMonitorID() { + m.monitor = nil +} + +// SetModel sets the "model" field. +func (m *ChannelMonitorHistoryMutation) SetModel(s string) { + m.model = &s +} + +// Model returns the value of the "model" field in the mutation. +func (m *ChannelMonitorHistoryMutation) Model() (r string, exists bool) { + v := m.model + if v == nil { + return + } + return *v, true +} + +// OldModel returns the old "model" field's value of the ChannelMonitorHistory entity. +// If the ChannelMonitorHistory object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorHistoryMutation) OldModel(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldModel is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldModel requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldModel: %w", err) + } + return oldValue.Model, nil +} + +// ResetModel resets all changes to the "model" field. +func (m *ChannelMonitorHistoryMutation) ResetModel() { + m.model = nil +} + +// SetStatus sets the "status" field. +func (m *ChannelMonitorHistoryMutation) SetStatus(c channelmonitorhistory.Status) { + m.status = &c +} + +// Status returns the value of the "status" field in the mutation. +func (m *ChannelMonitorHistoryMutation) Status() (r channelmonitorhistory.Status, exists bool) { + v := m.status + if v == nil { + return + } + return *v, true +} + +// OldStatus returns the old "status" field's value of the ChannelMonitorHistory entity. +// If the ChannelMonitorHistory object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorHistoryMutation) OldStatus(ctx context.Context) (v channelmonitorhistory.Status, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldStatus is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldStatus requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldStatus: %w", err) + } + return oldValue.Status, nil +} + +// ResetStatus resets all changes to the "status" field. +func (m *ChannelMonitorHistoryMutation) ResetStatus() { + m.status = nil +} + +// SetLatencyMs sets the "latency_ms" field. +func (m *ChannelMonitorHistoryMutation) SetLatencyMs(i int) { + m.latency_ms = &i + m.addlatency_ms = nil +} + +// LatencyMs returns the value of the "latency_ms" field in the mutation. +func (m *ChannelMonitorHistoryMutation) LatencyMs() (r int, exists bool) { + v := m.latency_ms + if v == nil { + return + } + return *v, true +} + +// OldLatencyMs returns the old "latency_ms" field's value of the ChannelMonitorHistory entity. +// If the ChannelMonitorHistory object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorHistoryMutation) OldLatencyMs(ctx context.Context) (v *int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldLatencyMs is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldLatencyMs requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldLatencyMs: %w", err) + } + return oldValue.LatencyMs, nil +} + +// AddLatencyMs adds i to the "latency_ms" field. +func (m *ChannelMonitorHistoryMutation) AddLatencyMs(i int) { + if m.addlatency_ms != nil { + *m.addlatency_ms += i + } else { + m.addlatency_ms = &i + } +} + +// AddedLatencyMs returns the value that was added to the "latency_ms" field in this mutation. +func (m *ChannelMonitorHistoryMutation) AddedLatencyMs() (r int, exists bool) { + v := m.addlatency_ms + if v == nil { + return + } + return *v, true +} + +// ClearLatencyMs clears the value of the "latency_ms" field. +func (m *ChannelMonitorHistoryMutation) ClearLatencyMs() { + m.latency_ms = nil + m.addlatency_ms = nil + m.clearedFields[channelmonitorhistory.FieldLatencyMs] = struct{}{} +} + +// LatencyMsCleared returns if the "latency_ms" field was cleared in this mutation. +func (m *ChannelMonitorHistoryMutation) LatencyMsCleared() bool { + _, ok := m.clearedFields[channelmonitorhistory.FieldLatencyMs] + return ok +} + +// ResetLatencyMs resets all changes to the "latency_ms" field. +func (m *ChannelMonitorHistoryMutation) ResetLatencyMs() { + m.latency_ms = nil + m.addlatency_ms = nil + delete(m.clearedFields, channelmonitorhistory.FieldLatencyMs) +} + +// SetPingLatencyMs sets the "ping_latency_ms" field. +func (m *ChannelMonitorHistoryMutation) SetPingLatencyMs(i int) { + m.ping_latency_ms = &i + m.addping_latency_ms = nil +} + +// PingLatencyMs returns the value of the "ping_latency_ms" field in the mutation. +func (m *ChannelMonitorHistoryMutation) PingLatencyMs() (r int, exists bool) { + v := m.ping_latency_ms + if v == nil { + return + } + return *v, true +} + +// OldPingLatencyMs returns the old "ping_latency_ms" field's value of the ChannelMonitorHistory entity. +// If the ChannelMonitorHistory object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorHistoryMutation) OldPingLatencyMs(ctx context.Context) (v *int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldPingLatencyMs is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldPingLatencyMs requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldPingLatencyMs: %w", err) + } + return oldValue.PingLatencyMs, nil +} + +// AddPingLatencyMs adds i to the "ping_latency_ms" field. +func (m *ChannelMonitorHistoryMutation) AddPingLatencyMs(i int) { + if m.addping_latency_ms != nil { + *m.addping_latency_ms += i + } else { + m.addping_latency_ms = &i + } +} + +// AddedPingLatencyMs returns the value that was added to the "ping_latency_ms" field in this mutation. +func (m *ChannelMonitorHistoryMutation) AddedPingLatencyMs() (r int, exists bool) { + v := m.addping_latency_ms + if v == nil { + return + } + return *v, true +} + +// ClearPingLatencyMs clears the value of the "ping_latency_ms" field. +func (m *ChannelMonitorHistoryMutation) ClearPingLatencyMs() { + m.ping_latency_ms = nil + m.addping_latency_ms = nil + m.clearedFields[channelmonitorhistory.FieldPingLatencyMs] = struct{}{} +} + +// PingLatencyMsCleared returns if the "ping_latency_ms" field was cleared in this mutation. +func (m *ChannelMonitorHistoryMutation) PingLatencyMsCleared() bool { + _, ok := m.clearedFields[channelmonitorhistory.FieldPingLatencyMs] + return ok +} + +// ResetPingLatencyMs resets all changes to the "ping_latency_ms" field. +func (m *ChannelMonitorHistoryMutation) ResetPingLatencyMs() { + m.ping_latency_ms = nil + m.addping_latency_ms = nil + delete(m.clearedFields, channelmonitorhistory.FieldPingLatencyMs) +} + +// SetMessage sets the "message" field. +func (m *ChannelMonitorHistoryMutation) SetMessage(s string) { + m.message = &s +} + +// Message returns the value of the "message" field in the mutation. +func (m *ChannelMonitorHistoryMutation) Message() (r string, exists bool) { + v := m.message + if v == nil { + return + } + return *v, true +} + +// OldMessage returns the old "message" field's value of the ChannelMonitorHistory entity. +// If the ChannelMonitorHistory object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorHistoryMutation) OldMessage(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldMessage is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldMessage requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldMessage: %w", err) + } + return oldValue.Message, nil +} + +// ClearMessage clears the value of the "message" field. +func (m *ChannelMonitorHistoryMutation) ClearMessage() { + m.message = nil + m.clearedFields[channelmonitorhistory.FieldMessage] = struct{}{} +} + +// MessageCleared returns if the "message" field was cleared in this mutation. +func (m *ChannelMonitorHistoryMutation) MessageCleared() bool { + _, ok := m.clearedFields[channelmonitorhistory.FieldMessage] + return ok +} + +// ResetMessage resets all changes to the "message" field. +func (m *ChannelMonitorHistoryMutation) ResetMessage() { + m.message = nil + delete(m.clearedFields, channelmonitorhistory.FieldMessage) +} + +// SetCheckedAt sets the "checked_at" field. +func (m *ChannelMonitorHistoryMutation) SetCheckedAt(t time.Time) { + m.checked_at = &t +} + +// CheckedAt returns the value of the "checked_at" field in the mutation. +func (m *ChannelMonitorHistoryMutation) CheckedAt() (r time.Time, exists bool) { + v := m.checked_at + if v == nil { + return + } + return *v, true +} + +// OldCheckedAt returns the old "checked_at" field's value of the ChannelMonitorHistory entity. +// If the ChannelMonitorHistory object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorHistoryMutation) OldCheckedAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldCheckedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldCheckedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCheckedAt: %w", err) + } + return oldValue.CheckedAt, nil +} + +// ResetCheckedAt resets all changes to the "checked_at" field. +func (m *ChannelMonitorHistoryMutation) ResetCheckedAt() { + m.checked_at = nil +} + +// ClearMonitor clears the "monitor" edge to the ChannelMonitor entity. +func (m *ChannelMonitorHistoryMutation) ClearMonitor() { + m.clearedmonitor = true + m.clearedFields[channelmonitorhistory.FieldMonitorID] = struct{}{} +} + +// MonitorCleared reports if the "monitor" edge to the ChannelMonitor entity was cleared. +func (m *ChannelMonitorHistoryMutation) MonitorCleared() bool { + return m.clearedmonitor +} + +// MonitorIDs returns the "monitor" edge IDs in the mutation. +// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use +// MonitorID instead. It exists only for internal usage by the builders. +func (m *ChannelMonitorHistoryMutation) MonitorIDs() (ids []int64) { + if id := m.monitor; id != nil { + ids = append(ids, *id) + } + return +} + +// ResetMonitor resets all changes to the "monitor" edge. +func (m *ChannelMonitorHistoryMutation) ResetMonitor() { + m.monitor = nil + m.clearedmonitor = false +} + +// Where appends a list predicates to the ChannelMonitorHistoryMutation builder. +func (m *ChannelMonitorHistoryMutation) Where(ps ...predicate.ChannelMonitorHistory) { + m.predicates = append(m.predicates, ps...) +} + +// WhereP appends storage-level predicates to the ChannelMonitorHistoryMutation builder. Using this method, +// users can use type-assertion to append predicates that do not depend on any generated package. +func (m *ChannelMonitorHistoryMutation) WhereP(ps ...func(*sql.Selector)) { + p := make([]predicate.ChannelMonitorHistory, len(ps)) + for i := range ps { + p[i] = ps[i] + } + m.Where(p...) +} + +// Op returns the operation name. +func (m *ChannelMonitorHistoryMutation) Op() Op { + return m.op +} + +// SetOp allows setting the mutation operation. +func (m *ChannelMonitorHistoryMutation) SetOp(op Op) { + m.op = op +} + +// Type returns the node type of this mutation (ChannelMonitorHistory). +func (m *ChannelMonitorHistoryMutation) Type() string { + return m.typ +} + +// Fields returns all fields that were changed during this mutation. Note that in +// order to get all numeric fields that were incremented/decremented, call +// AddedFields(). +func (m *ChannelMonitorHistoryMutation) Fields() []string { + fields := make([]string, 0, 7) + if m.monitor != nil { + fields = append(fields, channelmonitorhistory.FieldMonitorID) + } + if m.model != nil { + fields = append(fields, channelmonitorhistory.FieldModel) + } + if m.status != nil { + fields = append(fields, channelmonitorhistory.FieldStatus) + } + if m.latency_ms != nil { + fields = append(fields, channelmonitorhistory.FieldLatencyMs) + } + if m.ping_latency_ms != nil { + fields = append(fields, channelmonitorhistory.FieldPingLatencyMs) + } + if m.message != nil { + fields = append(fields, channelmonitorhistory.FieldMessage) + } + if m.checked_at != nil { + fields = append(fields, channelmonitorhistory.FieldCheckedAt) + } + return fields +} + +// Field returns the value of a field with the given name. The second boolean +// return value indicates that this field was not set, or was not defined in the +// schema. +func (m *ChannelMonitorHistoryMutation) Field(name string) (ent.Value, bool) { + switch name { + case channelmonitorhistory.FieldMonitorID: + return m.MonitorID() + case channelmonitorhistory.FieldModel: + return m.Model() + case channelmonitorhistory.FieldStatus: + return m.Status() + case channelmonitorhistory.FieldLatencyMs: + return m.LatencyMs() + case channelmonitorhistory.FieldPingLatencyMs: + return m.PingLatencyMs() + case channelmonitorhistory.FieldMessage: + return m.Message() + case channelmonitorhistory.FieldCheckedAt: + return m.CheckedAt() + } + return nil, false +} + +// OldField returns the old value of the field from the database. An error is +// returned if the mutation operation is not UpdateOne, or the query to the +// database failed. +func (m *ChannelMonitorHistoryMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case channelmonitorhistory.FieldMonitorID: + return m.OldMonitorID(ctx) + case channelmonitorhistory.FieldModel: + return m.OldModel(ctx) + case channelmonitorhistory.FieldStatus: + return m.OldStatus(ctx) + case channelmonitorhistory.FieldLatencyMs: + return m.OldLatencyMs(ctx) + case channelmonitorhistory.FieldPingLatencyMs: + return m.OldPingLatencyMs(ctx) + case channelmonitorhistory.FieldMessage: + return m.OldMessage(ctx) + case channelmonitorhistory.FieldCheckedAt: + return m.OldCheckedAt(ctx) + } + return nil, fmt.Errorf("unknown ChannelMonitorHistory field %s", name) +} + +// SetField sets the value of a field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *ChannelMonitorHistoryMutation) SetField(name string, value ent.Value) error { + switch name { + case channelmonitorhistory.FieldMonitorID: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetMonitorID(v) + return nil + case channelmonitorhistory.FieldModel: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetModel(v) + return nil + case channelmonitorhistory.FieldStatus: + v, ok := value.(channelmonitorhistory.Status) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetStatus(v) + return nil + case channelmonitorhistory.FieldLatencyMs: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetLatencyMs(v) + return nil + case channelmonitorhistory.FieldPingLatencyMs: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetPingLatencyMs(v) + return nil + case channelmonitorhistory.FieldMessage: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetMessage(v) + return nil + case channelmonitorhistory.FieldCheckedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCheckedAt(v) + return nil + } + return fmt.Errorf("unknown ChannelMonitorHistory field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *ChannelMonitorHistoryMutation) AddedFields() []string { + var fields []string + if m.addlatency_ms != nil { + fields = append(fields, channelmonitorhistory.FieldLatencyMs) + } + if m.addping_latency_ms != nil { + fields = append(fields, channelmonitorhistory.FieldPingLatencyMs) + } + return fields +} + +// AddedField returns the numeric value that was incremented/decremented on a field +// with the given name. The second boolean return value indicates that this field +// was not set, or was not defined in the schema. +func (m *ChannelMonitorHistoryMutation) AddedField(name string) (ent.Value, bool) { + switch name { + case channelmonitorhistory.FieldLatencyMs: + return m.AddedLatencyMs() + case channelmonitorhistory.FieldPingLatencyMs: + return m.AddedPingLatencyMs() + } + return nil, false +} + +// AddField adds the value to the field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *ChannelMonitorHistoryMutation) AddField(name string, value ent.Value) error { + switch name { + case channelmonitorhistory.FieldLatencyMs: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddLatencyMs(v) + return nil + case channelmonitorhistory.FieldPingLatencyMs: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddPingLatencyMs(v) + return nil + } + return fmt.Errorf("unknown ChannelMonitorHistory numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *ChannelMonitorHistoryMutation) ClearedFields() []string { + var fields []string + if m.FieldCleared(channelmonitorhistory.FieldLatencyMs) { + fields = append(fields, channelmonitorhistory.FieldLatencyMs) + } + if m.FieldCleared(channelmonitorhistory.FieldPingLatencyMs) { + fields = append(fields, channelmonitorhistory.FieldPingLatencyMs) + } + if m.FieldCleared(channelmonitorhistory.FieldMessage) { + fields = append(fields, channelmonitorhistory.FieldMessage) + } + return fields +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *ChannelMonitorHistoryMutation) FieldCleared(name string) bool { + _, ok := m.clearedFields[name] + return ok +} + +// ClearField clears the value of the field with the given name. It returns an +// error if the field is not defined in the schema. +func (m *ChannelMonitorHistoryMutation) ClearField(name string) error { + switch name { + case channelmonitorhistory.FieldLatencyMs: + m.ClearLatencyMs() + return nil + case channelmonitorhistory.FieldPingLatencyMs: + m.ClearPingLatencyMs() + return nil + case channelmonitorhistory.FieldMessage: + m.ClearMessage() + return nil + } + return fmt.Errorf("unknown ChannelMonitorHistory nullable field %s", name) +} + +// ResetField resets all changes in the mutation for the field with the given name. +// It returns an error if the field is not defined in the schema. +func (m *ChannelMonitorHistoryMutation) ResetField(name string) error { + switch name { + case channelmonitorhistory.FieldMonitorID: + m.ResetMonitorID() + return nil + case channelmonitorhistory.FieldModel: + m.ResetModel() + return nil + case channelmonitorhistory.FieldStatus: + m.ResetStatus() + return nil + case channelmonitorhistory.FieldLatencyMs: + m.ResetLatencyMs() + return nil + case channelmonitorhistory.FieldPingLatencyMs: + m.ResetPingLatencyMs() + return nil + case channelmonitorhistory.FieldMessage: + m.ResetMessage() + return nil + case channelmonitorhistory.FieldCheckedAt: + m.ResetCheckedAt() + return nil + } + return fmt.Errorf("unknown ChannelMonitorHistory field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *ChannelMonitorHistoryMutation) AddedEdges() []string { + edges := make([]string, 0, 1) + if m.monitor != nil { + edges = append(edges, channelmonitorhistory.EdgeMonitor) + } + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *ChannelMonitorHistoryMutation) AddedIDs(name string) []ent.Value { + switch name { + case channelmonitorhistory.EdgeMonitor: + if id := m.monitor; id != nil { + return []ent.Value{*id} + } + } + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *ChannelMonitorHistoryMutation) RemovedEdges() []string { + edges := make([]string, 0, 1) + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *ChannelMonitorHistoryMutation) RemovedIDs(name string) []ent.Value { + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *ChannelMonitorHistoryMutation) ClearedEdges() []string { + edges := make([]string, 0, 1) + if m.clearedmonitor { + edges = append(edges, channelmonitorhistory.EdgeMonitor) + } + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *ChannelMonitorHistoryMutation) EdgeCleared(name string) bool { + switch name { + case channelmonitorhistory.EdgeMonitor: + return m.clearedmonitor + } + return false +} + +// ClearEdge clears the value of the edge with the given name. It returns an error +// if that edge is not defined in the schema. +func (m *ChannelMonitorHistoryMutation) ClearEdge(name string) error { + switch name { + case channelmonitorhistory.EdgeMonitor: + m.ClearMonitor() + return nil + } + return fmt.Errorf("unknown ChannelMonitorHistory unique edge %s", name) +} + +// ResetEdge resets all changes to the edge with the given name in this mutation. +// It returns an error if the edge is not defined in the schema. +func (m *ChannelMonitorHistoryMutation) ResetEdge(name string) error { + switch name { + case channelmonitorhistory.EdgeMonitor: + m.ResetMonitor() + return nil + } + return fmt.Errorf("unknown ChannelMonitorHistory edge %s", name) +} + +// ChannelMonitorRequestTemplateMutation represents an operation that mutates the ChannelMonitorRequestTemplate nodes in the graph. +type ChannelMonitorRequestTemplateMutation struct { + config + op Op + typ string + id *int64 + created_at *time.Time + updated_at *time.Time + name *string + provider *channelmonitorrequesttemplate.Provider + description *string + extra_headers *map[string]string + body_override_mode *string + body_override *map[string]interface{} + clearedFields map[string]struct{} + monitors map[int64]struct{} + removedmonitors map[int64]struct{} + clearedmonitors bool + done bool + oldValue func(context.Context) (*ChannelMonitorRequestTemplate, error) + predicates []predicate.ChannelMonitorRequestTemplate +} + +var _ ent.Mutation = (*ChannelMonitorRequestTemplateMutation)(nil) + +// channelmonitorrequesttemplateOption allows management of the mutation configuration using functional options. +type channelmonitorrequesttemplateOption func(*ChannelMonitorRequestTemplateMutation) + +// newChannelMonitorRequestTemplateMutation creates new mutation for the ChannelMonitorRequestTemplate entity. +func newChannelMonitorRequestTemplateMutation(c config, op Op, opts ...channelmonitorrequesttemplateOption) *ChannelMonitorRequestTemplateMutation { + m := &ChannelMonitorRequestTemplateMutation{ + config: c, + op: op, + typ: TypeChannelMonitorRequestTemplate, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withChannelMonitorRequestTemplateID sets the ID field of the mutation. +func withChannelMonitorRequestTemplateID(id int64) channelmonitorrequesttemplateOption { + return func(m *ChannelMonitorRequestTemplateMutation) { + var ( + err error + once sync.Once + value *ChannelMonitorRequestTemplate + ) + m.oldValue = func(ctx context.Context) (*ChannelMonitorRequestTemplate, error) { + once.Do(func() { + if m.done { + err = errors.New("querying old values post mutation is not allowed") + } else { + value, err = m.Client().ChannelMonitorRequestTemplate.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withChannelMonitorRequestTemplate sets the old ChannelMonitorRequestTemplate of the mutation. +func withChannelMonitorRequestTemplate(node *ChannelMonitorRequestTemplate) channelmonitorrequesttemplateOption { + return func(m *ChannelMonitorRequestTemplateMutation) { + m.oldValue = func(context.Context) (*ChannelMonitorRequestTemplate, error) { + return node, nil + } + m.id = &node.ID + } +} + +// Client returns a new `ent.Client` from the mutation. If the mutation was +// executed in a transaction (ent.Tx), a transactional client is returned. +func (m ChannelMonitorRequestTemplateMutation) Client() *Client { + client := &Client{config: m.config} + client.init() + return client +} + +// Tx returns an `ent.Tx` for mutations that were executed in transactions; +// it returns an error otherwise. +func (m ChannelMonitorRequestTemplateMutation) Tx() (*Tx, error) { + if _, ok := m.driver.(*txDriver); !ok { + return nil, errors.New("ent: mutation is not running in a transaction") + } + tx := &Tx{config: m.config} + tx.init() + return tx, nil +} + +// ID returns the ID value in the mutation. Note that the ID is only available +// if it was provided to the builder or after it was returned from the database. +func (m *ChannelMonitorRequestTemplateMutation) ID() (id int64, exists bool) { + if m.id == nil { + return + } + return *m.id, true +} + +// IDs queries the database and returns the entity ids that match the mutation's predicate. +// That means, if the mutation is applied within a transaction with an isolation level such +// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated +// or updated by the mutation. +func (m *ChannelMonitorRequestTemplateMutation) IDs(ctx context.Context) ([]int64, error) { + switch { + case m.op.Is(OpUpdateOne | OpDeleteOne): + id, exists := m.ID() + if exists { + return []int64{id}, nil + } + fallthrough + case m.op.Is(OpUpdate | OpDelete): + return m.Client().ChannelMonitorRequestTemplate.Query().Where(m.predicates...).IDs(ctx) + default: + return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op) + } +} + +// SetCreatedAt sets the "created_at" field. +func (m *ChannelMonitorRequestTemplateMutation) SetCreatedAt(t time.Time) { + m.created_at = &t +} + +// CreatedAt returns the value of the "created_at" field in the mutation. +func (m *ChannelMonitorRequestTemplateMutation) CreatedAt() (r time.Time, exists bool) { + v := m.created_at + if v == nil { + return + } + return *v, true +} + +// OldCreatedAt returns the old "created_at" field's value of the ChannelMonitorRequestTemplate entity. +// If the ChannelMonitorRequestTemplate object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorRequestTemplateMutation) OldCreatedAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldCreatedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldCreatedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCreatedAt: %w", err) + } + return oldValue.CreatedAt, nil +} + +// ResetCreatedAt resets all changes to the "created_at" field. +func (m *ChannelMonitorRequestTemplateMutation) ResetCreatedAt() { + m.created_at = nil +} + +// SetUpdatedAt sets the "updated_at" field. +func (m *ChannelMonitorRequestTemplateMutation) SetUpdatedAt(t time.Time) { + m.updated_at = &t +} + +// UpdatedAt returns the value of the "updated_at" field in the mutation. +func (m *ChannelMonitorRequestTemplateMutation) UpdatedAt() (r time.Time, exists bool) { + v := m.updated_at + if v == nil { + return + } + return *v, true +} + +// OldUpdatedAt returns the old "updated_at" field's value of the ChannelMonitorRequestTemplate entity. +// If the ChannelMonitorRequestTemplate object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorRequestTemplateMutation) OldUpdatedAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldUpdatedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldUpdatedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldUpdatedAt: %w", err) + } + return oldValue.UpdatedAt, nil +} + +// ResetUpdatedAt resets all changes to the "updated_at" field. +func (m *ChannelMonitorRequestTemplateMutation) ResetUpdatedAt() { + m.updated_at = nil +} + +// SetName sets the "name" field. +func (m *ChannelMonitorRequestTemplateMutation) SetName(s string) { + m.name = &s +} + +// Name returns the value of the "name" field in the mutation. +func (m *ChannelMonitorRequestTemplateMutation) Name() (r string, exists bool) { + v := m.name + if v == nil { + return + } + return *v, true +} + +// OldName returns the old "name" field's value of the ChannelMonitorRequestTemplate entity. +// If the ChannelMonitorRequestTemplate object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorRequestTemplateMutation) OldName(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldName is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldName requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldName: %w", err) + } + return oldValue.Name, nil +} + +// ResetName resets all changes to the "name" field. +func (m *ChannelMonitorRequestTemplateMutation) ResetName() { + m.name = nil +} + +// SetProvider sets the "provider" field. +func (m *ChannelMonitorRequestTemplateMutation) SetProvider(c channelmonitorrequesttemplate.Provider) { + m.provider = &c +} + +// Provider returns the value of the "provider" field in the mutation. +func (m *ChannelMonitorRequestTemplateMutation) Provider() (r channelmonitorrequesttemplate.Provider, exists bool) { + v := m.provider + if v == nil { + return + } + return *v, true +} + +// OldProvider returns the old "provider" field's value of the ChannelMonitorRequestTemplate entity. +// If the ChannelMonitorRequestTemplate object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorRequestTemplateMutation) OldProvider(ctx context.Context) (v channelmonitorrequesttemplate.Provider, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldProvider is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldProvider requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldProvider: %w", err) + } + return oldValue.Provider, nil +} + +// ResetProvider resets all changes to the "provider" field. +func (m *ChannelMonitorRequestTemplateMutation) ResetProvider() { + m.provider = nil +} + +// SetDescription sets the "description" field. +func (m *ChannelMonitorRequestTemplateMutation) SetDescription(s string) { + m.description = &s +} + +// Description returns the value of the "description" field in the mutation. +func (m *ChannelMonitorRequestTemplateMutation) Description() (r string, exists bool) { + v := m.description + if v == nil { + return + } + return *v, true +} + +// OldDescription returns the old "description" field's value of the ChannelMonitorRequestTemplate entity. +// If the ChannelMonitorRequestTemplate object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorRequestTemplateMutation) OldDescription(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldDescription is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldDescription requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldDescription: %w", err) + } + return oldValue.Description, nil +} + +// ClearDescription clears the value of the "description" field. +func (m *ChannelMonitorRequestTemplateMutation) ClearDescription() { + m.description = nil + m.clearedFields[channelmonitorrequesttemplate.FieldDescription] = struct{}{} +} + +// DescriptionCleared returns if the "description" field was cleared in this mutation. +func (m *ChannelMonitorRequestTemplateMutation) DescriptionCleared() bool { + _, ok := m.clearedFields[channelmonitorrequesttemplate.FieldDescription] + return ok +} + +// ResetDescription resets all changes to the "description" field. +func (m *ChannelMonitorRequestTemplateMutation) ResetDescription() { + m.description = nil + delete(m.clearedFields, channelmonitorrequesttemplate.FieldDescription) +} + +// SetExtraHeaders sets the "extra_headers" field. +func (m *ChannelMonitorRequestTemplateMutation) SetExtraHeaders(value map[string]string) { + m.extra_headers = &value +} + +// ExtraHeaders returns the value of the "extra_headers" field in the mutation. +func (m *ChannelMonitorRequestTemplateMutation) ExtraHeaders() (r map[string]string, exists bool) { + v := m.extra_headers + if v == nil { + return + } + return *v, true +} + +// OldExtraHeaders returns the old "extra_headers" field's value of the ChannelMonitorRequestTemplate entity. +// If the ChannelMonitorRequestTemplate object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorRequestTemplateMutation) OldExtraHeaders(ctx context.Context) (v map[string]string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldExtraHeaders is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldExtraHeaders requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldExtraHeaders: %w", err) + } + return oldValue.ExtraHeaders, nil +} + +// ResetExtraHeaders resets all changes to the "extra_headers" field. +func (m *ChannelMonitorRequestTemplateMutation) ResetExtraHeaders() { + m.extra_headers = nil +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (m *ChannelMonitorRequestTemplateMutation) SetBodyOverrideMode(s string) { + m.body_override_mode = &s +} + +// BodyOverrideMode returns the value of the "body_override_mode" field in the mutation. +func (m *ChannelMonitorRequestTemplateMutation) BodyOverrideMode() (r string, exists bool) { + v := m.body_override_mode + if v == nil { + return + } + return *v, true +} + +// OldBodyOverrideMode returns the old "body_override_mode" field's value of the ChannelMonitorRequestTemplate entity. +// If the ChannelMonitorRequestTemplate object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorRequestTemplateMutation) OldBodyOverrideMode(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldBodyOverrideMode is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldBodyOverrideMode requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldBodyOverrideMode: %w", err) + } + return oldValue.BodyOverrideMode, nil +} + +// ResetBodyOverrideMode resets all changes to the "body_override_mode" field. +func (m *ChannelMonitorRequestTemplateMutation) ResetBodyOverrideMode() { + m.body_override_mode = nil +} + +// SetBodyOverride sets the "body_override" field. +func (m *ChannelMonitorRequestTemplateMutation) SetBodyOverride(value map[string]interface{}) { + m.body_override = &value +} + +// BodyOverride returns the value of the "body_override" field in the mutation. +func (m *ChannelMonitorRequestTemplateMutation) BodyOverride() (r map[string]interface{}, exists bool) { + v := m.body_override + if v == nil { + return + } + return *v, true +} + +// OldBodyOverride returns the old "body_override" field's value of the ChannelMonitorRequestTemplate entity. +// If the ChannelMonitorRequestTemplate object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ChannelMonitorRequestTemplateMutation) OldBodyOverride(ctx context.Context) (v map[string]interface{}, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldBodyOverride is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldBodyOverride requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldBodyOverride: %w", err) + } + return oldValue.BodyOverride, nil +} + +// ClearBodyOverride clears the value of the "body_override" field. +func (m *ChannelMonitorRequestTemplateMutation) ClearBodyOverride() { + m.body_override = nil + m.clearedFields[channelmonitorrequesttemplate.FieldBodyOverride] = struct{}{} +} + +// BodyOverrideCleared returns if the "body_override" field was cleared in this mutation. +func (m *ChannelMonitorRequestTemplateMutation) BodyOverrideCleared() bool { + _, ok := m.clearedFields[channelmonitorrequesttemplate.FieldBodyOverride] + return ok +} + +// ResetBodyOverride resets all changes to the "body_override" field. +func (m *ChannelMonitorRequestTemplateMutation) ResetBodyOverride() { + m.body_override = nil + delete(m.clearedFields, channelmonitorrequesttemplate.FieldBodyOverride) +} + +// AddMonitorIDs adds the "monitors" edge to the ChannelMonitor entity by ids. +func (m *ChannelMonitorRequestTemplateMutation) AddMonitorIDs(ids ...int64) { + if m.monitors == nil { + m.monitors = make(map[int64]struct{}) + } + for i := range ids { + m.monitors[ids[i]] = struct{}{} + } +} + +// ClearMonitors clears the "monitors" edge to the ChannelMonitor entity. +func (m *ChannelMonitorRequestTemplateMutation) ClearMonitors() { + m.clearedmonitors = true +} + +// MonitorsCleared reports if the "monitors" edge to the ChannelMonitor entity was cleared. +func (m *ChannelMonitorRequestTemplateMutation) MonitorsCleared() bool { + return m.clearedmonitors +} + +// RemoveMonitorIDs removes the "monitors" edge to the ChannelMonitor entity by IDs. +func (m *ChannelMonitorRequestTemplateMutation) RemoveMonitorIDs(ids ...int64) { + if m.removedmonitors == nil { + m.removedmonitors = make(map[int64]struct{}) + } + for i := range ids { + delete(m.monitors, ids[i]) + m.removedmonitors[ids[i]] = struct{}{} + } +} + +// RemovedMonitors returns the removed IDs of the "monitors" edge to the ChannelMonitor entity. +func (m *ChannelMonitorRequestTemplateMutation) RemovedMonitorsIDs() (ids []int64) { + for id := range m.removedmonitors { + ids = append(ids, id) + } + return +} + +// MonitorsIDs returns the "monitors" edge IDs in the mutation. +func (m *ChannelMonitorRequestTemplateMutation) MonitorsIDs() (ids []int64) { + for id := range m.monitors { + ids = append(ids, id) + } + return +} + +// ResetMonitors resets all changes to the "monitors" edge. +func (m *ChannelMonitorRequestTemplateMutation) ResetMonitors() { + m.monitors = nil + m.clearedmonitors = false + m.removedmonitors = nil +} + +// Where appends a list predicates to the ChannelMonitorRequestTemplateMutation builder. +func (m *ChannelMonitorRequestTemplateMutation) Where(ps ...predicate.ChannelMonitorRequestTemplate) { + m.predicates = append(m.predicates, ps...) +} + +// WhereP appends storage-level predicates to the ChannelMonitorRequestTemplateMutation builder. Using this method, +// users can use type-assertion to append predicates that do not depend on any generated package. +func (m *ChannelMonitorRequestTemplateMutation) WhereP(ps ...func(*sql.Selector)) { + p := make([]predicate.ChannelMonitorRequestTemplate, len(ps)) + for i := range ps { + p[i] = ps[i] + } + m.Where(p...) +} + +// Op returns the operation name. +func (m *ChannelMonitorRequestTemplateMutation) Op() Op { + return m.op +} + +// SetOp allows setting the mutation operation. +func (m *ChannelMonitorRequestTemplateMutation) SetOp(op Op) { + m.op = op +} + +// Type returns the node type of this mutation (ChannelMonitorRequestTemplate). +func (m *ChannelMonitorRequestTemplateMutation) Type() string { + return m.typ +} + +// Fields returns all fields that were changed during this mutation. Note that in +// order to get all numeric fields that were incremented/decremented, call +// AddedFields(). +func (m *ChannelMonitorRequestTemplateMutation) Fields() []string { + fields := make([]string, 0, 8) + if m.created_at != nil { + fields = append(fields, channelmonitorrequesttemplate.FieldCreatedAt) + } + if m.updated_at != nil { + fields = append(fields, channelmonitorrequesttemplate.FieldUpdatedAt) + } + if m.name != nil { + fields = append(fields, channelmonitorrequesttemplate.FieldName) + } + if m.provider != nil { + fields = append(fields, channelmonitorrequesttemplate.FieldProvider) + } + if m.description != nil { + fields = append(fields, channelmonitorrequesttemplate.FieldDescription) + } + if m.extra_headers != nil { + fields = append(fields, channelmonitorrequesttemplate.FieldExtraHeaders) + } + if m.body_override_mode != nil { + fields = append(fields, channelmonitorrequesttemplate.FieldBodyOverrideMode) + } + if m.body_override != nil { + fields = append(fields, channelmonitorrequesttemplate.FieldBodyOverride) + } + return fields +} + +// Field returns the value of a field with the given name. The second boolean +// return value indicates that this field was not set, or was not defined in the +// schema. +func (m *ChannelMonitorRequestTemplateMutation) Field(name string) (ent.Value, bool) { + switch name { + case channelmonitorrequesttemplate.FieldCreatedAt: + return m.CreatedAt() + case channelmonitorrequesttemplate.FieldUpdatedAt: + return m.UpdatedAt() + case channelmonitorrequesttemplate.FieldName: + return m.Name() + case channelmonitorrequesttemplate.FieldProvider: + return m.Provider() + case channelmonitorrequesttemplate.FieldDescription: + return m.Description() + case channelmonitorrequesttemplate.FieldExtraHeaders: + return m.ExtraHeaders() + case channelmonitorrequesttemplate.FieldBodyOverrideMode: + return m.BodyOverrideMode() + case channelmonitorrequesttemplate.FieldBodyOverride: + return m.BodyOverride() + } + return nil, false +} + +// OldField returns the old value of the field from the database. An error is +// returned if the mutation operation is not UpdateOne, or the query to the +// database failed. +func (m *ChannelMonitorRequestTemplateMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case channelmonitorrequesttemplate.FieldCreatedAt: + return m.OldCreatedAt(ctx) + case channelmonitorrequesttemplate.FieldUpdatedAt: + return m.OldUpdatedAt(ctx) + case channelmonitorrequesttemplate.FieldName: + return m.OldName(ctx) + case channelmonitorrequesttemplate.FieldProvider: + return m.OldProvider(ctx) + case channelmonitorrequesttemplate.FieldDescription: + return m.OldDescription(ctx) + case channelmonitorrequesttemplate.FieldExtraHeaders: + return m.OldExtraHeaders(ctx) + case channelmonitorrequesttemplate.FieldBodyOverrideMode: + return m.OldBodyOverrideMode(ctx) + case channelmonitorrequesttemplate.FieldBodyOverride: + return m.OldBodyOverride(ctx) + } + return nil, fmt.Errorf("unknown ChannelMonitorRequestTemplate field %s", name) +} + +// SetField sets the value of a field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *ChannelMonitorRequestTemplateMutation) SetField(name string, value ent.Value) error { + switch name { + case channelmonitorrequesttemplate.FieldCreatedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCreatedAt(v) + return nil + case channelmonitorrequesttemplate.FieldUpdatedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetUpdatedAt(v) + return nil + case channelmonitorrequesttemplate.FieldName: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetName(v) + return nil + case channelmonitorrequesttemplate.FieldProvider: + v, ok := value.(channelmonitorrequesttemplate.Provider) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetProvider(v) + return nil + case channelmonitorrequesttemplate.FieldDescription: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetDescription(v) + return nil + case channelmonitorrequesttemplate.FieldExtraHeaders: + v, ok := value.(map[string]string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetExtraHeaders(v) + return nil + case channelmonitorrequesttemplate.FieldBodyOverrideMode: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetBodyOverrideMode(v) + return nil + case channelmonitorrequesttemplate.FieldBodyOverride: + v, ok := value.(map[string]interface{}) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetBodyOverride(v) + return nil + } + return fmt.Errorf("unknown ChannelMonitorRequestTemplate field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *ChannelMonitorRequestTemplateMutation) AddedFields() []string { + return nil +} + +// AddedField returns the numeric value that was incremented/decremented on a field +// with the given name. The second boolean return value indicates that this field +// was not set, or was not defined in the schema. +func (m *ChannelMonitorRequestTemplateMutation) AddedField(name string) (ent.Value, bool) { + return nil, false +} + +// AddField adds the value to the field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *ChannelMonitorRequestTemplateMutation) AddField(name string, value ent.Value) error { + switch name { + } + return fmt.Errorf("unknown ChannelMonitorRequestTemplate numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *ChannelMonitorRequestTemplateMutation) ClearedFields() []string { + var fields []string + if m.FieldCleared(channelmonitorrequesttemplate.FieldDescription) { + fields = append(fields, channelmonitorrequesttemplate.FieldDescription) + } + if m.FieldCleared(channelmonitorrequesttemplate.FieldBodyOverride) { + fields = append(fields, channelmonitorrequesttemplate.FieldBodyOverride) + } + return fields +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *ChannelMonitorRequestTemplateMutation) FieldCleared(name string) bool { + _, ok := m.clearedFields[name] + return ok +} + +// ClearField clears the value of the field with the given name. It returns an +// error if the field is not defined in the schema. +func (m *ChannelMonitorRequestTemplateMutation) ClearField(name string) error { + switch name { + case channelmonitorrequesttemplate.FieldDescription: + m.ClearDescription() + return nil + case channelmonitorrequesttemplate.FieldBodyOverride: + m.ClearBodyOverride() + return nil + } + return fmt.Errorf("unknown ChannelMonitorRequestTemplate nullable field %s", name) +} + +// ResetField resets all changes in the mutation for the field with the given name. +// It returns an error if the field is not defined in the schema. +func (m *ChannelMonitorRequestTemplateMutation) ResetField(name string) error { + switch name { + case channelmonitorrequesttemplate.FieldCreatedAt: + m.ResetCreatedAt() + return nil + case channelmonitorrequesttemplate.FieldUpdatedAt: + m.ResetUpdatedAt() + return nil + case channelmonitorrequesttemplate.FieldName: + m.ResetName() + return nil + case channelmonitorrequesttemplate.FieldProvider: + m.ResetProvider() + return nil + case channelmonitorrequesttemplate.FieldDescription: + m.ResetDescription() + return nil + case channelmonitorrequesttemplate.FieldExtraHeaders: + m.ResetExtraHeaders() + return nil + case channelmonitorrequesttemplate.FieldBodyOverrideMode: + m.ResetBodyOverrideMode() + return nil + case channelmonitorrequesttemplate.FieldBodyOverride: + m.ResetBodyOverride() + return nil + } + return fmt.Errorf("unknown ChannelMonitorRequestTemplate field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *ChannelMonitorRequestTemplateMutation) AddedEdges() []string { + edges := make([]string, 0, 1) + if m.monitors != nil { + edges = append(edges, channelmonitorrequesttemplate.EdgeMonitors) + } + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *ChannelMonitorRequestTemplateMutation) AddedIDs(name string) []ent.Value { + switch name { + case channelmonitorrequesttemplate.EdgeMonitors: + ids := make([]ent.Value, 0, len(m.monitors)) + for id := range m.monitors { + ids = append(ids, id) + } + return ids + } + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *ChannelMonitorRequestTemplateMutation) RemovedEdges() []string { + edges := make([]string, 0, 1) + if m.removedmonitors != nil { + edges = append(edges, channelmonitorrequesttemplate.EdgeMonitors) + } + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *ChannelMonitorRequestTemplateMutation) RemovedIDs(name string) []ent.Value { + switch name { + case channelmonitorrequesttemplate.EdgeMonitors: + ids := make([]ent.Value, 0, len(m.removedmonitors)) + for id := range m.removedmonitors { + ids = append(ids, id) + } + return ids + } + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *ChannelMonitorRequestTemplateMutation) ClearedEdges() []string { + edges := make([]string, 0, 1) + if m.clearedmonitors { + edges = append(edges, channelmonitorrequesttemplate.EdgeMonitors) + } + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *ChannelMonitorRequestTemplateMutation) EdgeCleared(name string) bool { + switch name { + case channelmonitorrequesttemplate.EdgeMonitors: + return m.clearedmonitors + } + return false +} + +// ClearEdge clears the value of the edge with the given name. It returns an error +// if that edge is not defined in the schema. +func (m *ChannelMonitorRequestTemplateMutation) ClearEdge(name string) error { + switch name { + } + return fmt.Errorf("unknown ChannelMonitorRequestTemplate unique edge %s", name) +} + +// ResetEdge resets all changes to the edge with the given name in this mutation. +// It returns an error if the edge is not defined in the schema. +func (m *ChannelMonitorRequestTemplateMutation) ResetEdge(name string) error { + switch name { + case channelmonitorrequesttemplate.EdgeMonitors: + m.ResetMonitors() + return nil + } + return fmt.Errorf("unknown ChannelMonitorRequestTemplate edge %s", name) +} + // ErrorPassthroughRuleMutation represents an operation that mutates the ErrorPassthroughRule nodes in the graph. type ErrorPassthroughRuleMutation struct { config diff --git a/backend/ent/predicate/predicate.go b/backend/ent/predicate/predicate.go index 0aa90b90..dc86471e 100644 --- a/backend/ent/predicate/predicate.go +++ b/backend/ent/predicate/predicate.go @@ -27,6 +27,18 @@ type AuthIdentity func(*sql.Selector) // AuthIdentityChannel is the predicate function for authidentitychannel builders. type AuthIdentityChannel func(*sql.Selector) +// ChannelMonitor is the predicate function for channelmonitor builders. +type ChannelMonitor func(*sql.Selector) + +// ChannelMonitorDailyRollup is the predicate function for channelmonitordailyrollup builders. +type ChannelMonitorDailyRollup func(*sql.Selector) + +// ChannelMonitorHistory is the predicate function for channelmonitorhistory builders. +type ChannelMonitorHistory func(*sql.Selector) + +// ChannelMonitorRequestTemplate is the predicate function for channelmonitorrequesttemplate builders. +type ChannelMonitorRequestTemplate func(*sql.Selector) + // ErrorPassthroughRule is the predicate function for errorpassthroughrule builders. type ErrorPassthroughRule func(*sql.Selector) diff --git a/backend/ent/runtime/runtime.go b/backend/ent/runtime/runtime.go index eecb2377..6b344a55 100644 --- a/backend/ent/runtime/runtime.go +++ b/backend/ent/runtime/runtime.go @@ -12,6 +12,10 @@ import ( "github.com/Wei-Shaw/sub2api/ent/apikey" "github.com/Wei-Shaw/sub2api/ent/authidentity" "github.com/Wei-Shaw/sub2api/ent/authidentitychannel" + "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitordailyrollup" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" "github.com/Wei-Shaw/sub2api/ent/errorpassthroughrule" "github.com/Wei-Shaw/sub2api/ent/group" "github.com/Wei-Shaw/sub2api/ent/idempotencyrecord" @@ -427,6 +431,252 @@ func init() { authidentitychannelDescMetadata := authidentitychannelFields[6].Descriptor() // authidentitychannel.DefaultMetadata holds the default value on creation for the metadata field. authidentitychannel.DefaultMetadata = authidentitychannelDescMetadata.Default.(func() map[string]interface{}) + channelmonitorMixin := schema.ChannelMonitor{}.Mixin() + channelmonitorMixinFields0 := channelmonitorMixin[0].Fields() + _ = channelmonitorMixinFields0 + channelmonitorFields := schema.ChannelMonitor{}.Fields() + _ = channelmonitorFields + // channelmonitorDescCreatedAt is the schema descriptor for created_at field. + channelmonitorDescCreatedAt := channelmonitorMixinFields0[0].Descriptor() + // channelmonitor.DefaultCreatedAt holds the default value on creation for the created_at field. + channelmonitor.DefaultCreatedAt = channelmonitorDescCreatedAt.Default.(func() time.Time) + // channelmonitorDescUpdatedAt is the schema descriptor for updated_at field. + channelmonitorDescUpdatedAt := channelmonitorMixinFields0[1].Descriptor() + // channelmonitor.DefaultUpdatedAt holds the default value on creation for the updated_at field. + channelmonitor.DefaultUpdatedAt = channelmonitorDescUpdatedAt.Default.(func() time.Time) + // channelmonitor.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field. + channelmonitor.UpdateDefaultUpdatedAt = channelmonitorDescUpdatedAt.UpdateDefault.(func() time.Time) + // channelmonitorDescName is the schema descriptor for name field. + channelmonitorDescName := channelmonitorFields[0].Descriptor() + // channelmonitor.NameValidator is a validator for the "name" field. It is called by the builders before save. + channelmonitor.NameValidator = func() func(string) error { + validators := channelmonitorDescName.Validators + fns := [...]func(string) error{ + validators[0].(func(string) error), + validators[1].(func(string) error), + } + return func(name string) error { + for _, fn := range fns { + if err := fn(name); err != nil { + return err + } + } + return nil + } + }() + // channelmonitorDescEndpoint is the schema descriptor for endpoint field. + channelmonitorDescEndpoint := channelmonitorFields[2].Descriptor() + // channelmonitor.EndpointValidator is a validator for the "endpoint" field. It is called by the builders before save. + channelmonitor.EndpointValidator = func() func(string) error { + validators := channelmonitorDescEndpoint.Validators + fns := [...]func(string) error{ + validators[0].(func(string) error), + validators[1].(func(string) error), + } + return func(endpoint string) error { + for _, fn := range fns { + if err := fn(endpoint); err != nil { + return err + } + } + return nil + } + }() + // channelmonitorDescAPIKeyEncrypted is the schema descriptor for api_key_encrypted field. + channelmonitorDescAPIKeyEncrypted := channelmonitorFields[3].Descriptor() + // channelmonitor.APIKeyEncryptedValidator is a validator for the "api_key_encrypted" field. It is called by the builders before save. + channelmonitor.APIKeyEncryptedValidator = channelmonitorDescAPIKeyEncrypted.Validators[0].(func(string) error) + // channelmonitorDescPrimaryModel is the schema descriptor for primary_model field. + channelmonitorDescPrimaryModel := channelmonitorFields[4].Descriptor() + // channelmonitor.PrimaryModelValidator is a validator for the "primary_model" field. It is called by the builders before save. + channelmonitor.PrimaryModelValidator = func() func(string) error { + validators := channelmonitorDescPrimaryModel.Validators + fns := [...]func(string) error{ + validators[0].(func(string) error), + validators[1].(func(string) error), + } + return func(primary_model string) error { + for _, fn := range fns { + if err := fn(primary_model); err != nil { + return err + } + } + return nil + } + }() + // channelmonitorDescExtraModels is the schema descriptor for extra_models field. + channelmonitorDescExtraModels := channelmonitorFields[5].Descriptor() + // channelmonitor.DefaultExtraModels holds the default value on creation for the extra_models field. + channelmonitor.DefaultExtraModels = channelmonitorDescExtraModels.Default.([]string) + // channelmonitorDescGroupName is the schema descriptor for group_name field. + channelmonitorDescGroupName := channelmonitorFields[6].Descriptor() + // channelmonitor.DefaultGroupName holds the default value on creation for the group_name field. + channelmonitor.DefaultGroupName = channelmonitorDescGroupName.Default.(string) + // channelmonitor.GroupNameValidator is a validator for the "group_name" field. It is called by the builders before save. + channelmonitor.GroupNameValidator = channelmonitorDescGroupName.Validators[0].(func(string) error) + // channelmonitorDescEnabled is the schema descriptor for enabled field. + channelmonitorDescEnabled := channelmonitorFields[7].Descriptor() + // channelmonitor.DefaultEnabled holds the default value on creation for the enabled field. + channelmonitor.DefaultEnabled = channelmonitorDescEnabled.Default.(bool) + // channelmonitorDescIntervalSeconds is the schema descriptor for interval_seconds field. + channelmonitorDescIntervalSeconds := channelmonitorFields[8].Descriptor() + // channelmonitor.IntervalSecondsValidator is a validator for the "interval_seconds" field. It is called by the builders before save. + channelmonitor.IntervalSecondsValidator = channelmonitorDescIntervalSeconds.Validators[0].(func(int) error) + // channelmonitorDescExtraHeaders is the schema descriptor for extra_headers field. + channelmonitorDescExtraHeaders := channelmonitorFields[12].Descriptor() + // channelmonitor.DefaultExtraHeaders holds the default value on creation for the extra_headers field. + channelmonitor.DefaultExtraHeaders = channelmonitorDescExtraHeaders.Default.(map[string]string) + // channelmonitorDescBodyOverrideMode is the schema descriptor for body_override_mode field. + channelmonitorDescBodyOverrideMode := channelmonitorFields[13].Descriptor() + // channelmonitor.DefaultBodyOverrideMode holds the default value on creation for the body_override_mode field. + channelmonitor.DefaultBodyOverrideMode = channelmonitorDescBodyOverrideMode.Default.(string) + // channelmonitor.BodyOverrideModeValidator is a validator for the "body_override_mode" field. It is called by the builders before save. + channelmonitor.BodyOverrideModeValidator = channelmonitorDescBodyOverrideMode.Validators[0].(func(string) error) + channelmonitordailyrollupFields := schema.ChannelMonitorDailyRollup{}.Fields() + _ = channelmonitordailyrollupFields + // channelmonitordailyrollupDescModel is the schema descriptor for model field. + channelmonitordailyrollupDescModel := channelmonitordailyrollupFields[1].Descriptor() + // channelmonitordailyrollup.ModelValidator is a validator for the "model" field. It is called by the builders before save. + channelmonitordailyrollup.ModelValidator = func() func(string) error { + validators := channelmonitordailyrollupDescModel.Validators + fns := [...]func(string) error{ + validators[0].(func(string) error), + validators[1].(func(string) error), + } + return func(model string) error { + for _, fn := range fns { + if err := fn(model); err != nil { + return err + } + } + return nil + } + }() + // channelmonitordailyrollupDescTotalChecks is the schema descriptor for total_checks field. + channelmonitordailyrollupDescTotalChecks := channelmonitordailyrollupFields[3].Descriptor() + // channelmonitordailyrollup.DefaultTotalChecks holds the default value on creation for the total_checks field. + channelmonitordailyrollup.DefaultTotalChecks = channelmonitordailyrollupDescTotalChecks.Default.(int) + // channelmonitordailyrollupDescOkCount is the schema descriptor for ok_count field. + channelmonitordailyrollupDescOkCount := channelmonitordailyrollupFields[4].Descriptor() + // channelmonitordailyrollup.DefaultOkCount holds the default value on creation for the ok_count field. + channelmonitordailyrollup.DefaultOkCount = channelmonitordailyrollupDescOkCount.Default.(int) + // channelmonitordailyrollupDescOperationalCount is the schema descriptor for operational_count field. + channelmonitordailyrollupDescOperationalCount := channelmonitordailyrollupFields[5].Descriptor() + // channelmonitordailyrollup.DefaultOperationalCount holds the default value on creation for the operational_count field. + channelmonitordailyrollup.DefaultOperationalCount = channelmonitordailyrollupDescOperationalCount.Default.(int) + // channelmonitordailyrollupDescDegradedCount is the schema descriptor for degraded_count field. + channelmonitordailyrollupDescDegradedCount := channelmonitordailyrollupFields[6].Descriptor() + // channelmonitordailyrollup.DefaultDegradedCount holds the default value on creation for the degraded_count field. + channelmonitordailyrollup.DefaultDegradedCount = channelmonitordailyrollupDescDegradedCount.Default.(int) + // channelmonitordailyrollupDescFailedCount is the schema descriptor for failed_count field. + channelmonitordailyrollupDescFailedCount := channelmonitordailyrollupFields[7].Descriptor() + // channelmonitordailyrollup.DefaultFailedCount holds the default value on creation for the failed_count field. + channelmonitordailyrollup.DefaultFailedCount = channelmonitordailyrollupDescFailedCount.Default.(int) + // channelmonitordailyrollupDescErrorCount is the schema descriptor for error_count field. + channelmonitordailyrollupDescErrorCount := channelmonitordailyrollupFields[8].Descriptor() + // channelmonitordailyrollup.DefaultErrorCount holds the default value on creation for the error_count field. + channelmonitordailyrollup.DefaultErrorCount = channelmonitordailyrollupDescErrorCount.Default.(int) + // channelmonitordailyrollupDescSumLatencyMs is the schema descriptor for sum_latency_ms field. + channelmonitordailyrollupDescSumLatencyMs := channelmonitordailyrollupFields[9].Descriptor() + // channelmonitordailyrollup.DefaultSumLatencyMs holds the default value on creation for the sum_latency_ms field. + channelmonitordailyrollup.DefaultSumLatencyMs = channelmonitordailyrollupDescSumLatencyMs.Default.(int64) + // channelmonitordailyrollupDescCountLatency is the schema descriptor for count_latency field. + channelmonitordailyrollupDescCountLatency := channelmonitordailyrollupFields[10].Descriptor() + // channelmonitordailyrollup.DefaultCountLatency holds the default value on creation for the count_latency field. + channelmonitordailyrollup.DefaultCountLatency = channelmonitordailyrollupDescCountLatency.Default.(int) + // channelmonitordailyrollupDescSumPingLatencyMs is the schema descriptor for sum_ping_latency_ms field. + channelmonitordailyrollupDescSumPingLatencyMs := channelmonitordailyrollupFields[11].Descriptor() + // channelmonitordailyrollup.DefaultSumPingLatencyMs holds the default value on creation for the sum_ping_latency_ms field. + channelmonitordailyrollup.DefaultSumPingLatencyMs = channelmonitordailyrollupDescSumPingLatencyMs.Default.(int64) + // channelmonitordailyrollupDescCountPingLatency is the schema descriptor for count_ping_latency field. + channelmonitordailyrollupDescCountPingLatency := channelmonitordailyrollupFields[12].Descriptor() + // channelmonitordailyrollup.DefaultCountPingLatency holds the default value on creation for the count_ping_latency field. + channelmonitordailyrollup.DefaultCountPingLatency = channelmonitordailyrollupDescCountPingLatency.Default.(int) + // channelmonitordailyrollupDescComputedAt is the schema descriptor for computed_at field. + channelmonitordailyrollupDescComputedAt := channelmonitordailyrollupFields[13].Descriptor() + // channelmonitordailyrollup.DefaultComputedAt holds the default value on creation for the computed_at field. + channelmonitordailyrollup.DefaultComputedAt = channelmonitordailyrollupDescComputedAt.Default.(func() time.Time) + // channelmonitordailyrollup.UpdateDefaultComputedAt holds the default value on update for the computed_at field. + channelmonitordailyrollup.UpdateDefaultComputedAt = channelmonitordailyrollupDescComputedAt.UpdateDefault.(func() time.Time) + channelmonitorhistoryFields := schema.ChannelMonitorHistory{}.Fields() + _ = channelmonitorhistoryFields + // channelmonitorhistoryDescModel is the schema descriptor for model field. + channelmonitorhistoryDescModel := channelmonitorhistoryFields[1].Descriptor() + // channelmonitorhistory.ModelValidator is a validator for the "model" field. It is called by the builders before save. + channelmonitorhistory.ModelValidator = func() func(string) error { + validators := channelmonitorhistoryDescModel.Validators + fns := [...]func(string) error{ + validators[0].(func(string) error), + validators[1].(func(string) error), + } + return func(model string) error { + for _, fn := range fns { + if err := fn(model); err != nil { + return err + } + } + return nil + } + }() + // channelmonitorhistoryDescMessage is the schema descriptor for message field. + channelmonitorhistoryDescMessage := channelmonitorhistoryFields[5].Descriptor() + // channelmonitorhistory.DefaultMessage holds the default value on creation for the message field. + channelmonitorhistory.DefaultMessage = channelmonitorhistoryDescMessage.Default.(string) + // channelmonitorhistory.MessageValidator is a validator for the "message" field. It is called by the builders before save. + channelmonitorhistory.MessageValidator = channelmonitorhistoryDescMessage.Validators[0].(func(string) error) + // channelmonitorhistoryDescCheckedAt is the schema descriptor for checked_at field. + channelmonitorhistoryDescCheckedAt := channelmonitorhistoryFields[6].Descriptor() + // channelmonitorhistory.DefaultCheckedAt holds the default value on creation for the checked_at field. + channelmonitorhistory.DefaultCheckedAt = channelmonitorhistoryDescCheckedAt.Default.(func() time.Time) + channelmonitorrequesttemplateMixin := schema.ChannelMonitorRequestTemplate{}.Mixin() + channelmonitorrequesttemplateMixinFields0 := channelmonitorrequesttemplateMixin[0].Fields() + _ = channelmonitorrequesttemplateMixinFields0 + channelmonitorrequesttemplateFields := schema.ChannelMonitorRequestTemplate{}.Fields() + _ = channelmonitorrequesttemplateFields + // channelmonitorrequesttemplateDescCreatedAt is the schema descriptor for created_at field. + channelmonitorrequesttemplateDescCreatedAt := channelmonitorrequesttemplateMixinFields0[0].Descriptor() + // channelmonitorrequesttemplate.DefaultCreatedAt holds the default value on creation for the created_at field. + channelmonitorrequesttemplate.DefaultCreatedAt = channelmonitorrequesttemplateDescCreatedAt.Default.(func() time.Time) + // channelmonitorrequesttemplateDescUpdatedAt is the schema descriptor for updated_at field. + channelmonitorrequesttemplateDescUpdatedAt := channelmonitorrequesttemplateMixinFields0[1].Descriptor() + // channelmonitorrequesttemplate.DefaultUpdatedAt holds the default value on creation for the updated_at field. + channelmonitorrequesttemplate.DefaultUpdatedAt = channelmonitorrequesttemplateDescUpdatedAt.Default.(func() time.Time) + // channelmonitorrequesttemplate.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field. + channelmonitorrequesttemplate.UpdateDefaultUpdatedAt = channelmonitorrequesttemplateDescUpdatedAt.UpdateDefault.(func() time.Time) + // channelmonitorrequesttemplateDescName is the schema descriptor for name field. + channelmonitorrequesttemplateDescName := channelmonitorrequesttemplateFields[0].Descriptor() + // channelmonitorrequesttemplate.NameValidator is a validator for the "name" field. It is called by the builders before save. + channelmonitorrequesttemplate.NameValidator = func() func(string) error { + validators := channelmonitorrequesttemplateDescName.Validators + fns := [...]func(string) error{ + validators[0].(func(string) error), + validators[1].(func(string) error), + } + return func(name string) error { + for _, fn := range fns { + if err := fn(name); err != nil { + return err + } + } + return nil + } + }() + // channelmonitorrequesttemplateDescDescription is the schema descriptor for description field. + channelmonitorrequesttemplateDescDescription := channelmonitorrequesttemplateFields[2].Descriptor() + // channelmonitorrequesttemplate.DefaultDescription holds the default value on creation for the description field. + channelmonitorrequesttemplate.DefaultDescription = channelmonitorrequesttemplateDescDescription.Default.(string) + // channelmonitorrequesttemplate.DescriptionValidator is a validator for the "description" field. It is called by the builders before save. + channelmonitorrequesttemplate.DescriptionValidator = channelmonitorrequesttemplateDescDescription.Validators[0].(func(string) error) + // channelmonitorrequesttemplateDescExtraHeaders is the schema descriptor for extra_headers field. + channelmonitorrequesttemplateDescExtraHeaders := channelmonitorrequesttemplateFields[3].Descriptor() + // channelmonitorrequesttemplate.DefaultExtraHeaders holds the default value on creation for the extra_headers field. + channelmonitorrequesttemplate.DefaultExtraHeaders = channelmonitorrequesttemplateDescExtraHeaders.Default.(map[string]string) + // channelmonitorrequesttemplateDescBodyOverrideMode is the schema descriptor for body_override_mode field. + channelmonitorrequesttemplateDescBodyOverrideMode := channelmonitorrequesttemplateFields[4].Descriptor() + // channelmonitorrequesttemplate.DefaultBodyOverrideMode holds the default value on creation for the body_override_mode field. + channelmonitorrequesttemplate.DefaultBodyOverrideMode = channelmonitorrequesttemplateDescBodyOverrideMode.Default.(string) + // channelmonitorrequesttemplate.BodyOverrideModeValidator is a validator for the "body_override_mode" field. It is called by the builders before save. + channelmonitorrequesttemplate.BodyOverrideModeValidator = channelmonitorrequesttemplateDescBodyOverrideMode.Validators[0].(func(string) error) errorpassthroughruleMixin := schema.ErrorPassthroughRule{}.Mixin() errorpassthroughruleMixinFields0 := errorpassthroughruleMixin[0].Fields() _ = errorpassthroughruleMixinFields0 diff --git a/backend/ent/schema/channel_monitor.go b/backend/ent/schema/channel_monitor.go new file mode 100644 index 00000000..355ade4b --- /dev/null +++ b/backend/ent/schema/channel_monitor.go @@ -0,0 +1,110 @@ +package schema + +import ( + "github.com/Wei-Shaw/sub2api/ent/schema/mixins" + + "entgo.io/ent" + "entgo.io/ent/dialect/entsql" + "entgo.io/ent/schema" + "entgo.io/ent/schema/edge" + "entgo.io/ent/schema/field" + "entgo.io/ent/schema/index" +) + +// ChannelMonitor holds the schema definition for the ChannelMonitor entity. +// 渠道监控配置:定期对指定 provider/endpoint/api_key 下的模型做心跳测试。 +type ChannelMonitor struct { + ent.Schema +} + +func (ChannelMonitor) Annotations() []schema.Annotation { + return []schema.Annotation{ + entsql.Annotation{Table: "channel_monitors"}, + } +} + +func (ChannelMonitor) Mixin() []ent.Mixin { + return []ent.Mixin{ + mixins.TimeMixin{}, + } +} + +func (ChannelMonitor) Fields() []ent.Field { + return []ent.Field{ + field.String("name"). + NotEmpty(). + MaxLen(100), + field.Enum("provider"). + Values("openai", "anthropic", "gemini"), + field.String("endpoint"). + NotEmpty(). + MaxLen(500). + Comment("Provider base origin, e.g. https://api.openai.com"), + field.String("api_key_encrypted"). + NotEmpty(). + Sensitive(). + Comment("AES-256-GCM encrypted API key"), + field.String("primary_model"). + NotEmpty(). + MaxLen(200), + field.JSON("extra_models", []string{}). + Default([]string{}). + Comment("Additional model names to test alongside primary_model"), + field.String("group_name"). + Optional(). + Default(""). + MaxLen(100), + field.Bool("enabled"). + Default(true), + field.Int("interval_seconds"). + Range(15, 3600), + field.Time("last_checked_at"). + Optional(). + Nillable(), + field.Int64("created_by"), + + // ---- 自定义请求快照字段(来自模板 / 手动编辑) ---- + + // template_id: 关联的请求模板 ID(仅用于 UI 分组 + 一键应用)。 + // 实际运行时 checker 只读下面 3 个快照字段,**不再回查模板表**。 + // 模板被删除时此字段会被 SET NULL(见 Edges 的 OnDelete 注解)。 + field.Int64("template_id"). + Optional(). + Nillable(), + // extra_headers: 自定义 HTTP 头快照(来自模板 or 用户手填)。 + // 运行时 merge 进 adapter 默认 headers。 + field.JSON("extra_headers", map[string]string{}). + Default(map[string]string{}), + // body_override_mode: 同 ChannelMonitorRequestTemplate.body_override_mode + field.String("body_override_mode"). + Default("off"). + MaxLen(10), + // body_override: 同 ChannelMonitorRequestTemplate.body_override + field.JSON("body_override", map[string]any{}). + Optional(), + } +} + +func (ChannelMonitor) Edges() []ent.Edge { + return []ent.Edge{ + edge.To("history", ChannelMonitorHistory.Type). + Annotations(entsql.OnDelete(entsql.Cascade)), + edge.To("daily_rollups", ChannelMonitorDailyRollup.Type). + Annotations(entsql.OnDelete(entsql.Cascade)), + // 关联请求模板:模板被删除时 template_id 自动置空, + // 监控本身保留(继续用快照字段跑)。 + edge.To("request_template", ChannelMonitorRequestTemplate.Type). + Field("template_id"). + Unique(). + Annotations(entsql.OnDelete(entsql.SetNull)), + } +} + +func (ChannelMonitor) Indexes() []ent.Index { + return []ent.Index{ + index.Fields("enabled", "last_checked_at"), + index.Fields("provider"), + index.Fields("group_name"), + index.Fields("template_id"), + } +} diff --git a/backend/ent/schema/channel_monitor_daily_rollup.go b/backend/ent/schema/channel_monitor_daily_rollup.go new file mode 100644 index 00000000..23f032e3 --- /dev/null +++ b/backend/ent/schema/channel_monitor_daily_rollup.go @@ -0,0 +1,66 @@ +package schema + +import ( + "time" + + "entgo.io/ent" + "entgo.io/ent/dialect" + "entgo.io/ent/dialect/entsql" + "entgo.io/ent/schema" + "entgo.io/ent/schema/edge" + "entgo.io/ent/schema/field" + "entgo.io/ent/schema/index" +) + +// ChannelMonitorDailyRollup 按 (monitor_id, model, bucket_date) 维度聚合的渠道监控日统计。 +// 每天的明细被收敛为一行(保留 status 分布 + 延迟和),用于 7d/15d/30d 窗口的可用率 +// 加权计算(avg_latency = sum_latency_ms / count_latency;availability = ok_count / total_checks)。 +// 超过保留期由每日维护任务分批物理删(不用软删除,理由同 channel_monitor_history)。 +type ChannelMonitorDailyRollup struct { + ent.Schema +} + +func (ChannelMonitorDailyRollup) Annotations() []schema.Annotation { + return []schema.Annotation{ + entsql.Annotation{Table: "channel_monitor_daily_rollups"}, + } +} + +func (ChannelMonitorDailyRollup) Fields() []ent.Field { + return []ent.Field{ + field.Int64("monitor_id"), + field.String("model"). + NotEmpty(). + MaxLen(200), + field.Time("bucket_date"). + SchemaType(map[string]string{dialect.Postgres: "date"}), + field.Int("total_checks").Default(0), + field.Int("ok_count").Default(0), + field.Int("operational_count").Default(0), + field.Int("degraded_count").Default(0), + field.Int("failed_count").Default(0), + field.Int("error_count").Default(0), + field.Int64("sum_latency_ms").Default(0), + field.Int("count_latency").Default(0), + field.Int64("sum_ping_latency_ms").Default(0), + field.Int("count_ping_latency").Default(0), + field.Time("computed_at").Default(time.Now).UpdateDefault(time.Now), + } +} + +func (ChannelMonitorDailyRollup) Edges() []ent.Edge { + return []ent.Edge{ + edge.From("monitor", ChannelMonitor.Type). + Ref("daily_rollups"). + Field("monitor_id"). + Unique(). + Required(), + } +} + +func (ChannelMonitorDailyRollup) Indexes() []ent.Index { + return []ent.Index{ + index.Fields("monitor_id", "model", "bucket_date").Unique(), + index.Fields("bucket_date"), + } +} diff --git a/backend/ent/schema/channel_monitor_history.go b/backend/ent/schema/channel_monitor_history.go new file mode 100644 index 00000000..4366e79a --- /dev/null +++ b/backend/ent/schema/channel_monitor_history.go @@ -0,0 +1,66 @@ +package schema + +import ( + "time" + + "entgo.io/ent" + "entgo.io/ent/dialect/entsql" + "entgo.io/ent/schema" + "entgo.io/ent/schema/edge" + "entgo.io/ent/schema/field" + "entgo.io/ent/schema/index" +) + +// ChannelMonitorHistory holds the schema definition for the ChannelMonitorHistory entity. +// 渠道监控历史:每次检测每个模型一行记录。明细只保留 1 天,超过 1 天由每日维护任务 +// 先聚合到 channel_monitor_daily_rollups,再分批物理删(不用软删除:日志类表无恢复 +// 需求,软删会让行和索引只增不减,徒增磁盘和查询开销)。 +type ChannelMonitorHistory struct { + ent.Schema +} + +func (ChannelMonitorHistory) Annotations() []schema.Annotation { + return []schema.Annotation{ + entsql.Annotation{Table: "channel_monitor_histories"}, + } +} + +func (ChannelMonitorHistory) Fields() []ent.Field { + return []ent.Field{ + field.Int64("monitor_id"), + field.String("model"). + NotEmpty(). + MaxLen(200), + field.Enum("status"). + Values("operational", "degraded", "failed", "error"), + field.Int("latency_ms"). + Optional(). + Nillable(), + field.Int("ping_latency_ms"). + Optional(). + Nillable(), + field.String("message"). + Optional(). + Default(""). + MaxLen(500), + field.Time("checked_at"). + Default(time.Now), + } +} + +func (ChannelMonitorHistory) Edges() []ent.Edge { + return []ent.Edge{ + edge.From("monitor", ChannelMonitor.Type). + Ref("history"). + Field("monitor_id"). + Unique(). + Required(), + } +} + +func (ChannelMonitorHistory) Indexes() []ent.Index { + return []ent.Index{ + index.Fields("monitor_id", "model", "checked_at"), + index.Fields("checked_at"), + } +} diff --git a/backend/ent/schema/channel_monitor_request_template.go b/backend/ent/schema/channel_monitor_request_template.go new file mode 100644 index 00000000..59df2f29 --- /dev/null +++ b/backend/ent/schema/channel_monitor_request_template.go @@ -0,0 +1,80 @@ +package schema + +import ( + "github.com/Wei-Shaw/sub2api/ent/schema/mixins" + + "entgo.io/ent" + "entgo.io/ent/dialect/entsql" + "entgo.io/ent/schema" + "entgo.io/ent/schema/edge" + "entgo.io/ent/schema/field" + "entgo.io/ent/schema/index" +) + +// ChannelMonitorRequestTemplate 请求模板:一组可复用的 headers + 可选 body 覆盖配置。 +// +// 语义为快照:模板被"应用"到监控时,extra_headers / body_override_mode / body_override +// 会被**拷贝**到 channel_monitors 同名字段;后续模板变动不会自动影响已应用的监控—— +// 必须用户主动在模板编辑 Dialog 里点「应用到关联监控」才会覆盖快照。 +// 这样模板改错不会瞬间打挂所有已经跑起来的监控。 +type ChannelMonitorRequestTemplate struct { + ent.Schema +} + +func (ChannelMonitorRequestTemplate) Annotations() []schema.Annotation { + return []schema.Annotation{ + entsql.Annotation{Table: "channel_monitor_request_templates"}, + } +} + +func (ChannelMonitorRequestTemplate) Mixin() []ent.Mixin { + return []ent.Mixin{ + mixins.TimeMixin{}, + } +} + +func (ChannelMonitorRequestTemplate) Fields() []ent.Field { + return []ent.Field{ + field.String("name"). + NotEmpty(). + MaxLen(100), + field.Enum("provider"). + Values("openai", "anthropic", "gemini"), + field.String("description"). + Optional(). + Default(""). + MaxLen(500), + // extra_headers: 用户自定义 HTTP 头(如 User-Agent 伪装)。 + // 运行时 merge 进 adapter 默认 headers,用户值优先; + // hop-by-hop 黑名单(Host/Content-Length/...)由 checker 过滤。 + field.JSON("extra_headers", map[string]string{}). + Default(map[string]string{}), + // body_override_mode: 'off' | 'merge' | 'replace' + // off - 用 adapter 默认 body(忽略 body_override) + // merge - adapter 默认 body 与 body_override 浅合并(body_override 优先, + // model/messages/contents 等关键字段在 checker 里走黑名单跳过) + // replace - 直接用 body_override 作为完整 body;此时跳过 challenge 校验, + // 改为 HTTP 2xx + 响应文本非空即视为可用 + field.String("body_override_mode"). + Default("off"). + MaxLen(10), + // body_override: JSON 对象,根据 body_override_mode 使用。 + // 用 map[string]any 以便前端传任意结构(含嵌套)。 + field.JSON("body_override", map[string]any{}). + Optional(), + } +} + +func (ChannelMonitorRequestTemplate) Edges() []ent.Edge { + return []ent.Edge{ + edge.From("monitors", ChannelMonitor.Type). + Ref("request_template"), + } +} + +func (ChannelMonitorRequestTemplate) Indexes() []ent.Index { + return []ent.Index{ + // 同一 provider 内 name 唯一:允许 Anthropic + OpenAI 重名 "伪装官方客户端"。 + index.Fields("provider", "name").Unique(), + } +} diff --git a/backend/ent/tx.go b/backend/ent/tx.go index bde3e35b..611028e9 100644 --- a/backend/ent/tx.go +++ b/backend/ent/tx.go @@ -28,6 +28,14 @@ type Tx struct { AuthIdentity *AuthIdentityClient // AuthIdentityChannel is the client for interacting with the AuthIdentityChannel builders. AuthIdentityChannel *AuthIdentityChannelClient + // ChannelMonitor is the client for interacting with the ChannelMonitor builders. + ChannelMonitor *ChannelMonitorClient + // ChannelMonitorDailyRollup is the client for interacting with the ChannelMonitorDailyRollup builders. + ChannelMonitorDailyRollup *ChannelMonitorDailyRollupClient + // ChannelMonitorHistory is the client for interacting with the ChannelMonitorHistory builders. + ChannelMonitorHistory *ChannelMonitorHistoryClient + // ChannelMonitorRequestTemplate is the client for interacting with the ChannelMonitorRequestTemplate builders. + ChannelMonitorRequestTemplate *ChannelMonitorRequestTemplateClient // ErrorPassthroughRule is the client for interacting with the ErrorPassthroughRule builders. ErrorPassthroughRule *ErrorPassthroughRuleClient // Group is the client for interacting with the Group builders. @@ -212,6 +220,10 @@ func (tx *Tx) init() { tx.AnnouncementRead = NewAnnouncementReadClient(tx.config) tx.AuthIdentity = NewAuthIdentityClient(tx.config) tx.AuthIdentityChannel = NewAuthIdentityChannelClient(tx.config) + tx.ChannelMonitor = NewChannelMonitorClient(tx.config) + tx.ChannelMonitorDailyRollup = NewChannelMonitorDailyRollupClient(tx.config) + tx.ChannelMonitorHistory = NewChannelMonitorHistoryClient(tx.config) + tx.ChannelMonitorRequestTemplate = NewChannelMonitorRequestTemplateClient(tx.config) tx.ErrorPassthroughRule = NewErrorPassthroughRuleClient(tx.config) tx.Group = NewGroupClient(tx.config) tx.IdempotencyRecord = NewIdempotencyRecordClient(tx.config) diff --git a/backend/go.sum b/backend/go.sum index af6dc81a..0f366ee1 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -183,6 +183,8 @@ github.com/icholy/digest v1.1.0 h1:HfGg9Irj7i+IX1o1QAmPfIBNu/Q5A5Tu3n/MED9k9H4= github.com/icholy/digest v1.1.0/go.mod h1:QNrsSGQ5v7v9cReDI0+eyjsXGUoRSUZQHeQ5C4XLa0Y= github.com/imroc/req/v3 v3.57.0 h1:LMTUjNRUybUkTPn8oJDq8Kg3JRBOBTcnDhKu7mzupKI= github.com/imroc/req/v3 v3.57.0/go.mod h1:JL62ey1nvSLq81HORNcosvlf7SxZStONNqOprg0Pz00= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= diff --git a/backend/internal/handler/admin/channel_handler.go b/backend/internal/handler/admin/channel_handler.go index 9151d018..950e6e72 100644 --- a/backend/internal/handler/admin/channel_handler.go +++ b/backend/internal/handler/admin/channel_handler.go @@ -158,9 +158,6 @@ func channelToResponse(ch *service.Channel) *channelResponse { UpdatedAt: ch.UpdatedAt.Format("2006-01-02T15:04:05Z"), } resp.BillingModelSource = ch.BillingModelSource - if resp.BillingModelSource == "" { - resp.BillingModelSource = service.BillingModelSourceChannelMapped - } if resp.GroupIDs == nil { resp.GroupIDs = []int64{} } diff --git a/backend/internal/handler/admin/channel_handler_test.go b/backend/internal/handler/admin/channel_handler_test.go index f218cce4..12cd4bdd 100644 --- a/backend/internal/handler/admin/channel_handler_test.go +++ b/backend/internal/handler/admin/channel_handler_test.go @@ -91,7 +91,7 @@ func TestChannelToResponse_EmptyDefaults(t *testing.T) { ch := &service.Channel{ ID: 1, Name: "ch", - BillingModelSource: "", + BillingModelSource: service.BillingModelSourceChannelMapped, CreatedAt: now, UpdatedAt: now, GroupIDs: nil, @@ -105,6 +105,9 @@ func TestChannelToResponse_EmptyDefaults(t *testing.T) { }, } + // handler 层 channelToResponse 现在是纯透传:BillingModelSource 的空值兜底 + // 已下放到 service 层(Create/GetByID/List/Update/ListAvailable 出口统一处理), + // 因此这里构造 fixture 时直接传入归一化后的值。 resp := channelToResponse(ch) require.Equal(t, "channel_mapped", resp.BillingModelSource) require.NotNil(t, resp.GroupIDs) @@ -117,6 +120,19 @@ func TestChannelToResponse_EmptyDefaults(t *testing.T) { require.Equal(t, "token", resp.ModelPricing[0].BillingMode) } +func TestChannelToResponse_BillingModelSourcePassthrough(t *testing.T) { + // handler 不再兜底 BillingModelSource:空值应原样透传(由 service 层负责默认回填)。 + ch := &service.Channel{ + ID: 1, + Name: "ch", + BillingModelSource: "", + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } + resp := channelToResponse(ch) + require.Equal(t, "", resp.BillingModelSource, "handler 应纯透传,默认值由 service.normalizeBillingModelSource 负责") +} + func TestChannelToResponse_NilModels(t *testing.T) { now := time.Now() ch := &service.Channel{ diff --git a/backend/internal/handler/admin/channel_monitor_handler.go b/backend/internal/handler/admin/channel_monitor_handler.go new file mode 100644 index 00000000..e92c81fe --- /dev/null +++ b/backend/internal/handler/admin/channel_monitor_handler.go @@ -0,0 +1,427 @@ +package admin + +import ( + "strconv" + "strings" + "time" + + "github.com/Wei-Shaw/sub2api/internal/handler/dto" + infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors" + "github.com/Wei-Shaw/sub2api/internal/pkg/response" + middleware2 "github.com/Wei-Shaw/sub2api/internal/server/middleware" + "github.com/Wei-Shaw/sub2api/internal/service" + + "github.com/gin-gonic/gin" +) + +const ( + // monitorMaxPageSize 列表分页上限。 + monitorMaxPageSize = 100 + // monitorAPIKeyMaskPrefix 脱敏时保留的明文前缀长度。 + monitorAPIKeyMaskPrefix = 4 + // monitorAPIKeyMaskSuffix 脱敏后追加的占位字符串。 + monitorAPIKeyMaskSuffix = "***" +) + +// ChannelMonitorHandler 渠道监控管理后台 handler。 +type ChannelMonitorHandler struct { + monitorService *service.ChannelMonitorService +} + +// NewChannelMonitorHandler 创建 handler。 +func NewChannelMonitorHandler(monitorService *service.ChannelMonitorService) *ChannelMonitorHandler { + return &ChannelMonitorHandler{monitorService: monitorService} +} + +// --- Request / Response --- + +type channelMonitorCreateRequest struct { + Name string `json:"name" binding:"required,max=100"` + Provider string `json:"provider" binding:"required,oneof=openai anthropic gemini"` + Endpoint string `json:"endpoint" binding:"required,max=500"` + APIKey string `json:"api_key" binding:"required,max=2000"` + PrimaryModel string `json:"primary_model" binding:"required,max=200"` + ExtraModels []string `json:"extra_models"` + GroupName string `json:"group_name" binding:"max=100"` + Enabled *bool `json:"enabled"` + IntervalSeconds int `json:"interval_seconds" binding:"required,min=15,max=3600"` + TemplateID *int64 `json:"template_id"` + ExtraHeaders map[string]string `json:"extra_headers"` + BodyOverrideMode string `json:"body_override_mode" binding:"omitempty,oneof=off merge replace"` + BodyOverride map[string]any `json:"body_override"` +} + +type channelMonitorUpdateRequest struct { + Name *string `json:"name" binding:"omitempty,max=100"` + Provider *string `json:"provider" binding:"omitempty,oneof=openai anthropic gemini"` + Endpoint *string `json:"endpoint" binding:"omitempty,max=500"` + APIKey *string `json:"api_key" binding:"omitempty,max=2000"` + PrimaryModel *string `json:"primary_model" binding:"omitempty,max=200"` + ExtraModels *[]string `json:"extra_models"` + GroupName *string `json:"group_name" binding:"omitempty,max=100"` + Enabled *bool `json:"enabled"` + IntervalSeconds *int `json:"interval_seconds" binding:"omitempty,min=15,max=3600"` + TemplateID *int64 `json:"template_id"` + ClearTemplate bool `json:"clear_template"` // true 时把 template_id 置空,忽略 TemplateID + ExtraHeaders *map[string]string `json:"extra_headers"` + BodyOverrideMode *string `json:"body_override_mode" binding:"omitempty,oneof=off merge replace"` + BodyOverride *map[string]any `json:"body_override"` +} + +type channelMonitorResponse struct { + ID int64 `json:"id"` + Name string `json:"name"` + Provider string `json:"provider"` + Endpoint string `json:"endpoint"` + APIKeyMasked string `json:"api_key_masked"` + APIKeyDecryptFailed bool `json:"api_key_decrypt_failed"` + PrimaryModel string `json:"primary_model"` + ExtraModels []string `json:"extra_models"` + GroupName string `json:"group_name"` + Enabled bool `json:"enabled"` + IntervalSeconds int `json:"interval_seconds"` + LastCheckedAt *string `json:"last_checked_at"` + CreatedBy int64 `json:"created_by"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` + PrimaryStatus string `json:"primary_status"` + PrimaryLatencyMs *int `json:"primary_latency_ms"` + Availability7d float64 `json:"availability_7d"` + ExtraModelsStatus []dto.ChannelMonitorExtraModelStatus `json:"extra_models_status"` + // 请求自定义快照:前端编辑 / 展示「高级设置」用 + TemplateID *int64 `json:"template_id"` + ExtraHeaders map[string]string `json:"extra_headers"` + BodyOverrideMode string `json:"body_override_mode"` + BodyOverride map[string]any `json:"body_override"` +} + +type channelMonitorCheckResultResponse struct { + Model string `json:"model"` + Status string `json:"status"` + LatencyMs *int `json:"latency_ms"` + PingLatencyMs *int `json:"ping_latency_ms"` + Message string `json:"message"` + CheckedAt string `json:"checked_at"` +} + +type channelMonitorHistoryItemResponse struct { + ID int64 `json:"id"` + Model string `json:"model"` + Status string `json:"status"` + LatencyMs *int `json:"latency_ms"` + PingLatencyMs *int `json:"ping_latency_ms"` + Message string `json:"message"` + CheckedAt string `json:"checked_at"` +} + +// maskAPIKey 对 API Key 明文做脱敏:前 4 字符 + "***",长度 ≤ 4 时只显示 "***"。 +func maskAPIKey(plain string) string { + if len(plain) <= monitorAPIKeyMaskPrefix { + return monitorAPIKeyMaskSuffix + } + return plain[:monitorAPIKeyMaskPrefix] + monitorAPIKeyMaskSuffix +} + +func channelMonitorToResponse(m *service.ChannelMonitor) *channelMonitorResponse { + if m == nil { + return nil + } + extras := m.ExtraModels + if extras == nil { + extras = []string{} + } + headers := m.ExtraHeaders + if headers == nil { + headers = map[string]string{} + } + resp := &channelMonitorResponse{ + ID: m.ID, + Name: m.Name, + Provider: m.Provider, + Endpoint: m.Endpoint, + APIKeyMasked: maskAPIKey(m.APIKey), + APIKeyDecryptFailed: m.APIKeyDecryptFailed, + PrimaryModel: m.PrimaryModel, + ExtraModels: extras, + GroupName: m.GroupName, + Enabled: m.Enabled, + IntervalSeconds: m.IntervalSeconds, + CreatedBy: m.CreatedBy, + CreatedAt: m.CreatedAt.UTC().Format(time.RFC3339), + UpdatedAt: m.UpdatedAt.UTC().Format(time.RFC3339), + TemplateID: m.TemplateID, + ExtraHeaders: headers, + BodyOverrideMode: m.BodyOverrideMode, + BodyOverride: m.BodyOverride, + // PrimaryStatus / PrimaryLatencyMs / Availability7d 由 List handler 在批量聚合后填充。 + } + if m.LastCheckedAt != nil { + s := m.LastCheckedAt.UTC().Format(time.RFC3339) + resp.LastCheckedAt = &s + } + return resp +} + +func checkResultToResponse(r *service.CheckResult) channelMonitorCheckResultResponse { + return channelMonitorCheckResultResponse{ + Model: r.Model, + Status: r.Status, + LatencyMs: r.LatencyMs, + PingLatencyMs: r.PingLatencyMs, + Message: r.Message, + CheckedAt: r.CheckedAt.UTC().Format(time.RFC3339), + } +} + +func historyEntryToResponse(e *service.ChannelMonitorHistoryEntry) channelMonitorHistoryItemResponse { + return channelMonitorHistoryItemResponse{ + ID: e.ID, + Model: e.Model, + Status: e.Status, + LatencyMs: e.LatencyMs, + PingLatencyMs: e.PingLatencyMs, + Message: e.Message, + CheckedAt: e.CheckedAt.UTC().Format(time.RFC3339), + } +} + +// ParseChannelMonitorID 提取并校验路径参数 :id(admin 与 user handler 共享)。 +// 校验失败时已写入 4xx 响应,调用方只需 return。 +func ParseChannelMonitorID(c *gin.Context) (int64, bool) { + id, err := strconv.ParseInt(c.Param("id"), 10, 64) + if err != nil || id <= 0 { + response.ErrorFrom(c, infraerrors.BadRequest("INVALID_MONITOR_ID", "invalid monitor id")) + return 0, false + } + return id, true +} + +// parseListEnabled 解析 enabled query 参数:true/false 转为 *bool,空或非法则返回 nil。 +func parseListEnabled(raw string) *bool { + switch strings.ToLower(strings.TrimSpace(raw)) { + case "true", "1", "yes": + v := true + return &v + case "false", "0", "no": + v := false + return &v + default: + return nil + } +} + +// --- Handlers --- + +// List GET /api/v1/admin/channel-monitors +func (h *ChannelMonitorHandler) List(c *gin.Context) { + page, pageSize := response.ParsePagination(c) + if pageSize > monitorMaxPageSize { + pageSize = monitorMaxPageSize + } + + params := service.ChannelMonitorListParams{ + Page: page, + PageSize: pageSize, + Provider: strings.TrimSpace(c.Query("provider")), + Enabled: parseListEnabled(c.Query("enabled")), + Search: strings.TrimSpace(c.Query("search")), + } + + items, total, err := h.monitorService.List(c.Request.Context(), params) + if err != nil { + response.ErrorFrom(c, err) + return + } + + summaries := h.batchSummaryFor(c, items) + out := make([]*channelMonitorResponse, 0, len(items)) + for _, m := range items { + out = append(out, buildListItemResponse(m, summaries[m.ID])) + } + response.Paginated(c, out, total, page, pageSize) +} + +// batchSummaryFor 批量聚合 latest + 7d 可用率,避免每行 2 次 SQL(消除 N+1)。 +func (h *ChannelMonitorHandler) batchSummaryFor(c *gin.Context, items []*service.ChannelMonitor) map[int64]service.MonitorStatusSummary { + ids := make([]int64, 0, len(items)) + primaryByID := make(map[int64]string, len(items)) + extrasByID := make(map[int64][]string, len(items)) + for _, m := range items { + ids = append(ids, m.ID) + primaryByID[m.ID] = m.PrimaryModel + extrasByID[m.ID] = m.ExtraModels + } + return h.monitorService.BatchMonitorStatusSummary(c.Request.Context(), ids, primaryByID, extrasByID) +} + +// buildListItemResponse 把 monitor + summary 装成 admin list 的响应行。 +func buildListItemResponse(m *service.ChannelMonitor, summary service.MonitorStatusSummary) *channelMonitorResponse { + resp := channelMonitorToResponse(m) + resp.PrimaryStatus = summary.PrimaryStatus + resp.PrimaryLatencyMs = summary.PrimaryLatencyMs + resp.Availability7d = summary.Availability7d + resp.ExtraModelsStatus = make([]dto.ChannelMonitorExtraModelStatus, 0, len(summary.ExtraModels)) + for _, e := range summary.ExtraModels { + resp.ExtraModelsStatus = append(resp.ExtraModelsStatus, dto.ChannelMonitorExtraModelStatus{ + Model: e.Model, + Status: e.Status, + LatencyMs: e.LatencyMs, + }) + } + return resp +} + +// Get GET /api/v1/admin/channel-monitors/:id +func (h *ChannelMonitorHandler) Get(c *gin.Context) { + id, ok := ParseChannelMonitorID(c) + if !ok { + return + } + m, err := h.monitorService.Get(c.Request.Context(), id) + if err != nil { + response.ErrorFrom(c, err) + return + } + response.Success(c, channelMonitorToResponse(m)) +} + +// Create POST /api/v1/admin/channel-monitors +func (h *ChannelMonitorHandler) Create(c *gin.Context) { + var req channelMonitorCreateRequest + if err := c.ShouldBindJSON(&req); err != nil { + response.ErrorFrom(c, infraerrors.BadRequest("VALIDATION_ERROR", err.Error())) + return + } + + subject, _ := middleware2.GetAuthSubjectFromContext(c) + + enabled := true + if req.Enabled != nil { + enabled = *req.Enabled + } + + m, err := h.monitorService.Create(c.Request.Context(), service.ChannelMonitorCreateParams{ + Name: req.Name, + Provider: req.Provider, + Endpoint: req.Endpoint, + APIKey: req.APIKey, + PrimaryModel: req.PrimaryModel, + ExtraModels: req.ExtraModels, + GroupName: req.GroupName, + Enabled: enabled, + IntervalSeconds: req.IntervalSeconds, + CreatedBy: subject.UserID, + TemplateID: req.TemplateID, + ExtraHeaders: req.ExtraHeaders, + BodyOverrideMode: req.BodyOverrideMode, + BodyOverride: req.BodyOverride, + }) + if err != nil { + response.ErrorFrom(c, err) + return + } + response.Created(c, channelMonitorToResponse(m)) +} + +// Update PUT /api/v1/admin/channel-monitors/:id +func (h *ChannelMonitorHandler) Update(c *gin.Context) { + id, ok := ParseChannelMonitorID(c) + if !ok { + return + } + var req channelMonitorUpdateRequest + if err := c.ShouldBindJSON(&req); err != nil { + response.ErrorFrom(c, infraerrors.BadRequest("VALIDATION_ERROR", err.Error())) + return + } + + m, err := h.monitorService.Update(c.Request.Context(), id, service.ChannelMonitorUpdateParams{ + Name: req.Name, + Provider: req.Provider, + Endpoint: req.Endpoint, + APIKey: req.APIKey, + PrimaryModel: req.PrimaryModel, + ExtraModels: req.ExtraModels, + GroupName: req.GroupName, + Enabled: req.Enabled, + IntervalSeconds: req.IntervalSeconds, + TemplateID: req.TemplateID, + ClearTemplate: req.ClearTemplate, + ExtraHeaders: req.ExtraHeaders, + BodyOverrideMode: req.BodyOverrideMode, + BodyOverride: req.BodyOverride, + }) + if err != nil { + response.ErrorFrom(c, err) + return + } + response.Success(c, channelMonitorToResponse(m)) +} + +// Delete DELETE /api/v1/admin/channel-monitors/:id +func (h *ChannelMonitorHandler) Delete(c *gin.Context) { + id, ok := ParseChannelMonitorID(c) + if !ok { + return + } + if err := h.monitorService.Delete(c.Request.Context(), id); err != nil { + response.ErrorFrom(c, err) + return + } + response.Success(c, nil) +} + +// Run POST /api/v1/admin/channel-monitors/:id/run +func (h *ChannelMonitorHandler) Run(c *gin.Context) { + id, ok := ParseChannelMonitorID(c) + if !ok { + return + } + results, err := h.monitorService.RunCheck(c.Request.Context(), id) + if err != nil { + response.ErrorFrom(c, err) + return + } + out := make([]channelMonitorCheckResultResponse, 0, len(results)) + for _, r := range results { + out = append(out, checkResultToResponse(r)) + } + response.Success(c, gin.H{"results": out}) +} + +// History GET /api/v1/admin/channel-monitors/:id/history +func (h *ChannelMonitorHandler) History(c *gin.Context) { + id, ok := ParseChannelMonitorID(c) + if !ok { + return + } + limit := parseHistoryLimit(c.Query("limit")) + model := strings.TrimSpace(c.Query("model")) + + entries, err := h.monitorService.ListHistory(c.Request.Context(), id, model, limit) + if err != nil { + response.ErrorFrom(c, err) + return + } + out := make([]channelMonitorHistoryItemResponse, 0, len(entries)) + for _, e := range entries { + out = append(out, historyEntryToResponse(e)) + } + response.Success(c, gin.H{"items": out}) +} + +// parseHistoryLimit 解析 history 接口的 limit query。 +// 使用 service 包的统一上下限常量,避免在 handler 重复定义同名魔法值。 +func parseHistoryLimit(raw string) int { + if strings.TrimSpace(raw) == "" { + return service.MonitorHistoryDefaultLimit + } + v, err := strconv.Atoi(raw) + if err != nil || v <= 0 { + return service.MonitorHistoryDefaultLimit + } + if v > service.MonitorHistoryMaxLimit { + return service.MonitorHistoryMaxLimit + } + return v +} diff --git a/backend/internal/handler/admin/channel_monitor_template_handler.go b/backend/internal/handler/admin/channel_monitor_template_handler.go new file mode 100644 index 00000000..bebe0929 --- /dev/null +++ b/backend/internal/handler/admin/channel_monitor_template_handler.go @@ -0,0 +1,234 @@ +package admin + +import ( + "strconv" + "strings" + "time" + + infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors" + "github.com/Wei-Shaw/sub2api/internal/pkg/response" + "github.com/Wei-Shaw/sub2api/internal/service" + + "github.com/gin-gonic/gin" +) + +// ChannelMonitorRequestTemplateHandler 请求模板管理后台 handler。 +type ChannelMonitorRequestTemplateHandler struct { + templateService *service.ChannelMonitorRequestTemplateService +} + +// NewChannelMonitorRequestTemplateHandler 创建 handler。 +func NewChannelMonitorRequestTemplateHandler(templateService *service.ChannelMonitorRequestTemplateService) *ChannelMonitorRequestTemplateHandler { + return &ChannelMonitorRequestTemplateHandler{templateService: templateService} +} + +// --- DTO --- + +type channelMonitorTemplateCreateRequest struct { + Name string `json:"name" binding:"required,max=100"` + Provider string `json:"provider" binding:"required,oneof=openai anthropic gemini"` + Description string `json:"description" binding:"max=500"` + ExtraHeaders map[string]string `json:"extra_headers"` + BodyOverrideMode string `json:"body_override_mode" binding:"omitempty,oneof=off merge replace"` + BodyOverride map[string]any `json:"body_override"` +} + +type channelMonitorTemplateUpdateRequest struct { + Name *string `json:"name" binding:"omitempty,max=100"` + Description *string `json:"description" binding:"omitempty,max=500"` + ExtraHeaders *map[string]string `json:"extra_headers"` + BodyOverrideMode *string `json:"body_override_mode" binding:"omitempty,oneof=off merge replace"` + BodyOverride *map[string]any `json:"body_override"` +} + +type channelMonitorTemplateResponse struct { + ID int64 `json:"id"` + Name string `json:"name"` + Provider string `json:"provider"` + Description string `json:"description"` + ExtraHeaders map[string]string `json:"extra_headers"` + BodyOverrideMode string `json:"body_override_mode"` + BodyOverride map[string]any `json:"body_override"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` + AssociatedMonitors int64 `json:"associated_monitors"` +} + +func (h *ChannelMonitorRequestTemplateHandler) toResponse(c *gin.Context, t *service.ChannelMonitorRequestTemplate) *channelMonitorTemplateResponse { + if t == nil { + return nil + } + headers := t.ExtraHeaders + if headers == nil { + headers = map[string]string{} + } + count, _ := h.templateService.CountAssociatedMonitors(c.Request.Context(), t.ID) + return &channelMonitorTemplateResponse{ + ID: t.ID, + Name: t.Name, + Provider: t.Provider, + Description: t.Description, + ExtraHeaders: headers, + BodyOverrideMode: t.BodyOverrideMode, + BodyOverride: t.BodyOverride, + CreatedAt: t.CreatedAt.UTC().Format(time.RFC3339), + UpdatedAt: t.UpdatedAt.UTC().Format(time.RFC3339), + AssociatedMonitors: count, + } +} + +// parseTemplateID 提取并校验 :id。 +func parseTemplateID(c *gin.Context) (int64, bool) { + id, err := strconv.ParseInt(c.Param("id"), 10, 64) + if err != nil || id <= 0 { + response.ErrorFrom(c, infraerrors.BadRequest("INVALID_TEMPLATE_ID", "invalid template id")) + return 0, false + } + return id, true +} + +// --- Handlers --- + +// List GET /api/v1/admin/channel-monitor-templates?provider=anthropic +func (h *ChannelMonitorRequestTemplateHandler) List(c *gin.Context) { + items, err := h.templateService.List(c.Request.Context(), service.ChannelMonitorRequestTemplateListParams{ + Provider: strings.TrimSpace(c.Query("provider")), + }) + if err != nil { + response.ErrorFrom(c, err) + return + } + out := make([]*channelMonitorTemplateResponse, 0, len(items)) + for _, t := range items { + out = append(out, h.toResponse(c, t)) + } + response.Success(c, gin.H{"items": out}) +} + +// Get GET /api/v1/admin/channel-monitor-templates/:id +func (h *ChannelMonitorRequestTemplateHandler) Get(c *gin.Context) { + id, ok := parseTemplateID(c) + if !ok { + return + } + t, err := h.templateService.Get(c.Request.Context(), id) + if err != nil { + response.ErrorFrom(c, err) + return + } + response.Success(c, h.toResponse(c, t)) +} + +// Create POST /api/v1/admin/channel-monitor-templates +func (h *ChannelMonitorRequestTemplateHandler) Create(c *gin.Context) { + var req channelMonitorTemplateCreateRequest + if err := c.ShouldBindJSON(&req); err != nil { + response.ErrorFrom(c, infraerrors.BadRequest("VALIDATION_ERROR", err.Error())) + return + } + t, err := h.templateService.Create(c.Request.Context(), service.ChannelMonitorRequestTemplateCreateParams{ + Name: req.Name, + Provider: req.Provider, + Description: req.Description, + ExtraHeaders: req.ExtraHeaders, + BodyOverrideMode: req.BodyOverrideMode, + BodyOverride: req.BodyOverride, + }) + if err != nil { + response.ErrorFrom(c, err) + return + } + response.Created(c, h.toResponse(c, t)) +} + +// Update PUT /api/v1/admin/channel-monitor-templates/:id +func (h *ChannelMonitorRequestTemplateHandler) Update(c *gin.Context) { + id, ok := parseTemplateID(c) + if !ok { + return + } + var req channelMonitorTemplateUpdateRequest + if err := c.ShouldBindJSON(&req); err != nil { + response.ErrorFrom(c, infraerrors.BadRequest("VALIDATION_ERROR", err.Error())) + return + } + t, err := h.templateService.Update(c.Request.Context(), id, service.ChannelMonitorRequestTemplateUpdateParams{ + Name: req.Name, + Description: req.Description, + ExtraHeaders: req.ExtraHeaders, + BodyOverrideMode: req.BodyOverrideMode, + BodyOverride: req.BodyOverride, + }) + if err != nil { + response.ErrorFrom(c, err) + return + } + response.Success(c, h.toResponse(c, t)) +} + +// Delete DELETE /api/v1/admin/channel-monitor-templates/:id +func (h *ChannelMonitorRequestTemplateHandler) Delete(c *gin.Context) { + id, ok := parseTemplateID(c) + if !ok { + return + } + if err := h.templateService.Delete(c.Request.Context(), id); err != nil { + response.ErrorFrom(c, err) + return + } + response.Success(c, nil) +} + +type channelMonitorTemplateApplyRequest struct { + // MonitorIDs 必填、非空:用户在 picker 里勾选的要被覆盖的监控 ID 列表。 + // 仅当对应监控当前 template_id == :id 时才会真的被覆盖。 + MonitorIDs []int64 `json:"monitor_ids" binding:"required,min=1"` +} + +// Apply POST /api/v1/admin/channel-monitor-templates/:id/apply +// 把模板当前配置覆盖到 monitor_ids 列表里的关联监控(picker 选中的子集)。 +func (h *ChannelMonitorRequestTemplateHandler) Apply(c *gin.Context) { + id, ok := parseTemplateID(c) + if !ok { + return + } + var req channelMonitorTemplateApplyRequest + if err := c.ShouldBindJSON(&req); err != nil { + response.ErrorFrom(c, infraerrors.BadRequest("VALIDATION_ERROR", err.Error())) + return + } + affected, err := h.templateService.ApplyToMonitors(c.Request.Context(), id, req.MonitorIDs) + if err != nil { + response.ErrorFrom(c, err) + return + } + response.Success(c, gin.H{"affected": affected}) +} + +type associatedMonitorBriefResponse struct { + ID int64 `json:"id"` + Name string `json:"name"` + Provider string `json:"provider"` + Enabled bool `json:"enabled"` +} + +// AssociatedMonitors GET /api/v1/admin/channel-monitor-templates/:id/monitors +// 列出关联监控(picker 弹窗用)。 +func (h *ChannelMonitorRequestTemplateHandler) AssociatedMonitors(c *gin.Context) { + id, ok := parseTemplateID(c) + if !ok { + return + } + items, err := h.templateService.ListAssociatedMonitors(c.Request.Context(), id) + if err != nil { + response.ErrorFrom(c, err) + return + } + out := make([]associatedMonitorBriefResponse, 0, len(items)) + for _, m := range items { + out = append(out, associatedMonitorBriefResponse{ + ID: m.ID, Name: m.Name, Provider: m.Provider, Enabled: m.Enabled, + }) + } + response.Success(c, gin.H{"items": out}) +} diff --git a/backend/internal/handler/admin/setting_handler.go b/backend/internal/handler/admin/setting_handler.go index 11e7a652..4277f0f1 100644 --- a/backend/internal/handler/admin/setting_handler.go +++ b/backend/internal/handler/admin/setting_handler.go @@ -236,6 +236,11 @@ func (h *SettingHandler) GetSettings(c *gin.Context) { PaymentCancelRateLimitWindow: paymentCfg.CancelRateLimitWindow, PaymentCancelRateLimitUnit: paymentCfg.CancelRateLimitUnit, PaymentCancelRateLimitMode: paymentCfg.CancelRateLimitMode, + + ChannelMonitorEnabled: settings.ChannelMonitorEnabled, + ChannelMonitorDefaultIntervalSeconds: settings.ChannelMonitorDefaultIntervalSeconds, + + AvailableChannelsEnabled: settings.AvailableChannelsEnabled, } response.Success(c, systemSettingsResponseData(payload, authSourceDefaults)) } @@ -427,6 +432,13 @@ type UpdateSettingsRequest struct { PaymentCancelRateLimitWindow *int `json:"payment_cancel_rate_limit_window"` PaymentCancelRateLimitUnit *string `json:"payment_cancel_rate_limit_unit"` PaymentCancelRateLimitMode *string `json:"payment_cancel_rate_limit_window_mode"` + + // Channel Monitor feature switch + ChannelMonitorEnabled *bool `json:"channel_monitor_enabled"` + ChannelMonitorDefaultIntervalSeconds *int `json:"channel_monitor_default_interval_seconds"` + + // Available Channels feature switch (user-facing) + AvailableChannelsEnabled *bool `json:"available_channels_enabled"` } // UpdateSettings 更新系统设置 @@ -1222,6 +1234,24 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) { } return previousSettings.AccountQuotaNotifyEmails }(), + ChannelMonitorEnabled: func() bool { + if req.ChannelMonitorEnabled != nil { + return *req.ChannelMonitorEnabled + } + return previousSettings.ChannelMonitorEnabled + }(), + ChannelMonitorDefaultIntervalSeconds: func() int { + if req.ChannelMonitorDefaultIntervalSeconds != nil { + return *req.ChannelMonitorDefaultIntervalSeconds + } + return previousSettings.ChannelMonitorDefaultIntervalSeconds + }(), + AvailableChannelsEnabled: func() bool { + if req.AvailableChannelsEnabled != nil { + return *req.AvailableChannelsEnabled + } + return previousSettings.AvailableChannelsEnabled + }(), } authSourceDefaults := &service.AuthSourceDefaultSettings{ @@ -1453,6 +1483,11 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) { PaymentCancelRateLimitWindow: updatedPaymentCfg.CancelRateLimitWindow, PaymentCancelRateLimitUnit: updatedPaymentCfg.CancelRateLimitUnit, PaymentCancelRateLimitMode: updatedPaymentCfg.CancelRateLimitMode, + + ChannelMonitorEnabled: updatedSettings.ChannelMonitorEnabled, + ChannelMonitorDefaultIntervalSeconds: updatedSettings.ChannelMonitorDefaultIntervalSeconds, + + AvailableChannelsEnabled: updatedSettings.AvailableChannelsEnabled, } response.Success(c, systemSettingsResponseData(payload, updatedAuthSourceDefaults)) } @@ -1809,6 +1844,15 @@ func diffSettings(before *service.SystemSettings, after *service.SystemSettings, if !equalNotifyEmailEntries(before.AccountQuotaNotifyEmails, after.AccountQuotaNotifyEmails) { changed = append(changed, "account_quota_notify_emails") } + if before.ChannelMonitorEnabled != after.ChannelMonitorEnabled { + changed = append(changed, "channel_monitor_enabled") + } + if before.ChannelMonitorDefaultIntervalSeconds != after.ChannelMonitorDefaultIntervalSeconds { + changed = append(changed, "channel_monitor_default_interval_seconds") + } + if before.AvailableChannelsEnabled != after.AvailableChannelsEnabled { + changed = append(changed, "available_channels_enabled") + } changed = appendAuthSourceDefaultChanges(changed, beforeAuthSourceDefaults, afterAuthSourceDefaults) return changed } diff --git a/backend/internal/handler/available_channel_handler.go b/backend/internal/handler/available_channel_handler.go new file mode 100644 index 00000000..8982b80d --- /dev/null +++ b/backend/internal/handler/available_channel_handler.go @@ -0,0 +1,283 @@ +package handler + +import ( + "sort" + + "github.com/Wei-Shaw/sub2api/internal/pkg/response" + "github.com/Wei-Shaw/sub2api/internal/server/middleware" + "github.com/Wei-Shaw/sub2api/internal/service" + + "github.com/gin-gonic/gin" +) + +// AvailableChannelHandler 处理用户侧「可用渠道」查询。 +// +// 用户侧接口委托 ChannelService.ListAvailable,并在返回前做三层过滤: +// 1. 行过滤:只保留状态为 Active 且与当前用户可访问分组有交集的渠道; +// 2. 分组过滤:渠道的 Groups 只保留用户可访问的那些; +// 3. 平台过滤:渠道的 SupportedModels 只保留平台在用户可见 Groups 中出现过的模型, +// 防止"渠道同时挂在 antigravity / anthropic 两个平台的分组上,用户只访问 +// antigravity,却看到 anthropic 模型"这类跨平台信息泄漏; +// 4. 字段白名单:仅返回用户需要的字段(省略 BillingModelSource / RestrictModels +// / 内部 ID / Status 等管理字段)。 +type AvailableChannelHandler struct { + channelService *service.ChannelService + apiKeyService *service.APIKeyService + settingService *service.SettingService +} + +// NewAvailableChannelHandler 创建用户侧可用渠道 handler。 +func NewAvailableChannelHandler( + channelService *service.ChannelService, + apiKeyService *service.APIKeyService, + settingService *service.SettingService, +) *AvailableChannelHandler { + return &AvailableChannelHandler{ + channelService: channelService, + apiKeyService: apiKeyService, + settingService: settingService, + } +} + +// featureEnabled 返回 available-channels 开关是否启用。默认关闭(opt-in)。 +func (h *AvailableChannelHandler) featureEnabled(c *gin.Context) bool { + if h.settingService == nil { + return false + } + return h.settingService.GetAvailableChannelsRuntime(c.Request.Context()).Enabled +} + +// userAvailableGroup 用户可见的分组概要(白名单字段)。 +// +// 前端据此区分专属 vs 公开分组(IsExclusive)、订阅 vs 标准分组(SubscriptionType, +// 订阅视觉加深),并用 RateMultiplier 作为默认倍率;用户专属倍率前端走 +// /groups/rates,和 API 密钥页面保持一致。 +type userAvailableGroup struct { + ID int64 `json:"id"` + Name string `json:"name"` + Platform string `json:"platform"` + SubscriptionType string `json:"subscription_type"` + RateMultiplier float64 `json:"rate_multiplier"` + IsExclusive bool `json:"is_exclusive"` +} + +// userSupportedModelPricing 用户可见的定价字段白名单。 +type userSupportedModelPricing struct { + BillingMode string `json:"billing_mode"` + InputPrice *float64 `json:"input_price"` + OutputPrice *float64 `json:"output_price"` + CacheWritePrice *float64 `json:"cache_write_price"` + CacheReadPrice *float64 `json:"cache_read_price"` + ImageOutputPrice *float64 `json:"image_output_price"` + PerRequestPrice *float64 `json:"per_request_price"` + Intervals []userPricingIntervalDTO `json:"intervals"` +} + +// userPricingIntervalDTO 定价区间白名单(去掉内部 ID、SortOrder 等前端不渲染的字段)。 +type userPricingIntervalDTO struct { + MinTokens int `json:"min_tokens"` + MaxTokens *int `json:"max_tokens"` + TierLabel string `json:"tier_label,omitempty"` + InputPrice *float64 `json:"input_price"` + OutputPrice *float64 `json:"output_price"` + CacheWritePrice *float64 `json:"cache_write_price"` + CacheReadPrice *float64 `json:"cache_read_price"` + PerRequestPrice *float64 `json:"per_request_price"` +} + +// userSupportedModel 用户可见的支持模型条目。 +type userSupportedModel struct { + Name string `json:"name"` + Platform string `json:"platform"` + Pricing *userSupportedModelPricing `json:"pricing"` +} + +// userChannelPlatformSection 单渠道内某个平台的子视图:用户可见的分组 + 该平台 +// 支持的模型。按 platform 聚合后让前端可以把渠道名作为 row-group 一次渲染, +// 后面的平台行按 sections 顺序铺开。 +type userChannelPlatformSection struct { + Platform string `json:"platform"` + Groups []userAvailableGroup `json:"groups"` + SupportedModels []userSupportedModel `json:"supported_models"` +} + +// userAvailableChannel 用户可见的渠道条目(白名单字段)。 +// +// 每个渠道聚合为一条记录,内嵌 platforms 子数组:每个 section 对应一个平台, +// 包含该平台的 groups 和 supported_models。 +type userAvailableChannel struct { + Name string `json:"name"` + Description string `json:"description"` + Platforms []userChannelPlatformSection `json:"platforms"` +} + +// List 列出当前用户可见的「可用渠道」。 +// GET /api/v1/channels/available +func (h *AvailableChannelHandler) List(c *gin.Context) { + subject, ok := middleware.GetAuthSubjectFromContext(c) + if !ok { + response.Unauthorized(c, "User not authenticated") + return + } + + // Feature 未启用时返回空数组(不暴露渠道信息)。检查放在认证之后, + // 保持与未开关前的 401 行为一致:未登录先 401,登录后再按开关决定。 + if !h.featureEnabled(c) { + response.Success(c, []userAvailableChannel{}) + return + } + + userGroups, err := h.apiKeyService.GetAvailableGroups(c.Request.Context(), subject.UserID) + if err != nil { + response.ErrorFrom(c, err) + return + } + allowedGroupIDs := make(map[int64]struct{}, len(userGroups)) + for i := range userGroups { + allowedGroupIDs[userGroups[i].ID] = struct{}{} + } + + channels, err := h.channelService.ListAvailable(c.Request.Context()) + if err != nil { + response.ErrorFrom(c, err) + return + } + + out := make([]userAvailableChannel, 0, len(channels)) + for _, ch := range channels { + if ch.Status != service.StatusActive { + continue + } + visibleGroups := filterUserVisibleGroups(ch.Groups, allowedGroupIDs) + if len(visibleGroups) == 0 { + continue + } + sections := buildPlatformSections(ch, visibleGroups) + if len(sections) == 0 { + continue + } + out = append(out, userAvailableChannel{ + Name: ch.Name, + Description: ch.Description, + Platforms: sections, + }) + } + + response.Success(c, out) +} + +// buildPlatformSections 把一个渠道按 visibleGroups 的平台集合拆成有序的 section 列表: +// 每个 section 对应一个平台,只包含该平台的 groups 和 supported_models。 +// 输出按 platform 字母序稳定排序,便于前端等效比较与回归测试。 +func buildPlatformSections( + ch service.AvailableChannel, + visibleGroups []userAvailableGroup, +) []userChannelPlatformSection { + groupsByPlatform := make(map[string][]userAvailableGroup, 4) + for _, g := range visibleGroups { + if g.Platform == "" { + continue + } + groupsByPlatform[g.Platform] = append(groupsByPlatform[g.Platform], g) + } + if len(groupsByPlatform) == 0 { + return nil + } + + platforms := make([]string, 0, len(groupsByPlatform)) + for p := range groupsByPlatform { + platforms = append(platforms, p) + } + sort.Strings(platforms) + + sections := make([]userChannelPlatformSection, 0, len(platforms)) + for _, platform := range platforms { + platformSet := map[string]struct{}{platform: {}} + sections = append(sections, userChannelPlatformSection{ + Platform: platform, + Groups: groupsByPlatform[platform], + SupportedModels: toUserSupportedModels(ch.SupportedModels, platformSet), + }) + } + return sections +} + +// filterUserVisibleGroups 仅保留用户可访问的分组。 +func filterUserVisibleGroups( + groups []service.AvailableGroupRef, + allowed map[int64]struct{}, +) []userAvailableGroup { + visible := make([]userAvailableGroup, 0, len(groups)) + for _, g := range groups { + if _, ok := allowed[g.ID]; !ok { + continue + } + visible = append(visible, userAvailableGroup{ + ID: g.ID, + Name: g.Name, + Platform: g.Platform, + SubscriptionType: g.SubscriptionType, + RateMultiplier: g.RateMultiplier, + IsExclusive: g.IsExclusive, + }) + } + return visible +} + +// toUserSupportedModels 将 service 层支持模型转换为用户 DTO(字段白名单)。 +// 仅保留平台在 allowedPlatforms 中的条目,防止跨平台模型信息泄漏。 +// allowedPlatforms 为 nil 时不做平台过滤(保留全部,供测试或明确无过滤场景使用)。 +func toUserSupportedModels( + src []service.SupportedModel, + allowedPlatforms map[string]struct{}, +) []userSupportedModel { + out := make([]userSupportedModel, 0, len(src)) + for i := range src { + m := src[i] + if allowedPlatforms != nil { + if _, ok := allowedPlatforms[m.Platform]; !ok { + continue + } + } + out = append(out, userSupportedModel{ + Name: m.Name, + Platform: m.Platform, + Pricing: toUserPricing(m.Pricing), + }) + } + return out +} + +// toUserPricing 将 service 层定价转换为用户 DTO;入参为 nil 时返回 nil。 +func toUserPricing(p *service.ChannelModelPricing) *userSupportedModelPricing { + if p == nil { + return nil + } + intervals := make([]userPricingIntervalDTO, 0, len(p.Intervals)) + for _, iv := range p.Intervals { + intervals = append(intervals, userPricingIntervalDTO{ + MinTokens: iv.MinTokens, + MaxTokens: iv.MaxTokens, + TierLabel: iv.TierLabel, + InputPrice: iv.InputPrice, + OutputPrice: iv.OutputPrice, + CacheWritePrice: iv.CacheWritePrice, + CacheReadPrice: iv.CacheReadPrice, + PerRequestPrice: iv.PerRequestPrice, + }) + } + billingMode := string(p.BillingMode) + if billingMode == "" { + billingMode = string(service.BillingModeToken) + } + return &userSupportedModelPricing{ + BillingMode: billingMode, + InputPrice: p.InputPrice, + OutputPrice: p.OutputPrice, + CacheWritePrice: p.CacheWritePrice, + CacheReadPrice: p.CacheReadPrice, + ImageOutputPrice: p.ImageOutputPrice, + PerRequestPrice: p.PerRequestPrice, + Intervals: intervals, + } +} diff --git a/backend/internal/handler/available_channel_handler_test.go b/backend/internal/handler/available_channel_handler_test.go new file mode 100644 index 00000000..0a7ce6c4 --- /dev/null +++ b/backend/internal/handler/available_channel_handler_test.go @@ -0,0 +1,157 @@ +//go:build unit + +package handler + +import ( + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/Wei-Shaw/sub2api/internal/service" + + "github.com/gin-gonic/gin" + "github.com/stretchr/testify/require" +) + +func TestUserAvailableChannel_Unauthenticated401(t *testing.T) { + // 没有 AuthSubject 注入时,handler 应返回 401 且不触达 service 依赖。 + gin.SetMode(gin.TestMode) + h := &AvailableChannelHandler{} // nil services — 401 路径不会调用它们 + w := httptest.NewRecorder() + c, _ := gin.CreateTestContext(w) + c.Request = httptest.NewRequest(http.MethodGet, "/api/v1/channels/available", nil) + + h.List(c) + + require.Equal(t, http.StatusUnauthorized, w.Code) +} + +func TestFilterUserVisibleGroups_IntersectionOnly(t *testing.T) { + // 渠道挂在 {g1, g2, g3},用户只允许 {g1, g3} —— 响应必须仅含 g1/g3。 + groups := []service.AvailableGroupRef{ + {ID: 1, Name: "g1", Platform: "anthropic"}, + {ID: 2, Name: "g2", Platform: "anthropic"}, + {ID: 3, Name: "g3", Platform: "openai"}, + } + allowed := map[int64]struct{}{1: {}, 3: {}} + + visible := filterUserVisibleGroups(groups, allowed) + require.Len(t, visible, 2) + ids := []int64{visible[0].ID, visible[1].ID} + require.ElementsMatch(t, []int64{1, 3}, ids) +} + +func TestToUserSupportedModels_FiltersByAllowedPlatforms(t *testing.T) { + // 用户可访问分组只覆盖 anthropic;anthropic 平台的模型保留,openai 模型被剔除。 + src := []service.SupportedModel{ + {Name: "claude-sonnet-4-6", Platform: "anthropic", Pricing: nil}, + {Name: "gpt-4o", Platform: "openai", Pricing: nil}, + } + allowed := map[string]struct{}{"anthropic": {}} + out := toUserSupportedModels(src, allowed) + require.Len(t, out, 1) + require.Equal(t, "claude-sonnet-4-6", out[0].Name) +} + +func TestToUserSupportedModels_NilAllowedPlatformsKeepsAll(t *testing.T) { + // 显式传 nil allowedPlatforms 表示不做过滤。 + src := []service.SupportedModel{ + {Name: "a", Platform: "anthropic"}, + {Name: "b", Platform: "openai"}, + } + require.Len(t, toUserSupportedModels(src, nil), 2) +} + +func TestUserAvailableChannel_FieldWhitelist(t *testing.T) { + // 通过序列化 userAvailableChannel 结构体验证响应形状: + // 只有 name / description / platforms;不含管理端字段。 + row := userAvailableChannel{ + Name: "ch", + Description: "d", + Platforms: []userChannelPlatformSection{ + { + Platform: "anthropic", + Groups: []userAvailableGroup{{ID: 1, Name: "g1", Platform: "anthropic"}}, + SupportedModels: []userSupportedModel{}, + }, + }, + } + raw, err := json.Marshal(row) + require.NoError(t, err) + var decoded map[string]any + require.NoError(t, json.Unmarshal(raw, &decoded)) + + for _, key := range []string{"id", "status", "billing_model_source", "restrict_models"} { + _, exists := decoded[key] + require.Falsef(t, exists, "user DTO must not expose %q", key) + } + for _, key := range []string{"name", "description", "platforms"} { + _, exists := decoded[key] + require.Truef(t, exists, "user DTO must expose %q", key) + } + + // 验证 section 的字段(platform / groups / supported_models)。 + rawSection, err := json.Marshal(row.Platforms[0]) + require.NoError(t, err) + var sectionDecoded map[string]any + require.NoError(t, json.Unmarshal(rawSection, §ionDecoded)) + for _, key := range []string{"platform", "groups", "supported_models"} { + _, exists := sectionDecoded[key] + require.Truef(t, exists, "platform section must expose %q", key) + } + + // Group DTO 暴露区分专属/公开、订阅类型、默认倍率所需的字段, + // 前端据此渲染 GroupBadge 并与 API 密钥页保持一致的视觉。 + rawGroup, err := json.Marshal(row.Platforms[0].Groups[0]) + require.NoError(t, err) + var groupDecoded map[string]any + require.NoError(t, json.Unmarshal(rawGroup, &groupDecoded)) + for _, key := range []string{"id", "name", "platform", "subscription_type", "rate_multiplier", "is_exclusive"} { + _, exists := groupDecoded[key] + require.Truef(t, exists, "group DTO must expose %q", key) + } + + // pricing interval 白名单:不应暴露 id / sort_order。 + pricing := toUserPricing(&service.ChannelModelPricing{ + BillingMode: service.BillingModeToken, + Intervals: []service.PricingInterval{ + {ID: 7, MinTokens: 0, MaxTokens: nil, SortOrder: 3}, + }, + }) + require.NotNil(t, pricing) + require.Len(t, pricing.Intervals, 1) + rawIv, err := json.Marshal(pricing.Intervals[0]) + require.NoError(t, err) + var ivDecoded map[string]any + require.NoError(t, json.Unmarshal(rawIv, &ivDecoded)) + for _, key := range []string{"id", "pricing_id", "sort_order"} { + _, exists := ivDecoded[key] + require.Falsef(t, exists, "user pricing interval must not expose %q", key) + } +} + +func TestBuildPlatformSections_GroupsByPlatform(t *testing.T) { + // 一个渠道横跨 anthropic / openai / 空平台:应该生成 2 个 section, + // 按 platform 字母序排序,各自 groups 和 supported_models 只含同平台条目。 + ch := service.AvailableChannel{ + Name: "ch", + SupportedModels: []service.SupportedModel{ + {Name: "claude-sonnet-4-6", Platform: "anthropic"}, + {Name: "gpt-4o", Platform: "openai"}, + }, + } + visible := []userAvailableGroup{ + {ID: 1, Name: "g-openai", Platform: "openai"}, + {ID: 2, Name: "g-ant", Platform: "anthropic"}, + {ID: 3, Name: "g-empty", Platform: ""}, + } + sections := buildPlatformSections(ch, visible) + require.Len(t, sections, 2) + require.Equal(t, "anthropic", sections[0].Platform) + require.Equal(t, "openai", sections[1].Platform) + require.Len(t, sections[0].Groups, 1) + require.Equal(t, int64(2), sections[0].Groups[0].ID) + require.Len(t, sections[0].SupportedModels, 1) + require.Equal(t, "claude-sonnet-4-6", sections[0].SupportedModels[0].Name) +} diff --git a/backend/internal/handler/channel_monitor_user_handler.go b/backend/internal/handler/channel_monitor_user_handler.go new file mode 100644 index 00000000..cc36b334 --- /dev/null +++ b/backend/internal/handler/channel_monitor_user_handler.go @@ -0,0 +1,176 @@ +package handler + +import ( + "time" + + "github.com/Wei-Shaw/sub2api/internal/handler/admin" + "github.com/Wei-Shaw/sub2api/internal/handler/dto" + "github.com/Wei-Shaw/sub2api/internal/pkg/response" + "github.com/Wei-Shaw/sub2api/internal/service" + + "github.com/gin-gonic/gin" +) + +// ChannelMonitorUserHandler 渠道监控用户只读 handler。 +type ChannelMonitorUserHandler struct { + monitorService *service.ChannelMonitorService + settingService *service.SettingService +} + +// NewChannelMonitorUserHandler 创建 handler。 +// settingService 用于每次请求前读取功能开关;关闭时 List/GetStatus 直接返回空/404。 +func NewChannelMonitorUserHandler( + monitorService *service.ChannelMonitorService, + settingService *service.SettingService, +) *ChannelMonitorUserHandler { + return &ChannelMonitorUserHandler{ + monitorService: monitorService, + settingService: settingService, + } +} + +// featureEnabled 返回当前渠道监控功能是否开启。 +// settingService 为 nil(测试场景)视为启用。 +func (h *ChannelMonitorUserHandler) featureEnabled(c *gin.Context) bool { + if h.settingService == nil { + return true + } + return h.settingService.GetChannelMonitorRuntime(c.Request.Context()).Enabled +} + +// --- Response --- + +type channelMonitorUserListItem struct { + ID int64 `json:"id"` + Name string `json:"name"` + Provider string `json:"provider"` + GroupName string `json:"group_name"` + PrimaryModel string `json:"primary_model"` + PrimaryStatus string `json:"primary_status"` + PrimaryLatencyMs *int `json:"primary_latency_ms"` + PrimaryPingLatencyMs *int `json:"primary_ping_latency_ms"` + Availability7d float64 `json:"availability_7d"` + ExtraModels []dto.ChannelMonitorExtraModelStatus `json:"extra_models"` + Timeline []channelMonitorUserTimelinePoint `json:"timeline"` +} + +// channelMonitorUserTimelinePoint 主模型最近一次检测的 timeline 点。 +// 仅用于用户视图 list 响应,admin 视图不使用。 +type channelMonitorUserTimelinePoint struct { + Status string `json:"status"` + LatencyMs *int `json:"latency_ms"` + PingLatencyMs *int `json:"ping_latency_ms"` + CheckedAt string `json:"checked_at"` +} + +type channelMonitorUserDetailResponse struct { + ID int64 `json:"id"` + Name string `json:"name"` + Provider string `json:"provider"` + GroupName string `json:"group_name"` + Models []channelMonitorUserModelStat `json:"models"` +} + +type channelMonitorUserModelStat struct { + Model string `json:"model"` + LatestStatus string `json:"latest_status"` + LatestLatencyMs *int `json:"latest_latency_ms"` + Availability7d float64 `json:"availability_7d"` + Availability15d float64 `json:"availability_15d"` + Availability30d float64 `json:"availability_30d"` + AvgLatency7dMs *int `json:"avg_latency_7d_ms"` +} + +func userMonitorViewToItem(v *service.UserMonitorView) channelMonitorUserListItem { + extras := make([]dto.ChannelMonitorExtraModelStatus, 0, len(v.ExtraModels)) + for _, e := range v.ExtraModels { + extras = append(extras, dto.ChannelMonitorExtraModelStatus{ + Model: e.Model, + Status: e.Status, + LatencyMs: e.LatencyMs, + }) + } + timeline := make([]channelMonitorUserTimelinePoint, 0, len(v.Timeline)) + for _, p := range v.Timeline { + timeline = append(timeline, channelMonitorUserTimelinePoint{ + Status: p.Status, + LatencyMs: p.LatencyMs, + PingLatencyMs: p.PingLatencyMs, + CheckedAt: p.CheckedAt.UTC().Format(time.RFC3339), + }) + } + return channelMonitorUserListItem{ + ID: v.ID, + Name: v.Name, + Provider: v.Provider, + GroupName: v.GroupName, + PrimaryModel: v.PrimaryModel, + PrimaryStatus: v.PrimaryStatus, + PrimaryLatencyMs: v.PrimaryLatencyMs, + PrimaryPingLatencyMs: v.PrimaryPingLatencyMs, + Availability7d: v.Availability7d, + ExtraModels: extras, + Timeline: timeline, + } +} + +func userMonitorDetailToResponse(d *service.UserMonitorDetail) *channelMonitorUserDetailResponse { + models := make([]channelMonitorUserModelStat, 0, len(d.Models)) + for _, m := range d.Models { + models = append(models, channelMonitorUserModelStat{ + Model: m.Model, + LatestStatus: m.LatestStatus, + LatestLatencyMs: m.LatestLatencyMs, + Availability7d: m.Availability7d, + Availability15d: m.Availability15d, + Availability30d: m.Availability30d, + AvgLatency7dMs: m.AvgLatency7dMs, + }) + } + return &channelMonitorUserDetailResponse{ + ID: d.ID, + Name: d.Name, + Provider: d.Provider, + GroupName: d.GroupName, + Models: models, + } +} + +// --- Handlers --- + +// List GET /api/v1/channel-monitors +func (h *ChannelMonitorUserHandler) List(c *gin.Context) { + if !h.featureEnabled(c) { + response.Success(c, gin.H{"items": []channelMonitorUserListItem{}}) + return + } + views, err := h.monitorService.ListUserView(c.Request.Context()) + if err != nil { + response.ErrorFrom(c, err) + return + } + items := make([]channelMonitorUserListItem, 0, len(views)) + for _, v := range views { + items = append(items, userMonitorViewToItem(v)) + } + response.Success(c, gin.H{"items": items}) +} + +// GetStatus GET /api/v1/channel-monitors/:id/status +func (h *ChannelMonitorUserHandler) GetStatus(c *gin.Context) { + if !h.featureEnabled(c) { + response.ErrorFrom(c, service.ErrChannelMonitorNotFound) + return + } + // 复用 admin.ParseChannelMonitorID 保持错误码与日志一致。 + id, ok := admin.ParseChannelMonitorID(c) + if !ok { + return + } + detail, err := h.monitorService.GetUserDetail(c.Request.Context(), id) + if err != nil { + response.ErrorFrom(c, err) + return + } + response.Success(c, userMonitorDetailToResponse(detail)) +} diff --git a/backend/internal/handler/dto/channel_monitor.go b/backend/internal/handler/dto/channel_monitor.go new file mode 100644 index 00000000..3c0c5e11 --- /dev/null +++ b/backend/internal/handler/dto/channel_monitor.go @@ -0,0 +1,10 @@ +package dto + +// ChannelMonitorExtraModelStatus 渠道监控附加模型最近一次状态。 +// 同时被 admin handler(List 响应)与 user handler(List 响应)复用, +// 字段必须保持一致以保证前端拿到统一结构。 +type ChannelMonitorExtraModelStatus struct { + Model string `json:"model"` + Status string `json:"status"` + LatencyMs *int `json:"latency_ms"` +} diff --git a/backend/internal/handler/dto/public_settings_injection_schema_test.go b/backend/internal/handler/dto/public_settings_injection_schema_test.go new file mode 100644 index 00000000..428fed3d --- /dev/null +++ b/backend/internal/handler/dto/public_settings_injection_schema_test.go @@ -0,0 +1,70 @@ +package dto + +import ( + "reflect" + "strings" + "testing" + + "github.com/Wei-Shaw/sub2api/internal/service" +) + +// TestPublicSettingsInjectionPayload_SchemaDoesNotDrift guarantees the SSR +// injection struct exposes every JSON field consumed by the frontend. +// +// Why this test exists: before we extracted a named PublicSettingsInjectionPayload +// type, the inline struct was manually kept in sync with dto.PublicSettings and +// drifted — ChannelMonitorEnabled / AvailableChannelsEnabled were missing, which +// made the frontend read `undefined` on refresh and hide the "可用渠道" menu +// until the async /api/v1/settings/public round-trip finished. +// +// This test compares the two JSON-tag sets and fails if injection is missing +// any field that dto.PublicSettings exposes. Adding a new feature flag with +// only a DTO entry will fail this test until the injection struct is updated. +// +// Intentional exclusions (fields present on dto.PublicSettings that SSR does +// not need to inject) are listed in `dtoOnlyFields` below with a reason. +func TestPublicSettingsInjectionPayload_SchemaDoesNotDrift(t *testing.T) { + injection := jsonTags(reflect.TypeOf(service.PublicSettingsInjectionPayload{})) + dtoKeys := jsonTags(reflect.TypeOf(PublicSettings{})) + + // Fields that legitimately live only on the DTO. Keep tiny; document each. + dtoOnlyFields := map[string]string{ + // sora_client_enabled is an upstream-only field the fork does not surface. + "sora_client_enabled": "upstream-only field, not used on this fork", + // force_email_on_third_party_signup lives on the DTO but is not injected via SSR. + "force_email_on_third_party_signup": "auth-source default, not a feature flag", + } + + var missing []string + for key := range dtoKeys { + if _, ok := injection[key]; ok { + continue + } + if _, allowed := dtoOnlyFields[key]; allowed { + continue + } + missing = append(missing, key) + } + if len(missing) > 0 { + t.Fatalf("service.PublicSettingsInjectionPayload is missing JSON fields present on dto.PublicSettings: %s\n"+ + "add the field to PublicSettingsInjectionPayload (and GetPublicSettingsForInjection), or "+ + "document the exclusion in dtoOnlyFields with a reason.", strings.Join(missing, ", ")) + } +} + +func jsonTags(t reflect.Type) map[string]struct{} { + out := make(map[string]struct{}) + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + tag := f.Tag.Get("json") + if tag == "" || tag == "-" { + continue + } + name := strings.SplitN(tag, ",", 2)[0] + if name == "" { + continue + } + out[name] = struct{}{} + } + return out +} diff --git a/backend/internal/handler/dto/settings.go b/backend/internal/handler/dto/settings.go index a9933e63..2affbc46 100644 --- a/backend/internal/handler/dto/settings.go +++ b/backend/internal/handler/dto/settings.go @@ -184,6 +184,13 @@ type SystemSettings struct { BalanceLowNotifyRechargeURL string `json:"balance_low_notify_recharge_url"` AccountQuotaNotifyEnabled bool `json:"account_quota_notify_enabled"` AccountQuotaNotifyEmails []NotifyEmailEntry `json:"account_quota_notify_emails"` + + // Channel Monitor feature switch + ChannelMonitorEnabled bool `json:"channel_monitor_enabled"` + ChannelMonitorDefaultIntervalSeconds int `json:"channel_monitor_default_interval_seconds"` + + // Available Channels feature switch (user-facing aggregate view) + AvailableChannelsEnabled bool `json:"available_channels_enabled"` } type DefaultSubscriptionSetting struct { @@ -231,6 +238,11 @@ type PublicSettings struct { AccountQuotaNotifyEnabled bool `json:"account_quota_notify_enabled"` BalanceLowNotifyThreshold float64 `json:"balance_low_notify_threshold"` BalanceLowNotifyRechargeURL string `json:"balance_low_notify_recharge_url"` + + ChannelMonitorEnabled bool `json:"channel_monitor_enabled"` + ChannelMonitorDefaultIntervalSeconds int `json:"channel_monitor_default_interval_seconds"` + + AvailableChannelsEnabled bool `json:"available_channels_enabled"` } // OverloadCooldownSettings 529过载冷却配置 DTO diff --git a/backend/internal/handler/gateway_handler.go b/backend/internal/handler/gateway_handler.go index 94a22935..ef532559 100644 --- a/backend/internal/handler/gateway_handler.go +++ b/backend/internal/handler/gateway_handler.go @@ -304,6 +304,12 @@ func (h *GatewayHandler) Messages(c *gin.Context) { selection, err := h.gatewayService.SelectAccountWithLoadAwareness(c.Request.Context(), apiKey.GroupID, sessionKey, reqModel, fs.FailedAccountIDs, "", int64(0)) // Gemini 不使用会话限制 if err != nil { if len(fs.FailedAccountIDs) == 0 { + reqLog.Warn("gateway.select_account_no_available", + zap.String("model", reqModel), + zap.Int64p("group_id", apiKey.GroupID), + zap.String("platform", platform), + zap.Error(err), + ) h.handleStreamingAwareError(c, http.StatusServiceUnavailable, "api_error", "No available accounts: "+err.Error(), streamStarted) return } @@ -347,6 +353,11 @@ func (h *GatewayHandler) Messages(c *gin.Context) { accountReleaseFunc := selection.ReleaseFunc if !selection.Acquired { if selection.WaitPlan == nil { + reqLog.Warn("gateway.select_account_no_slot_no_wait_plan", + zap.Int64("account_id", account.ID), + zap.String("model", reqModel), + zap.String("platform", platform), + ) h.handleStreamingAwareError(c, http.StatusServiceUnavailable, "api_error", "No available accounts", streamStarted) return } @@ -528,6 +539,13 @@ func (h *GatewayHandler) Messages(c *gin.Context) { selection, err := h.gatewayService.SelectAccountWithLoadAwareness(c.Request.Context(), currentAPIKey.GroupID, sessionKey, reqModel, fs.FailedAccountIDs, parsedReq.MetadataUserID, subject.UserID) if err != nil { if len(fs.FailedAccountIDs) == 0 { + reqLog.Warn("gateway.select_account_no_available", + zap.String("model", reqModel), + zap.Int64p("group_id", currentAPIKey.GroupID), + zap.String("platform", platform), + zap.Bool("fallback_used", fallbackUsed), + zap.Error(err), + ) h.handleStreamingAwareError(c, http.StatusServiceUnavailable, "api_error", "No available accounts: "+err.Error(), streamStarted) return } @@ -571,6 +589,11 @@ func (h *GatewayHandler) Messages(c *gin.Context) { accountReleaseFunc := selection.ReleaseFunc if !selection.Acquired { if selection.WaitPlan == nil { + reqLog.Warn("gateway.select_account_no_slot_no_wait_plan", + zap.Int64("account_id", account.ID), + zap.String("model", reqModel), + zap.String("platform", platform), + ) h.handleStreamingAwareError(c, http.StatusServiceUnavailable, "api_error", "No available accounts", streamStarted) return } diff --git a/backend/internal/handler/handler.go b/backend/internal/handler/handler.go index 906a74f1..aee9d927 100644 --- a/backend/internal/handler/handler.go +++ b/backend/internal/handler/handler.go @@ -6,50 +6,54 @@ import ( // AdminHandlers contains all admin-related HTTP handlers type AdminHandlers struct { - Dashboard *admin.DashboardHandler - User *admin.UserHandler - Group *admin.GroupHandler - Account *admin.AccountHandler - Announcement *admin.AnnouncementHandler - DataManagement *admin.DataManagementHandler - Backup *admin.BackupHandler - OAuth *admin.OAuthHandler - OpenAIOAuth *admin.OpenAIOAuthHandler - GeminiOAuth *admin.GeminiOAuthHandler - AntigravityOAuth *admin.AntigravityOAuthHandler - Proxy *admin.ProxyHandler - Redeem *admin.RedeemHandler - Promo *admin.PromoHandler - Setting *admin.SettingHandler - Ops *admin.OpsHandler - System *admin.SystemHandler - Subscription *admin.SubscriptionHandler - Usage *admin.UsageHandler - UserAttribute *admin.UserAttributeHandler - ErrorPassthrough *admin.ErrorPassthroughHandler - TLSFingerprintProfile *admin.TLSFingerprintProfileHandler - APIKey *admin.AdminAPIKeyHandler - ScheduledTest *admin.ScheduledTestHandler - Channel *admin.ChannelHandler - Payment *admin.PaymentHandler + Dashboard *admin.DashboardHandler + User *admin.UserHandler + Group *admin.GroupHandler + Account *admin.AccountHandler + Announcement *admin.AnnouncementHandler + DataManagement *admin.DataManagementHandler + Backup *admin.BackupHandler + OAuth *admin.OAuthHandler + OpenAIOAuth *admin.OpenAIOAuthHandler + GeminiOAuth *admin.GeminiOAuthHandler + AntigravityOAuth *admin.AntigravityOAuthHandler + Proxy *admin.ProxyHandler + Redeem *admin.RedeemHandler + Promo *admin.PromoHandler + Setting *admin.SettingHandler + Ops *admin.OpsHandler + System *admin.SystemHandler + Subscription *admin.SubscriptionHandler + Usage *admin.UsageHandler + UserAttribute *admin.UserAttributeHandler + ErrorPassthrough *admin.ErrorPassthroughHandler + TLSFingerprintProfile *admin.TLSFingerprintProfileHandler + APIKey *admin.AdminAPIKeyHandler + ScheduledTest *admin.ScheduledTestHandler + Channel *admin.ChannelHandler + ChannelMonitor *admin.ChannelMonitorHandler + ChannelMonitorTemplate *admin.ChannelMonitorRequestTemplateHandler + Payment *admin.PaymentHandler } // Handlers contains all HTTP handlers type Handlers struct { - Auth *AuthHandler - User *UserHandler - APIKey *APIKeyHandler - Usage *UsageHandler - Redeem *RedeemHandler - Subscription *SubscriptionHandler - Announcement *AnnouncementHandler - Admin *AdminHandlers - Gateway *GatewayHandler - OpenAIGateway *OpenAIGatewayHandler - Setting *SettingHandler - Totp *TotpHandler - Payment *PaymentHandler - PaymentWebhook *PaymentWebhookHandler + Auth *AuthHandler + User *UserHandler + APIKey *APIKeyHandler + Usage *UsageHandler + Redeem *RedeemHandler + Subscription *SubscriptionHandler + Announcement *AnnouncementHandler + ChannelMonitor *ChannelMonitorUserHandler + Admin *AdminHandlers + Gateway *GatewayHandler + OpenAIGateway *OpenAIGatewayHandler + Setting *SettingHandler + Totp *TotpHandler + Payment *PaymentHandler + PaymentWebhook *PaymentWebhookHandler + AvailableChannel *AvailableChannelHandler } // BuildInfo contains build-time information diff --git a/backend/internal/handler/payment_webhook_handler.go b/backend/internal/handler/payment_webhook_handler.go index c06a5b7e..9ae799fd 100644 --- a/backend/internal/handler/payment_webhook_handler.go +++ b/backend/internal/handler/payment_webhook_handler.go @@ -2,6 +2,7 @@ package handler import ( "context" + "errors" "fmt" "io" "log/slog" @@ -114,6 +115,20 @@ func (h *PaymentWebhookHandler) handleNotify(c *gin.Context, providerKey string) } if err := h.paymentService.HandlePaymentNotification(c.Request.Context(), notification, resolvedProviderKey); err != nil { + // Unknown order: ack with 2xx so the provider stops retrying. This + // guards against foreign environments whose webhook endpoints are + // (mis)configured to point at us — without a 2xx, the provider will + // retry for days and spam our error logs. We still emit a WARN so the + // event is discoverable in logs. + if errors.Is(err, service.ErrOrderNotFound) { + slog.Warn("[Payment Webhook] unknown order, acking to stop retries", + "provider", resolvedProviderKey, + "outTradeNo", notification.OrderID, + "tradeNo", notification.TradeNo, + ) + writeSuccessResponse(c, resolvedProviderKey) + return + } slog.Error("[Payment Webhook] handle notification failed", "provider", resolvedProviderKey, "error", err) c.String(http.StatusInternalServerError, "handle failed") return diff --git a/backend/internal/handler/payment_webhook_handler_test.go b/backend/internal/handler/payment_webhook_handler_test.go index 88221b5c..7551fc83 100644 --- a/backend/internal/handler/payment_webhook_handler_test.go +++ b/backend/internal/handler/payment_webhook_handler_test.go @@ -6,11 +6,13 @@ import ( "context" "encoding/json" "errors" + "fmt" "net/http" "net/http/httptest" "testing" "github.com/Wei-Shaw/sub2api/internal/payment" + "github.com/Wei-Shaw/sub2api/internal/service" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -91,6 +93,43 @@ func TestWriteSuccessResponse(t *testing.T) { } } +// TestUnknownOrderWebhookAcksWithSuccess exercises the response contract that +// handleNotify relies on when HandlePaymentNotification returns ErrOrderNotFound: +// we still need to emit the provider-specific 2xx so the provider stops +// retrying. We can't easily drive handleNotify end-to-end without mocking the +// concrete *service.PaymentService, so this test locks down the two ingredients +// the fix depends on: +// 1. errors.Is recognises the sentinel through fmt.Errorf %w wrapping (which +// is how service layer wraps it with the out_trade_no context). +// 2. writeSuccessResponse produces the provider-specific body for Stripe +// (empty 200) — matching what handleNotify calls on the ack path. +// +// If either contract breaks, the Stripe "unknown order → 500 loop" regresses. +func TestUnknownOrderWebhookAcksWithSuccess(t *testing.T) { + gin.SetMode(gin.TestMode) + + // 1) Sentinel recognition through wrapping. + wrapped := fmt.Errorf("%w: out_trade_no=sub2_missing_42", service.ErrOrderNotFound) + require.True(t, errors.Is(wrapped, service.ErrOrderNotFound), + "handleNotify uses errors.Is on the wrapped service error; regression here "+ + "would mean unknown-order webhooks go back to returning 500 and looping forever") + + // A distinct error must NOT match — otherwise a DB failure would be silently + // swallowed as an ack. + other := errors.New("lookup order failed: connection refused") + require.False(t, errors.Is(other, service.ErrOrderNotFound)) + + // 2) Provider-specific success body is what handleNotify emits on the + // ack path. Asserted again here because this is the shape Stripe expects + // to consider the webhook acknowledged. + w := httptest.NewRecorder() + c, _ := gin.CreateTestContext(w) + writeSuccessResponse(c, payment.TypeStripe) + require.Equal(t, http.StatusOK, w.Code, + "Stripe requires 2xx to stop retrying; anything else restarts the retry loop") + require.Empty(t, w.Body.String(), "Stripe expects an empty body on the ack path") +} + func TestWebhookConstants(t *testing.T) { t.Run("maxWebhookBodySize is 1MB", func(t *testing.T) { assert.Equal(t, int64(1<<20), int64(maxWebhookBodySize)) diff --git a/backend/internal/handler/setting_handler.go b/backend/internal/handler/setting_handler.go index c0f5c28b..96964de4 100644 --- a/backend/internal/handler/setting_handler.go +++ b/backend/internal/handler/setting_handler.go @@ -70,5 +70,10 @@ func (h *SettingHandler) GetPublicSettings(c *gin.Context) { AccountQuotaNotifyEnabled: settings.AccountQuotaNotifyEnabled, BalanceLowNotifyThreshold: settings.BalanceLowNotifyThreshold, BalanceLowNotifyRechargeURL: settings.BalanceLowNotifyRechargeURL, + + ChannelMonitorEnabled: settings.ChannelMonitorEnabled, + ChannelMonitorDefaultIntervalSeconds: settings.ChannelMonitorDefaultIntervalSeconds, + + AvailableChannelsEnabled: settings.AvailableChannelsEnabled, }) } diff --git a/backend/internal/handler/wire.go b/backend/internal/handler/wire.go index 4b54d41a..6d175488 100644 --- a/backend/internal/handler/wire.go +++ b/backend/internal/handler/wire.go @@ -34,35 +34,39 @@ func ProvideAdminHandlers( apiKeyHandler *admin.AdminAPIKeyHandler, scheduledTestHandler *admin.ScheduledTestHandler, channelHandler *admin.ChannelHandler, + channelMonitorHandler *admin.ChannelMonitorHandler, + channelMonitorTemplateHandler *admin.ChannelMonitorRequestTemplateHandler, paymentHandler *admin.PaymentHandler, ) *AdminHandlers { return &AdminHandlers{ - Dashboard: dashboardHandler, - User: userHandler, - Group: groupHandler, - Account: accountHandler, - Announcement: announcementHandler, - DataManagement: dataManagementHandler, - Backup: backupHandler, - OAuth: oauthHandler, - OpenAIOAuth: openaiOAuthHandler, - GeminiOAuth: geminiOAuthHandler, - AntigravityOAuth: antigravityOAuthHandler, - Proxy: proxyHandler, - Redeem: redeemHandler, - Promo: promoHandler, - Setting: settingHandler, - Ops: opsHandler, - System: systemHandler, - Subscription: subscriptionHandler, - Usage: usageHandler, - UserAttribute: userAttributeHandler, - ErrorPassthrough: errorPassthroughHandler, - TLSFingerprintProfile: tlsFingerprintProfileHandler, - APIKey: apiKeyHandler, - ScheduledTest: scheduledTestHandler, - Channel: channelHandler, - Payment: paymentHandler, + Dashboard: dashboardHandler, + User: userHandler, + Group: groupHandler, + Account: accountHandler, + Announcement: announcementHandler, + DataManagement: dataManagementHandler, + Backup: backupHandler, + OAuth: oauthHandler, + OpenAIOAuth: openaiOAuthHandler, + GeminiOAuth: geminiOAuthHandler, + AntigravityOAuth: antigravityOAuthHandler, + Proxy: proxyHandler, + Redeem: redeemHandler, + Promo: promoHandler, + Setting: settingHandler, + Ops: opsHandler, + System: systemHandler, + Subscription: subscriptionHandler, + Usage: usageHandler, + UserAttribute: userAttributeHandler, + ErrorPassthrough: errorPassthroughHandler, + TLSFingerprintProfile: tlsFingerprintProfileHandler, + APIKey: apiKeyHandler, + ScheduledTest: scheduledTestHandler, + Channel: channelHandler, + ChannelMonitor: channelMonitorHandler, + ChannelMonitorTemplate: channelMonitorTemplateHandler, + Payment: paymentHandler, } } @@ -85,6 +89,7 @@ func ProvideHandlers( redeemHandler *RedeemHandler, subscriptionHandler *SubscriptionHandler, announcementHandler *AnnouncementHandler, + channelMonitorUserHandler *ChannelMonitorUserHandler, adminHandlers *AdminHandlers, gatewayHandler *GatewayHandler, openaiGatewayHandler *OpenAIGatewayHandler, @@ -92,24 +97,27 @@ func ProvideHandlers( totpHandler *TotpHandler, paymentHandler *PaymentHandler, paymentWebhookHandler *PaymentWebhookHandler, + availableChannelHandler *AvailableChannelHandler, _ *service.IdempotencyCoordinator, _ *service.IdempotencyCleanupService, ) *Handlers { return &Handlers{ - Auth: authHandler, - User: userHandler, - APIKey: apiKeyHandler, - Usage: usageHandler, - Redeem: redeemHandler, - Subscription: subscriptionHandler, - Announcement: announcementHandler, - Admin: adminHandlers, - Gateway: gatewayHandler, - OpenAIGateway: openaiGatewayHandler, - Setting: settingHandler, - Totp: totpHandler, - Payment: paymentHandler, - PaymentWebhook: paymentWebhookHandler, + Auth: authHandler, + User: userHandler, + APIKey: apiKeyHandler, + Usage: usageHandler, + Redeem: redeemHandler, + Subscription: subscriptionHandler, + Announcement: announcementHandler, + ChannelMonitor: channelMonitorUserHandler, + Admin: adminHandlers, + Gateway: gatewayHandler, + OpenAIGateway: openaiGatewayHandler, + Setting: settingHandler, + Totp: totpHandler, + Payment: paymentHandler, + PaymentWebhook: paymentWebhookHandler, + AvailableChannel: availableChannelHandler, } } @@ -123,12 +131,14 @@ var ProviderSet = wire.NewSet( NewRedeemHandler, NewSubscriptionHandler, NewAnnouncementHandler, + NewChannelMonitorUserHandler, NewGatewayHandler, NewOpenAIGatewayHandler, NewTotpHandler, ProvideSettingHandler, NewPaymentHandler, NewPaymentWebhookHandler, + NewAvailableChannelHandler, // Admin handlers admin.NewDashboardHandler, @@ -156,6 +166,8 @@ var ProviderSet = wire.NewSet( admin.NewAdminAPIKeyHandler, admin.NewScheduledTestHandler, admin.NewChannelHandler, + admin.NewChannelMonitorHandler, + admin.NewChannelMonitorRequestTemplateHandler, admin.NewPaymentHandler, // AdminHandlers and Handlers constructors diff --git a/backend/internal/repository/channel_monitor_repo.go b/backend/internal/repository/channel_monitor_repo.go new file mode 100644 index 00000000..800ee43b --- /dev/null +++ b/backend/internal/repository/channel_monitor_repo.go @@ -0,0 +1,755 @@ +package repository + +import ( + "context" + "database/sql" + "fmt" + "strings" + "time" + + dbent "github.com/Wei-Shaw/sub2api/ent" + "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory" + "github.com/Wei-Shaw/sub2api/internal/service" + "github.com/lib/pq" +) + +// channelMonitorRepository 实现 service.ChannelMonitorRepository。 +// +// 选型说明: +// - CRUD 走 ent,复用项目的事务上下文支持 +// - 聚合查询(latest per model / availability)走原生 SQL,避免 ent 在 GROUP BY 上 +// 的样板代码,并保证索引能被命中 +type channelMonitorRepository struct { + client *dbent.Client + db *sql.DB +} + +// NewChannelMonitorRepository 创建仓储实例。 +func NewChannelMonitorRepository(client *dbent.Client, db *sql.DB) service.ChannelMonitorRepository { + return &channelMonitorRepository{client: client, db: db} +} + +// ---------- CRUD ---------- + +func (r *channelMonitorRepository) Create(ctx context.Context, m *service.ChannelMonitor) error { + client := clientFromContext(ctx, r.client) + builder := client.ChannelMonitor.Create(). + SetName(m.Name). + SetProvider(channelmonitor.Provider(m.Provider)). + SetEndpoint(m.Endpoint). + SetAPIKeyEncrypted(m.APIKey). // 调用方传入的已是密文 + SetPrimaryModel(m.PrimaryModel). + SetExtraModels(emptySliceIfNil(m.ExtraModels)). + SetGroupName(m.GroupName). + SetEnabled(m.Enabled). + SetIntervalSeconds(m.IntervalSeconds). + SetCreatedBy(m.CreatedBy). + SetExtraHeaders(emptyHeadersIfNilRepo(m.ExtraHeaders)). + SetBodyOverrideMode(defaultBodyModeRepo(m.BodyOverrideMode)) + if m.TemplateID != nil { + builder = builder.SetTemplateID(*m.TemplateID) + } + if m.BodyOverride != nil { + builder = builder.SetBodyOverride(m.BodyOverride) + } + + created, err := builder.Save(ctx) + if err != nil { + return translatePersistenceError(err, service.ErrChannelMonitorNotFound, nil) + } + m.ID = created.ID + m.CreatedAt = created.CreatedAt + m.UpdatedAt = created.UpdatedAt + return nil +} + +func (r *channelMonitorRepository) GetByID(ctx context.Context, id int64) (*service.ChannelMonitor, error) { + row, err := r.client.ChannelMonitor.Query(). + Where(channelmonitor.IDEQ(id)). + Only(ctx) + if err != nil { + return nil, translatePersistenceError(err, service.ErrChannelMonitorNotFound, nil) + } + return entToServiceMonitor(row), nil +} + +func (r *channelMonitorRepository) Update(ctx context.Context, m *service.ChannelMonitor) error { + client := clientFromContext(ctx, r.client) + updater := client.ChannelMonitor.UpdateOneID(m.ID). + SetName(m.Name). + SetProvider(channelmonitor.Provider(m.Provider)). + SetEndpoint(m.Endpoint). + SetAPIKeyEncrypted(m.APIKey). + SetPrimaryModel(m.PrimaryModel). + SetExtraModels(emptySliceIfNil(m.ExtraModels)). + SetGroupName(m.GroupName). + SetEnabled(m.Enabled). + SetIntervalSeconds(m.IntervalSeconds). + SetExtraHeaders(emptyHeadersIfNilRepo(m.ExtraHeaders)). + SetBodyOverrideMode(defaultBodyModeRepo(m.BodyOverrideMode)) + if m.TemplateID != nil { + updater = updater.SetTemplateID(*m.TemplateID) + } else { + updater = updater.ClearTemplateID() + } + if m.BodyOverride != nil { + updater = updater.SetBodyOverride(m.BodyOverride) + } else { + updater = updater.ClearBodyOverride() + } + + updated, err := updater.Save(ctx) + if err != nil { + return translatePersistenceError(err, service.ErrChannelMonitorNotFound, nil) + } + m.UpdatedAt = updated.UpdatedAt + return nil +} + +func (r *channelMonitorRepository) Delete(ctx context.Context, id int64) error { + client := clientFromContext(ctx, r.client) + if err := client.ChannelMonitor.DeleteOneID(id).Exec(ctx); err != nil { + return translatePersistenceError(err, service.ErrChannelMonitorNotFound, nil) + } + return nil +} + +func (r *channelMonitorRepository) List(ctx context.Context, params service.ChannelMonitorListParams) ([]*service.ChannelMonitor, int64, error) { + q := r.client.ChannelMonitor.Query() + if params.Provider != "" { + q = q.Where(channelmonitor.ProviderEQ(channelmonitor.Provider(params.Provider))) + } + if params.Enabled != nil { + q = q.Where(channelmonitor.EnabledEQ(*params.Enabled)) + } + if s := strings.TrimSpace(params.Search); s != "" { + q = q.Where(channelmonitor.Or( + channelmonitor.NameContainsFold(s), + channelmonitor.GroupNameContainsFold(s), + channelmonitor.PrimaryModelContainsFold(s), + )) + } + + total, err := q.Count(ctx) + if err != nil { + return nil, 0, fmt.Errorf("count monitors: %w", err) + } + + pageSize := params.PageSize + if pageSize <= 0 { + pageSize = 20 + } + page := params.Page + if page <= 0 { + page = 1 + } + + rows, err := q. + Order(dbent.Desc(channelmonitor.FieldID)). + Offset((page - 1) * pageSize). + Limit(pageSize). + All(ctx) + if err != nil { + return nil, 0, fmt.Errorf("list monitors: %w", err) + } + + out := make([]*service.ChannelMonitor, 0, len(rows)) + for _, row := range rows { + out = append(out, entToServiceMonitor(row)) + } + return out, int64(total), nil +} + +// ---------- 调度器辅助 ---------- + +func (r *channelMonitorRepository) ListEnabled(ctx context.Context) ([]*service.ChannelMonitor, error) { + rows, err := r.client.ChannelMonitor.Query(). + Where(channelmonitor.EnabledEQ(true)). + All(ctx) + if err != nil { + return nil, fmt.Errorf("list enabled monitors: %w", err) + } + out := make([]*service.ChannelMonitor, 0, len(rows)) + for _, row := range rows { + out = append(out, entToServiceMonitor(row)) + } + return out, nil +} + +func (r *channelMonitorRepository) MarkChecked(ctx context.Context, id int64, checkedAt time.Time) error { + client := clientFromContext(ctx, r.client) + if err := client.ChannelMonitor.UpdateOneID(id). + SetLastCheckedAt(checkedAt). + Exec(ctx); err != nil { + return translatePersistenceError(err, service.ErrChannelMonitorNotFound, nil) + } + return nil +} + +func (r *channelMonitorRepository) InsertHistoryBatch(ctx context.Context, rows []*service.ChannelMonitorHistoryRow) error { + if len(rows) == 0 { + return nil + } + client := clientFromContext(ctx, r.client) + bulk := make([]*dbent.ChannelMonitorHistoryCreate, 0, len(rows)) + for _, row := range rows { + c := client.ChannelMonitorHistory.Create(). + SetMonitorID(row.MonitorID). + SetModel(row.Model). + SetStatus(channelmonitorhistory.Status(row.Status)). + SetMessage(row.Message). + SetCheckedAt(row.CheckedAt) + if row.LatencyMs != nil { + c = c.SetLatencyMs(*row.LatencyMs) + } + if row.PingLatencyMs != nil { + c = c.SetPingLatencyMs(*row.PingLatencyMs) + } + bulk = append(bulk, c) + } + if _, err := client.ChannelMonitorHistory.CreateBulk(bulk...).Save(ctx); err != nil { + return fmt.Errorf("insert history bulk: %w", err) + } + return nil +} + +// DeleteHistoryBefore 物理删 checked_at < before 的明细,分批 channelMonitorPruneBatchSize 行一批, +// 避免单事务删除过多引起锁/WAL 压力。借助 (checked_at) 索引定位小批 id,再按 id 删。 +func (r *channelMonitorRepository) DeleteHistoryBefore(ctx context.Context, before time.Time) (int64, error) { + return deleteChannelMonitorBatched(ctx, r.db, channelMonitorPruneHistorySQL, before) +} + +// ListHistory 按 checked_at 倒序返回某个监控的最近 N 条历史记录。 +// model 为空时不过滤;非空时只返回该模型的记录。 +func (r *channelMonitorRepository) ListHistory(ctx context.Context, monitorID int64, model string, limit int) ([]*service.ChannelMonitorHistoryEntry, error) { + q := r.client.ChannelMonitorHistory.Query(). + Where(channelmonitorhistory.MonitorIDEQ(monitorID)) + if strings.TrimSpace(model) != "" { + q = q.Where(channelmonitorhistory.ModelEQ(model)) + } + rows, err := q. + Order(dbent.Desc(channelmonitorhistory.FieldCheckedAt)). + Limit(limit). + All(ctx) + if err != nil { + return nil, fmt.Errorf("list history: %w", err) + } + out := make([]*service.ChannelMonitorHistoryEntry, 0, len(rows)) + for _, row := range rows { + entry := &service.ChannelMonitorHistoryEntry{ + ID: row.ID, + Model: row.Model, + Status: string(row.Status), + LatencyMs: row.LatencyMs, + PingLatencyMs: row.PingLatencyMs, + Message: row.Message, + CheckedAt: row.CheckedAt, + } + out = append(out, entry) + } + return out, nil +} + +// ---------- 用户视图聚合(原生 SQL) ---------- + +// ListLatestPerModel 用 DISTINCT ON 取每个 (monitor_id, model) 的最近一条记录。 +// 借助 (monitor_id, model, checked_at DESC) 索引可走 Index Scan。 +func (r *channelMonitorRepository) ListLatestPerModel(ctx context.Context, monitorID int64) ([]*service.ChannelMonitorLatest, error) { + const q = ` + SELECT DISTINCT ON (model) + model, status, latency_ms, ping_latency_ms, checked_at + FROM channel_monitor_histories + WHERE monitor_id = $1 + ORDER BY model, checked_at DESC + ` + rows, err := r.db.QueryContext(ctx, q, monitorID) + if err != nil { + return nil, fmt.Errorf("query latest per model: %w", err) + } + defer func() { _ = rows.Close() }() + + out := make([]*service.ChannelMonitorLatest, 0) + for rows.Next() { + l := &service.ChannelMonitorLatest{} + var latency, ping sql.NullInt64 + if err := rows.Scan(&l.Model, &l.Status, &latency, &ping, &l.CheckedAt); err != nil { + return nil, fmt.Errorf("scan latest row: %w", err) + } + assignNullInt(&l.LatencyMs, latency) + assignNullInt(&l.PingLatencyMs, ping) + out = append(out, l) + } + return out, rows.Err() +} + +// assignNullInt 把 sql.NullInt64 解包到 *int 指针目标(valid 才分配新 int)。 +// 集中实现避免 latency / ping 两处重复 if latency.Valid { v := int(...) ... } 模板。 +func assignNullInt(dst **int, n sql.NullInt64) { + if !n.Valid { + return + } + v := int(n.Int64) + *dst = &v +} + +// ComputeAvailability 计算指定窗口内每个模型的可用率与平均延迟。 +// "可用" = status IN (operational, degraded)。 +// +// 数据来源:明细表只保留 1 天;窗口前其余天数走聚合表。 +// 明细保留 30 天(monitorHistoryRetentionDays),窗口 <= 30 天时直接扫 histories, +// 精度到秒,避免与聚合表 UNION 带来的 UTC 日切精度损失。 +func (r *channelMonitorRepository) ComputeAvailability(ctx context.Context, monitorID int64, windowDays int) ([]*service.ChannelMonitorAvailability, error) { + if windowDays <= 0 { + windowDays = 7 + } + const q = ` + SELECT model, + COUNT(*) AS total, + COUNT(*) FILTER (WHERE status IN ('operational','degraded')) AS ok, + CASE WHEN COUNT(latency_ms) > 0 + THEN SUM(latency_ms) FILTER (WHERE latency_ms IS NOT NULL)::float8 / COUNT(latency_ms) + ELSE NULL END AS avg_latency_ms + FROM channel_monitor_histories + WHERE monitor_id = $1 + AND checked_at >= NOW() - ($2::int || ' days')::interval + GROUP BY model + ` + rows, err := r.db.QueryContext(ctx, q, monitorID, windowDays) + if err != nil { + return nil, fmt.Errorf("query availability: %w", err) + } + defer func() { _ = rows.Close() }() + + out := make([]*service.ChannelMonitorAvailability, 0) + for rows.Next() { + row, err := scanAvailabilityRow(rows, windowDays) + if err != nil { + return nil, err + } + out = append(out, row) + } + return out, rows.Err() +} + +// scanAvailabilityRow 把单行 (model, total, ok, avg_latency) 扫描为 ChannelMonitorAvailability。 +// 仅服务于 ComputeAvailability(4 列);批量版本因为多一列 monitor_id 直接 inline 调 finalizeAvailabilityRow。 +func scanAvailabilityRow(rows interface{ Scan(...any) error }, windowDays int) (*service.ChannelMonitorAvailability, error) { + row := &service.ChannelMonitorAvailability{WindowDays: windowDays} + var avgLatency sql.NullFloat64 + if err := rows.Scan(&row.Model, &row.TotalChecks, &row.OperationalChecks, &avgLatency); err != nil { + return nil, fmt.Errorf("scan availability row: %w", err) + } + finalizeAvailabilityRow(row, avgLatency) + return row, nil +} + +// finalizeAvailabilityRow 根据 OperationalChecks/TotalChecks 算出可用率, +// 并把 sql.NullFloat64 的平均延迟解包为 *int。两处复用避免维护漂移。 +func finalizeAvailabilityRow(row *service.ChannelMonitorAvailability, avgLatency sql.NullFloat64) { + if row.TotalChecks > 0 { + row.AvailabilityPct = float64(row.OperationalChecks) * 100.0 / float64(row.TotalChecks) + } + if avgLatency.Valid { + v := int(avgLatency.Float64) + row.AvgLatencyMs = &v + } +} + +// ListLatestForMonitorIDs 一次性查询多个监控的"每个 (monitor_id, model) 最近一条"记录。 +// 利用 PG 的 DISTINCT ON 特性,借助 (monitor_id, model, checked_at DESC) 索引可走 Index Scan。 +func (r *channelMonitorRepository) ListLatestForMonitorIDs(ctx context.Context, ids []int64) (map[int64][]*service.ChannelMonitorLatest, error) { + out := make(map[int64][]*service.ChannelMonitorLatest, len(ids)) + if len(ids) == 0 { + return out, nil + } + const q = ` + SELECT DISTINCT ON (monitor_id, model) + monitor_id, model, status, latency_ms, ping_latency_ms, checked_at + FROM channel_monitor_histories + WHERE monitor_id = ANY($1) + ORDER BY monitor_id, model, checked_at DESC + ` + rows, err := r.db.QueryContext(ctx, q, pq.Array(ids)) + if err != nil { + return nil, fmt.Errorf("query latest batch: %w", err) + } + defer func() { _ = rows.Close() }() + + for rows.Next() { + var monitorID int64 + l := &service.ChannelMonitorLatest{} + var latency, ping sql.NullInt64 + if err := rows.Scan(&monitorID, &l.Model, &l.Status, &latency, &ping, &l.CheckedAt); err != nil { + return nil, fmt.Errorf("scan latest batch row: %w", err) + } + assignNullInt(&l.LatencyMs, latency) + assignNullInt(&l.PingLatencyMs, ping) + out[monitorID] = append(out[monitorID], l) + } + if err := rows.Err(); err != nil { + return nil, err + } + return out, nil +} + +// ListRecentHistoryForMonitors 为多个 monitor 批量取各自"指定模型"最近 N 条历史(按 checked_at DESC,最新在前)。 +// primaryModels[monitorID] 指定该监控要过滤的模型名;monitor 不在 primaryModels 中的记录不返回。 +// 通过 CTE + unnest(两个 int8/text 数组) 构造 (monitor_id, model) 白名单, +// 再用 ROW_NUMBER() OVER (PARTITION BY monitor_id) 取各自前 N 条。 +// +// 返回值:map[monitorID] -> []*ChannelMonitorHistoryEntry(不含 message,减少网络开销)。 +// 空 ids / 空 primaryModels 返回空 map,不报错。 +func (r *channelMonitorRepository) ListRecentHistoryForMonitors( + ctx context.Context, + ids []int64, + primaryModels map[int64]string, + perMonitorLimit int, +) (map[int64][]*service.ChannelMonitorHistoryEntry, error) { + out := make(map[int64][]*service.ChannelMonitorHistoryEntry, len(ids)) + pairIDs, pairModels := buildMonitorModelPairs(ids, primaryModels) + if len(pairIDs) == 0 { + return out, nil + } + perMonitorLimit = clampTimelineLimit(perMonitorLimit) + + const q = ` + WITH targets AS ( + SELECT unnest($1::bigint[]) AS monitor_id, + unnest($2::text[]) AS model + ), + ranked AS ( + SELECT h.monitor_id, + h.status, + h.latency_ms, + h.ping_latency_ms, + h.checked_at, + ROW_NUMBER() OVER (PARTITION BY h.monitor_id ORDER BY h.checked_at DESC) AS rn + FROM channel_monitor_histories h + JOIN targets t + ON t.monitor_id = h.monitor_id AND t.model = h.model + ) + SELECT monitor_id, status, latency_ms, ping_latency_ms, checked_at + FROM ranked + WHERE rn <= $3 + ORDER BY monitor_id, checked_at DESC + ` + rows, err := r.db.QueryContext(ctx, q, pq.Array(pairIDs), pq.Array(pairModels), perMonitorLimit) + if err != nil { + return nil, fmt.Errorf("query recent history batch: %w", err) + } + defer func() { _ = rows.Close() }() + + for rows.Next() { + var monitorID int64 + entry := &service.ChannelMonitorHistoryEntry{} + var latency, ping sql.NullInt64 + if err := rows.Scan(&monitorID, &entry.Status, &latency, &ping, &entry.CheckedAt); err != nil { + return nil, fmt.Errorf("scan recent history row: %w", err) + } + assignNullInt(&entry.LatencyMs, latency) + assignNullInt(&entry.PingLatencyMs, ping) + out[monitorID] = append(out[monitorID], entry) + } + if err := rows.Err(); err != nil { + return nil, err + } + return out, nil +} + +// buildMonitorModelPairs 基于 ids 过滤出有效的 (monitor_id, model) 对,model 为空时跳过。 +// 保证两个数组长度一致且一一对应,供 unnest 展开。 +func buildMonitorModelPairs(ids []int64, primaryModels map[int64]string) ([]int64, []string) { + if len(ids) == 0 || len(primaryModels) == 0 { + return nil, nil + } + pairIDs := make([]int64, 0, len(ids)) + pairModels := make([]string, 0, len(ids)) + for _, id := range ids { + model, ok := primaryModels[id] + if !ok || strings.TrimSpace(model) == "" { + continue + } + pairIDs = append(pairIDs, id) + pairModels = append(pairModels, model) + } + return pairIDs, pairModels +} + +// timelineLimit* 批量 timeline 查询的 perMonitorLimit 夹紧范围。 +// 下限 1 表示至少返回最近一条;上限 200 控制单次响应体与 SQL 内存占用(ROW_NUMBER 窗口上限)。 +const ( + timelineLimitMin = 1 + timelineLimitMax = 200 +) + +// clampTimelineLimit 把 perMonitorLimit 夹紧到 [timelineLimitMin, timelineLimitMax],避免非法值或超大查询。 +func clampTimelineLimit(n int) int { + if n < timelineLimitMin { + return timelineLimitMin + } + if n > timelineLimitMax { + return timelineLimitMax + } + return n +} + +// ComputeAvailabilityForMonitors 一次性计算多个监控在某个窗口内的每模型可用率与平均延迟。 +// 明细保留 30 天,直接扫 histories(窗口 <= 30 天时无需聚合)。 +func (r *channelMonitorRepository) ComputeAvailabilityForMonitors(ctx context.Context, ids []int64, windowDays int) (map[int64][]*service.ChannelMonitorAvailability, error) { + out := make(map[int64][]*service.ChannelMonitorAvailability, len(ids)) + if len(ids) == 0 { + return out, nil + } + if windowDays <= 0 { + windowDays = 7 + } + const q = ` + SELECT monitor_id, + model, + COUNT(*) AS total, + COUNT(*) FILTER (WHERE status IN ('operational','degraded')) AS ok, + CASE WHEN COUNT(latency_ms) > 0 + THEN SUM(latency_ms) FILTER (WHERE latency_ms IS NOT NULL)::float8 / COUNT(latency_ms) + ELSE NULL END AS avg_latency_ms + FROM channel_monitor_histories + WHERE monitor_id = ANY($1) + AND checked_at >= NOW() - ($2::int || ' days')::interval + GROUP BY monitor_id, model + ` + rows, err := r.db.QueryContext(ctx, q, pq.Array(ids), windowDays) + if err != nil { + return nil, fmt.Errorf("query availability batch: %w", err) + } + defer func() { _ = rows.Close() }() + + for rows.Next() { + var monitorID int64 + row := &service.ChannelMonitorAvailability{WindowDays: windowDays} + var avgLatency sql.NullFloat64 + if err := rows.Scan(&monitorID, &row.Model, &row.TotalChecks, &row.OperationalChecks, &avgLatency); err != nil { + return nil, fmt.Errorf("scan availability batch row: %w", err) + } + // 批量查询多了首列 monitor_id;其余字段的可用率/平均延迟换算与单 monitor 版本一致, + // 抽出 finalizeAvailabilityRow 复用,避免两处分别维护除法与 NullFloat 解包。 + finalizeAvailabilityRow(row, avgLatency) + out[monitorID] = append(out[monitorID], row) + } + if err := rows.Err(); err != nil { + return nil, err + } + return out, nil +} + +// ---------- 聚合维护 ---------- + +// UpsertDailyRollupsFor 把 targetDate 当天([targetDate, targetDate+1d))的明细 +// 按 (monitor_id, model, bucket_date) 聚合写入 channel_monitor_daily_rollups。 +// - 用 ON CONFLICT (monitor_id, model, bucket_date) DO UPDATE 实现幂等回填, +// 重复执行只会用最新统计覆盖; +// - $1::date 让 PG 自动把入参 truncate 到 UTC 日期,调用方不需要预处理 targetDate。 +func (r *channelMonitorRepository) UpsertDailyRollupsFor(ctx context.Context, targetDate time.Time) (int64, error) { + const q = ` + INSERT INTO channel_monitor_daily_rollups ( + monitor_id, model, bucket_date, + total_checks, ok_count, + operational_count, degraded_count, failed_count, error_count, + sum_latency_ms, count_latency, + sum_ping_latency_ms, count_ping_latency, + computed_at + ) + SELECT + monitor_id, + model, + $1::date AS bucket_date, + COUNT(*) AS total_checks, + COUNT(*) FILTER (WHERE status IN ('operational','degraded')) AS ok_count, + COUNT(*) FILTER (WHERE status = 'operational') AS operational_count, + COUNT(*) FILTER (WHERE status = 'degraded') AS degraded_count, + COUNT(*) FILTER (WHERE status = 'failed') AS failed_count, + COUNT(*) FILTER (WHERE status = 'error') AS error_count, + COALESCE(SUM(latency_ms) FILTER (WHERE latency_ms IS NOT NULL), 0) AS sum_latency_ms, + COUNT(latency_ms) AS count_latency, + COALESCE(SUM(ping_latency_ms) FILTER (WHERE ping_latency_ms IS NOT NULL), 0) AS sum_ping_latency_ms, + COUNT(ping_latency_ms) AS count_ping_latency, + NOW() + FROM channel_monitor_histories + WHERE checked_at >= $1::date + AND checked_at < ($1::date + INTERVAL '1 day') + GROUP BY monitor_id, model + ON CONFLICT (monitor_id, model, bucket_date) DO UPDATE SET + total_checks = EXCLUDED.total_checks, + ok_count = EXCLUDED.ok_count, + operational_count = EXCLUDED.operational_count, + degraded_count = EXCLUDED.degraded_count, + failed_count = EXCLUDED.failed_count, + error_count = EXCLUDED.error_count, + sum_latency_ms = EXCLUDED.sum_latency_ms, + count_latency = EXCLUDED.count_latency, + sum_ping_latency_ms = EXCLUDED.sum_ping_latency_ms, + count_ping_latency = EXCLUDED.count_ping_latency, + computed_at = NOW() + ` + res, err := r.db.ExecContext(ctx, q, targetDate) + if err != nil { + return 0, fmt.Errorf("upsert daily rollups for %s: %w", targetDate.Format("2006-01-02"), err) + } + n, err := res.RowsAffected() + if err != nil { + return 0, fmt.Errorf("rows affected (upsert rollups): %w", err) + } + return n, nil +} + +// DeleteRollupsBefore 物理删 bucket_date < beforeDate 的聚合行,同样分批。 +func (r *channelMonitorRepository) DeleteRollupsBefore(ctx context.Context, beforeDate time.Time) (int64, error) { + return deleteChannelMonitorBatched(ctx, r.db, channelMonitorPruneRollupSQL, beforeDate) +} + +// channelMonitorPruneBatchSize 单批删除上限。与 ops_cleanup_service 保持一致的 5000, +// 在大表上按 id 小批删可以避免长事务和 WAL 堆积。 +const channelMonitorPruneBatchSize = 5000 + +// channelMonitorPruneHistorySQL 分批物理删明细表过期行。 +const channelMonitorPruneHistorySQL = ` +WITH batch AS ( + SELECT id FROM channel_monitor_histories + WHERE checked_at < $1 + ORDER BY id + LIMIT $2 +) +DELETE FROM channel_monitor_histories +WHERE id IN (SELECT id FROM batch) +` + +// channelMonitorPruneRollupSQL 分批物理删 rollup 表过期行。bucket_date 需要 ::date 转型 +// 保证与 DATE 列一致比较。 +const channelMonitorPruneRollupSQL = ` +WITH batch AS ( + SELECT id FROM channel_monitor_daily_rollups + WHERE bucket_date < $1::date + ORDER BY id + LIMIT $2 +) +DELETE FROM channel_monitor_daily_rollups +WHERE id IN (SELECT id FROM batch) +` + +// deleteChannelMonitorBatched 循环执行分批 DELETE,直到影响行为 0。返回累计删除行数。 +// cutoff 由调用方按列类型传入(明细用 time.Time 对 TIMESTAMPTZ,rollup 用 time.Time SQL 侧 ::date 转型)。 +func deleteChannelMonitorBatched(ctx context.Context, db *sql.DB, query string, cutoff time.Time) (int64, error) { + var total int64 + for { + res, err := db.ExecContext(ctx, query, cutoff, channelMonitorPruneBatchSize) + if err != nil { + return total, fmt.Errorf("channel_monitor prune batch: %w", err) + } + affected, err := res.RowsAffected() + if err != nil { + return total, fmt.Errorf("channel_monitor prune rows affected: %w", err) + } + total += affected + if affected == 0 { + break + } + } + return total, nil +} + +// LoadAggregationWatermark 读 watermark 表(id=1)。 +// watermark 表不是 ent schema(只有一行),直接走原生 SQL。 +// - 行不存在或 last_aggregated_date IS NULL:返回 (nil, nil),由调用方决定首次回填策略 +func (r *channelMonitorRepository) LoadAggregationWatermark(ctx context.Context) (*time.Time, error) { + const q = `SELECT last_aggregated_date FROM channel_monitor_aggregation_watermark WHERE id = 1` + var t sql.NullTime + if err := r.db.QueryRowContext(ctx, q).Scan(&t); err != nil { + if err == sql.ErrNoRows { + return nil, nil + } + return nil, fmt.Errorf("load aggregation watermark: %w", err) + } + if !t.Valid { + return nil, nil + } + return &t.Time, nil +} + +// UpdateAggregationWatermark 更新 watermark(UPSERT 到 id=1)。 +// $1::date 让 PG 把入参 truncate 到 UTC 日期,与 last_aggregated_date 列的 DATE 类型一致。 +func (r *channelMonitorRepository) UpdateAggregationWatermark(ctx context.Context, date time.Time) error { + const q = ` + INSERT INTO channel_monitor_aggregation_watermark (id, last_aggregated_date, updated_at) + VALUES (1, $1::date, NOW()) + ON CONFLICT (id) DO UPDATE SET + last_aggregated_date = EXCLUDED.last_aggregated_date, + updated_at = NOW() + ` + if _, err := r.db.ExecContext(ctx, q, date); err != nil { + return fmt.Errorf("update aggregation watermark: %w", err) + } + return nil +} + +// ---------- helpers ---------- + +func entToServiceMonitor(row *dbent.ChannelMonitor) *service.ChannelMonitor { + if row == nil { + return nil + } + extras := row.ExtraModels + if extras == nil { + extras = []string{} + } + headers := row.ExtraHeaders + if headers == nil { + headers = map[string]string{} + } + out := &service.ChannelMonitor{ + ID: row.ID, + Name: row.Name, + Provider: string(row.Provider), + Endpoint: row.Endpoint, + APIKey: row.APIKeyEncrypted, // 仍为密文,service 层负责解密 + PrimaryModel: row.PrimaryModel, + ExtraModels: extras, + GroupName: row.GroupName, + Enabled: row.Enabled, + IntervalSeconds: row.IntervalSeconds, + LastCheckedAt: row.LastCheckedAt, + CreatedBy: row.CreatedBy, + CreatedAt: row.CreatedAt, + UpdatedAt: row.UpdatedAt, + ExtraHeaders: headers, + BodyOverrideMode: row.BodyOverrideMode, + BodyOverride: row.BodyOverride, + } + if row.TemplateID != nil { + id := *row.TemplateID + out.TemplateID = &id + } + return out +} + +// emptyHeadersIfNilRepo 与 service.emptyHeadersIfNil 功能一致, +// repo 独立一份避免 import 循环。 +func emptyHeadersIfNilRepo(h map[string]string) map[string]string { + if h == nil { + return map[string]string{} + } + return h +} + +// defaultBodyModeRepo 空串归一为 off(同上不循环)。 +func defaultBodyModeRepo(mode string) string { + if mode == "" { + return "off" + } + return mode +} + +func emptySliceIfNil(in []string) []string { + if in == nil { + return []string{} + } + return in +} diff --git a/backend/internal/repository/channel_monitor_template_repo.go b/backend/internal/repository/channel_monitor_template_repo.go new file mode 100644 index 00000000..845d186b --- /dev/null +++ b/backend/internal/repository/channel_monitor_template_repo.go @@ -0,0 +1,195 @@ +package repository + +import ( + "context" + "database/sql" + "fmt" + + dbent "github.com/Wei-Shaw/sub2api/ent" + "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" + "github.com/Wei-Shaw/sub2api/internal/service" +) + +// channelMonitorRequestTemplateRepository 实现 service.ChannelMonitorRequestTemplateRepository。 +// 与 channelMonitorRepository 分开一个文件,职责清晰。 +type channelMonitorRequestTemplateRepository struct { + client *dbent.Client + db *sql.DB +} + +// NewChannelMonitorRequestTemplateRepository 创建模板仓储实例。 +func NewChannelMonitorRequestTemplateRepository(client *dbent.Client, db *sql.DB) service.ChannelMonitorRequestTemplateRepository { + return &channelMonitorRequestTemplateRepository{client: client, db: db} +} + +// ---------- CRUD ---------- + +func (r *channelMonitorRequestTemplateRepository) Create(ctx context.Context, t *service.ChannelMonitorRequestTemplate) error { + client := clientFromContext(ctx, r.client) + builder := client.ChannelMonitorRequestTemplate.Create(). + SetName(t.Name). + SetProvider(channelmonitorrequesttemplate.Provider(t.Provider)). + SetDescription(t.Description). + SetExtraHeaders(emptyHeadersIfNilRepo(t.ExtraHeaders)). + SetBodyOverrideMode(defaultBodyModeRepo(t.BodyOverrideMode)) + if t.BodyOverride != nil { + builder = builder.SetBodyOverride(t.BodyOverride) + } + + created, err := builder.Save(ctx) + if err != nil { + return translatePersistenceError(err, service.ErrChannelMonitorTemplateNotFound, nil) + } + t.ID = created.ID + t.CreatedAt = created.CreatedAt + t.UpdatedAt = created.UpdatedAt + return nil +} + +func (r *channelMonitorRequestTemplateRepository) GetByID(ctx context.Context, id int64) (*service.ChannelMonitorRequestTemplate, error) { + row, err := r.client.ChannelMonitorRequestTemplate.Query(). + Where(channelmonitorrequesttemplate.IDEQ(id)). + Only(ctx) + if err != nil { + return nil, translatePersistenceError(err, service.ErrChannelMonitorTemplateNotFound, nil) + } + return entToServiceTemplate(row), nil +} + +func (r *channelMonitorRequestTemplateRepository) Update(ctx context.Context, t *service.ChannelMonitorRequestTemplate) error { + client := clientFromContext(ctx, r.client) + updater := client.ChannelMonitorRequestTemplate.UpdateOneID(t.ID). + SetName(t.Name). + SetDescription(t.Description). + SetExtraHeaders(emptyHeadersIfNilRepo(t.ExtraHeaders)). + SetBodyOverrideMode(defaultBodyModeRepo(t.BodyOverrideMode)) + if t.BodyOverride != nil { + updater = updater.SetBodyOverride(t.BodyOverride) + } else { + updater = updater.ClearBodyOverride() + } + updated, err := updater.Save(ctx) + if err != nil { + return translatePersistenceError(err, service.ErrChannelMonitorTemplateNotFound, nil) + } + t.UpdatedAt = updated.UpdatedAt + return nil +} + +func (r *channelMonitorRequestTemplateRepository) Delete(ctx context.Context, id int64) error { + client := clientFromContext(ctx, r.client) + if err := client.ChannelMonitorRequestTemplate.DeleteOneID(id).Exec(ctx); err != nil { + return translatePersistenceError(err, service.ErrChannelMonitorTemplateNotFound, nil) + } + return nil +} + +func (r *channelMonitorRequestTemplateRepository) List(ctx context.Context, params service.ChannelMonitorRequestTemplateListParams) ([]*service.ChannelMonitorRequestTemplate, error) { + q := r.client.ChannelMonitorRequestTemplate.Query() + if params.Provider != "" { + q = q.Where(channelmonitorrequesttemplate.ProviderEQ(channelmonitorrequesttemplate.Provider(params.Provider))) + } + rows, err := q. + Order(dbent.Asc(channelmonitorrequesttemplate.FieldProvider), dbent.Asc(channelmonitorrequesttemplate.FieldName)). + All(ctx) + if err != nil { + return nil, fmt.Errorf("list monitor templates: %w", err) + } + out := make([]*service.ChannelMonitorRequestTemplate, 0, len(rows)) + for _, row := range rows { + out = append(out, entToServiceTemplate(row)) + } + return out, nil +} + +// ApplyToMonitors 把模板当前配置覆盖到 monitorIDs 列表里的关联监控。 +// WHERE 双重过滤:template_id = id AND id IN (monitorIDs),防止用户传了未关联本模板的 id +// 就被覆盖。走 ent UpdateMany 保留 hooks。 +func (r *channelMonitorRequestTemplateRepository) ApplyToMonitors(ctx context.Context, id int64, monitorIDs []int64) (int64, error) { + if len(monitorIDs) == 0 { + return 0, nil + } + client := clientFromContext(ctx, r.client) + tpl, err := client.ChannelMonitorRequestTemplate.Query(). + Where(channelmonitorrequesttemplate.IDEQ(id)). + Only(ctx) + if err != nil { + return 0, translatePersistenceError(err, service.ErrChannelMonitorTemplateNotFound, nil) + } + + updater := client.ChannelMonitor.Update(). + Where( + channelmonitor.TemplateIDEQ(id), + channelmonitor.IDIn(monitorIDs...), + ). + SetExtraHeaders(emptyHeadersIfNilRepo(tpl.ExtraHeaders)). + SetBodyOverrideMode(defaultBodyModeRepo(tpl.BodyOverrideMode)) + if tpl.BodyOverride != nil { + updater = updater.SetBodyOverride(tpl.BodyOverride) + } else { + updater = updater.ClearBodyOverride() + } + + affected, err := updater.Save(ctx) + if err != nil { + return 0, fmt.Errorf("apply template to monitors: %w", err) + } + return int64(affected), nil +} + +// CountAssociatedMonitors 统计关联监控数(UI 展示「N 个配置」用)。 +func (r *channelMonitorRequestTemplateRepository) CountAssociatedMonitors(ctx context.Context, id int64) (int64, error) { + count, err := r.client.ChannelMonitor.Query(). + Where(channelmonitor.TemplateIDEQ(id)). + Count(ctx) + if err != nil { + return 0, fmt.Errorf("count monitors for template %d: %w", id, err) + } + return int64(count), nil +} + +// ListAssociatedMonitors 列出模板关联的所有监控简略字段。 +// ORDER BY name 稳定输出方便前端展示。 +func (r *channelMonitorRequestTemplateRepository) ListAssociatedMonitors(ctx context.Context, id int64) ([]*service.AssociatedMonitorBrief, error) { + rows, err := r.client.ChannelMonitor.Query(). + Where(channelmonitor.TemplateIDEQ(id)). + Order(dbent.Asc(channelmonitor.FieldName)). + All(ctx) + if err != nil { + return nil, fmt.Errorf("list associated monitors for template %d: %w", id, err) + } + out := make([]*service.AssociatedMonitorBrief, 0, len(rows)) + for _, row := range rows { + out = append(out, &service.AssociatedMonitorBrief{ + ID: row.ID, + Name: row.Name, + Provider: string(row.Provider), + Enabled: row.Enabled, + }) + } + return out, nil +} + +// ---------- helpers ---------- + +func entToServiceTemplate(row *dbent.ChannelMonitorRequestTemplate) *service.ChannelMonitorRequestTemplate { + if row == nil { + return nil + } + headers := row.ExtraHeaders + if headers == nil { + headers = map[string]string{} + } + return &service.ChannelMonitorRequestTemplate{ + ID: row.ID, + Name: row.Name, + Provider: string(row.Provider), + Description: row.Description, + ExtraHeaders: headers, + BodyOverrideMode: row.BodyOverrideMode, + BodyOverride: row.BodyOverride, + CreatedAt: row.CreatedAt, + UpdatedAt: row.UpdatedAt, + } +} diff --git a/backend/internal/repository/wire.go b/backend/internal/repository/wire.go index d96ab5f2..6d24d312 100644 --- a/backend/internal/repository/wire.go +++ b/backend/internal/repository/wire.go @@ -89,6 +89,8 @@ var ProviderSet = wire.NewSet( NewErrorPassthroughRepository, NewTLSFingerprintProfileRepository, NewChannelRepository, + NewChannelMonitorRepository, + NewChannelMonitorRequestTemplateRepository, // Cache implementations NewGatewayCache, diff --git a/backend/internal/server/api_contract_test.go b/backend/internal/server/api_contract_test.go index 856846ae..e89ef3d9 100644 --- a/backend/internal/server/api_contract_test.go +++ b/backend/internal/server/api_contract_test.go @@ -771,6 +771,9 @@ func TestAPIContracts(t *testing.T) { "balance_low_notify_threshold": 0, "balance_low_notify_recharge_url": "", "account_quota_notify_emails": [], + "channel_monitor_enabled": true, + "channel_monitor_default_interval_seconds": 60, + "available_channels_enabled": false, "wechat_connect_enabled": false, "wechat_connect_app_id": "", "wechat_connect_app_secret_configured": false, @@ -943,6 +946,9 @@ func TestAPIContracts(t *testing.T) { "balance_low_notify_threshold": 0, "balance_low_notify_recharge_url": "", "account_quota_notify_emails": [], + "channel_monitor_enabled": true, + "channel_monitor_default_interval_seconds": 60, + "available_channels_enabled": false, "wechat_connect_enabled": true, "wechat_connect_app_id": "wx-open-config", "wechat_connect_app_secret_configured": true, diff --git a/backend/internal/server/routes/admin.go b/backend/internal/server/routes/admin.go index 07618e31..70160f7e 100644 --- a/backend/internal/server/routes/admin.go +++ b/backend/internal/server/routes/admin.go @@ -88,6 +88,9 @@ func RegisterAdminRoutes( // 渠道管理 registerChannelRoutes(admin, h) + + // 渠道监控 + registerChannelMonitorRoutes(admin, h) } } @@ -567,3 +570,27 @@ func registerChannelRoutes(admin *gin.RouterGroup, h *handler.Handlers) { channels.DELETE("/:id", h.Admin.Channel.Delete) } } + +func registerChannelMonitorRoutes(admin *gin.RouterGroup, h *handler.Handlers) { + monitors := admin.Group("/channel-monitors") + { + monitors.GET("", h.Admin.ChannelMonitor.List) + monitors.POST("", h.Admin.ChannelMonitor.Create) + monitors.GET("/:id", h.Admin.ChannelMonitor.Get) + monitors.PUT("/:id", h.Admin.ChannelMonitor.Update) + monitors.DELETE("/:id", h.Admin.ChannelMonitor.Delete) + monitors.POST("/:id/run", h.Admin.ChannelMonitor.Run) + monitors.GET("/:id/history", h.Admin.ChannelMonitor.History) + } + + templates := admin.Group("/channel-monitor-templates") + { + templates.GET("", h.Admin.ChannelMonitorTemplate.List) + templates.POST("", h.Admin.ChannelMonitorTemplate.Create) + templates.GET("/:id", h.Admin.ChannelMonitorTemplate.Get) + templates.PUT("/:id", h.Admin.ChannelMonitorTemplate.Update) + templates.DELETE("/:id", h.Admin.ChannelMonitorTemplate.Delete) + templates.GET("/:id/monitors", h.Admin.ChannelMonitorTemplate.AssociatedMonitors) + templates.POST("/:id/apply", h.Admin.ChannelMonitorTemplate.Apply) + } +} diff --git a/backend/internal/server/routes/user.go b/backend/internal/server/routes/user.go index b76bb3cd..babab125 100644 --- a/backend/internal/server/routes/user.go +++ b/backend/internal/server/routes/user.go @@ -68,6 +68,12 @@ func RegisterUserRoutes( groups.GET("/rates", h.APIKey.GetUserGroupRates) } + // 用户可用渠道(非管理员接口) + channels := authenticated.Group("/channels") + { + channels.GET("/available", h.AvailableChannel.List) + } + // 使用记录 usage := authenticated.Group("/usage") { @@ -103,5 +109,12 @@ func RegisterUserRoutes( subscriptions.GET("/progress", h.Subscription.GetProgress) subscriptions.GET("/summary", h.Subscription.GetSummary) } + + // 渠道监控(用户只读) + monitors := authenticated.Group("/channel-monitors") + { + monitors.GET("", h.ChannelMonitor.List) + monitors.GET("/:id/status", h.ChannelMonitor.GetStatus) + } } } diff --git a/backend/internal/service/channel.go b/backend/internal/service/channel.go index 93beb972..158bf8a3 100644 --- a/backend/internal/service/channel.go +++ b/backend/internal/service/channel.go @@ -111,6 +111,18 @@ func (c *Channel) IsActive() bool { return c.Status == StatusActive } +// normalizeBillingModelSource 若 BillingModelSource 为空则回填默认值 ChannelMapped。 +// 作为 *Channel 的实体方法集中管理默认值,service 层只需在 Channel 进入内存 +// (缓存装填、repo 读出)时调用一次,下游读路径就无需重复兜底。 +func (c *Channel) normalizeBillingModelSource() { + if c == nil { + return + } + if c.BillingModelSource == "" { + c.BillingModelSource = BillingModelSourceChannelMapped + } +} + // GetModelPricing 根据模型名查找渠道定价,未找到返回 nil。 // 精确匹配,大小写不敏感。返回值拷贝,不污染缓存。 func (c *Channel) GetModelPricing(model string) *ChannelModelPricing { @@ -345,3 +357,209 @@ type ChannelUsageFields struct { BillingModelSource string // 计费模型来源:"requested" / "upstream" / "channel_mapped" ModelMappingChain string // 映射链描述,如 "a→b→c" } + +// SupportedModel 渠道的一个支持模型条目(无通配符、可直接展示给用户) +type SupportedModel struct { + Name string // 用户侧模型名 + Platform string // 所属平台 + Pricing *ChannelModelPricing // 定价详情(nil 表示未配置定价) +} + +// wildcardSuffix 是模型模式中的通配符后缀标记(仅支持尾部匹配)。 +const wildcardSuffix = "*" + +// splitWildcardSuffix 将模型模式拆分为 (prefix, isWildcard)。 +// +// "claude-opus-*" → ("claude-opus-", true) +// "claude-opus-4" → ("claude-opus-4", false) +// "*" → ("", true) +// +// 注意:返回的 prefix 保持原始大小写,由调用方按需 ToLower。 +func splitWildcardSuffix(pattern string) (prefix string, isWildcard bool) { + if strings.HasSuffix(pattern, wildcardSuffix) { + return strings.TrimSuffix(pattern, wildcardSuffix), true + } + return pattern, false +} + +// GetModelPricingByPlatform 在指定平台下查找精确模型的定价,未找到返回 nil。 +// 与 GetModelPricing 的区别:按 Platform 隔离,避免跨平台同名模型误匹配。 +func (c *Channel) GetModelPricingByPlatform(platform, model string) *ChannelModelPricing { + if c == nil { + return nil + } + modelLower := strings.ToLower(model) + for i := range c.ModelPricing { + if c.ModelPricing[i].Platform != platform { + continue + } + for _, m := range c.ModelPricing[i].Models { + if strings.ToLower(m) == modelLower { + cp := c.ModelPricing[i].Clone() + return &cp + } + } + } + return nil +} + +// platformPricingIndex 是单个平台下定价信息的复合索引。 +// 一次扫描即可同时支持精确查找(exact 分支)与有序遍历(wildcard 分支), +// 避免 SupportedModels 对每个平台重复扫描定价列表。 +// +// byLower 与 names/originalCase 共享同一套去重规则:以 lower-case 模型名为 key, +// 首个命中保留其原始大小写。names 维持按定价行扫描顺序的稳定迭代。 +type platformPricingIndex struct { + byLower map[string]*ChannelModelPricing // lowercased model name → pricing (Clone'd) + originalCase map[string]string // lowercased model name → original-case model name + names []string // priced model names in their ORIGINAL case, insertion-ordered, deduped case-insensitively (first wins) +} + +// buildPricingIndex 对渠道的定价列表做一次扫描,按 platform 聚合为查找索引。 +// 索引值是定价条目的 Clone 指针,调用方可安全按需返回副本而不污染缓存。 +// 通配符后缀条目(如 "claude-*")不被索引(它们是模式,不是具体模型名)。 +// 同一平台中以大小写不敏感方式去重,先出现者保留原始大小写。 +func buildPricingIndex(pricings []ChannelModelPricing) map[string]*platformPricingIndex { + idx := make(map[string]*platformPricingIndex) + for i := range pricings { + p := pricings[i] + pidx, ok := idx[p.Platform] + if !ok { + pidx = &platformPricingIndex{ + byLower: make(map[string]*ChannelModelPricing), + originalCase: make(map[string]string), + names: make([]string, 0), + } + idx[p.Platform] = pidx + } + for _, m := range p.Models { + if _, wild := splitWildcardSuffix(m); wild { + continue + } + lower := strings.ToLower(m) + if _, exists := pidx.byLower[lower]; exists { + continue // 首个命中胜出(case-insensitive 去重后第一个定价 / 第一个原始大小写) + } + cp := pricings[i].Clone() + pidx.byLower[lower] = &cp + pidx.originalCase[lower] = m + pidx.names = append(pidx.names, m) + } + } + return idx +} + +// SupportedModels 计算渠道的支持模型列表,结果保证不含通配符。 +// +// 算法(mapping ∪ pricing 并联): +// +// - Pass A(mapping):遍历 ModelMapping +// - 精确 src → target:显示名 = src(用户视角),定价用 target 在同 platform 定价里查 +// (mapping 改写后实际计费的是 target;这是用户感知的"实际花费")。 +// target 为空或为通配符时退化为按 src 自查。 +// - 通配符 src(如 "claude-3-*"):用同 platform 定价里前缀匹配的模型作为候选展开, +// 每个候选用自身定价(通配符场景一般是 passthrough,target 通常也是通配符)。 +// - "*" 单独 mapping key 走通配符分支(前缀为空 → 全展开)。 +// - Pass B(pricing-only):遍历 ModelPricing 中所有非通配符模型,对未在 Pass A 添加过的 +// 补齐——显示名 = 定价模型名,定价 = 自身(这是关键修复:定价存在即代表渠道支持该模型, +// 即使没配映射)。 +// +// 显示名命中定价时使用**定价的原始大小写**(定价是模型身份的事实来源)。 +// 按 (Platform, Name) 稳定排序,按 (Platform, lowercase(Name)) 去重,先到者胜出。 +// +// 注意:定价仅在 channel.ModelPricing 内查找——全局 LiteLLM 回落由调用方 +// (`ChannelService.ListAvailable`)在合成展示数据时叠加。 +func (c *Channel) SupportedModels() []SupportedModel { + if c == nil { + return nil + } + if len(c.ModelMapping) == 0 && len(c.ModelPricing) == 0 { + return nil + } + + idx := buildPricingIndex(c.ModelPricing) + + type dedupKey struct { + platform string + name string + } + seen := make(map[dedupKey]struct{}) + result := make([]SupportedModel, 0) + + // lookup 在 platform pricing index 中按精确名查定价,命中时返回定价大小写。 + lookup := func(pidx *platformPricingIndex, name string) (display string, pricing *ChannelModelPricing) { + if pidx == nil || name == "" { + return name, nil + } + lower := strings.ToLower(name) + if p, ok := pidx.byLower[lower]; ok { + return pidx.originalCase[lower], p + } + return name, nil + } + + add := func(platform, displayName string, pricing *ChannelModelPricing) { + key := dedupKey{platform: platform, name: strings.ToLower(displayName)} + if _, ok := seen[key]; ok { + return + } + seen[key] = struct{}{} + result = append(result, SupportedModel{ + Name: displayName, + Platform: platform, + Pricing: pricing, + }) + } + + // Pass A:从 mapping 展开 + for platform, mapping := range c.ModelMapping { + if len(mapping) == 0 { + continue + } + pidx := idx[platform] + for src, target := range mapping { + prefix, isWild := splitWildcardSuffix(src) + if isWild { + if pidx == nil { + continue + } + prefixLower := strings.ToLower(prefix) + for _, candidate := range pidx.names { + if strings.HasPrefix(strings.ToLower(candidate), prefixLower) { + display, pricing := lookup(pidx, candidate) + add(platform, display, pricing) + } + } + continue + } + // 精确 mapping:定价按 target 查;target 缺失/通配则退化按 src 查 + pricingKey := target + if pricingKey == "" { + pricingKey = src + } + if _, targetWild := splitWildcardSuffix(pricingKey); targetWild { + pricingKey = src + } + _, pricing := lookup(pidx, pricingKey) + // 显示名优先用 src 在定价里的原始大小写(若 src 本身是个定价模型名) + displayName, _ := lookup(pidx, src) + add(platform, displayName, pricing) + } + } + + // Pass B:从 pricing 补齐 mapping 未覆盖的具体模型(修复"定价存在但没配映射 → 不显示") + for platform, pidx := range idx { + for _, name := range pidx.names { + display, pricing := lookup(pidx, name) + add(platform, display, pricing) + } + } + + sort.SliceStable(result, func(i, j int) bool { + if result[i].Platform != result[j].Platform { + return result[i].Platform < result[j].Platform + } + return result[i].Name < result[j].Name + }) + return result +} diff --git a/backend/internal/service/channel_available.go b/backend/internal/service/channel_available.go new file mode 100644 index 00000000..815730e3 --- /dev/null +++ b/backend/internal/service/channel_available.go @@ -0,0 +1,149 @@ +package service + +import ( + "context" + "fmt" + "sort" + "strings" +) + +// AvailableGroupRef 渠道视图中关联分组的简要信息。 +// +// 用户侧「可用渠道」页面据此展示:专属分组 vs 公开分组(IsExclusive)、 +// 订阅 vs 标准(SubscriptionType)、默认倍率(RateMultiplier)。用户专属倍率 +// 不在这里暴露,前端自己通过 /groups/rates 拉取,和 API 密钥页面保持一致。 +type AvailableGroupRef struct { + ID int64 + Name string + Platform string + SubscriptionType string + RateMultiplier float64 + IsExclusive bool +} + +// AvailableChannel 可用渠道视图:用于「可用渠道」页面展示渠道基础信息 + +// 关联的分组 + 推导出的支持模型列表(无通配符)。 +type AvailableChannel struct { + ID int64 + Name string + Description string + Status string + BillingModelSource string + RestrictModels bool + Groups []AvailableGroupRef + SupportedModels []SupportedModel +} + +// ListAvailable 返回所有渠道的可用视图:每个渠道附带关联分组信息与支持模型列表。 +// +// 支持模型通过 (*Channel).SupportedModels() 计算(mapping ∪ pricing 并联)。 +// 对于渠道未配置定价的模型,进一步用 PricingService 的全局 LiteLLM 数据合成 +// 一份展示用定价,让用户看到默认价格而非"未配置"。 +// +// 关联分组信息通过 groupRepo.ListActive 查询后按 ID 映射;渠道 GroupIDs 中未在活跃列表中 +// 的分组(已停用或删除)会被忽略。 +// +// 前置条件:s.groupRepo 必须非 nil(由 wire DI 保证)。直接 nil-deref 用于 fail-fast, +// 避免静默掩盖注入缺失。 +func (s *ChannelService) ListAvailable(ctx context.Context) ([]AvailableChannel, error) { + channels, err := s.repo.ListAll(ctx) + if err != nil { + return nil, fmt.Errorf("list channels: %w", err) + } + + groups, err := s.groupRepo.ListActive(ctx) + if err != nil { + return nil, fmt.Errorf("list active groups: %w", err) + } + groupByID := make(map[int64]AvailableGroupRef, len(groups)) + for i := range groups { + g := groups[i] + groupByID[g.ID] = AvailableGroupRef{ + ID: g.ID, + Name: g.Name, + Platform: g.Platform, + SubscriptionType: g.SubscriptionType, + RateMultiplier: g.RateMultiplier, + IsExclusive: g.IsExclusive, + } + } + + out := make([]AvailableChannel, 0, len(channels)) + for i := range channels { + ch := &channels[i] + groups := make([]AvailableGroupRef, 0, len(ch.GroupIDs)) + for _, gid := range ch.GroupIDs { + if ref, ok := groupByID[gid]; ok { + groups = append(groups, ref) + } + } + sort.SliceStable(groups, func(i, j int) bool { return groups[i].Name < groups[j].Name }) + + ch.normalizeBillingModelSource() + + supported := ch.SupportedModels() + s.fillGlobalPricingFallback(supported) + + out = append(out, AvailableChannel{ + ID: ch.ID, + Name: ch.Name, + Description: ch.Description, + Status: ch.Status, + BillingModelSource: ch.BillingModelSource, + RestrictModels: ch.RestrictModels, + Groups: groups, + SupportedModels: supported, + }) + } + + sort.SliceStable(out, func(i, j int) bool { + return strings.ToLower(out[i].Name) < strings.ToLower(out[j].Name) + }) + return out, nil +} + +// fillGlobalPricingFallback 对未命中渠道定价的支持模型,从全局 LiteLLM 数据合成一份 +// 展示用定价(按 token 计费)。仅用于「可用渠道」展示,不影响真实计费链路。 +// +// 当 s.pricingService 为 nil(测试场景),跳过回落。 +func (s *ChannelService) fillGlobalPricingFallback(models []SupportedModel) { + if s.pricingService == nil { + return + } + for i := range models { + if models[i].Pricing != nil { + continue + } + lp := s.pricingService.GetModelPricing(models[i].Name) + if lp == nil { + continue + } + models[i].Pricing = synthesizePricingFromLiteLLM(lp) + } +} + +// synthesizePricingFromLiteLLM 把 LiteLLM 的定价数据转成 ChannelModelPricing 形态, +// 仅用于展示。BillingMode 固定为 token;图片场景的 OutputCostPerImageToken 也归到 +// ImageOutputPrice 字段(与渠道侧"图片输出按 token 计价"语义一致)。 +// +// LiteLLM 中字段 0 视为未配置,不带入展示。 +func synthesizePricingFromLiteLLM(lp *LiteLLMModelPricing) *ChannelModelPricing { + if lp == nil { + return nil + } + return &ChannelModelPricing{ + BillingMode: BillingModeToken, + InputPrice: nonZeroPtr(lp.InputCostPerToken), + OutputPrice: nonZeroPtr(lp.OutputCostPerToken), + CacheWritePrice: nonZeroPtr(lp.CacheCreationInputTokenCost), + CacheReadPrice: nonZeroPtr(lp.CacheReadInputTokenCost), + ImageOutputPrice: nonZeroPtr(lp.OutputCostPerImageToken), + } +} + +func nonZeroPtr(v float64) *float64 { + if v == 0 { + return nil + } + return &v +} diff --git a/backend/internal/service/channel_available_test.go b/backend/internal/service/channel_available_test.go new file mode 100644 index 00000000..8be70ceb --- /dev/null +++ b/backend/internal/service/channel_available_test.go @@ -0,0 +1,177 @@ +//go:build unit + +package service + +import ( + "context" + "errors" + "testing" + + "github.com/Wei-Shaw/sub2api/internal/pkg/pagination" + "github.com/stretchr/testify/require" +) + +// stubGroupRepoForAvailable 是 ListAvailable 测试用的 GroupRepository stub, +// 仅实现 ListActive;其他方法对本测试无关,返回零值即可。 +// listActiveErr 非 nil 时,ListActive 返回该错误用于错误传播测试。 +// listActiveCalls 记录调用次数,用于断言「失败短路时不再访问 groupRepo」等行为。 +type stubGroupRepoForAvailable struct { + activeGroups []Group + listActiveErr error + listActiveCalls int +} + +func (s *stubGroupRepoForAvailable) ListActive(ctx context.Context) ([]Group, error) { + s.listActiveCalls++ + if s.listActiveErr != nil { + return nil, s.listActiveErr + } + return s.activeGroups, nil +} + +func (s *stubGroupRepoForAvailable) Create(ctx context.Context, group *Group) error { return nil } +func (s *stubGroupRepoForAvailable) GetByID(ctx context.Context, id int64) (*Group, error) { + return nil, nil +} +func (s *stubGroupRepoForAvailable) GetByIDLite(ctx context.Context, id int64) (*Group, error) { + return nil, nil +} +func (s *stubGroupRepoForAvailable) Update(ctx context.Context, group *Group) error { return nil } +func (s *stubGroupRepoForAvailable) Delete(ctx context.Context, id int64) error { return nil } +func (s *stubGroupRepoForAvailable) DeleteCascade(ctx context.Context, id int64) ([]int64, error) { + return nil, nil +} +func (s *stubGroupRepoForAvailable) List(ctx context.Context, params pagination.PaginationParams) ([]Group, *pagination.PaginationResult, error) { + return nil, nil, nil +} +func (s *stubGroupRepoForAvailable) ListWithFilters(ctx context.Context, params pagination.PaginationParams, platform, status, search string, isExclusive *bool) ([]Group, *pagination.PaginationResult, error) { + return nil, nil, nil +} +func (s *stubGroupRepoForAvailable) ListActiveByPlatform(ctx context.Context, platform string) ([]Group, error) { + return nil, nil +} +func (s *stubGroupRepoForAvailable) ExistsByName(ctx context.Context, name string) (bool, error) { + return false, nil +} +func (s *stubGroupRepoForAvailable) GetAccountCount(ctx context.Context, groupID int64) (int64, int64, error) { + return 0, 0, nil +} +func (s *stubGroupRepoForAvailable) DeleteAccountGroupsByGroupID(ctx context.Context, groupID int64) (int64, error) { + return 0, nil +} +func (s *stubGroupRepoForAvailable) GetAccountIDsByGroupIDs(ctx context.Context, groupIDs []int64) ([]int64, error) { + return nil, nil +} +func (s *stubGroupRepoForAvailable) BindAccountsToGroup(ctx context.Context, groupID int64, accountIDs []int64) error { + return nil +} +func (s *stubGroupRepoForAvailable) UpdateSortOrders(ctx context.Context, updates []GroupSortOrderUpdate) error { + return nil +} + +// newAvailableChannelService 构造一个 ChannelService,channelRepo.ListAll 返回给定 channels, +// groupRepo 由参数决定。传入空 stub 表示「活跃分组列表为空」。 +func newAvailableChannelService(channels []Channel, groupRepo GroupRepository) *ChannelService { + repo := &mockChannelRepository{ + listAllFn: func(ctx context.Context) ([]Channel, error) { return channels, nil }, + } + return NewChannelService(repo, groupRepo, nil, nil) +} + +func TestListAvailable_EmptyActiveGroups_NoGroupsAttached(t *testing.T) { + // 活跃分组列表为空时,渠道的 Groups 应为空切片,不报错。 + channels := []Channel{{ + ID: 1, + Name: "chA", + Status: StatusActive, + GroupIDs: []int64{10, 20}, + }} + svc := newAvailableChannelService(channels, &stubGroupRepoForAvailable{}) + out, err := svc.ListAvailable(context.Background()) + require.NoError(t, err) + require.Len(t, out, 1) + require.Empty(t, out[0].Groups) +} + +func TestListAvailable_InactiveGroupIDSilentlyDropped(t *testing.T) { + // 渠道 GroupIDs 中引用的 group 未出现在 ListActive 结果中(已停用或删除),应被静默丢弃。 + channels := []Channel{{ + ID: 1, + Name: "chA", + Status: StatusActive, + GroupIDs: []int64{1, 99}, + }} + groupRepo := &stubGroupRepoForAvailable{ + activeGroups: []Group{{ID: 1, Name: "g1", Platform: "anthropic"}}, + } + svc := newAvailableChannelService(channels, groupRepo) + out, err := svc.ListAvailable(context.Background()) + require.NoError(t, err) + require.Len(t, out, 1) + require.Len(t, out[0].Groups, 1) + require.Equal(t, int64(1), out[0].Groups[0].ID) +} + +func TestListAvailable_SortedByName(t *testing.T) { + channels := []Channel{ + {ID: 1, Name: "beta"}, + {ID: 2, Name: "Alpha"}, + {ID: 3, Name: "charlie"}, + } + svc := newAvailableChannelService(channels, &stubGroupRepoForAvailable{}) + out, err := svc.ListAvailable(context.Background()) + require.NoError(t, err) + require.Len(t, out, 3) + require.Equal(t, "Alpha", out[0].Name) + require.Equal(t, "beta", out[1].Name) + require.Equal(t, "charlie", out[2].Name) +} + +func TestListAvailable_ListAllErrorPropagates(t *testing.T) { + // ListAll 返回错误时 ListAvailable 应直接返回包装后的错误,且不再访问 groupRepo(短路)。 + sentinel := errors.New("list-all-boom") + repo := &mockChannelRepository{ + listAllFn: func(ctx context.Context) ([]Channel, error) { return nil, sentinel }, + } + groupRepo := &stubGroupRepoForAvailable{} + svc := NewChannelService(repo, groupRepo, nil, nil) + out, err := svc.ListAvailable(context.Background()) + require.Nil(t, out) + require.ErrorIs(t, err, sentinel) + require.Contains(t, err.Error(), "list channels", "wrap 前缀缺失,可能 %w 被改为 %v") + require.Equal(t, 0, groupRepo.listActiveCalls, "ListAll 失败后不应再调用 groupRepo.ListActive") +} + +func TestListAvailable_ListActiveErrorPropagates(t *testing.T) { + // groupRepo.ListActive 返回错误时 ListAvailable 应直接返回包装后的错误。 + sentinel := errors.New("list-active-boom") + svc := newAvailableChannelService( + []Channel{{ID: 1, Name: "chA"}}, + &stubGroupRepoForAvailable{listActiveErr: sentinel}, + ) + out, err := svc.ListAvailable(context.Background()) + require.Nil(t, out) + require.ErrorIs(t, err, sentinel) + require.Contains(t, err.Error(), "list active groups", "wrap 前缀缺失,可能 %w 被改为 %v") +} + +func TestListAvailable_DefaultsEmptyBillingModelSource(t *testing.T) { + // 渠道 BillingModelSource 为空时应回填为 BillingModelSourceChannelMapped, + // 显式值应原样保留(由 service 层统一处理,避免各 handler 重复默认逻辑)。 + channels := []Channel{ + {ID: 1, Name: "empty", BillingModelSource: ""}, + {ID: 2, Name: "explicit", BillingModelSource: BillingModelSourceUpstream}, + } + svc := newAvailableChannelService(channels, &stubGroupRepoForAvailable{}) + out, err := svc.ListAvailable(context.Background()) + require.NoError(t, err) + require.Len(t, out, 2) + + // 按 Name 查找,避免依赖排序副作用。 + byName := make(map[string]string, len(out)) + for _, ch := range out { + byName[ch.Name] = ch.BillingModelSource + } + require.Equal(t, BillingModelSourceChannelMapped, byName["empty"]) + require.Equal(t, BillingModelSourceUpstream, byName["explicit"]) +} diff --git a/backend/internal/service/channel_monitor_aggregator.go b/backend/internal/service/channel_monitor_aggregator.go new file mode 100644 index 00000000..09020f5f --- /dev/null +++ b/backend/internal/service/channel_monitor_aggregator.go @@ -0,0 +1,292 @@ +package service + +import ( + "context" + "fmt" + "log/slog" +) + +// 渠道监控聚合层:把 latest + availability 拼成 admin/user 视图所需的 summary / detail。 +// 所有方法都遵守"失败仅日志,返回零值"的原则,避免 N+1 查询失败拖垮列表渲染。 + +// BatchMonitorStatusSummary 批量聚合多个监控的 latest + 7d 可用率(admin/user list 用,消除 N+1)。 +// 失败时返回空 map,错误仅日志,不影响列表渲染。 +// +// 参数: +// - ids: 要聚合的 monitor ID 列表 +// - primaryByID: monitor ID -> primary model(用于读 7d 可用率与 latest 状态) +// - extrasByID: monitor ID -> extra models 列表(用于读 latest 状态填充 ExtraModels) +func (s *ChannelMonitorService) BatchMonitorStatusSummary( + ctx context.Context, + ids []int64, + primaryByID map[int64]string, + extrasByID map[int64][]string, +) map[int64]MonitorStatusSummary { + out := make(map[int64]MonitorStatusSummary, len(ids)) + if len(ids) == 0 { + return out + } + latestMap, err := s.repo.ListLatestForMonitorIDs(ctx, ids) + if err != nil { + slog.Warn("channel_monitor: batch load latest failed", "error", err) + latestMap = map[int64][]*ChannelMonitorLatest{} + } + availMap, err := s.repo.ComputeAvailabilityForMonitors(ctx, ids, monitorAvailability7Days) + if err != nil { + slog.Warn("channel_monitor: batch compute availability failed", "error", err) + availMap = map[int64][]*ChannelMonitorAvailability{} + } + + for _, id := range ids { + out[id] = buildStatusSummary( + indexLatestByModel(latestMap[id]), + indexAvailabilityByModel(availMap[id]), + primaryByID[id], + extrasByID[id], + ) + } + return out +} + +// ListUserView 用户只读视图:列出所有 enabled 监控的概览。 +// 使用批量聚合接口避免 N+1: +// +// 1 次查 monitors; +// 1 次批量 latest(含 ping_latency_ms); +// 1 次批量 7d availability; +// 1 次批量 timeline(主模型最近 N 条)。 +func (s *ChannelMonitorService) ListUserView(ctx context.Context) ([]*UserMonitorView, error) { + monitors, err := s.repo.ListEnabled(ctx) + if err != nil { + return nil, fmt.Errorf("list enabled monitors: %w", err) + } + if len(monitors) == 0 { + return []*UserMonitorView{}, nil + } + + ids, primaryByID, extrasByID := collectMonitorIndexes(monitors) + summaries := s.BatchMonitorStatusSummary(ctx, ids, primaryByID, extrasByID) + latestMap := s.batchLatest(ctx, ids) + timelineMap := s.batchTimeline(ctx, ids, primaryByID) + + views := make([]*UserMonitorView, 0, len(monitors)) + for _, m := range monitors { + primaryLatest := pickLatest(latestMap[m.ID], m.PrimaryModel) + views = append(views, buildUserViewFromSummary(m, summaries[m.ID], primaryLatest, timelineMap[m.ID])) + } + return views, nil +} + +// collectMonitorIndexes 把 monitors 列表按 ID 展开为聚合查询所需的三个索引结构。 +func collectMonitorIndexes(monitors []*ChannelMonitor) ([]int64, map[int64]string, map[int64][]string) { + ids := make([]int64, 0, len(monitors)) + primaryByID := make(map[int64]string, len(monitors)) + extrasByID := make(map[int64][]string, len(monitors)) + for _, m := range monitors { + ids = append(ids, m.ID) + primaryByID[m.ID] = m.PrimaryModel + extrasByID[m.ID] = m.ExtraModels + } + return ids, primaryByID, extrasByID +} + +// batchLatest 批量取 latest per model,失败仅日志(与现有 BatchMonitorStatusSummary 一致,不阻断列表渲染)。 +func (s *ChannelMonitorService) batchLatest(ctx context.Context, ids []int64) map[int64][]*ChannelMonitorLatest { + latestMap, err := s.repo.ListLatestForMonitorIDs(ctx, ids) + if err != nil { + slog.Warn("channel_monitor: user view batch latest failed", "error", err) + return map[int64][]*ChannelMonitorLatest{} + } + return latestMap +} + +// batchTimeline 批量取每个 monitor 主模型最近 monitorTimelineMaxPoints 条历史。 +func (s *ChannelMonitorService) batchTimeline( + ctx context.Context, + ids []int64, + primaryByID map[int64]string, +) map[int64][]*ChannelMonitorHistoryEntry { + timelineMap, err := s.repo.ListRecentHistoryForMonitors(ctx, ids, primaryByID, monitorTimelineMaxPoints) + if err != nil { + slog.Warn("channel_monitor: user view batch timeline failed", "error", err) + return map[int64][]*ChannelMonitorHistoryEntry{} + } + return timelineMap +} + +// pickLatest 从 latest 切片中挑出指定 model 对应项,未命中返回 nil。 +func pickLatest(rows []*ChannelMonitorLatest, model string) *ChannelMonitorLatest { + if model == "" { + return nil + } + for _, r := range rows { + if r.Model == model { + return r + } + } + return nil +} + +// GetUserDetail 用户只读视图:单个监控详情(每个模型 7d/15d/30d 可用率与平均延迟)。 +// 不暴露 api_key。 +func (s *ChannelMonitorService) GetUserDetail(ctx context.Context, id int64) (*UserMonitorDetail, error) { + m, err := s.repo.GetByID(ctx, id) + if err != nil { + return nil, err + } + if !m.Enabled { + return nil, ErrChannelMonitorNotFound + } + + latest, err := s.repo.ListLatestPerModel(ctx, id) + if err != nil { + return nil, fmt.Errorf("list latest per model: %w", err) + } + availMap, err := s.collectAvailabilityWindows(ctx, id) + if err != nil { + return nil, err + } + + models := mergeModelDetails(m, latest, availMap) + return &UserMonitorDetail{ + ID: m.ID, + Name: m.Name, + Provider: m.Provider, + GroupName: m.GroupName, + Models: models, + }, nil +} + +// collectAvailabilityWindows 一次性查询 7/15/30 天三个窗口,按模型组织。 +func (s *ChannelMonitorService) collectAvailabilityWindows(ctx context.Context, monitorID int64) (map[int]map[string]*ChannelMonitorAvailability, error) { + out := make(map[int]map[string]*ChannelMonitorAvailability, 3) + windows := []int{monitorAvailability7Days, monitorAvailability15Days, monitorAvailability30Days} + for _, w := range windows { + rows, err := s.repo.ComputeAvailability(ctx, monitorID, w) + if err != nil { + return nil, fmt.Errorf("compute availability %dd: %w", w, err) + } + out[w] = indexAvailabilityByModel(rows) + } + return out, nil +} + +// ---------- 纯函数 helper(无 IO,可在 batch / 单 monitor / detail 路径复用)---------- + +// indexLatestByModel 把 latest 切片按 model 索引(小工具,避免在 hot path 重复写)。 +func indexLatestByModel(rows []*ChannelMonitorLatest) map[string]*ChannelMonitorLatest { + m := make(map[string]*ChannelMonitorLatest, len(rows)) + for _, r := range rows { + m[r.Model] = r + } + return m +} + +// indexAvailabilityByModel 把 availability 切片按 model 索引。 +func indexAvailabilityByModel(rows []*ChannelMonitorAvailability) map[string]*ChannelMonitorAvailability { + m := make(map[string]*ChannelMonitorAvailability, len(rows)) + for _, r := range rows { + m[r.Model] = r + } + return m +} + +// buildStatusSummary 由 latest + availability 字典构造 MonitorStatusSummary。 +// 不做任何 IO,纯组装,便于在 batch 与单 monitor 路径复用。 +func buildStatusSummary( + latestByModel map[string]*ChannelMonitorLatest, + availByModel map[string]*ChannelMonitorAvailability, + primary string, + extras []string, +) MonitorStatusSummary { + summary := MonitorStatusSummary{ExtraModels: make([]ExtraModelStatus, 0, len(extras))} + if primary != "" { + if l, ok := latestByModel[primary]; ok { + summary.PrimaryStatus = l.Status + summary.PrimaryLatencyMs = l.LatencyMs + } + if a, ok := availByModel[primary]; ok { + summary.Availability7d = a.AvailabilityPct + } + } + for _, model := range extras { + entry := ExtraModelStatus{Model: model} + if l, ok := latestByModel[model]; ok { + entry.Status = l.Status + entry.LatencyMs = l.LatencyMs + } + summary.ExtraModels = append(summary.ExtraModels, entry) + } + return summary +} + +// buildUserViewFromSummary 用预聚合好的 MonitorStatusSummary + 主模型 latest + timeline 装填 UserMonitorView(无 IO)。 +// primaryLatest 可能为 nil(该监控尚无历史);timelineEntries 可能为空。 +func buildUserViewFromSummary( + m *ChannelMonitor, + summary MonitorStatusSummary, + primaryLatest *ChannelMonitorLatest, + timelineEntries []*ChannelMonitorHistoryEntry, +) *UserMonitorView { + view := &UserMonitorView{ + ID: m.ID, + Name: m.Name, + Provider: m.Provider, + GroupName: m.GroupName, + PrimaryModel: m.PrimaryModel, + PrimaryStatus: summary.PrimaryStatus, + PrimaryLatencyMs: summary.PrimaryLatencyMs, + Availability7d: summary.Availability7d, + ExtraModels: summary.ExtraModels, + Timeline: buildTimelinePoints(timelineEntries), + } + if primaryLatest != nil { + view.PrimaryPingLatencyMs = primaryLatest.PingLatencyMs + } + return view +} + +// buildTimelinePoints 把 history entry 裁剪为 timeline 点(去除 message/ID/Model,减小响应体)。 +func buildTimelinePoints(entries []*ChannelMonitorHistoryEntry) []UserMonitorTimelinePoint { + out := make([]UserMonitorTimelinePoint, 0, len(entries)) + for _, e := range entries { + out = append(out, UserMonitorTimelinePoint{ + Status: e.Status, + LatencyMs: e.LatencyMs, + PingLatencyMs: e.PingLatencyMs, + CheckedAt: e.CheckedAt, + }) + } + return out +} + +// mergeModelDetails 合并 latest + availability 三个窗口为 ModelDetail 列表。 +// 复用 indexLatestByModel,避免在多处重复写 build map 逻辑。 +func mergeModelDetails( + m *ChannelMonitor, + latest []*ChannelMonitorLatest, + availMap map[int]map[string]*ChannelMonitorAvailability, +) []ModelDetail { + all := append([]string{m.PrimaryModel}, m.ExtraModels...) + latestByModel := indexLatestByModel(latest) + out := make([]ModelDetail, 0, len(all)) + for _, model := range all { + d := ModelDetail{Model: model} + if l, ok := latestByModel[model]; ok { + d.LatestStatus = l.Status + d.LatestLatencyMs = l.LatencyMs + } + if a, ok := availMap[monitorAvailability7Days][model]; ok { + d.Availability7d = a.AvailabilityPct + d.AvgLatency7dMs = a.AvgLatencyMs + } + if a, ok := availMap[monitorAvailability15Days][model]; ok { + d.Availability15d = a.AvailabilityPct + } + if a, ok := availMap[monitorAvailability30Days][model]; ok { + d.Availability30d = a.AvailabilityPct + } + out = append(out, d) + } + return out +} diff --git a/backend/internal/service/channel_monitor_challenge.go b/backend/internal/service/channel_monitor_challenge.go new file mode 100644 index 00000000..e81a9e2a --- /dev/null +++ b/backend/internal/service/channel_monitor_challenge.go @@ -0,0 +1,80 @@ +package service + +import ( + "fmt" + "math/rand/v2" + "regexp" + "strconv" +) + +// monitorChallengePromptTemplate 1:1 复刻 BingZi-233/check-cx 的 few-shot 模板。 +const monitorChallengePromptTemplate = `Calculate and respond with ONLY the number, nothing else. + +Q: 3 + 5 = ? +A: 8 + +Q: 12 - 7 = ? +A: 5 + +Q: %d %s %d = ? +A:` + +// monitorChallengeNumberRegex 提取响应中的所有整数(含负号)。 +var monitorChallengeNumberRegex = regexp.MustCompile(`-?\d+`) + +// monitorChallenge 一次 challenge 的 prompt + 期望答案。 +type monitorChallenge struct { + Prompt string + Expected string +} + +// generateChallenge 生成一次随机算术 challenge: +// - 随机两个 [monitorChallengeMin, monitorChallengeMax] 整数 +// - 50% 加 / 50% 减;减法用 max - min 保证非负 +// - 渲染 few-shot 模板 +// +// 不强求加密随机:math/rand/v2 足够分散,避免 crypto/rand 的开销。 +func generateChallenge() monitorChallenge { + a := randIntInRange(monitorChallengeMin, monitorChallengeMax) + b := randIntInRange(monitorChallengeMin, monitorChallengeMax) + + if rand.IntN(2) == 0 { //nolint:gosec // 仅用于生成测试问题,无安全影响 + // 加法 + return monitorChallenge{ + Prompt: fmt.Sprintf(monitorChallengePromptTemplate, a, "+", b), + Expected: strconv.Itoa(a + b), + } + } + + // 减法,保证非负 + hi, lo := a, b + if lo > hi { + hi, lo = lo, hi + } + return monitorChallenge{ + Prompt: fmt.Sprintf(monitorChallengePromptTemplate, hi, "-", lo), + Expected: strconv.Itoa(hi - lo), + } +} + +// randIntInRange 返回 [min, max] 闭区间的随机整数。 +func randIntInRange(minVal, maxVal int) int { + if maxVal <= minVal { + return minVal + } + return minVal + rand.IntN(maxVal-minVal+1) //nolint:gosec +} + +// validateChallenge 在响应文本中查找 expected 整数答案,返回是否通过校验。 +func validateChallenge(responseText, expected string) bool { + if responseText == "" || expected == "" { + return false + } + matches := monitorChallengeNumberRegex.FindAllString(responseText, -1) + for _, m := range matches { + if m == expected { + return true + } + } + return false +} diff --git a/backend/internal/service/channel_monitor_checker.go b/backend/internal/service/channel_monitor_checker.go new file mode 100644 index 00000000..33570629 --- /dev/null +++ b/backend/internal/service/channel_monitor_checker.go @@ -0,0 +1,443 @@ +package service + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "net/url" + "regexp" + "strings" + "time" + + "github.com/tidwall/gjson" +) + +// monitorHTTPClient 共享一个 http.Client,避免每次检测重建 transport。 +// 自定义 Transport 在 dial 时强制再次校验 IP,防止 DNS rebinding 绕过 validateEndpoint。 +var monitorHTTPClient = newSSRFSafeHTTPClient(monitorRequestTimeout) + +// monitorPingHTTPClient 用于 endpoint origin 的 HEAD ping,超时更短。 +var monitorPingHTTPClient = newSSRFSafeHTTPClient(monitorPingTimeout) + +// newSSRFSafeHTTPClient 返回一个使用 safeDialContext 的 http.Client。 +// 仅供监控模块对外发起请求使用——所有目标都应是公网 endpoint。 +func newSSRFSafeHTTPClient(timeout time.Duration) *http.Client { + tr := &http.Transport{ + DialContext: safeDialContext, + ForceAttemptHTTP2: true, + MaxIdleConns: 16, + IdleConnTimeout: monitorIdleConnTimeout, + TLSHandshakeTimeout: monitorTLSHandshakeTimeout, + ResponseHeaderTimeout: monitorResponseHeaderTimeout, + } + return &http.Client{Timeout: timeout, Transport: tr} +} + +// CheckOptions 承载一次检测的自定义入参。 +// 所有字段都是可选(零值即等价于"用默认行为")。 +type CheckOptions struct { + // ExtraHeaders 用户自定义 HTTP 头(merge 到 adapter 默认 headers,用户优先)。 + ExtraHeaders map[string]string + // BodyOverrideMode: off | merge | replace + BodyOverrideMode string + // BodyOverride 在 merge 模式下做浅合并(key 命中黑名单时静默丢弃), + // 在 replace 模式下直接当作完整 body。 + BodyOverride map[string]any +} + +// runCheckForModel 对单个 (provider, model) 做一次完整检测。 +// 不返回 error:所有失败都包装进 CheckResult.Status=error/failed。 +// +// opts 承载模板 / 监控快照带来的自定义配置。nil 等同于 "off + 无 extra headers"。 +func runCheckForModel(ctx context.Context, provider, endpoint, apiKey, model string, opts *CheckOptions) *CheckResult { + res := &CheckResult{ + Model: model, + Status: MonitorStatusError, + CheckedAt: time.Now(), + } + + challenge := generateChallenge() + mode := bodyOverrideMode(opts) + + start := time.Now() + respText, rawBody, statusCode, err := callProvider(ctx, provider, endpoint, apiKey, model, challenge.Prompt, opts) + latency := time.Since(start) + latencyMs := int(latency / time.Millisecond) + res.LatencyMs = &latencyMs + + if err != nil { + res.Status = MonitorStatusError + res.Message = truncateMessage(sanitizeErrorMessage(err.Error())) + return res + } + if statusCode < 200 || statusCode >= 300 { + // 错误路径:用 rawBody 而非 respText(gjson textPath 抽取在错误响应里通常为空, + // 会丢掉真正的上游错误信息,例如 `{"error":{"message":"No available accounts ..."}}`)。 + res.Status = MonitorStatusError + bodySnippet := truncateForErrorBody(rawBody) + res.Message = truncateMessage(sanitizeErrorMessage(fmt.Sprintf("upstream HTTP %d: %s", statusCode, bodySnippet))) + return res + } + + // Replace 模式:跳过 challenge 校验(用户 body 是静态的,challenge 没法嵌入)。 + // 改用「HTTP 2xx + 响应文本(adapter.textPath 抽取)非空」作为 operational 判定。 + // 响应文本为空则降级为 failed(视为上游回了 200 但没实际内容)。 + if mode == MonitorBodyOverrideModeReplace { + if strings.TrimSpace(respText) == "" { + res.Status = MonitorStatusFailed + res.Message = truncateMessage("replace-mode: upstream returned 2xx with empty text") + return res + } + return finalizeOperationalOrDegraded(res, latency, latencyMs) + } + + if !validateChallenge(respText, challenge.Expected) { + res.Status = MonitorStatusFailed + res.Message = truncateMessage(sanitizeErrorMessage(fmt.Sprintf("challenge mismatch (expected %s, got %q)", challenge.Expected, respText))) + return res + } + + return finalizeOperationalOrDegraded(res, latency, latencyMs) +} + +// finalizeOperationalOrDegraded 负责走到最后一步的 operational/degraded 判定。 +// 拆出来是为了让 runCheckForModel 不超过 30 行。 +func finalizeOperationalOrDegraded(res *CheckResult, latency time.Duration, latencyMs int) *CheckResult { + if latency >= monitorDegradedThreshold { + res.Status = MonitorStatusDegraded + res.Message = truncateMessage(fmt.Sprintf("slow response: %dms", latencyMs)) + return res + } + res.Status = MonitorStatusOperational + return res +} + +// bodyOverrideMode 归一取 opts.BodyOverrideMode,nil opts / 空串都视为 off。 +func bodyOverrideMode(opts *CheckOptions) string { + if opts == nil || opts.BodyOverrideMode == "" { + return MonitorBodyOverrideModeOff + } + return opts.BodyOverrideMode +} + +// pingEndpointOrigin 对 endpoint 的 origin (scheme://host) 发起 HEAD 请求,返回耗时。 +// 失败时返回 nil(不影响主状态判定)。 +func pingEndpointOrigin(ctx context.Context, endpoint string) *int { + origin, err := extractOrigin(endpoint) + if err != nil || origin == "" { + return nil + } + req, err := http.NewRequestWithContext(ctx, http.MethodHead, origin, nil) + if err != nil { + return nil + } + start := time.Now() + resp, err := monitorPingHTTPClient.Do(req) + if err != nil { + return nil + } + defer func() { _ = resp.Body.Close() }() + _, _ = io.Copy(io.Discard, io.LimitReader(resp.Body, monitorPingDiscardMaxBytes)) + ms := int(time.Since(start) / time.Millisecond) + return &ms +} + +// providerAdapter 描述某个 provider 在 challenge 检测中需要的 4 件事: +// - 拼出请求路径(含 model 占位) +// - 序列化请求体 +// - 构造鉴权头 +// - 从响应 JSON 中按 path 提取文本(gjson path) +// +// 加新 provider 只需要在 providerAdapters 里增加一个条目,无需触碰 callProvider / validateProvider。 +type providerAdapter struct { + buildPath func(model string) string + buildBody func(model, prompt string) ([]byte, error) + buildHeaders func(apiKey string) map[string]string + textPath string // gjson 提取响应文本的 path +} + +// providerAdapters 全部已支持的 provider。键值即 MonitorProvider* 字符串。 +// +//nolint:gochecknoglobals // 适配器表是只读静态数据,初始化后不变更。 +var providerAdapters = map[string]providerAdapter{ + MonitorProviderOpenAI: { + buildPath: func(string) string { return providerOpenAIPath }, + buildBody: func(model, prompt string) ([]byte, error) { + return json.Marshal(map[string]any{ + "model": model, + "messages": []map[string]string{{"role": "user", "content": prompt}}, + "max_tokens": monitorChallengeMaxTokens, + "stream": false, + }) + }, + buildHeaders: func(apiKey string) map[string]string { + return map[string]string{"Authorization": "Bearer " + apiKey} + }, + textPath: "choices.0.message.content", + }, + MonitorProviderAnthropic: { + buildPath: func(string) string { return providerAnthropicPath }, + buildBody: func(model, prompt string) ([]byte, error) { + return json.Marshal(map[string]any{ + "model": model, + "messages": []map[string]string{{"role": "user", "content": prompt}}, + "max_tokens": monitorChallengeMaxTokens, + }) + }, + buildHeaders: func(apiKey string) map[string]string { + return map[string]string{ + "x-api-key": apiKey, + "anthropic-version": monitorAnthropicAPIVersion, + } + }, + textPath: "content.0.text", + }, + MonitorProviderGemini: { + // Gemini 把 model 名写在 URL path 上:/v1beta/models/{model}:generateContent + buildPath: func(model string) string { return fmt.Sprintf(providerGeminiPathTemplate, model) }, + buildBody: func(_, prompt string) ([]byte, error) { + return json.Marshal(map[string]any{ + "contents": []map[string]any{ + {"parts": []map[string]any{{"text": prompt}}}, + }, + "generationConfig": map[string]any{"maxOutputTokens": monitorChallengeMaxTokens}, + }) + }, + // 使用 x-goog-api-key header 而不是 ?key= query,避免 *url.Error 把 key 回填到错误日志。 + buildHeaders: func(apiKey string) map[string]string { + return map[string]string{"x-goog-api-key": apiKey} + }, + textPath: "candidates.0.content.parts.0.text", + }, +} + +// isSupportedProvider 校验 provider 字符串是否在 adapter 表中。 +// 供 validate.go 的 validateProvider 复用,避免两份 switch 漂移。 +func isSupportedProvider(p string) bool { + _, ok := providerAdapters[p] + return ok +} + +// callProvider 通过 providerAdapters 分发到具体实现。 +// opts 承载用户的自定义 headers / body 覆盖(可为 nil)。 +// +// 返回值: +// - extractedText: 按 textPath 抽出的成功文本,仅在 status 2xx 时有意义;非 2xx 时通常为空串 +// - rawBody: 完整响应体的字符串形式(已被 monitorResponseMaxBytes 截断),用于错误路径保留上游真实回包 +// - status: HTTP 状态码 +// - err: 网络 / 序列化错误 +func callProvider(ctx context.Context, provider, endpoint, apiKey, model, prompt string, opts *CheckOptions) (extractedText, rawBody string, status int, err error) { + adapter, ok := providerAdapters[provider] + if !ok { + return "", "", 0, fmt.Errorf("unsupported provider %q", provider) + } + body, err := buildRequestBody(adapter, provider, model, prompt, opts) + if err != nil { + return "", "", 0, err + } + headers := mergeHeaders(adapter.buildHeaders(apiKey), opts) + full := joinURL(endpoint, adapter.buildPath(model)) + respBytes, status, err := postRawJSON(ctx, full, body, headers) + if err != nil { + return "", "", status, err + } + return gjson.GetBytes(respBytes, adapter.textPath).String(), string(respBytes), status, nil +} + +// mergeHeaders 把用户自定义 headers 合并到 adapter 默认 headers 上。 +// 用户值覆盖默认;命中黑名单(hop-by-hop / 由 http.Client 自管的)的 key 静默丢弃。 +func mergeHeaders(base map[string]string, opts *CheckOptions) map[string]string { + if opts == nil || len(opts.ExtraHeaders) == 0 { + return base + } + out := make(map[string]string, len(base)+len(opts.ExtraHeaders)) + for k, v := range base { + out[k] = v + } + for k, v := range opts.ExtraHeaders { + if IsForbiddenHeaderName(k) { + continue + } + out[k] = v + } + return out +} + +// buildRequestBody 根据 body_override_mode 构造请求 body。 +// +// - off: adapter 默认 body +// - merge: adapter 默认 body 与 BodyOverride 浅合并;BodyOverride 中命中 +// bodyMergeKeyDenyList[provider] 的 key 会被静默丢弃,避免破坏 challenge / model 路由 +// - replace: 直接 marshal BodyOverride 作为完整 body +// +// 任何 mode 返回的 []byte 都已经是合法 JSON,可直接送入 postRawJSON。 +func buildRequestBody(adapter providerAdapter, provider, model, prompt string, opts *CheckOptions) ([]byte, error) { + mode := bodyOverrideMode(opts) + + if mode == MonitorBodyOverrideModeReplace { + if opts == nil || len(opts.BodyOverride) == 0 { + return nil, fmt.Errorf("replace mode: body_override is empty") + } + body, err := json.Marshal(opts.BodyOverride) + if err != nil { + return nil, fmt.Errorf("marshal body_override (replace): %w", err) + } + return body, nil + } + + defaultBody, err := adapter.buildBody(model, prompt) + if err != nil { + return nil, fmt.Errorf("marshal default body: %w", err) + } + if mode != MonitorBodyOverrideModeMerge || opts == nil || len(opts.BodyOverride) == 0 { + return defaultBody, nil + } + + var defaultMap map[string]any + if err := json.Unmarshal(defaultBody, &defaultMap); err != nil { + return nil, fmt.Errorf("unmarshal default body for merge: %w", err) + } + deny := bodyMergeKeyDenyList[provider] + for k, v := range opts.BodyOverride { + if deny[k] { + continue + } + defaultMap[k] = v + } + merged, err := json.Marshal(defaultMap) + if err != nil { + return nil, fmt.Errorf("marshal merged body: %w", err) + } + return merged, nil +} + +// bodyMergeKeyDenyList 在 merge 模式下,禁止用户覆盖这些 provider-specific 的关键字段。 +// 思路抄 check-cx 的 EXCLUDED_METADATA_KEYS:保护 challenge / model 路由不被用户误伤。 +// 用户想动这些字段就用 replace 模式(已知会跳 challenge 校验)。 +// +//nolint:gochecknoglobals // 静态查表,初始化后不变。 +var bodyMergeKeyDenyList = map[string]map[string]bool{ + MonitorProviderOpenAI: {"model": true, "messages": true, "stream": true}, + MonitorProviderAnthropic: {"model": true, "messages": true}, + MonitorProviderGemini: {"contents": true}, +} + +// postRawJSON 发送 POST + 已序列化好的 JSON 字节,限制响应体大小,返回响应字节、HTTP status、错误。 +// adapter 自行 marshal 是为了精确控制字段顺序与类型,所以这里直接收 []byte 而不是 any。 +func postRawJSON(ctx context.Context, fullURL string, payload []byte, headers map[string]string) ([]byte, int, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodPost, fullURL, bytes.NewReader(payload)) + if err != nil { + return nil, 0, fmt.Errorf("build request: %w", err) + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Accept", "application/json") + for k, v := range headers { + req.Header.Set(k, v) + } + + resp, err := monitorHTTPClient.Do(req) + if err != nil { + return nil, 0, fmt.Errorf("do request: %w", err) + } + defer func() { _ = resp.Body.Close() }() + + respBody, err := io.ReadAll(io.LimitReader(resp.Body, monitorResponseMaxBytes)) + if err != nil { + return nil, resp.StatusCode, fmt.Errorf("read body: %w", err) + } + return respBody, resp.StatusCode, nil +} + +// joinURL 把 base origin 与 path 拼成完整 URL。 +// 容忍 base 末尾有/无斜杠,path 必带前导斜杠。 +func joinURL(base, path string) string { + base = strings.TrimRight(base, "/") + if !strings.HasPrefix(path, "/") { + path = "/" + path + } + return base + path +} + +// extractOrigin 从一个 endpoint URL 中提取 scheme://host[:port] 部分。 +func extractOrigin(endpoint string) (string, error) { + u, err := url.Parse(endpoint) + if err != nil { + return "", err + } + if u.Scheme == "" || u.Host == "" { + return "", errors.New("endpoint missing scheme or host") + } + return u.Scheme + "://" + u.Host, nil +} + +// monitorSensitiveQueryParamRegex 匹配 URL query 中可能泄露凭证的参数: +// key / api_key / api-key / access_token / token / authorization / x-api-key。 +// 大小写不敏感,匹配 `?name=value` 或 `&name=value` 形式(value 截到 & 或字符串末尾)。 +var monitorSensitiveQueryParamRegex = regexp.MustCompile(`(?i)([?&](?:key|api[_-]?key|access[_-]?token|token|authorization|x-api-key)=)[^&\s"']+`) + +// monitorAPIKeyPatterns 匹配常见 provider 的 API key 字面量。 +// 顺序敏感:sk-ant- 必须放在 sk- 之前,否则会被通用 sk- 模式先消费。 +var monitorAPIKeyPatterns = []struct { + pattern *regexp.Regexp + replace string +}{ + // Anthropic(带前缀,必须先匹配):sk-ant-xxxxxxx + {regexp.MustCompile(`sk-ant-[A-Za-z0-9_-]{20,}`), "sk-ant-***REDACTED***"}, + // OpenAI / Anthropic 通用 sk-: sk-xxxxxxx + {regexp.MustCompile(`sk-[A-Za-z0-9-]{20,}`), "sk-***REDACTED***"}, + // Gemini / Google API Key:固定前缀 + 35 位 + {regexp.MustCompile(`AIza[A-Za-z0-9_-]{35}`), "AIza***REDACTED***"}, + // JWT 三段式(Bearer 后常出现):eyJxxx.eyJxxx.signature + {regexp.MustCompile(`eyJ[A-Za-z0-9_-]{8,}\.eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}`), "eyJ***REDACTED.JWT***"}, +} + +// sanitizeErrorMessage 擦除错误/响应文本中可能泄露的 API key。 +// 处理两类来源: +// 1. URL query 中的 ?key= / ?api_key= 等(Go *url.Error 会回填完整 URL) +// 2. 上游 HTTP body 文本里直接出现的 sk-* / AIza* / JWT 等密钥碎片 +// +// 注意:与 gemini_messages_compat_service.go 的 sanitizeUpstreamErrorMessage 关注点类似但参数集更广, +// 监控模块独立维护,避免互相耦合。 +func sanitizeErrorMessage(msg string) string { + if msg == "" { + return msg + } + msg = monitorSensitiveQueryParamRegex.ReplaceAllString(msg, `${1}REDACTED`) + for _, p := range monitorAPIKeyPatterns { + msg = p.pattern.ReplaceAllString(msg, p.replace) + } + return msg +} + +// truncateMessage 把消息按 monitorMessageMaxBytes 截断,避免 DB 列溢出与日志过长。 +func truncateMessage(msg string) string { + if len(msg) <= monitorMessageMaxBytes { + return msg + } + const ellipsis = "...(truncated)" + cutoff := monitorMessageMaxBytes - len(ellipsis) + if cutoff < 0 { + cutoff = 0 + } + return msg[:cutoff] + ellipsis +} + +// truncateForErrorBody 把上游错误响应 body 压到 monitorErrorBodySnippetMaxBytes 以内, +// 并顺手把连续空白折成一个空格:上游 HTML 错误页常含大量缩进/换行,保留会浪费预算。 +// 被 truncateMessage 做最终总截断兜底,所以这里只负责 body 自身的精简。 +func truncateForErrorBody(body string) string { + body = strings.Join(strings.Fields(body), " ") + if len(body) <= monitorErrorBodySnippetMaxBytes { + return body + } + const ellipsis = "...(body truncated)" + cutoff := monitorErrorBodySnippetMaxBytes - len(ellipsis) + if cutoff < 0 { + cutoff = 0 + } + return body[:cutoff] + ellipsis +} diff --git a/backend/internal/service/channel_monitor_checker_body_test.go b/backend/internal/service/channel_monitor_checker_body_test.go new file mode 100644 index 00000000..323cf8b7 --- /dev/null +++ b/backend/internal/service/channel_monitor_checker_body_test.go @@ -0,0 +1,173 @@ +//go:build unit + +package service + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "strings" + "testing" + "time" +) + +// swapMonitorHTTPClient 临时替换 monitorHTTPClient 为不带 SSRF 校验的普通 client, +// 让 httptest (127.0.0.1) 能连通。测试结束后恢复。 +func swapMonitorHTTPClient(t *testing.T) { + t.Helper() + orig := monitorHTTPClient + monitorHTTPClient = &http.Client{Timeout: 5 * time.Second} + t.Cleanup(func() { monitorHTTPClient = orig }) +} + +// captureHandler 把每次收到的请求 body 和 headers 存起来,测试断言用。 +type captureHandler struct { + lastBody map[string]any + lastHeaders http.Header + respondText string // 写到 Anthropic content[0].text 里(校验用) + status int +} + +func (h *captureHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + h.lastHeaders = r.Header.Clone() + defer func() { _ = r.Body.Close() }() + var parsed map[string]any + _ = json.NewDecoder(r.Body).Decode(&parsed) + h.lastBody = parsed + + if h.status == 0 { + h.status = 200 + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(h.status) + // 构造 Anthropic 格式的响应:content[0].text = h.respondText + _ = json.NewEncoder(w).Encode(map[string]any{ + "content": []map[string]any{ + {"type": "text", "text": h.respondText}, + }, + }) +} + +func setupFakeAnthropic(t *testing.T, handler *captureHandler) string { + t.Helper() + swapMonitorHTTPClient(t) + srv := httptest.NewServer(handler) + t.Cleanup(srv.Close) + return srv.URL +} + +func TestRunCheckForModel_OffMode_PreservesDefaultBody(t *testing.T) { + h := &captureHandler{respondText: "the answer is 42"} + endpoint := setupFakeAnthropic(t, h) + + // 跑一次 off 模式(opts=nil),确认默认 body 行为未变 + _ = runCheckForModel(context.Background(), MonitorProviderAnthropic, endpoint, "sk-fake", "claude-x", nil) + + if h.lastBody["model"] != "claude-x" { + t.Errorf("default body should contain model=claude-x, got %v", h.lastBody["model"]) + } + if _, ok := h.lastBody["messages"]; !ok { + t.Error("default body should contain messages") + } + if h.lastHeaders.Get("x-api-key") != "sk-fake" { + t.Errorf("expected adapter's x-api-key header, got %q", h.lastHeaders.Get("x-api-key")) + } +} + +func TestRunCheckForModel_MergeMode_UserFieldsWinButDenyListProtects(t *testing.T) { + h := &captureHandler{respondText: "the answer is 42"} + endpoint := setupFakeAnthropic(t, h) + + opts := &CheckOptions{ + BodyOverrideMode: MonitorBodyOverrideModeMerge, + BodyOverride: map[string]any{ + "system": "You are Claude Code...", + "max_tokens": float64(999), // 应该覆盖默认 50 + "model": "hacked-model", // 应该被黑名单挡住,保留原 model + "messages": []any{}, // 同上,被挡 + }, + ExtraHeaders: map[string]string{ + "User-Agent": "claude-cli/1.0", + "Content-Length": "999", // 黑名单 + "x-custom": "ok", + }, + } + _ = runCheckForModel(context.Background(), MonitorProviderAnthropic, endpoint, "sk-fake", "claude-x", opts) + + if h.lastBody["system"] != "You are Claude Code..." { + t.Errorf("merge mode should inject system, got %v", h.lastBody["system"]) + } + // max_tokens 覆盖生效 + if mt, ok := h.lastBody["max_tokens"].(float64); !ok || mt != 999 { + t.Errorf("merge mode should override max_tokens to 999, got %v", h.lastBody["max_tokens"]) + } + // model 在黑名单 — 应该保留默认值 + if h.lastBody["model"] != "claude-x" { + t.Errorf("model should be protected by deny list, got %v", h.lastBody["model"]) + } + // messages 在黑名单 — 应该保留默认值(非空) + msgs, _ := h.lastBody["messages"].([]any) + if len(msgs) == 0 { + t.Error("messages should be protected by deny list (kept default, non-empty)") + } + // header 合并 + if h.lastHeaders.Get("User-Agent") != "claude-cli/1.0" { + t.Errorf("extra User-Agent should override, got %q", h.lastHeaders.Get("User-Agent")) + } + if h.lastHeaders.Get("x-custom") != "ok" { + t.Errorf("extra custom header should be present, got %q", h.lastHeaders.Get("x-custom")) + } + // Content-Length 黑名单:会被 net/http 自动重算,但不应由用户的 "999" 决定。 + // 我们无法直接断言丢弃(http.Client 总会填上),只断言请求成功即可。 +} + +func TestRunCheckForModel_ReplaceMode_FullBodyUsedAndChallengeSkipped(t *testing.T) { + // replace 模式下我们的 body 完全自定义,challenge 数学题不会出现在请求里, + // 上游也不会回正确答案 — 但只要 2xx + 响应文本非空,就算 operational + h := &captureHandler{respondText: "any non-empty text"} + endpoint := setupFakeAnthropic(t, h) + + userBody := map[string]any{ + "model": "user-forced-model", + "messages": []any{map[string]any{"role": "user", "content": "hi"}}, + "max_tokens": float64(10), + "system": "You are someone else", + } + opts := &CheckOptions{ + BodyOverrideMode: MonitorBodyOverrideModeReplace, + BodyOverride: userBody, + } + res := runCheckForModel(context.Background(), MonitorProviderAnthropic, endpoint, "sk-fake", "claude-x", opts) + + // 请求 body = 用户提供的原样 + if h.lastBody["model"] != "user-forced-model" { + t.Errorf("replace mode should use user's model, got %v", h.lastBody["model"]) + } + if h.lastBody["system"] != "You are someone else" { + t.Errorf("replace mode should use user's system, got %v", h.lastBody["system"]) + } + // challenge 虽然没命中,但由于 replace 模式跳过 challenge 校验 + 响应非空 → operational + if res.Status != MonitorStatusOperational { + t.Errorf("replace mode with 2xx + non-empty text should be operational, got status=%s message=%q", + res.Status, res.Message) + } +} + +func TestRunCheckForModel_ReplaceMode_EmptyResponseIsFailed(t *testing.T) { + h := &captureHandler{respondText: ""} // 上游 200 但 content[0].text 为空 + endpoint := setupFakeAnthropic(t, h) + + opts := &CheckOptions{ + BodyOverrideMode: MonitorBodyOverrideModeReplace, + BodyOverride: map[string]any{"model": "x", "messages": []any{}}, + } + res := runCheckForModel(context.Background(), MonitorProviderAnthropic, endpoint, "sk-fake", "claude-x", opts) + + if res.Status != MonitorStatusFailed { + t.Errorf("replace mode with empty text should be failed, got status=%s", res.Status) + } + if !strings.Contains(res.Message, "replace-mode") { + t.Errorf("failure message should hint replace-mode, got %q", res.Message) + } +} diff --git a/backend/internal/service/channel_monitor_const.go b/backend/internal/service/channel_monitor_const.go new file mode 100644 index 00000000..2e1614f7 --- /dev/null +++ b/backend/internal/service/channel_monitor_const.go @@ -0,0 +1,142 @@ +package service + +import ( + "time" + + infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors" +) + +// ChannelMonitor 全局常量。 +// 这些是 MVP 阶段的硬编码值,按需可以提到 config 中。 +const ( + // monitorRequestTimeout 单次模型请求总超时(含 Body 读取)。 + monitorRequestTimeout = 45 * time.Second + // monitorPingTimeout HEAD 请求 endpoint origin 的超时。 + monitorPingTimeout = 8 * time.Second + // monitorDegradedThreshold 主请求成功但耗时超过该阈值视为 degraded。 + monitorDegradedThreshold = 6 * time.Second + // monitorHistoryRetentionDays 明细历史保留天数。 + // 60s 默认间隔 * 30 天 ≈ 43200 行/monitor/model,一般部署总量 <= 2M 行, + // PG 无压力;所以直接保留完整明细一个月,可用率查询可以全走原始行不依赖聚合。 + // 聚合表 channel_monitor_daily_rollups 仍然保留,作为长期历史回填/降级查询的兜底。 + monitorHistoryRetentionDays = 30 + // monitorRollupRetentionDays 日聚合保留天数。 + // 日聚合行由 RunDailyMaintenance 在超过该窗口后软删。 + monitorRollupRetentionDays = 30 + // monitorMaintenanceMaxDaysPerRun 单次维护任务最多聚合的天数。 + // 用于限制首次上线回填(30 天)+ 少量余量,避免长事务。 + monitorMaintenanceMaxDaysPerRun = 35 + // monitorWorkerConcurrency 调度器并发执行的监控数(pond 池容量)。 + monitorWorkerConcurrency = 5 + // monitorStartupLoadTimeout Start 时一次性加载所有 enabled monitor 的总超时。 + monitorStartupLoadTimeout = 10 * time.Second + // monitorMinIntervalSeconds / monitorMaxIntervalSeconds 用户配置的检测间隔上下限。 + monitorMinIntervalSeconds = 15 + monitorMaxIntervalSeconds = 3600 + // monitorMessageMaxBytes message 字段最大字节数(与 schema/migration 一致)。 + monitorMessageMaxBytes = 500 + // monitorResponseMaxBytes 单次模型响应最大读取字节,防止 OOM。 + monitorResponseMaxBytes = 64 * 1024 + // monitorErrorBodySnippetMaxBytes 非 2xx 响应时保留上游 body 片段的最大字节数。 + // 留 300 字节足够覆盖典型结构化错误(如 `{"error":{"message":"..."}}`), + // 又给 "upstream HTTP : " 前缀留出余量,避免最终被 monitorMessageMaxBytes (500) 截得太狠。 + monitorErrorBodySnippetMaxBytes = 300 + // monitorChallengeMin / monitorChallengeMax challenge 操作数范围。 + monitorChallengeMin = 1 + monitorChallengeMax = 50 + + // providerOpenAIPath OpenAI Chat Completions 路径。 + providerOpenAIPath = "/v1/chat/completions" + // providerAnthropicPath Anthropic Messages 路径。 + providerAnthropicPath = "/v1/messages" + // providerGeminiPathTemplate Gemini generateContent 路径模板(含 model 占位)。 + providerGeminiPathTemplate = "/v1beta/models/%s:generateContent" + + // MonitorProviderOpenAI / Anthropic / Gemini provider 字符串常量(也是 ent enum 的实际值)。 + MonitorProviderOpenAI = "openai" + MonitorProviderAnthropic = "anthropic" + MonitorProviderGemini = "gemini" + + // MonitorStatusOperational 等监控状态字符串常量(与 ent enum 一致)。 + MonitorStatusOperational = "operational" + MonitorStatusDegraded = "degraded" + MonitorStatusFailed = "failed" + MonitorStatusError = "error" + + // monitorAvailability7Days / 15 / 30 用于聚合查询窗口。 + monitorAvailability7Days = 7 + monitorAvailability15Days = 15 + monitorAvailability30Days = 30 + + // MonitorHistoryDefaultLimit 历史查询默认返回条数(handler 层共享)。 + MonitorHistoryDefaultLimit = 100 + // MonitorHistoryMaxLimit 历史查询最大返回条数(handler 层共享)。 + MonitorHistoryMaxLimit = 1000 + + // monitorTimelineMaxPoints 用户视图 timeline 每个监控最多返回的历史点数。 + monitorTimelineMaxPoints = 60 + + // monitorEndpointResolveTimeout validateEndpoint 解析 hostname 的最长耗时。 + monitorEndpointResolveTimeout = 5 * time.Second + + // ---- checker / runner 行为参数(消除 magic 值)---- + + // monitorAnthropicAPIVersion Anthropic Messages API 版本头。 + monitorAnthropicAPIVersion = "2023-06-01" + // monitorChallengeMaxTokens 单次 challenge 请求的 max_tokens(足够回答个位数算术)。 + monitorChallengeMaxTokens = 50 + + // monitorRunOneBuffer runOne 的总超时缓冲(除请求超时与 ping 超时外的额外裕量)。 + monitorRunOneBuffer = 10 * time.Second + + // monitorIdleConnTimeout HTTP transport 空闲连接关闭超时。 + monitorIdleConnTimeout = 30 * time.Second + // monitorTLSHandshakeTimeout HTTP transport TLS 握手超时。 + monitorTLSHandshakeTimeout = 10 * time.Second + // monitorResponseHeaderTimeout HTTP transport 等待响应头超时。 + monitorResponseHeaderTimeout = 30 * time.Second + // monitorPingDiscardMaxBytes ping 时丢弃响应体的最大字节数。 + monitorPingDiscardMaxBytes = 1024 + + // monitorDialTimeout 自定义 dialer 单次连接超时。 + monitorDialTimeout = 10 * time.Second + // monitorDialKeepAlive 自定义 dialer keep-alive 间隔。 + monitorDialKeepAlive = 30 * time.Second +) + +// 业务错误(统一在此声明,避免散落)。 +var ( + ErrChannelMonitorNotFound = infraerrors.NotFound( + "CHANNEL_MONITOR_NOT_FOUND", "channel monitor not found", + ) + ErrChannelMonitorInvalidProvider = infraerrors.BadRequest( + "CHANNEL_MONITOR_INVALID_PROVIDER", "provider must be one of openai/anthropic/gemini", + ) + ErrChannelMonitorInvalidInterval = infraerrors.BadRequest( + "CHANNEL_MONITOR_INVALID_INTERVAL", "interval_seconds must be in [15, 3600]", + ) + ErrChannelMonitorInvalidEndpoint = infraerrors.BadRequest( + "CHANNEL_MONITOR_INVALID_ENDPOINT", "endpoint must be a valid https URL", + ) + ErrChannelMonitorEndpointScheme = infraerrors.BadRequest( + "CHANNEL_MONITOR_ENDPOINT_SCHEME", "endpoint must use https scheme", + ) + ErrChannelMonitorEndpointPath = infraerrors.BadRequest( + "CHANNEL_MONITOR_ENDPOINT_PATH", "endpoint must be base origin only (no path/query/fragment)", + ) + ErrChannelMonitorEndpointPrivate = infraerrors.BadRequest( + "CHANNEL_MONITOR_ENDPOINT_PRIVATE", "endpoint must be a public host", + ) + ErrChannelMonitorEndpointUnreachable = infraerrors.BadRequest( + "CHANNEL_MONITOR_ENDPOINT_UNREACHABLE", "endpoint hostname could not be resolved", + ) + ErrChannelMonitorMissingAPIKey = infraerrors.BadRequest( + "CHANNEL_MONITOR_MISSING_API_KEY", "api_key is required when creating a monitor", + ) + ErrChannelMonitorMissingPrimaryModel = infraerrors.BadRequest( + "CHANNEL_MONITOR_MISSING_PRIMARY_MODEL", "primary_model is required", + ) + ErrChannelMonitorAPIKeyDecryptFailed = infraerrors.InternalServer( + "CHANNEL_MONITOR_KEY_DECRYPT_FAILED", "api key decryption failed; please re-edit the monitor with a fresh key", + ) +) diff --git a/backend/internal/service/channel_monitor_runner.go b/backend/internal/service/channel_monitor_runner.go new file mode 100644 index 00000000..08178bc6 --- /dev/null +++ b/backend/internal/service/channel_monitor_runner.go @@ -0,0 +1,291 @@ +package service + +import ( + "context" + "log/slog" + "sync" + "time" + + "github.com/alitto/pond/v2" +) + +// MonitorScheduler 调度器接口,供 ChannelMonitorService 在 CRUD 时回调, +// 用 setter 注入避免 service ↔ runner 的 wire 依赖环。 +type MonitorScheduler interface { + // Schedule 为指定监控创建(或重置)独立定时任务。 + // 当 m.Enabled=false 时等同于 Unschedule(m.ID)。 + Schedule(m *ChannelMonitor) + // Unschedule 取消指定监控的定时任务(若存在)。 + Unschedule(id int64) +} + +// monitorRunnerSvc 抽出 runner 实际依赖的两个 service 方法: +// - 启动时加载 enabled monitor +// - 每次 ticker 触发执行检测 +// +// 用接口而非 *ChannelMonitorService 是为了让 runner 单元测试可注入轻量 stub, +// 避免依赖完整的 repo + encryptor 链路。生产实现 *ChannelMonitorService 自然满足。 +type monitorRunnerSvc interface { + ListEnabledMonitors(ctx context.Context) ([]*ChannelMonitor, error) + RunCheck(ctx context.Context, id int64) ([]*CheckResult, error) +} + +// ChannelMonitorRunner 渠道监控调度器。 +// +// 设计: +// - 每个 enabled monitor 对应一个独立 goroutine + ticker(按各自 IntervalSeconds) +// - Start 时一次性加载所有 enabled monitor 并为每个建立任务 +// - Service 在 Create/Update/Delete 后通过 MonitorScheduler 接口回调, +// 即时重建/取消对应任务(无需轮询 DB) +// - 实际 HTTP 检测交给 pond 池(容量 monitorWorkerConcurrency), +// 防止突发并发拖垮上游 +// +// 历史清理与日聚合维护由 OpsCleanupService 的 cron 触发 +// ChannelMonitorService.RunDailyMaintenance(复用 leader lock + heartbeat), +// 不在 runner 职责内。 +type ChannelMonitorRunner struct { + svc monitorRunnerSvc + settingService *SettingService + + pool pond.Pool + parentCtx context.Context + parentCancel context.CancelFunc + + mu sync.Mutex + tasks map[int64]*scheduledMonitor + wg sync.WaitGroup + started bool + stopped bool + + // inFlight 跟踪正在执行的 monitor.ID。fire 调度前会检查避免重复提交, + // 防止单次检测耗时 > interval 时同一 monitor 被并发执行。 + inFlight map[int64]struct{} + inFlightMu sync.Mutex +} + +// scheduledMonitor 单个监控的运行时上下文。 +type scheduledMonitor struct { + id int64 + name string + interval time.Duration + cancel context.CancelFunc +} + +// NewChannelMonitorRunner 构造调度器。Start 在 wire 中调用一次。 +// settingService 用于在每次 fire 前读取功能开关;传 nil 时视为总是启用(兼容测试)。 +// +// pool 在构造时即建好:避免 Start 在 mu 内赋值、fire/Stop 在 mu 外读取的竞态隐患, +// 且 pond.NewPool 创建本身近似零开销,提前建池不会浪费资源。 +func NewChannelMonitorRunner(svc *ChannelMonitorService, settingService *SettingService) *ChannelMonitorRunner { + return newChannelMonitorRunner(svc, settingService) +} + +// newChannelMonitorRunner 内部构造,接受最小化接口,便于单元测试注入 stub。 +func newChannelMonitorRunner(svc monitorRunnerSvc, settingService *SettingService) *ChannelMonitorRunner { + ctx, cancel := context.WithCancel(context.Background()) + return &ChannelMonitorRunner{ + svc: svc, + settingService: settingService, + pool: pond.NewPool(monitorWorkerConcurrency), + parentCtx: ctx, + parentCancel: cancel, + tasks: make(map[int64]*scheduledMonitor), + inFlight: make(map[int64]struct{}), + } +} + +// Start 加载所有 enabled monitor 并为每个建立独立定时任务。 +// 调用方需保证只调一次(wire ProvideChannelMonitorRunner 内只调一次)。 +func (r *ChannelMonitorRunner) Start() { + if r == nil || r.svc == nil { + return + } + r.mu.Lock() + if r.started || r.stopped { + r.mu.Unlock() + return + } + r.started = true + r.mu.Unlock() + + ctx, cancel := context.WithTimeout(context.Background(), monitorStartupLoadTimeout) + defer cancel() + enabled, err := r.svc.ListEnabledMonitors(ctx) + if err != nil { + slog.Error("channel_monitor: load enabled monitors failed at startup", "error", err) + return + } + for _, m := range enabled { + r.Schedule(m) + } + slog.Info("channel_monitor: runner started", "scheduled_tasks", len(enabled)) +} + +// Schedule 为指定监控创建(或重置)独立定时任务。 +// - m.Enabled=false → 等同于 Unschedule(m.ID) +// - 已存在的任务会先被取消再重建(适用于 IntervalSeconds 变更场景) +// - 新任务立即触发首次检测,之后按 IntervalSeconds 周期触发 +func (r *ChannelMonitorRunner) Schedule(m *ChannelMonitor) { + if r == nil || m == nil { + return + } + if !m.Enabled { + r.Unschedule(m.ID) + return + } + interval := time.Duration(m.IntervalSeconds) * time.Second + if interval <= 0 { + // Create/Update 已通过 validateInterval 校验区间,正常路径不可能到这里。 + // 真触发说明数据库中存在违反约束的数据或校验链路有 bug,记 Error 暴露问题。 + slog.Error("channel_monitor: skip schedule for invalid interval", + "monitor_id", m.ID, "interval_seconds", m.IntervalSeconds) + return + } + + r.mu.Lock() + if r.stopped { + r.mu.Unlock() + return + } + if !r.started { + // Start 之前调用 Schedule 通常意味着 wire 顺序错乱: + // 当前 wire 顺序是 SetScheduler → Start,CRUD 钩子最早也只能在请求到达时触发, + // 此时 Start 早已完成。出现此分支时把 monitor 信息打出来便于排查, + // 不入队、不缓存——交给运维通过重启或修复 wire 解决。 + r.mu.Unlock() + slog.Warn("channel_monitor: schedule before runner started, skip", + "monitor_id", m.ID, "name", m.Name) + return + } + if existing, ok := r.tasks[m.ID]; ok { + existing.cancel() + } + ctx, cancel := context.WithCancel(r.parentCtx) + task := &scheduledMonitor{ + id: m.ID, + name: m.Name, + interval: interval, + cancel: cancel, + } + r.tasks[m.ID] = task + r.wg.Add(1) + r.mu.Unlock() + + go r.runScheduled(ctx, task) +} + +// Unschedule 取消指定监控的定时任务(若存在)。 +// 已经在执行中的检测会通过 ctx 取消信号传递。 +func (r *ChannelMonitorRunner) Unschedule(id int64) { + if r == nil { + return + } + r.mu.Lock() + task, ok := r.tasks[id] + if ok { + delete(r.tasks, id) + } + r.mu.Unlock() + if ok { + task.cancel() + } +} + +// Stop 优雅停止:取消所有任务、关闭池。 +func (r *ChannelMonitorRunner) Stop() { + if r == nil { + return + } + r.mu.Lock() + if r.stopped { + r.mu.Unlock() + return + } + r.stopped = true + r.parentCancel() + r.tasks = nil + r.mu.Unlock() + + r.wg.Wait() + r.pool.StopAndWait() +} + +// runScheduled 单个监控的循环:立即触发首次(满足"新建/启用即跑"), +// 之后按 interval 周期触发;ctx 取消即退出。 +func (r *ChannelMonitorRunner) runScheduled(ctx context.Context, task *scheduledMonitor) { + defer r.wg.Done() + + r.fire(ctx, task) + + ticker := time.NewTicker(task.interval) + defer ticker.Stop() + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + r.fire(ctx, task) + } + } +} + +// fire 提交一次检测到 worker 池。功能开关关闭时跳过本次(不取消任务, +// 重新启用时立即恢复);池满或重复在飞时也跳过。 +func (r *ChannelMonitorRunner) fire(ctx context.Context, task *scheduledMonitor) { + if r.settingService != nil && !r.settingService.GetChannelMonitorRuntime(ctx).Enabled { + return + } + if !r.tryAcquireInFlight(task.id) { + slog.Debug("channel_monitor: skip already in-flight", + "monitor_id", task.id, "name", task.name) + return + } + if _, ok := r.pool.TrySubmit(func() { + r.runOne(task.id, task.name) + }); !ok { + // 池满:丢弃本次检测,但必须释放已占用的 inFlight 槽,否则该 monitor 会被永久卡住。 + r.releaseInFlight(task.id) + slog.Warn("channel_monitor: worker pool full, skip submission", + "monitor_id", task.id, "name", task.name) + } +} + +// tryAcquireInFlight 原子地占用 monitor 的 in-flight 槽。 +// 已被占用返回 false(调用方应跳过本次提交)。 +func (r *ChannelMonitorRunner) tryAcquireInFlight(id int64) bool { + r.inFlightMu.Lock() + defer r.inFlightMu.Unlock() + if _, exists := r.inFlight[id]; exists { + return false + } + r.inFlight[id] = struct{}{} + return true +} + +// releaseInFlight 释放 in-flight 槽。runOne 完成(含 panic recover)后必须调用。 +func (r *ChannelMonitorRunner) releaseInFlight(id int64) { + r.inFlightMu.Lock() + delete(r.inFlight, id) + r.inFlightMu.Unlock() +} + +// runOne 执行单个监控的检测。所有错误只记日志,不熔断。 +// 任务结束时(含 panic recover)必须释放 in-flight 槽。 +func (r *ChannelMonitorRunner) runOne(id int64, name string) { + ctx, cancel := context.WithTimeout(context.Background(), monitorRequestTimeout+monitorPingTimeout+monitorRunOneBuffer) + defer cancel() + + defer r.releaseInFlight(id) + + defer func() { + if rec := recover(); rec != nil { + slog.Error("channel_monitor: runner panic", + "monitor_id", id, "name", name, "panic", rec) + } + }() + + if _, err := r.svc.RunCheck(ctx, id); err != nil { + slog.Warn("channel_monitor: run check failed", + "monitor_id", id, "name", name, "error", err) + } +} diff --git a/backend/internal/service/channel_monitor_runner_test.go b/backend/internal/service/channel_monitor_runner_test.go new file mode 100644 index 00000000..5eed3c20 --- /dev/null +++ b/backend/internal/service/channel_monitor_runner_test.go @@ -0,0 +1,277 @@ +//go:build unit + +package service + +import ( + "context" + "sync" + "sync/atomic" + "testing" + "time" +) + +// stubMonitorSvc 实现 monitorRunnerSvc,用于隔离 runner 与真实 service/repo。 +type stubMonitorSvc struct { + enabled []*ChannelMonitor + runCount atomic.Int64 + runCalled chan int64 // 每次 RunCheck 触发时 push 一次(缓冲足够大避免阻塞) + runErr error + listErr error + runHoldFor time.Duration // RunCheck 内额外阻塞的时长,用来测试 Stop 等待行为 +} + +func (s *stubMonitorSvc) ListEnabledMonitors(_ context.Context) ([]*ChannelMonitor, error) { + if s.listErr != nil { + return nil, s.listErr + } + return s.enabled, nil +} + +func (s *stubMonitorSvc) RunCheck(ctx context.Context, id int64) ([]*CheckResult, error) { + s.runCount.Add(1) + if s.runCalled != nil { + select { + case s.runCalled <- id: + default: + } + } + if s.runHoldFor > 0 { + select { + case <-time.After(s.runHoldFor): + case <-ctx.Done(): + } + } + return nil, s.runErr +} + +func newRunnerForTest(svc monitorRunnerSvc) *ChannelMonitorRunner { + return newChannelMonitorRunner(svc, nil) +} + +// 等待 condition 在 timeout 内变 true,否则 t.Fatalf。轮询 5ms 一次。 +func waitFor(t *testing.T, timeout time.Duration, msg string, cond func() bool) { + t.Helper() + deadline := time.Now().Add(timeout) + for time.Now().Before(deadline) { + if cond() { + return + } + time.Sleep(5 * time.Millisecond) + } + if !cond() { + t.Fatalf("waitFor timed out: %s", msg) + } +} + +func runnerTaskCount(r *ChannelMonitorRunner) int { + r.mu.Lock() + defer r.mu.Unlock() + return len(r.tasks) +} + +func runnerTaskPtr(r *ChannelMonitorRunner, id int64) *scheduledMonitor { + r.mu.Lock() + defer r.mu.Unlock() + return r.tasks[id] +} + +// TestSchedule_AddsTaskAndFiresOnce 验证 Schedule 后立即触发一次首检测,并把任务记入 tasks 表。 +func TestSchedule_AddsTaskAndFiresOnce(t *testing.T) { + svc := &stubMonitorSvc{runCalled: make(chan int64, 4)} + r := newRunnerForTest(svc) + r.Start() // svc.enabled 为空,Start 立即完成 + + r.Schedule(&ChannelMonitor{ID: 1, Name: "m1", Enabled: true, IntervalSeconds: 60}) + + if got := runnerTaskCount(r); got != 1 { + t.Fatalf("expected 1 scheduled task, got %d", got) + } + + select { + case id := <-svc.runCalled: + if id != 1 { + t.Fatalf("expected first fire for id=1, got %d", id) + } + case <-time.After(2 * time.Second): + t.Fatal("expected immediate first fire within 2s") + } + + r.Stop() +} + +// TestSchedule_ReplaceCancelsOldTask 验证对同一 id 二次 Schedule 会替换旧 task 实例。 +// (旧 goroutine 通过 ctx 取消退出;这里以 task 指针不同 + Stop 不超时作为证据。) +func TestSchedule_ReplaceCancelsOldTask(t *testing.T) { + svc := &stubMonitorSvc{runCalled: make(chan int64, 8)} + r := newRunnerForTest(svc) + r.Start() + + m := &ChannelMonitor{ID: 7, Name: "m7", Enabled: true, IntervalSeconds: 60} + r.Schedule(m) + first := runnerTaskPtr(r, 7) + if first == nil { + t.Fatal("first schedule did not register task") + } + + r.Schedule(m) + second := runnerTaskPtr(r, 7) + if second == nil { + t.Fatal("second schedule did not register task") + } + if first == second { + t.Fatal("re-Schedule should create a new scheduledMonitor instance") + } + + stoppedWithin(t, r, 3*time.Second) +} + +// TestUnschedule_RemovesTask 验证 Unschedule 删除 task 并使对应 goroutine 退出。 +func TestUnschedule_RemovesTask(t *testing.T) { + svc := &stubMonitorSvc{runCalled: make(chan int64, 4)} + r := newRunnerForTest(svc) + r.Start() + + r.Schedule(&ChannelMonitor{ID: 3, Enabled: true, IntervalSeconds: 60}) + waitFor(t, time.Second, "task registered", func() bool { return runnerTaskCount(r) == 1 }) + + r.Unschedule(3) + if got := runnerTaskCount(r); got != 0 { + t.Fatalf("expected tasks empty after Unschedule, got %d", got) + } + + stoppedWithin(t, r, 3*time.Second) +} + +// TestSchedule_DisabledRedirectsToUnschedule 验证 Enabled=false 等同于 Unschedule。 +func TestSchedule_DisabledRedirectsToUnschedule(t *testing.T) { + svc := &stubMonitorSvc{runCalled: make(chan int64, 4)} + r := newRunnerForTest(svc) + r.Start() + + r.Schedule(&ChannelMonitor{ID: 9, Enabled: true, IntervalSeconds: 60}) + waitFor(t, time.Second, "task registered", func() bool { return runnerTaskCount(r) == 1 }) + + r.Schedule(&ChannelMonitor{ID: 9, Enabled: false, IntervalSeconds: 60}) + if got := runnerTaskCount(r); got != 0 { + t.Fatalf("expected tasks empty after disabled re-Schedule, got %d", got) + } + + stoppedWithin(t, r, 3*time.Second) +} + +// TestSchedule_InvalidIntervalSkipped 验证 IntervalSeconds<=0 不会注册任务(防御性检查)。 +func TestSchedule_InvalidIntervalSkipped(t *testing.T) { + svc := &stubMonitorSvc{} + r := newRunnerForTest(svc) + r.Start() + + r.Schedule(&ChannelMonitor{ID: 1, Enabled: true, IntervalSeconds: 0}) + if got := runnerTaskCount(r); got != 0 { + t.Fatalf("expected no task for invalid interval, got %d", got) + } + r.Stop() +} + +// TestSchedule_BeforeStartIsNoOp 验证 Start 之前调用 Schedule 不会注册任务。 +func TestSchedule_BeforeStartIsNoOp(t *testing.T) { + svc := &stubMonitorSvc{} + r := newRunnerForTest(svc) + // 故意不调用 Start + + r.Schedule(&ChannelMonitor{ID: 1, Enabled: true, IntervalSeconds: 60}) + if got := runnerTaskCount(r); got != 0 { + t.Fatalf("expected no task before Start, got %d", got) + } + r.Stop() +} + +// TestStart_LoadsAllEnabledMonitors 验证 Start 会为 ListEnabledMonitors 返回的每条记录建立任务。 +func TestStart_LoadsAllEnabledMonitors(t *testing.T) { + svc := &stubMonitorSvc{ + enabled: []*ChannelMonitor{ + {ID: 1, Enabled: true, IntervalSeconds: 60}, + {ID: 2, Enabled: true, IntervalSeconds: 60}, + {ID: 3, Enabled: true, IntervalSeconds: 60}, + }, + } + r := newRunnerForTest(svc) + r.Start() + waitFor(t, 2*time.Second, "all 3 tasks scheduled", func() bool { return runnerTaskCount(r) == 3 }) + + stoppedWithin(t, r, 3*time.Second) +} + +// TestStop_DrainsAllGoroutines 验证 Stop 会等待所有调度 goroutine 退出(无游离)。 +func TestStop_DrainsAllGoroutines(t *testing.T) { + svc := &stubMonitorSvc{} + r := newRunnerForTest(svc) + r.Start() + + for id := int64(1); id <= 5; id++ { + r.Schedule(&ChannelMonitor{ID: id, Enabled: true, IntervalSeconds: 60}) + } + waitFor(t, 2*time.Second, "5 tasks scheduled", func() bool { return runnerTaskCount(r) == 5 }) + + stoppedWithin(t, r, 3*time.Second) +} + +// TestStop_WaitsForInFlightCheck 验证 Stop 会等待正在执行的 RunCheck 退出(pool.StopAndWait)。 +func TestStop_WaitsForInFlightCheck(t *testing.T) { + svc := &stubMonitorSvc{ + runCalled: make(chan int64, 1), + runHoldFor: 200 * time.Millisecond, + } + r := newRunnerForTest(svc) + r.Start() + r.Schedule(&ChannelMonitor{ID: 1, Enabled: true, IntervalSeconds: 60}) + + select { + case <-svc.runCalled: + case <-time.After(2 * time.Second): + t.Fatal("first fire never happened") + } + + start := time.Now() + stoppedWithin(t, r, 3*time.Second) + elapsed := time.Since(start) + // Stop 必须等待 in-flight check 跑完(runHoldFor=200ms),耗时下界约 100ms。 + if elapsed < 100*time.Millisecond { + t.Fatalf("Stop returned too fast (%v); did not wait for in-flight check", elapsed) + } +} + +// TestInFlight_PoolFullReleasesSlot 直接驱动 fire 路径,模拟 pool.TrySubmit 失败时 inFlight 必须释放。 +// 用一个小型 stub pool 替换 r.pool 不便(pond.Pool 是接口但 mock 麻烦), +// 改为:占满 inFlight 后直接 fire,验证不会在 inFlight 空槽时永久卡住。 +func TestInFlight_AcquireReleaseSymmetric(t *testing.T) { + svc := &stubMonitorSvc{} + r := newRunnerForTest(svc) + + if !r.tryAcquireInFlight(42) { + t.Fatal("first acquire should succeed") + } + if r.tryAcquireInFlight(42) { + t.Fatal("second acquire (no release) must fail") + } + r.releaseInFlight(42) + if !r.tryAcquireInFlight(42) { + t.Fatal("acquire after release should succeed") + } + r.releaseInFlight(42) +} + +// stoppedWithin 在 timeout 内并行调用 Stop,超时则 Fatal。验证 Stop 不会阻塞。 +func stoppedWithin(t *testing.T, r *ChannelMonitorRunner, timeout time.Duration) { + t.Helper() + done := make(chan struct{}) + var once sync.Once + go func() { + r.Stop() + once.Do(func() { close(done) }) + }() + select { + case <-done: + case <-time.After(timeout): + t.Fatalf("Stop did not return within %s — leaked goroutine?", timeout) + } +} diff --git a/backend/internal/service/channel_monitor_service.go b/backend/internal/service/channel_monitor_service.go new file mode 100644 index 00000000..7050e141 --- /dev/null +++ b/backend/internal/service/channel_monitor_service.go @@ -0,0 +1,539 @@ +package service + +import ( + "context" + "fmt" + "log/slog" + "strings" + "sync" + "time" + + "golang.org/x/sync/errgroup" +) + +// ChannelMonitorRepository 渠道监控数据访问接口。 +// 入参/返回的指针类型均使用 service 包的 ChannelMonitor 模型, +// repository 实现负责与 ent 模型互转,并保持 api_key_encrypted 字段为密文。 +type ChannelMonitorRepository interface { + // CRUD + Create(ctx context.Context, m *ChannelMonitor) error + GetByID(ctx context.Context, id int64) (*ChannelMonitor, error) + Update(ctx context.Context, m *ChannelMonitor) error + Delete(ctx context.Context, id int64) error + List(ctx context.Context, params ChannelMonitorListParams) ([]*ChannelMonitor, int64, error) + + // 调度器辅助 + ListEnabled(ctx context.Context) ([]*ChannelMonitor, error) + MarkChecked(ctx context.Context, id int64, checkedAt time.Time) error + InsertHistoryBatch(ctx context.Context, rows []*ChannelMonitorHistoryRow) error + DeleteHistoryBefore(ctx context.Context, before time.Time) (int64, error) + + // 历史记录 + ListHistory(ctx context.Context, monitorID int64, model string, limit int) ([]*ChannelMonitorHistoryEntry, error) + + // 用户视图聚合 + ListLatestPerModel(ctx context.Context, monitorID int64) ([]*ChannelMonitorLatest, error) + ComputeAvailability(ctx context.Context, monitorID int64, windowDays int) ([]*ChannelMonitorAvailability, error) + + // 批量聚合(admin/user list 用,避免 N+1) + ListLatestForMonitorIDs(ctx context.Context, ids []int64) (map[int64][]*ChannelMonitorLatest, error) + ComputeAvailabilityForMonitors(ctx context.Context, ids []int64, windowDays int) (map[int64][]*ChannelMonitorAvailability, error) + // ListRecentHistoryForMonitors 批量取多个 monitor 各自主模型(primaryModels[monitorID])最近 perMonitorLimit 条历史。 + // 返回的 entry 已按 checked_at DESC 排序(最新在前),不含 message 字段。 + ListRecentHistoryForMonitors(ctx context.Context, ids []int64, primaryModels map[int64]string, perMonitorLimit int) (map[int64][]*ChannelMonitorHistoryEntry, error) + + // ---------- 聚合维护(OpsCleanupService 调用) ---------- + + // UpsertDailyRollupsFor 把 targetDate 当天的明细按 (monitor_id, model, bucket_date) + // 聚合到 channel_monitor_daily_rollups。targetDate 会被截断到日期; + // 用 ON CONFLICT DO UPDATE 实现幂等回填,返回 upsert 影响的行数。 + UpsertDailyRollupsFor(ctx context.Context, targetDate time.Time) (int64, error) + // DeleteRollupsBefore 软删 bucket_date < beforeDate 的聚合行,返回删除行数。 + DeleteRollupsBefore(ctx context.Context, beforeDate time.Time) (int64, error) + // LoadAggregationWatermark 读 watermark(id=1)。 + // 返回 nil 表示从未聚合过;watermark 表本身预期已存在单行(migration 110 写入)。 + LoadAggregationWatermark(ctx context.Context) (*time.Time, error) + // UpdateAggregationWatermark 写 watermark(UPSERT 到 id=1)。 + UpdateAggregationWatermark(ctx context.Context, date time.Time) error +} + +// ChannelMonitorService 渠道监控管理服务。 +type ChannelMonitorService struct { + repo ChannelMonitorRepository + encryptor SecretEncryptor + // scheduler 由 wire 通过 SetScheduler 注入;CRUD 后调用对应钩子即时同步任务。 + // 测试或未注入场景下保持 nil,所有钩子调用变为 no-op。 + scheduler MonitorScheduler +} + +// NewChannelMonitorService 创建渠道监控服务实例。 +func NewChannelMonitorService(repo ChannelMonitorRepository, encryptor SecretEncryptor) *ChannelMonitorService { + return &ChannelMonitorService{repo: repo, encryptor: encryptor} +} + +// ---------- CRUD ---------- + +// List 列表查询(支持 provider/enabled/search 过滤 + 分页)。 +// 返回的 ChannelMonitor.APIKey 已解密为明文,handler 层负责脱敏。 +func (s *ChannelMonitorService) List(ctx context.Context, params ChannelMonitorListParams) ([]*ChannelMonitor, int64, error) { + if params.Page < 1 { + params.Page = 1 + } + if params.PageSize < 1 || params.PageSize > 200 { + params.PageSize = 20 + } + items, total, err := s.repo.List(ctx, params) + if err != nil { + return nil, 0, fmt.Errorf("list channel monitors: %w", err) + } + for _, it := range items { + s.decryptInPlace(it) + } + return items, total, nil +} + +// Get 查询单个监控(解密 API Key)。 +func (s *ChannelMonitorService) Get(ctx context.Context, id int64) (*ChannelMonitor, error) { + m, err := s.repo.GetByID(ctx, id) + if err != nil { + return nil, err + } + s.decryptInPlace(m) + return m, nil +} + +// Create 创建监控(内部加密 api_key)。 +func (s *ChannelMonitorService) Create(ctx context.Context, p ChannelMonitorCreateParams) (*ChannelMonitor, error) { + if err := validateCreateParams(p); err != nil { + return nil, err + } + if err := validateBodyModeParams(p.BodyOverrideMode, p.BodyOverride); err != nil { + return nil, err + } + if err := validateExtraHeaders(p.ExtraHeaders); err != nil { + return nil, err + } + encrypted, err := s.encryptor.Encrypt(p.APIKey) + if err != nil { + return nil, fmt.Errorf("encrypt api key: %w", err) + } + m := &ChannelMonitor{ + Name: strings.TrimSpace(p.Name), + Provider: p.Provider, + Endpoint: normalizeEndpoint(p.Endpoint), + APIKey: encrypted, // 注意:传入 repository 时该字段为密文 + PrimaryModel: strings.TrimSpace(p.PrimaryModel), + ExtraModels: normalizeModels(p.ExtraModels), + GroupName: strings.TrimSpace(p.GroupName), + Enabled: p.Enabled, + IntervalSeconds: p.IntervalSeconds, + CreatedBy: p.CreatedBy, + TemplateID: p.TemplateID, + ExtraHeaders: emptyHeadersIfNil(p.ExtraHeaders), + BodyOverrideMode: defaultBodyMode(p.BodyOverrideMode), + BodyOverride: p.BodyOverride, + } + if err := s.repo.Create(ctx, m); err != nil { + return nil, fmt.Errorf("create channel monitor: %w", err) + } + // 不再调 s.Get 重走解密链:已知刚加密的明文,直接构造响应。 + // 这样可避免 SecretEncryptor 解密失败时 APIKey 被静默清空的问题(见 Fix 4)。 + m.APIKey = strings.TrimSpace(p.APIKey) + if s.scheduler != nil { + s.scheduler.Schedule(m) + } + return m, nil +} + +// validateCreateParams 把 Create 入参的所有校验聚拢为一个函数,避免 Create 主体超过 30 行。 +func validateCreateParams(p ChannelMonitorCreateParams) error { + if err := validateProvider(p.Provider); err != nil { + return err + } + if err := validateInterval(p.IntervalSeconds); err != nil { + return err + } + if err := validateEndpoint(p.Endpoint); err != nil { + return err + } + if strings.TrimSpace(p.APIKey) == "" { + return ErrChannelMonitorMissingAPIKey + } + if strings.TrimSpace(p.PrimaryModel) == "" { + return ErrChannelMonitorMissingPrimaryModel + } + return nil +} + +// Update 更新监控。APIKey 字段:nil 或空字符串 = 不修改;非空 = 加密后覆盖。 +func (s *ChannelMonitorService) Update(ctx context.Context, id int64, p ChannelMonitorUpdateParams) (*ChannelMonitor, error) { + existing, err := s.repo.GetByID(ctx, id) + if err != nil { + return nil, err + } + if err := applyMonitorUpdate(existing, p); err != nil { + return nil, err + } + + newPlainAPIKey, apiKeyUpdated, err := s.applyAPIKeyUpdate(existing, p.APIKey) + if err != nil { + return nil, err + } + + if err := s.repo.Update(ctx, existing); err != nil { + return nil, fmt.Errorf("update channel monitor: %w", err) + } + + // 不再调 s.Get 重走解密链:避免二次解密带来的"密文被静默清空"风险(与 Create 一致)。 + if apiKeyUpdated { + existing.APIKey = newPlainAPIKey + } else { + s.decryptInPlace(existing) + } + if s.scheduler != nil { + // Schedule 内部根据 Enabled 自动选择 Unschedule 或重建任务, + // IntervalSeconds 变化也会被自然吸收(旧 task 取消 + 新 task 用新 interval)。 + s.scheduler.Schedule(existing) + } + return existing, nil +} + +// applyAPIKeyUpdate 处理 Update 中的 APIKey 字段: +// - 入参 raw 为 nil 或空白:不修改 existing.APIKey(仍为密文),返回 updated=false +// - 非空:加密后写入 existing.APIKey;同时把明文返回给调用方, +// 供写库成功后塞回 existing 避免把密文吐回客户端 +func (s *ChannelMonitorService) applyAPIKeyUpdate(existing *ChannelMonitor, raw *string) (plain string, updated bool, err error) { + if raw == nil || strings.TrimSpace(*raw) == "" { + return "", false, nil + } + plain = strings.TrimSpace(*raw) + encrypted, encErr := s.encryptor.Encrypt(plain) + if encErr != nil { + return "", false, fmt.Errorf("encrypt api key: %w", encErr) + } + existing.APIKey = encrypted + return plain, true, nil +} + +// Delete 删除监控(历史通过外键 CASCADE 自动清理)。 +func (s *ChannelMonitorService) Delete(ctx context.Context, id int64) error { + if err := s.repo.Delete(ctx, id); err != nil { + return fmt.Errorf("delete channel monitor: %w", err) + } + if s.scheduler != nil { + s.scheduler.Unschedule(id) + } + return nil +} + +// ListHistory 列出某个监控最近的检测历史。 +// model 为空表示返回所有模型;limit <= 0 时使用默认值,超过上限会被截断。 +func (s *ChannelMonitorService) ListHistory(ctx context.Context, id int64, model string, limit int) ([]*ChannelMonitorHistoryEntry, error) { + if _, err := s.repo.GetByID(ctx, id); err != nil { + return nil, err + } + if limit <= 0 { + limit = MonitorHistoryDefaultLimit + } + if limit > MonitorHistoryMaxLimit { + limit = MonitorHistoryMaxLimit + } + entries, err := s.repo.ListHistory(ctx, id, strings.TrimSpace(model), limit) + if err != nil { + return nil, fmt.Errorf("list history: %w", err) + } + return entries, nil +} + +// ---------- 业务 ---------- + +// RunCheck 同步触发对一个监控的检测:并发跑 primary + extra 模型, +// 写历史记录并更新 last_checked_at。返回每个模型的检测结果。 +func (s *ChannelMonitorService) RunCheck(ctx context.Context, id int64) ([]*CheckResult, error) { + m, err := s.Get(ctx, id) // 已解密 APIKey + if err != nil { + return nil, err + } + if m.APIKeyDecryptFailed { + return nil, ErrChannelMonitorAPIKeyDecryptFailed + } + results := s.runChecksConcurrent(ctx, m) + s.persistCheckResults(ctx, m, results) + return results, nil +} + +// persistCheckResults 写入本次检测的历史记录并更新 last_checked_at。 +// 任一写库失败都只记日志,不影响调用方拿到 results(与 MVP 期望一致:宁可漏记历史也要先返回结果)。 +func (s *ChannelMonitorService) persistCheckResults(ctx context.Context, m *ChannelMonitor, results []*CheckResult) { + rows := make([]*ChannelMonitorHistoryRow, 0, len(results)) + for _, r := range results { + rows = append(rows, &ChannelMonitorHistoryRow{ + MonitorID: m.ID, + Model: r.Model, + Status: r.Status, + LatencyMs: r.LatencyMs, + PingLatencyMs: r.PingLatencyMs, + Message: r.Message, + CheckedAt: r.CheckedAt, + }) + } + if err := s.repo.InsertHistoryBatch(ctx, rows); err != nil { + slog.Error("channel_monitor: insert history failed", + "monitor_id", m.ID, "name", m.Name, "error", err) + } + if err := s.repo.MarkChecked(ctx, m.ID, time.Now()); err != nil { + slog.Error("channel_monitor: mark checked failed", + "monitor_id", m.ID, "error", err) + } +} + +// runChecksConcurrent 对 primary + extra 模型并发执行检测。 +// errgroup 仅用于等待,不传播错误(每个 model 失败都已打包进 CheckResult)。 +func (s *ChannelMonitorService) runChecksConcurrent(ctx context.Context, m *ChannelMonitor) []*CheckResult { + models := append([]string{m.PrimaryModel}, m.ExtraModels...) + results := make([]*CheckResult, len(models)) + + // ping 共享一次,所有模型记录同一个 ping 延迟。 + pingMs := pingEndpointOrigin(ctx, m.Endpoint) + + // 所有模型共用同一份 CheckOptions(来自监控的快照字段)。 + opts := &CheckOptions{ + ExtraHeaders: m.ExtraHeaders, + BodyOverrideMode: m.BodyOverrideMode, + BodyOverride: m.BodyOverride, + } + + var eg errgroup.Group + var mu sync.Mutex + for i, model := range models { + i, model := i, model + eg.Go(func() error { + r := runCheckForModel(ctx, m.Provider, m.Endpoint, m.APIKey, model, opts) + r.PingLatencyMs = pingMs + mu.Lock() + results[i] = r + mu.Unlock() + return nil + }) + } + _ = eg.Wait() + return results +} + +// ---------- 调度器协作 ---------- + +// SetScheduler 由 wire 在 runner 构造后注入,用于在 CRUD 时即时同步任务表。 +// 通过 setter 注入避免 service ↔ runner 的依赖环。 +func (s *ChannelMonitorService) SetScheduler(sched MonitorScheduler) { + s.scheduler = sched +} + +// ListEnabledMonitors 返回所有 enabled=true 的监控(解密后),供 runner 启动时建立任务表。 +func (s *ChannelMonitorService) ListEnabledMonitors(ctx context.Context) ([]*ChannelMonitor, error) { + all, err := s.repo.ListEnabled(ctx) + if err != nil { + return nil, err + } + for _, m := range all { + s.decryptInPlace(m) + } + return all, nil +} + +// cleanupOldHistory 删除 monitorHistoryRetentionDays 天之前的明细历史记录。 +// 由 RunDailyMaintenance 调用;SoftDeleteMixin 自动把 DELETE 改为 UPDATE deleted_at。 +func (s *ChannelMonitorService) cleanupOldHistory(ctx context.Context) error { + before := time.Now().UTC().AddDate(0, 0, -monitorHistoryRetentionDays) + deleted, err := s.repo.DeleteHistoryBefore(ctx, before) + if err != nil { + return fmt.Errorf("delete history before %s: %w", before.Format(time.RFC3339), err) + } + if deleted > 0 { + slog.Info("channel_monitor: history cleanup", + "deleted_rows", deleted, "before", before.Format(time.RFC3339)) + } + return nil +} + +// RunDailyMaintenance 每日维护任务:聚合昨天之前未聚合的明细,软删过期明细和聚合。 +// 由 OpsCleanupService 的 cron 调度触发(共享 schedule 和 leader lock)。 +// +// 幂等性: +// - watermark 保证已聚合的日期不会重复处理; +// - UpsertDailyRollupsFor 内部使用 ON CONFLICT DO UPDATE,同一日重复跑结果一致。 +// +// 每一步失败都只记 slog.Warn,整体函数始终返回 nil 让后续步骤能继续跑 +// (与 OpsCleanupService.runCleanupOnce 风格一致)。 +func (s *ChannelMonitorService) RunDailyMaintenance(ctx context.Context) error { + now := time.Now().UTC() + today := now.Truncate(24 * time.Hour) + + if err := s.runDailyAggregation(ctx, today); err != nil { + slog.Warn("channel_monitor: maintenance step failed", + "step", "aggregate", "error", err) + } + if err := s.cleanupOldHistory(ctx); err != nil { + slog.Warn("channel_monitor: maintenance step failed", + "step", "prune_history", "error", err) + } + if err := s.cleanupOldRollups(ctx, today); err != nil { + slog.Warn("channel_monitor: maintenance step failed", + "step", "prune_rollups", "error", err) + } + return nil +} + +// runDailyAggregation 从 watermark+1 聚合到昨天(UTC)。 +// 首次跑(watermark nil):从 today-monitorRollupRetentionDays 开始回填。 +// 每次最多聚合 monitorMaintenanceMaxDaysPerRun 天,避免长事务。 +func (s *ChannelMonitorService) runDailyAggregation(ctx context.Context, today time.Time) error { + watermark, err := s.repo.LoadAggregationWatermark(ctx) + if err != nil { + return fmt.Errorf("load watermark: %w", err) + } + + start := s.resolveAggregationStart(watermark, today) + if !start.Before(today) { + return nil // 没有需要聚合的日期 + } + + iterations := 0 + for d := start; d.Before(today); d = d.Add(24 * time.Hour) { + if iterations >= monitorMaintenanceMaxDaysPerRun { + slog.Info("channel_monitor: maintenance aggregation capped", + "max_days", monitorMaintenanceMaxDaysPerRun, + "next_resume", d.Format("2006-01-02")) + break + } + affected, upErr := s.repo.UpsertDailyRollupsFor(ctx, d) + if upErr != nil { + return fmt.Errorf("upsert rollups for %s: %w", d.Format("2006-01-02"), upErr) + } + if err := s.repo.UpdateAggregationWatermark(ctx, d); err != nil { + return fmt.Errorf("update watermark to %s: %w", d.Format("2006-01-02"), err) + } + slog.Info("channel_monitor: rollups upserted", + "date", d.Format("2006-01-02"), "affected_rows", affected) + iterations++ + } + return nil +} + +// resolveAggregationStart 计算本次聚合起点: +// - watermark == nil:today - monitorRollupRetentionDays(首次回填最多 30 天) +// - watermark != nil:*watermark + 1 day +func (s *ChannelMonitorService) resolveAggregationStart(watermark *time.Time, today time.Time) time.Time { + if watermark == nil { + return today.AddDate(0, 0, -monitorRollupRetentionDays) + } + return watermark.UTC().Truncate(24 * time.Hour).Add(24 * time.Hour) +} + +// cleanupOldRollups 软删 bucket_date < today - monitorRollupRetentionDays 的日聚合行。 +func (s *ChannelMonitorService) cleanupOldRollups(ctx context.Context, today time.Time) error { + cutoff := today.AddDate(0, 0, -monitorRollupRetentionDays) + deleted, err := s.repo.DeleteRollupsBefore(ctx, cutoff) + if err != nil { + return fmt.Errorf("delete rollups before %s: %w", cutoff.Format("2006-01-02"), err) + } + if deleted > 0 { + slog.Info("channel_monitor: rollups cleanup", + "deleted_rows", deleted, "before", cutoff.Format("2006-01-02")) + } + return nil +} + +// ---------- helpers ---------- + +// decryptInPlace 把 ChannelMonitor.APIKey 从密文解密为明文。 +// 解密失败时把字段清空 + 设置 APIKeyDecryptFailed=true(不返回错误,避免阻断列表渲染)。 +// runner / RunCheck 必须读取该标志位并拒绝执行检测。 +func (s *ChannelMonitorService) decryptInPlace(m *ChannelMonitor) { + if m == nil || m.APIKey == "" { + return + } + plain, err := s.encryptor.Decrypt(m.APIKey) + if err != nil { + slog.Warn("channel_monitor: decrypt api key failed", + "monitor_id", m.ID, "error", err) + m.APIKey = "" + m.APIKeyDecryptFailed = true + return + } + m.APIKey = plain +} + +// applyMonitorUpdate 把 update params 中非 nil 的字段应用到 existing 上。 +// APIKey 字段在调用方单独处理(涉及加密)。 +// +// 行数稍超过 30:这是逐字段平铺的 dispatcher,每个 if 都是 1-3 行的"非 nil 则覆盖"模式, +// 拆分反而会增加跳转噪音、影响可读性,故保留为单函数。 +func applyMonitorUpdate(existing *ChannelMonitor, p ChannelMonitorUpdateParams) error { + if p.Name != nil { + existing.Name = strings.TrimSpace(*p.Name) + } + if p.Provider != nil { + if err := validateProvider(*p.Provider); err != nil { + return err + } + existing.Provider = *p.Provider + } + if p.Endpoint != nil { + if err := validateEndpoint(*p.Endpoint); err != nil { + return err + } + existing.Endpoint = normalizeEndpoint(*p.Endpoint) + } + if p.PrimaryModel != nil { + existing.PrimaryModel = strings.TrimSpace(*p.PrimaryModel) + } + if p.ExtraModels != nil { + existing.ExtraModels = normalizeModels(*p.ExtraModels) + } + if p.GroupName != nil { + existing.GroupName = strings.TrimSpace(*p.GroupName) + } + if p.Enabled != nil { + existing.Enabled = *p.Enabled + } + if p.IntervalSeconds != nil { + if err := validateInterval(*p.IntervalSeconds); err != nil { + return err + } + existing.IntervalSeconds = *p.IntervalSeconds + } + return applyMonitorAdvancedUpdate(existing, p) +} + +// applyMonitorAdvancedUpdate 处理自定义请求快照相关字段,从 applyMonitorUpdate 拆出避免过长。 +func applyMonitorAdvancedUpdate(existing *ChannelMonitor, p ChannelMonitorUpdateParams) error { + if p.ClearTemplate { + existing.TemplateID = nil + } else if p.TemplateID != nil { + id := *p.TemplateID + existing.TemplateID = &id + } + if p.ExtraHeaders != nil { + if err := validateExtraHeaders(*p.ExtraHeaders); err != nil { + return err + } + existing.ExtraHeaders = emptyHeadersIfNil(*p.ExtraHeaders) + } + // BodyOverrideMode / BodyOverride 联合校验,和模板一致。 + newMode := existing.BodyOverrideMode + newBody := existing.BodyOverride + if p.BodyOverrideMode != nil { + newMode = *p.BodyOverrideMode + } + if p.BodyOverride != nil { + newBody = *p.BodyOverride + } + if p.BodyOverrideMode != nil || p.BodyOverride != nil { + if err := validateBodyModeParams(newMode, newBody); err != nil { + return err + } + existing.BodyOverrideMode = defaultBodyMode(newMode) + existing.BodyOverride = newBody + } + return nil +} diff --git a/backend/internal/service/channel_monitor_ssrf.go b/backend/internal/service/channel_monitor_ssrf.go new file mode 100644 index 00000000..8d93f600 --- /dev/null +++ b/backend/internal/service/channel_monitor_ssrf.go @@ -0,0 +1,152 @@ +package service + +import ( + "context" + "net" + "strings" +) + +// SSRF 防护 helper: +// - validateEndpoint 在 admin 提交时阻止 http/loopback/私网/云元数据 URL +// - safeDialContext 在 socket 层再次校验真实 IP,防止 DNS rebinding +// +// 已知 cloud metadata hostname 拒绝列表(小写比较)。 +var monitorBlockedHostnames = map[string]struct{}{ + "localhost": {}, + "localhost.localdomain": {}, + "metadata": {}, + "metadata.google.internal": {}, + "metadata.goog": {}, + "instance-data": {}, + "instance-data.ec2.internal": {}, +} + +// CIDR 列表:包含所有需要拒绝的 IPv4/IPv6 段。 +// 解析时只 panic 一次(启动时确认),生产路径只做 Contains。 +var monitorBlockedCIDRs = mustParseCIDRs([]string{ + "127.0.0.0/8", // IPv4 loopback + "10.0.0.0/8", // RFC1918 + "172.16.0.0/12", // RFC1918 + "192.168.0.0/16", // RFC1918 + "169.254.0.0/16", // link-local(含云元数据 169.254.169.254) + "100.64.0.0/10", // CGNAT + "0.0.0.0/8", // "this network" + "::1/128", // IPv6 loopback + "fc00::/7", // IPv6 ULA + "fe80::/10", // IPv6 link-local + "::/128", // IPv6 unspecified +}) + +// monitorDialer 共享 Dialer,与 net/http 默认值对齐。 +var monitorDialer = &net.Dialer{ + Timeout: monitorDialTimeout, + KeepAlive: monitorDialKeepAlive, +} + +// mustParseCIDRs 在包初始化时解析 CIDR 字符串,失败 panic。 +func mustParseCIDRs(cidrs []string) []*net.IPNet { + out := make([]*net.IPNet, 0, len(cidrs)) + for _, c := range cidrs { + _, n, err := net.ParseCIDR(c) + if err != nil { + panic("channel_monitor_ssrf: invalid CIDR " + c + ": " + err.Error()) + } + out = append(out, n) + } + return out +} + +// isBlockedHostname 判断 hostname 是否命中黑名单。 +func isBlockedHostname(hostname string) bool { + if hostname == "" { + return true + } + _, blocked := monitorBlockedHostnames[strings.ToLower(hostname)] + return blocked +} + +// isPrivateIP 判断 IP 是否落在禁止段(loopback/RFC1918/link-local/ULA 等)。 +func isPrivateIP(ip net.IP) bool { + if ip == nil { + return true + } + if ip.IsUnspecified() || ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() || ip.IsInterfaceLocalMulticast() { + return true + } + for _, n := range monitorBlockedCIDRs { + if n.Contains(ip) { + return true + } + } + return false +} + +// isPrivateOrLoopbackHost 解析 hostname 的所有 A/AAAA 记录, +// 任一 IP 落在私网/loopback 段即认为不安全。 +// +// hostname 是 IP 字面量时也走同一路径。 +func isPrivateOrLoopbackHost(ctx context.Context, hostname string) (bool, error) { + if isBlockedHostname(hostname) { + return true, nil + } + // IP 字面量直接判断。 + if ip := net.ParseIP(hostname); ip != nil { + return isPrivateIP(ip), nil + } + resolver := net.DefaultResolver + addrs, err := resolver.LookupIPAddr(ctx, hostname) + if err != nil { + return false, err + } + if len(addrs) == 0 { + return true, nil + } + for _, a := range addrs { + if isPrivateIP(a.IP) { + return true, nil + } + } + return false, nil +} + +// safeDialContext 在真实 dial 前再次校验目标 IP,防止 DNS rebinding。 +// 解析 hostname 后逐个 IP 尝试连接,命中私网即拒绝(即便 validateEndpoint 时返回的是公网 IP)。 +func safeDialContext(ctx context.Context, network, address string) (net.Conn, error) { + host, port, err := net.SplitHostPort(address) + if err != nil { + return nil, err + } + // 字面量 IP 走快速路径。 + if ip := net.ParseIP(host); ip != nil { + if isPrivateIP(ip) { + return nil, &net.AddrError{Err: "blocked by SSRF policy", Addr: address} + } + return monitorDialer.DialContext(ctx, network, address) + } + if isBlockedHostname(host) { + return nil, &net.AddrError{Err: "blocked by SSRF policy", Addr: address} + } + addrs, err := net.DefaultResolver.LookupIPAddr(ctx, host) + if err != nil { + return nil, err + } + if len(addrs) == 0 { + return nil, &net.AddrError{Err: "no addresses for host", Addr: host} + } + var lastErr error + for _, a := range addrs { + if isPrivateIP(a.IP) { + lastErr = &net.AddrError{Err: "blocked by SSRF policy", Addr: a.IP.String()} + continue + } + conn, err := monitorDialer.DialContext(ctx, network, net.JoinHostPort(a.IP.String(), port)) + if err == nil { + return conn, nil + } + lastErr = err + } + if lastErr == nil { + lastErr = &net.AddrError{Err: "no usable addresses", Addr: host} + } + return nil, lastErr +} diff --git a/backend/internal/service/channel_monitor_template_service.go b/backend/internal/service/channel_monitor_template_service.go new file mode 100644 index 00000000..8d2e8173 --- /dev/null +++ b/backend/internal/service/channel_monitor_template_service.go @@ -0,0 +1,251 @@ +package service + +import ( + "context" + "fmt" + "regexp" + "strings" +) + +// ChannelMonitorRequestTemplateRepository 模板数据访问接口。 +type ChannelMonitorRequestTemplateRepository interface { + Create(ctx context.Context, t *ChannelMonitorRequestTemplate) error + GetByID(ctx context.Context, id int64) (*ChannelMonitorRequestTemplate, error) + Update(ctx context.Context, t *ChannelMonitorRequestTemplate) error + Delete(ctx context.Context, id int64) error + List(ctx context.Context, params ChannelMonitorRequestTemplateListParams) ([]*ChannelMonitorRequestTemplate, error) + // ApplyToMonitors 把模板当前的 extra_headers / body_override_mode / body_override + // 批量覆盖到指定 monitorIDs 的监控上(同时还要求这些监控当前 template_id = id, + // 防止误覆盖未关联的监控)。monitorIDs 必须非空;空列表直接返回 0 不写库。 + // 返回被覆盖的监控数量。 + ApplyToMonitors(ctx context.Context, id int64, monitorIDs []int64) (int64, error) + // CountAssociatedMonitors 统计 template_id = id 的监控数(用于 UI 展示「应用到 N 个配置」)。 + CountAssociatedMonitors(ctx context.Context, id int64) (int64, error) + // ListAssociatedMonitors 列出所有 template_id = id 的监控简略信息(id/name/provider/enabled) + // 给 apply picker UI 用,避免前端再做一次 list+filter。 + ListAssociatedMonitors(ctx context.Context, id int64) ([]*AssociatedMonitorBrief, error) +} + +// AssociatedMonitorBrief 模板关联监控的简略信息(picker / 列表展示用)。 +type AssociatedMonitorBrief struct { + ID int64 + Name string + Provider string + Enabled bool +} + +// ChannelMonitorRequestTemplateService 模板管理 service。 +type ChannelMonitorRequestTemplateService struct { + repo ChannelMonitorRequestTemplateRepository +} + +// NewChannelMonitorRequestTemplateService 创建模板 service。 +func NewChannelMonitorRequestTemplateService(repo ChannelMonitorRequestTemplateRepository) *ChannelMonitorRequestTemplateService { + return &ChannelMonitorRequestTemplateService{repo: repo} +} + +// ---------- CRUD ---------- + +// List 按 provider 过滤(空串 = 全部),不分页(模板量级小)。 +func (s *ChannelMonitorRequestTemplateService) List(ctx context.Context, params ChannelMonitorRequestTemplateListParams) ([]*ChannelMonitorRequestTemplate, error) { + if params.Provider != "" { + if err := validateProvider(params.Provider); err != nil { + return nil, err + } + } + return s.repo.List(ctx, params) +} + +// Get 返回单个模板。 +func (s *ChannelMonitorRequestTemplateService) Get(ctx context.Context, id int64) (*ChannelMonitorRequestTemplate, error) { + return s.repo.GetByID(ctx, id) +} + +// Create 创建模板(会校验 headers 黑名单和 body 模式匹配)。 +func (s *ChannelMonitorRequestTemplateService) Create(ctx context.Context, p ChannelMonitorRequestTemplateCreateParams) (*ChannelMonitorRequestTemplate, error) { + if err := validateTemplateCreateParams(p); err != nil { + return nil, err + } + t := &ChannelMonitorRequestTemplate{ + Name: strings.TrimSpace(p.Name), + Provider: p.Provider, + Description: strings.TrimSpace(p.Description), + ExtraHeaders: emptyHeadersIfNil(p.ExtraHeaders), + BodyOverrideMode: defaultBodyMode(p.BodyOverrideMode), + BodyOverride: p.BodyOverride, + } + if err := s.repo.Create(ctx, t); err != nil { + return nil, fmt.Errorf("create template: %w", err) + } + return t, nil +} + +// Update 更新模板(provider 不可改)。 +func (s *ChannelMonitorRequestTemplateService) Update(ctx context.Context, id int64, p ChannelMonitorRequestTemplateUpdateParams) (*ChannelMonitorRequestTemplate, error) { + existing, err := s.repo.GetByID(ctx, id) + if err != nil { + return nil, err + } + if err := applyTemplateUpdate(existing, p); err != nil { + return nil, err + } + if err := s.repo.Update(ctx, existing); err != nil { + return nil, fmt.Errorf("update template: %w", err) + } + return existing, nil +} + +// Delete 删除模板。关联监控的 template_id 会被 SET NULL,监控保留快照继续跑。 +func (s *ChannelMonitorRequestTemplateService) Delete(ctx context.Context, id int64) error { + if err := s.repo.Delete(ctx, id); err != nil { + return fmt.Errorf("delete template: %w", err) + } + return nil +} + +// ApplyToMonitors 把模板当前配置应用到 monitorIDs 列表里的关联监控。 +// monitorIDs 必须非空且每个 id 都必须当前 template_id = id;不满足条件的会被 SQL WHERE 过滤掉。 +// 返回实际被覆盖的监控数。 +func (s *ChannelMonitorRequestTemplateService) ApplyToMonitors(ctx context.Context, id int64, monitorIDs []int64) (int64, error) { + if _, err := s.repo.GetByID(ctx, id); err != nil { + return 0, err + } + if len(monitorIDs) == 0 { + return 0, ErrChannelMonitorTemplateApplyEmpty + } + affected, err := s.repo.ApplyToMonitors(ctx, id, monitorIDs) + if err != nil { + return 0, fmt.Errorf("apply template to monitors: %w", err) + } + return affected, nil +} + +// CountAssociatedMonitors 返回关联监控数。 +func (s *ChannelMonitorRequestTemplateService) CountAssociatedMonitors(ctx context.Context, id int64) (int64, error) { + return s.repo.CountAssociatedMonitors(ctx, id) +} + +// ListAssociatedMonitors 返回模板关联的所有监控简略信息。 +// 给前端 apply picker 用,handler 直接吐 JSON 不再做 join。 +func (s *ChannelMonitorRequestTemplateService) ListAssociatedMonitors(ctx context.Context, id int64) ([]*AssociatedMonitorBrief, error) { + if _, err := s.repo.GetByID(ctx, id); err != nil { + return nil, err + } + return s.repo.ListAssociatedMonitors(ctx, id) +} + +// ---------- 校验 & 工具 ---------- + +// validateTemplateCreateParams 聚合 create 入参校验,避免函数超过 30 行。 +func validateTemplateCreateParams(p ChannelMonitorRequestTemplateCreateParams) error { + if strings.TrimSpace(p.Name) == "" { + return ErrChannelMonitorTemplateMissingName + } + if err := validateProvider(p.Provider); err != nil { + return ErrChannelMonitorTemplateInvalidProvider + } + if err := validateBodyModeParams(p.BodyOverrideMode, p.BodyOverride); err != nil { + return err + } + if err := validateExtraHeaders(p.ExtraHeaders); err != nil { + return err + } + return nil +} + +// applyTemplateUpdate 把 update params 中非 nil 字段应用到 existing 上。 +func applyTemplateUpdate(existing *ChannelMonitorRequestTemplate, p ChannelMonitorRequestTemplateUpdateParams) error { + if p.Name != nil { + name := strings.TrimSpace(*p.Name) + if name == "" { + return ErrChannelMonitorTemplateMissingName + } + existing.Name = name + } + if p.Description != nil { + existing.Description = strings.TrimSpace(*p.Description) + } + if p.ExtraHeaders != nil { + if err := validateExtraHeaders(*p.ExtraHeaders); err != nil { + return err + } + existing.ExtraHeaders = emptyHeadersIfNil(*p.ExtraHeaders) + } + // BodyOverrideMode / BodyOverride 联合校验:任一变化都用「更新后的值」做校验。 + newMode := existing.BodyOverrideMode + newBody := existing.BodyOverride + if p.BodyOverrideMode != nil { + newMode = *p.BodyOverrideMode + } + if p.BodyOverride != nil { + newBody = *p.BodyOverride + } + if err := validateBodyModeParams(newMode, newBody); err != nil { + return err + } + existing.BodyOverrideMode = defaultBodyMode(newMode) + existing.BodyOverride = newBody + return nil +} + +// validateBodyModeParams 校验 body_override_mode 合法,且 merge/replace 模式下 body_override 非空。 +func validateBodyModeParams(mode string, body map[string]any) error { + switch mode { + case "", MonitorBodyOverrideModeOff: + return nil + case MonitorBodyOverrideModeMerge, MonitorBodyOverrideModeReplace: + if len(body) == 0 { + return ErrChannelMonitorTemplateBodyRequired + } + return nil + default: + return ErrChannelMonitorTemplateInvalidBodyMode + } +} + +// headerNameRegex 合法 header 名:RFC 7230 token(ASCII 可见字符减特殊符号)。 +var headerNameRegex = regexp.MustCompile(`^[A-Za-z0-9!#$%&'*+\-.^_` + "`" + `|~]+$`) + +// forbiddenHeaderNames hop-by-hop + HTTP 客户端自管的 header;禁止用户覆盖, +// 否则会让 Go http.Client 行为异常(双重 Content-Length、连接复用错乱等)。 +var forbiddenHeaderNames = map[string]bool{ + "host": true, + "content-length": true, + "content-encoding": true, + "transfer-encoding": true, + "connection": true, +} + +// IsForbiddenHeaderName 对外暴露,checker 运行时也会再过滤一次做兜底。 +func IsForbiddenHeaderName(name string) bool { + return forbiddenHeaderNames[strings.ToLower(strings.TrimSpace(name))] +} + +// validateExtraHeaders 校验 header 名字格式 + 黑名单。保存时就拒绝非法 header,早失败。 +func validateExtraHeaders(h map[string]string) error { + for k := range h { + if !headerNameRegex.MatchString(k) { + return ErrChannelMonitorTemplateHeaderInvalidName + } + if IsForbiddenHeaderName(k) { + return ErrChannelMonitorTemplateHeaderForbidden + } + } + return nil +} + +// emptyHeadersIfNil 把 nil map 归一成空 map(repo 层写库时 JSONB 需要非 nil)。 +func emptyHeadersIfNil(h map[string]string) map[string]string { + if h == nil { + return map[string]string{} + } + return h +} + +// defaultBodyMode 空串归一为 off。 +func defaultBodyMode(mode string) string { + if mode == "" { + return MonitorBodyOverrideModeOff + } + return mode +} diff --git a/backend/internal/service/channel_monitor_template_types.go b/backend/internal/service/channel_monitor_template_types.go new file mode 100644 index 00000000..e5bf7568 --- /dev/null +++ b/backend/internal/service/channel_monitor_template_types.go @@ -0,0 +1,77 @@ +package service + +import ( + infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors" + "time" +) + +// ChannelMonitorRequestTemplate 请求模板(service 层模型)。 +// 作用:把一组可复用的 headers + 可选 body 覆盖配置抽出来管理, +// 被监控「应用」时以快照方式拷贝到监控本身的同名字段。 +type ChannelMonitorRequestTemplate struct { + ID int64 + Name string + Provider string + Description string + ExtraHeaders map[string]string + BodyOverrideMode string + BodyOverride map[string]any + CreatedAt time.Time + UpdatedAt time.Time +} + +// ChannelMonitorRequestTemplateListParams 列表过滤。 +type ChannelMonitorRequestTemplateListParams struct { + Provider string // 空 = 全部;非空则按 provider 过滤 +} + +// ChannelMonitorRequestTemplateCreateParams 创建参数。 +type ChannelMonitorRequestTemplateCreateParams struct { + Name string + Provider string + Description string + ExtraHeaders map[string]string + BodyOverrideMode string + BodyOverride map[string]any +} + +// ChannelMonitorRequestTemplateUpdateParams 更新参数(指针字段 = 不修改)。 +// 注意 Provider 不可修改:改 provider 会让已关联监控的 body 黑名单语义错乱。 +type ChannelMonitorRequestTemplateUpdateParams struct { + Name *string + Description *string + ExtraHeaders *map[string]string + BodyOverrideMode *string + BodyOverride *map[string]any +} + +// 模板相关错误(命名与现有 ErrChannelMonitor* 风格保持一致)。 +var ( + ErrChannelMonitorTemplateNotFound = infraerrors.NotFound( + "CHANNEL_MONITOR_TEMPLATE_NOT_FOUND", "channel monitor request template not found", + ) + ErrChannelMonitorTemplateInvalidProvider = infraerrors.BadRequest( + "CHANNEL_MONITOR_TEMPLATE_INVALID_PROVIDER", "template provider must be one of openai/anthropic/gemini", + ) + ErrChannelMonitorTemplateMissingName = infraerrors.BadRequest( + "CHANNEL_MONITOR_TEMPLATE_MISSING_NAME", "template name is required", + ) + ErrChannelMonitorTemplateInvalidBodyMode = infraerrors.BadRequest( + "CHANNEL_MONITOR_TEMPLATE_INVALID_BODY_MODE", "body_override_mode must be one of off/merge/replace", + ) + ErrChannelMonitorTemplateBodyRequired = infraerrors.BadRequest( + "CHANNEL_MONITOR_TEMPLATE_BODY_REQUIRED", "body_override is required when body_override_mode is merge or replace", + ) + ErrChannelMonitorTemplateHeaderForbidden = infraerrors.BadRequest( + "CHANNEL_MONITOR_TEMPLATE_HEADER_FORBIDDEN", "header name is forbidden (hop-by-hop or computed by HTTP client)", + ) + ErrChannelMonitorTemplateHeaderInvalidName = infraerrors.BadRequest( + "CHANNEL_MONITOR_TEMPLATE_HEADER_INVALID_NAME", "header name contains invalid characters", + ) + ErrChannelMonitorTemplateProviderMismatch = infraerrors.BadRequest( + "CHANNEL_MONITOR_TEMPLATE_PROVIDER_MISMATCH", "monitor provider does not match template provider", + ) + ErrChannelMonitorTemplateApplyEmpty = infraerrors.BadRequest( + "CHANNEL_MONITOR_TEMPLATE_APPLY_EMPTY", "monitor_ids must be a non-empty array", + ) +) diff --git a/backend/internal/service/channel_monitor_types.go b/backend/internal/service/channel_monitor_types.go new file mode 100644 index 00000000..b797a89b --- /dev/null +++ b/backend/internal/service/channel_monitor_types.go @@ -0,0 +1,203 @@ +package service + +import "time" + +// MonitorBodyOverrideMode 自定义请求体处理模式。 +// +// - off 使用 adapter 默认 body(忽略 BodyOverride) +// - merge adapter 默认 body 与 BodyOverride 浅合并(用户优先; +// model/messages/contents 等关键字段在 checker 黑名单内会被静默丢弃) +// - replace 完全用 BodyOverride 作为 body;跳过 challenge 校验, +// 改成 HTTP 2xx + 响应非空即视为可用(用户负责构造 body) +const ( + MonitorBodyOverrideModeOff = "off" + MonitorBodyOverrideModeMerge = "merge" + MonitorBodyOverrideModeReplace = "replace" +) + +// ChannelMonitor 渠道监控配置(service 层模型,不直接暴露 ent 类型)。 +type ChannelMonitor struct { + ID int64 + Name string + Provider string + Endpoint string + APIKey string // 解密后的明文 API Key(仅在 service 内部使用,handler 层不应直接序列化返回) + PrimaryModel string + ExtraModels []string + GroupName string + Enabled bool + IntervalSeconds int + LastCheckedAt *time.Time + CreatedBy int64 + CreatedAt time.Time + UpdatedAt time.Time + + // 请求自定义快照(来自模板拷贝 or 用户手填,运行时直接读取) + TemplateID *int64 // 仅用于 UI 分组 + 一键应用,运行时不用 + ExtraHeaders map[string]string // 与 adapter 默认 headers 合并,用户优先 + BodyOverrideMode string // off / merge / replace + BodyOverride map[string]any // 仅 mode != off 时使用 + + // APIKeyDecryptFailed 表示 APIKey 字段无法解密(密钥不一致或损坏)。 + // 此时 APIKey 为空字符串,runner / RunCheck 必须跳过该监控并提示重填。 + APIKeyDecryptFailed bool +} + +// ChannelMonitorListParams 列表查询过滤参数。 +type ChannelMonitorListParams struct { + Page int + PageSize int + Provider string + Enabled *bool + Search string +} + +// ChannelMonitorCreateParams 创建参数。 +type ChannelMonitorCreateParams struct { + Name string + Provider string + Endpoint string + APIKey string + PrimaryModel string + ExtraModels []string + GroupName string + Enabled bool + IntervalSeconds int + CreatedBy int64 + TemplateID *int64 + ExtraHeaders map[string]string + BodyOverrideMode string + BodyOverride map[string]any +} + +// ChannelMonitorUpdateParams 更新参数(指针字段表示"未提供则不更新")。 +type ChannelMonitorUpdateParams struct { + Name *string + Provider *string + Endpoint *string + APIKey *string // 空字符串表示不修改;非空字符串覆盖 + PrimaryModel *string + ExtraModels *[]string + GroupName *string + Enabled *bool + IntervalSeconds *int + // 自定义快照字段:指针为 nil 表示不更新,非 nil 覆盖 + // TemplateID *(*int64):用 ** 表达三态:nil=不更新;&nil=清空;&&id=设为 id。 + // 简化处理:用 ClearTemplate 显式标志 + TemplateID(普通指针) + TemplateID *int64 + ClearTemplate bool // true 时无视 TemplateID,把监控的 template_id 置空 + ExtraHeaders *map[string]string + BodyOverrideMode *string + BodyOverride *map[string]any +} + +// CheckResult 单个模型一次检测的结果。 +type CheckResult struct { + Model string + Status string // operational / degraded / failed / error + LatencyMs *int + PingLatencyMs *int + Message string + CheckedAt time.Time +} + +// UserMonitorView 用户只读视图:监控概览(含主模型最近状态 + 7d 可用率 + 附加模型最近状态)。 +type UserMonitorView struct { + ID int64 + Name string + Provider string + GroupName string + PrimaryModel string + PrimaryStatus string + PrimaryLatencyMs *int + PrimaryPingLatencyMs *int // 主模型最近一次 ping 延迟 + Availability7d float64 // 0-100 + ExtraModels []ExtraModelStatus + Timeline []UserMonitorTimelinePoint // 主模型最近 N 个历史点(按 checked_at DESC,最新在前) +} + +// UserMonitorTimelinePoint 用户视图 timeline 单点数据(去除 message 以减小响应体)。 +type UserMonitorTimelinePoint struct { + Status string `json:"status"` + LatencyMs *int `json:"latency_ms"` + PingLatencyMs *int `json:"ping_latency_ms"` + CheckedAt time.Time `json:"checked_at"` +} + +// ExtraModelStatus 附加模型最近一次状态。 +type ExtraModelStatus struct { + Model string + Status string + LatencyMs *int +} + +// UserMonitorDetail 用户只读视图:监控详情(含全部模型 7d/15d/30d 可用率与平均延迟)。 +type UserMonitorDetail struct { + ID int64 + Name string + Provider string + GroupName string + Models []ModelDetail +} + +// ModelDetail 单个模型的可用率/延迟统计。 +type ModelDetail struct { + Model string + LatestStatus string + LatestLatencyMs *int + Availability7d float64 // 0-100 + Availability15d float64 + Availability30d float64 + AvgLatency7dMs *int +} + +// ChannelMonitorHistoryRow 历史记录入库行(service 层向 repository 提交的数据)。 +type ChannelMonitorHistoryRow struct { + MonitorID int64 + Model string + Status string + LatencyMs *int + PingLatencyMs *int + Message string + CheckedAt time.Time +} + +// ChannelMonitorHistoryEntry 历史记录查询返回行(含 ent 主键 ID)。 +type ChannelMonitorHistoryEntry struct { + ID int64 + Model string + Status string + LatencyMs *int + PingLatencyMs *int + Message string + CheckedAt time.Time +} + +// ChannelMonitorLatest 最近一次检测的简明信息(用于 UserMonitorView 聚合)。 +type ChannelMonitorLatest struct { + Model string + Status string + LatencyMs *int + PingLatencyMs *int + CheckedAt time.Time +} + +// ChannelMonitorAvailability 单个模型在某窗口内的可用率与平均延迟(用于 UserMonitorDetail 聚合)。 +type ChannelMonitorAvailability struct { + Model string + WindowDays int + TotalChecks int + OperationalChecks int // operational + degraded 视为可用 + AvailabilityPct float64 + AvgLatencyMs *int +} + +// MonitorStatusSummary 监控状态聚合(admin list 用,单次 repo 查询消除前端 N+1)。 +// PrimaryStatus / PrimaryLatencyMs 描述主模型最近状态;Availability7d 是主模型 7 天可用率; +// ExtraModels 描述附加模型最近状态(用于 hover 展示)。 +type MonitorStatusSummary struct { + PrimaryStatus string // 空字符串表示无历史 + PrimaryLatencyMs *int + Availability7d float64 // 0-100,无历史时为 0 + ExtraModels []ExtraModelStatus +} diff --git a/backend/internal/service/channel_monitor_validate.go b/backend/internal/service/channel_monitor_validate.go new file mode 100644 index 00000000..16bbec71 --- /dev/null +++ b/backend/internal/service/channel_monitor_validate.go @@ -0,0 +1,99 @@ +package service + +import ( + "context" + "net/url" + "strings" +) + +// 渠道监控参数校验与归一化辅助函数。 +// 校验失败一律返回 channel_monitor_const.go 中预定义的 Err* 错误,错误信息不含具体 IP/hostname,避免泄露内网拓扑。 + +// validateProvider 校验 provider 字符串。 +// 唯一来源于 providerAdapters:新增 provider 只需要在 channel_monitor_checker.go 注册 adapter。 +func validateProvider(p string) error { + if !isSupportedProvider(p) { + return ErrChannelMonitorInvalidProvider + } + return nil +} + +// validateInterval 校验 interval_seconds 范围。 +func validateInterval(sec int) error { + if sec < monitorMinIntervalSeconds || sec > monitorMaxIntervalSeconds { + return ErrChannelMonitorInvalidInterval + } + return nil +} + +// validateEndpoint 校验 endpoint: +// - scheme 强制 https(拒绝 http,避免明文凭证 + 部分 SSRF 利用面) +// - 必须为 origin(无 path/query/fragment),防止用户填 https://api.openai.com/v1 +// 导致 joinURL 拼出 /v1/v1/chat/completions +// - hostname 不能是 localhost/metadata 等已知元数据 hostname +// - 解析所有 IP,任一落在 loopback/RFC1918/link-local/ULA 段即拒绝(防 SSRF) +// +// 错误信息不暴露具体 IP / hostname,避免泄露内网拓扑。 +func validateEndpoint(ep string) error { + ep = strings.TrimSpace(ep) + if ep == "" { + return ErrChannelMonitorInvalidEndpoint + } + u, err := url.Parse(ep) + if err != nil { + return ErrChannelMonitorInvalidEndpoint + } + if u.Scheme != "https" { + return ErrChannelMonitorEndpointScheme + } + if u.Host == "" { + return ErrChannelMonitorInvalidEndpoint + } + if u.Path != "" && u.Path != "/" { + return ErrChannelMonitorEndpointPath + } + if u.RawQuery != "" || u.Fragment != "" { + return ErrChannelMonitorEndpointPath + } + + hostname := u.Hostname() + ctx, cancel := context.WithTimeout(context.Background(), monitorEndpointResolveTimeout) + defer cancel() + blocked, err := isPrivateOrLoopbackHost(ctx, hostname) + if err != nil { + return ErrChannelMonitorEndpointUnreachable + } + if blocked { + return ErrChannelMonitorEndpointPrivate + } + return nil +} + +// normalizeEndpoint 去除前后空白与末尾 `/`,保证存储统一为 origin。 +// validateEndpoint 已确保格式合法(仅 origin),这里只做最终归一化。 +func normalizeEndpoint(ep string) string { + ep = strings.TrimSpace(ep) + ep = strings.TrimRight(ep, "/") + return ep +} + +// normalizeModels 去除空白、重复模型名。保留输入顺序(map 的迭代顺序无关)。 +func normalizeModels(in []string) []string { + if len(in) == 0 { + return []string{} + } + seen := make(map[string]struct{}, len(in)) + out := make([]string, 0, len(in)) + for _, m := range in { + m = strings.TrimSpace(m) + if m == "" { + continue + } + if _, ok := seen[m]; ok { + continue + } + seen[m] = struct{}{} + out = append(out, m) + } + return out +} diff --git a/backend/internal/service/channel_service.go b/backend/internal/service/channel_service.go index c29550d9..4e08df4a 100644 --- a/backend/internal/service/channel_service.go +++ b/backend/internal/service/channel_service.go @@ -141,17 +141,23 @@ const ( // ChannelService 渠道管理服务 type ChannelService struct { repo ChannelRepository + groupRepo GroupRepository authCacheInvalidator APIKeyAuthCacheInvalidator + pricingService *PricingService // 用于「可用渠道」展示时回落到全局定价;可为 nil(测试场景) cache atomic.Value // *channelCache cacheSF singleflight.Group } -// NewChannelService 创建渠道服务实例 -func NewChannelService(repo ChannelRepository, authCacheInvalidator APIKeyAuthCacheInvalidator) *ChannelService { +// NewChannelService 创建渠道服务实例。 +// pricingService 仅供 ListAvailable 在渠道未配置定价时回落到全局 LiteLLM 数据; +// 计费热路径走独立的 ModelPricingResolver,与此参数无关。可传 nil。 +func NewChannelService(repo ChannelRepository, groupRepo GroupRepository, authCacheInvalidator APIKeyAuthCacheInvalidator, pricingService *PricingService) *ChannelService { s := &ChannelService{ repo: repo, + groupRepo: groupRepo, authCacheInvalidator: authCacheInvalidator, + pricingService: pricingService, } return s } @@ -299,6 +305,9 @@ func (s *ChannelService) fetchChannelData(ctx context.Context) ([]Channel, map[i } // populateChannelCache 将渠道列表和分组平台映射填充到缓存快照中。 +// 装填时对每个 Channel 统一归一化 BillingModelSource,让缓存命中的所有下游 +// (gateway routing / billing / 未来任何 cache-backed 读路径)都拿到已归一化的实体, +// 避免"每个出口各自记得 normalize"反模式。 func populateChannelCache(channels []Channel, groupPlatforms map[int64]string) *channelCache { cache := newEmptyChannelCache() cache.groupPlatform = groupPlatforms @@ -306,6 +315,7 @@ func populateChannelCache(channels []Channel, groupPlatforms map[int64]string) * cache.loadedAt = time.Now() for i := range channels { + channels[i].normalizeBillingModelSource() ch := &channels[i] cache.byID[ch.ID] = ch for _, gid := range ch.GroupIDs { @@ -516,14 +526,13 @@ func (s *ChannelService) ResolveChannelMappingAndRestrict(ctx context.Context, g // resolveMapping 基于已查找的渠道信息解析模型映射。 // antigravity 分组依次尝试所有匹配平台,确保跨平台同名映射各自独立。 func resolveMapping(lk *channelLookup, groupID int64, model string) ChannelMappingResult { + // lk.channel 来自已装填的缓存,BillingModelSource 已在 populateChannelCache 阶段归一化, + // 这里无需重复兜底。 result := ChannelMappingResult{ MappedModel: model, ChannelID: lk.channel.ID, BillingModelSource: lk.channel.BillingModelSource, } - if result.BillingModelSource == "" { - result.BillingModelSource = BillingModelSourceChannelMapped - } modelLower := strings.ToLower(model) if mapped := lookupMappingAcrossPlatforms(lk.cache, groupID, lk.platform, modelLower); mapped != "" { @@ -684,9 +693,7 @@ func (s *ChannelService) Create(ctx context.Context, input *CreateChannelInput) ApplyPricingToAccountStats: input.ApplyPricingToAccountStats, AccountStatsPricingRules: input.AccountStatsPricingRules, } - if channel.BillingModelSource == "" { - channel.BillingModelSource = BillingModelSourceChannelMapped - } + channel.normalizeBillingModelSource() if err := validateChannelConfig(channel.ModelPricing, channel.ModelMapping); err != nil { return nil, err @@ -702,12 +709,23 @@ func (s *ChannelService) Create(ctx context.Context, input *CreateChannelInput) } s.invalidateCache() - return s.repo.GetByID(ctx, channel.ID) + created, err := s.repo.GetByID(ctx, channel.ID) + if err != nil { + return nil, err + } + created.normalizeBillingModelSource() + return created, nil } -// GetByID 获取渠道详情 +// GetByID 获取渠道详情。返回前统一把空 BillingModelSource 回填为 ChannelMapped, +// 让所有 handler 无需重复处理历史空值。 func (s *ChannelService) GetByID(ctx context.Context, id int64) (*Channel, error) { - return s.repo.GetByID(ctx, id) + ch, err := s.repo.GetByID(ctx, id) + if err != nil { + return nil, err + } + ch.normalizeBillingModelSource() + return ch, nil } // Update 更新渠道 @@ -739,7 +757,12 @@ func (s *ChannelService) Update(ctx context.Context, id int64, input *UpdateChan s.invalidateCache() s.invalidateAuthCacheForGroups(ctx, oldGroupIDs, channel.GroupIDs) - return s.repo.GetByID(ctx, id) + updated, err := s.repo.GetByID(ctx, id) + if err != nil { + return nil, err + } + updated.normalizeBillingModelSource() + return updated, nil } // applyUpdateInput 将更新请求的字段应用到渠道实体上。 @@ -857,7 +880,14 @@ func (s *ChannelService) Delete(ctx context.Context, id int64) error { // List 获取渠道列表 func (s *ChannelService) List(ctx context.Context, params pagination.PaginationParams, status, search string) ([]Channel, *pagination.PaginationResult, error) { - return s.repo.List(ctx, params, status, search) + channels, res, err := s.repo.List(ctx, params, status, search) + if err != nil { + return nil, nil, err + } + for i := range channels { + channels[i].normalizeBillingModelSource() + } + return channels, res, nil } // modelEntry 表示一个模型模式条目(用于冲突检测) @@ -884,12 +914,7 @@ func conflictsBetween(a, b modelEntry) bool { // toModelEntry 将模型名转换为 modelEntry func toModelEntry(pattern string) modelEntry { - lower := strings.ToLower(pattern) - isWild := strings.HasSuffix(lower, "*") - prefix := lower - if isWild { - prefix = strings.TrimSuffix(lower, "*") - } + prefix, isWild := splitWildcardSuffix(strings.ToLower(pattern)) return modelEntry{pattern: pattern, prefix: prefix, wildcard: isWild} } diff --git a/backend/internal/service/channel_service_test.go b/backend/internal/service/channel_service_test.go index e1345618..e737a211 100644 --- a/backend/internal/service/channel_service_test.go +++ b/backend/internal/service/channel_service_test.go @@ -189,11 +189,11 @@ func (m *mockChannelAuthCacheInvalidator) InvalidateAuthCacheByGroupID(_ context // --------------------------------------------------------------------------- func newTestChannelService(repo *mockChannelRepository) *ChannelService { - return NewChannelService(repo, nil) + return NewChannelService(repo, nil, nil, nil) } func newTestChannelServiceWithAuth(repo *mockChannelRepository, auth *mockChannelAuthCacheInvalidator) *ChannelService { - return NewChannelService(repo, auth) + return NewChannelService(repo, nil, auth, nil) } // makeStandardRepo returns a repo that serves one active channel with anthropic pricing diff --git a/backend/internal/service/channel_test.go b/backend/internal/service/channel_test.go index deac64d6..164861fb 100644 --- a/backend/internal/service/channel_test.go +++ b/backend/internal/service/channel_test.go @@ -433,3 +433,296 @@ func TestValidateIntervals_UnboundedNotLast(t *testing.T) { require.Contains(t, err.Error(), "unbounded") require.Contains(t, err.Error(), "last") } + +func TestSupportedModels_ExactKeysAndPricing(t *testing.T) { + ch := &Channel{ + ModelPricing: []ChannelModelPricing{ + {ID: 10, Platform: "anthropic", Models: []string{"claude-sonnet-4-6"}, InputPrice: testPtrFloat64(3e-6)}, + {ID: 11, Platform: "anthropic", Models: []string{"claude-opus-4-6"}, InputPrice: testPtrFloat64(1.5e-5)}, + }, + ModelMapping: map[string]map[string]string{ + "anthropic": { + "claude-sonnet-4-6": "claude-sonnet-4-6", + "claude-opus-4-6": "claude-opus-4-6", + }, + }, + } + + got := ch.SupportedModels() + require.Len(t, got, 2) + require.Equal(t, "anthropic", got[0].Platform) + require.Equal(t, "claude-opus-4-6", got[0].Name) + require.NotNil(t, got[0].Pricing) + require.Equal(t, int64(11), got[0].Pricing.ID) + require.Equal(t, "claude-sonnet-4-6", got[1].Name) + require.Equal(t, int64(10), got[1].Pricing.ID) +} + +func TestSupportedModels_WildcardExpandedFromPricing(t *testing.T) { + ch := &Channel{ + ModelPricing: []ChannelModelPricing{ + {ID: 1, Platform: "anthropic", Models: []string{"claude-sonnet-4-6", "claude-sonnet-4-5"}}, + {ID: 2, Platform: "anthropic", Models: []string{"claude-opus-4-6"}}, + }, + ModelMapping: map[string]map[string]string{ + "anthropic": { + "claude-sonnet-*": "claude-sonnet-4-6", + }, + }, + } + + got := ch.SupportedModels() + names := make([]string, 0, len(got)) + for _, m := range got { + names = append(names, m.Name) + } + require.ElementsMatch(t, []string{"claude-sonnet-4-5", "claude-sonnet-4-6", "claude-opus-4-6"}, names) + for _, m := range got { + require.NotContains(t, m.Name, "*") + } +} + + +func TestSupportedModels_MissingPricingKeepsNilPricing(t *testing.T) { + ch := &Channel{ + ModelMapping: map[string]map[string]string{ + "anthropic": {"claude-sonnet-4-6": "claude-sonnet-4-6"}, + }, + } + + got := ch.SupportedModels() + require.Len(t, got, 1) + require.Equal(t, "claude-sonnet-4-6", got[0].Name) + require.Nil(t, got[0].Pricing) +} + +func TestSupportedModels_DedupAndSort(t *testing.T) { + ch := &Channel{ + ModelPricing: []ChannelModelPricing{ + {ID: 1, Platform: "anthropic", Models: []string{"claude-sonnet-4-6", "claude-sonnet-4-5"}}, + {ID: 2, Platform: "openai", Models: []string{"gpt-4o"}}, + }, + ModelMapping: map[string]map[string]string{ + "anthropic": { + "claude-sonnet-4-6": "upstream-a", + "claude-sonnet-*": "upstream-a", + }, + "openai": {"gpt-4o": "gpt-4o"}, + }, + } + + got := ch.SupportedModels() + require.Len(t, got, 3) + require.Equal(t, "anthropic", got[0].Platform) + require.Equal(t, "claude-sonnet-4-5", got[0].Name) + require.Equal(t, "anthropic", got[1].Platform) + require.Equal(t, "claude-sonnet-4-6", got[1].Name) + require.Equal(t, "openai", got[2].Platform) + require.Equal(t, "gpt-4o", got[2].Name) +} + +func TestSupportedModels_NilChannelAndEmpty(t *testing.T) { + var nilCh *Channel + require.Nil(t, nilCh.SupportedModels()) + + empty := &Channel{} + require.Nil(t, empty.SupportedModels()) +} + +func TestGetModelPricingByPlatform(t *testing.T) { + ch := &Channel{ + ModelPricing: []ChannelModelPricing{ + {ID: 1, Platform: "anthropic", Models: []string{"claude-sonnet-4-6"}, InputPrice: testPtrFloat64(3e-6)}, + {ID: 2, Platform: "openai", Models: []string{"claude-sonnet-4-6"}, InputPrice: testPtrFloat64(1e-6)}, + }, + } + + ant := ch.GetModelPricingByPlatform("anthropic", "claude-sonnet-4-6") + require.NotNil(t, ant) + require.Equal(t, int64(1), ant.ID) + + oa := ch.GetModelPricingByPlatform("openai", "claude-sonnet-4-6") + require.NotNil(t, oa) + require.Equal(t, int64(2), oa.ID) + + require.Nil(t, ch.GetModelPricingByPlatform("gemini", "claude-sonnet-4-6")) +} + +func TestSupportedModels_WildcardOnlyPricingRowsSkipped(t *testing.T) { + // 定价中含通配符条目(pattern),不应被当作具体模型名展开。 + ch := &Channel{ + ModelPricing: []ChannelModelPricing{ + {ID: 1, Platform: "anthropic", Models: []string{"claude-sonnet-*", "claude-sonnet-4-6"}}, + }, + ModelMapping: map[string]map[string]string{ + "anthropic": {"claude-sonnet-*": "claude-sonnet-4-6"}, + }, + } + got := ch.SupportedModels() + require.Len(t, got, 1) + require.Equal(t, "claude-sonnet-4-6", got[0].Name) + for _, m := range got { + require.NotContains(t, m.Name, "*") + } +} + +func TestSupportedModels_WildcardPrefixMatchesNothing(t *testing.T) { + // 通配符模式无任何对应定价模型时,该平台 mapping 路不产出; + // 但其他平台的 pricing-only 模型仍会通过 Pass B 出现。 + ch := &Channel{ + ModelPricing: []ChannelModelPricing{ + {ID: 1, Platform: "openai", Models: []string{"gpt-4o"}}, + }, + ModelMapping: map[string]map[string]string{ + "anthropic": {"gpt-foo-*": "gpt-foo-1"}, + }, + } + got := ch.SupportedModels() + require.Len(t, got, 1) + require.Equal(t, "openai", got[0].Platform) + require.Equal(t, "gpt-4o", got[0].Name) +} + +func TestSupportedModels_CrossPlatformPricingDoesNotBleed(t *testing.T) { + // anthropic 的通配符不应把 openai 定价行拉到 anthropic 平台下; + // openai 的 pricing-only 模型则正常通过 Pass B 暴露在 openai 平台下。 + ch := &Channel{ + ModelPricing: []ChannelModelPricing{ + {ID: 1, Platform: "openai", Models: []string{"claude-sonnet-4-6"}}, + }, + ModelMapping: map[string]map[string]string{ + "anthropic": {"claude-sonnet-*": "x"}, + }, + } + got := ch.SupportedModels() + require.Len(t, got, 1) + require.Equal(t, "openai", got[0].Platform, "不能把 openai 定价标记为 anthropic 模型") + require.Equal(t, "claude-sonnet-4-6", got[0].Name) +} + +func TestSupportedModels_CaseInsensitiveDedup(t *testing.T) { + // 两行定价用不同大小写定义了同一模型,结果应去重为 1 条;首次出现的原始大小写保留。 + ch := &Channel{ + ModelPricing: []ChannelModelPricing{ + {ID: 1, Platform: "openai", Models: []string{"GPT-4o"}}, + {ID: 2, Platform: "openai", Models: []string{"gpt-4o"}}, + }, + ModelMapping: map[string]map[string]string{ + "openai": {"gpt-*": "x"}, + }, + } + got := ch.SupportedModels() + require.Len(t, got, 1) + require.Equal(t, "GPT-4o", got[0].Name) +} + +func TestSupportedModels_EmptyPlatformMapping(t *testing.T) { + // ModelMapping 平台 key 存在但 value 为空 map:mapping 路跳过该平台, + // 但 pricing 路仍会把该平台的定价模型补齐(关键修复:azcc 这种"只配定价不配映射"渠道)。 + ch := &Channel{ + ModelPricing: []ChannelModelPricing{ + {ID: 1, Platform: "anthropic", Models: []string{"claude-sonnet-4-6"}}, + }, + ModelMapping: map[string]map[string]string{ + "anthropic": {}, + }, + } + got := ch.SupportedModels() + require.Len(t, got, 1) + require.Equal(t, "anthropic", got[0].Platform) + require.Equal(t, "claude-sonnet-4-6", got[0].Name) + require.NotNil(t, got[0].Pricing) +} + +func TestSupportedModels_ExactKeyUsesPricedCaseWhenAvailable(t *testing.T) { + // mapping key uses uppercase, pricing uses lowercase — pricing's case should win. + ch := &Channel{ + ModelPricing: []ChannelModelPricing{ + {ID: 1, Platform: "openai", Models: []string{"gpt-4o"}}, + }, + ModelMapping: map[string]map[string]string{ + "openai": {"GPT-4o": "gpt-4o"}, + }, + } + got := ch.SupportedModels() + require.Len(t, got, 1) + require.Equal(t, "gpt-4o", got[0].Name) // pricing's case wins +} + +func TestSupportedModels_AsteriskOnlyMappingExpandsAllPriced(t *testing.T) { + // 映射 key 为单独的 "*":前缀为空 → 命中该平台所有定价模型(透传场景)。 + ch := &Channel{ + ModelPricing: []ChannelModelPricing{ + {ID: 1, Platform: "openai", Models: []string{"gpt-4o", "gpt-4o-mini"}}, + }, + ModelMapping: map[string]map[string]string{ + "openai": {"*": "gpt-4o"}, + }, + } + got := ch.SupportedModels() + require.Len(t, got, 2) + names := []string{got[0].Name, got[1].Name} + require.ElementsMatch(t, []string{"gpt-4o", "gpt-4o-mini"}, names) +} + +func TestSupportedModels_PricingOnlyNoMapping(t *testing.T) { + // 渠道完全没配 mapping,只配了定价 —— 应该把所有定价模型作为支持模型返回。 + // 这是修复前的核心 bug 场景(前端显示"未配置模型")。 + ch := &Channel{ + ModelPricing: []ChannelModelPricing{ + {ID: 1, Platform: "anthropic", Models: []string{"claude-opus-4-6"}, InputPrice: testPtrFloat64(1.5e-5)}, + {ID: 2, Platform: "anthropic", Models: []string{"claude-haiku-4-5"}, InputPrice: testPtrFloat64(3e-7)}, + }, + } + got := ch.SupportedModels() + require.Len(t, got, 2) + require.Equal(t, "claude-haiku-4-5", got[0].Name) + require.NotNil(t, got[0].Pricing) + require.Equal(t, int64(2), got[0].Pricing.ID) + require.Equal(t, "claude-opus-4-6", got[1].Name) + require.Equal(t, int64(1), got[1].Pricing.ID) +} + +func TestSupportedModels_ExactMappingUsesTargetPricing(t *testing.T) { + // 精确 mapping `src → target`:定价应按 target 查(实际计费的是 target), + // 而不是按 src 自查。 + ch := &Channel{ + ModelPricing: []ChannelModelPricing{ + {ID: 100, Platform: "anthropic", Models: []string{"req-model"}, InputPrice: testPtrFloat64(3e-6)}, + {ID: 200, Platform: "anthropic", Models: []string{"served-model"}, InputPrice: testPtrFloat64(1.5e-5)}, + }, + ModelMapping: map[string]map[string]string{ + "anthropic": { + "req-model": "served-model", + }, + }, + } + got := ch.SupportedModels() + require.Len(t, got, 2) + require.Equal(t, "req-model", got[0].Name) + require.NotNil(t, got[0].Pricing) + require.Equal(t, int64(200), got[0].Pricing.ID, "req-model 显示但定价是 served-model 的(mapping target)") + require.Equal(t, "served-model", got[1].Name) + require.Equal(t, int64(200), got[1].Pricing.ID) +} + +func TestSupportedModels_ExactMappingTargetMissingFromPricing(t *testing.T) { + // `src → target` 但 target 不在渠道定价里 —— 结果中 src 的 Pricing 为 nil + // (等待 ListAvailable 阶段的全局 LiteLLM 回落填充)。 + ch := &Channel{ + ModelPricing: []ChannelModelPricing{ + {ID: 1, Platform: "anthropic", Models: []string{"some-priced-model"}, InputPrice: testPtrFloat64(1.5e-5)}, + }, + ModelMapping: map[string]map[string]string{ + "anthropic": { + "missing-src": "missing-target", + }, + }, + } + got := ch.SupportedModels() + require.Len(t, got, 2) + require.Equal(t, "missing-src", got[0].Name) + require.Nil(t, got[0].Pricing, "target 在渠道定价中缺失时不虚假填充,留给 ListAvailable 走 LiteLLM 回落") + require.Equal(t, "some-priced-model", got[1].Name) + require.NotNil(t, got[1].Pricing) +} diff --git a/backend/internal/service/domain_constants.go b/backend/internal/service/domain_constants.go index 1b7d7a9e..cf47b76f 100644 --- a/backend/internal/service/domain_constants.go +++ b/backend/internal/service/domain_constants.go @@ -243,6 +243,23 @@ const ( // SettingKeyOpsRuntimeLogConfig stores JSON config for runtime log settings. SettingKeyOpsRuntimeLogConfig = "ops_runtime_log_config" + // ========================= + // Channel Monitor (渠道监控) + // ========================= + + // SettingKeyChannelMonitorEnabled is a DB-backed soft switch for the channel monitor feature. + // When false: runner skips scheduling and user-facing endpoints return an empty list. + SettingKeyChannelMonitorEnabled = "channel_monitor_enabled" + + // SettingKeyChannelMonitorDefaultIntervalSeconds controls the default interval (seconds) + // pre-filled when creating a new channel monitor from the admin UI. Range: [15, 3600]. + SettingKeyChannelMonitorDefaultIntervalSeconds = "channel_monitor_default_interval_seconds" + + // SettingKeyAvailableChannelsEnabled is a DB-backed soft switch for the "Available Channels" + // user-facing aggregate view. When false: user endpoint returns an empty list and the + // sidebar entry is hidden. Defaults to false (opt-in feature). + SettingKeyAvailableChannelsEnabled = "available_channels_enabled" + // ========================= // Overload Cooldown (529) // ========================= diff --git a/backend/internal/service/model_pricing_resolver_test.go b/backend/internal/service/model_pricing_resolver_test.go index 905c4df6..4548c1d5 100644 --- a/backend/internal/service/model_pricing_resolver_test.go +++ b/backend/internal/service/model_pricing_resolver_test.go @@ -184,7 +184,7 @@ func newResolverWithChannel(t *testing.T, pricing []ChannelModelPricing) *ModelP return map[int64]string{groupID: "anthropic"}, nil }, } - cs := NewChannelService(repo, nil) + cs := NewChannelService(repo, nil, nil, nil) bs := newTestBillingServiceForResolver() return NewModelPricingResolver(cs, bs) } @@ -517,7 +517,7 @@ func TestResolve_WithChannelOverride_CacheError(t *testing.T) { return nil, errors.New("database unavailable") }, } - cs := NewChannelService(repo, nil) + cs := NewChannelService(repo, nil, nil, nil) bs := newTestBillingServiceForResolver() r := NewModelPricingResolver(cs, bs) diff --git a/backend/internal/service/ops_cleanup_service.go b/backend/internal/service/ops_cleanup_service.go index 1cae6fe5..08a10a02 100644 --- a/backend/internal/service/ops_cleanup_service.go +++ b/backend/internal/service/ops_cleanup_service.go @@ -36,11 +36,15 @@ return 0 // - Scheduling: 5-field cron spec (minute hour dom month dow). // - Multi-instance: best-effort Redis leader lock so only one node runs cleanup. // - Safety: deletes in batches to avoid long transactions. +// +// 附带:在 runCleanupOnce 末尾调用 ChannelMonitorService.RunDailyMaintenance, +// 统一共享 cron schedule + leader lock + heartbeat,避免再引一套调度。 type OpsCleanupService struct { - opsRepo OpsRepository - db *sql.DB - redisClient *redis.Client - cfg *config.Config + opsRepo OpsRepository + db *sql.DB + redisClient *redis.Client + cfg *config.Config + channelMonitorSvc *ChannelMonitorService instanceID string @@ -57,13 +61,15 @@ func NewOpsCleanupService( db *sql.DB, redisClient *redis.Client, cfg *config.Config, + channelMonitorSvc *ChannelMonitorService, ) *OpsCleanupService { return &OpsCleanupService{ - opsRepo: opsRepo, - db: db, - redisClient: redisClient, - cfg: cfg, - instanceID: uuid.NewString(), + opsRepo: opsRepo, + db: db, + redisClient: redisClient, + cfg: cfg, + channelMonitorSvc: channelMonitorSvc, + instanceID: uuid.NewString(), } } @@ -248,6 +254,15 @@ func (s *OpsCleanupService) runCleanupOnce(ctx context.Context) (opsCleanupDelet out.dailyPreagg = n } + // Channel monitor 每日维护(聚合昨日明细 + 软删过期明细/聚合)。 + // 失败只记日志,不影响 ops 清理的成功状态(与 ops 各步骤风格一致); + // 维护本身已经把每步错误打到 slog,heartbeat result 不再分项记录。 + if s.channelMonitorSvc != nil { + if err := s.channelMonitorSvc.RunDailyMaintenance(ctx); err != nil { + logger.LegacyPrintf("service.ops_cleanup", "[OpsCleanup] channel monitor maintenance failed: %v", err) + } + } + return out, nil } diff --git a/backend/internal/service/payment_fulfillment.go b/backend/internal/service/payment_fulfillment.go index 71f1eb2f..243edff3 100644 --- a/backend/internal/service/payment_fulfillment.go +++ b/backend/internal/service/payment_fulfillment.go @@ -2,6 +2,7 @@ package service import ( "context" + "errors" "fmt" "log/slog" "math" @@ -16,6 +17,14 @@ import ( infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors" ) +// ErrOrderNotFound is returned by HandlePaymentNotification when the webhook +// references an out_trade_no that does not exist in our DB. Callers (webhook +// handlers) should treat this as a terminal, non-retryable condition and still +// respond with a 2xx success to the provider — otherwise the provider will keep +// retrying forever (e.g. when a foreign environment's webhook endpoint is +// misconfigured to point at us, or when our orders table has been wiped). +var ErrOrderNotFound = errors.New("payment order not found") + // --- Payment Notification & Fulfillment --- func (s *PaymentService) HandlePaymentNotification(ctx context.Context, n *payment.PaymentNotification, pk string) error { @@ -30,7 +39,10 @@ func (s *PaymentService) HandlePaymentNotification(ctx context.Context, n *payme if oid, ok := parseLegacyPaymentOrderID(n.OrderID, err); ok { return s.confirmPayment(ctx, oid, n.TradeNo, n.Amount, pk, n.Metadata) } - return fmt.Errorf("order not found for out_trade_no: %s", n.OrderID) + if dbent.IsNotFound(err) { + return fmt.Errorf("%w: out_trade_no=%s", ErrOrderNotFound, n.OrderID) + } + return fmt.Errorf("lookup order failed for out_trade_no %s: %w", n.OrderID, err) } return s.confirmPayment(ctx, order.ID, n.TradeNo, n.Amount, pk, n.Metadata) } diff --git a/backend/internal/service/payment_fulfillment_order_not_found_test.go b/backend/internal/service/payment_fulfillment_order_not_found_test.go new file mode 100644 index 00000000..f6787e29 --- /dev/null +++ b/backend/internal/service/payment_fulfillment_order_not_found_test.go @@ -0,0 +1,106 @@ +//go:build unit + +package service + +import ( + "context" + "database/sql" + "errors" + "testing" + + "entgo.io/ent/dialect" + entsql "entgo.io/ent/dialect/sql" + _ "modernc.org/sqlite" + + dbent "github.com/Wei-Shaw/sub2api/ent" + "github.com/Wei-Shaw/sub2api/ent/enttest" + "github.com/Wei-Shaw/sub2api/internal/payment" + "github.com/stretchr/testify/require" +) + +// newOrderNotFoundTestClient wires an in-memory sqlite-backed ent.Client so +// tests can exercise HandlePaymentNotification's real DB lookup path without +// standing up a service stack. +func newOrderNotFoundTestClient(t *testing.T) *dbent.Client { + t.Helper() + + db, err := sql.Open("sqlite", "file:payment_order_not_found?mode=memory&cache=shared&_fk=1") + require.NoError(t, err) + t.Cleanup(func() { _ = db.Close() }) + + _, err = db.Exec("PRAGMA foreign_keys = ON") + require.NoError(t, err) + + drv := entsql.OpenDB(dialect.SQLite, db) + client := enttest.NewClient(t, enttest.WithOptions(dbent.Driver(drv))) + t.Cleanup(func() { _ = client.Close() }) + return client +} + +// TestHandlePaymentNotification_UnknownOrder_ReturnsSentinel exercises the +// happy-path of the webhook 404 fix: when the notification references an +// out_trade_no that does not exist in our DB, HandlePaymentNotification must +// return an error that errors.Is(err, ErrOrderNotFound) recognizes. The +// webhook handler relies on that contract to ack with a 2xx so the provider +// stops retrying. +func TestHandlePaymentNotification_UnknownOrder_ReturnsSentinel(t *testing.T) { + ctx := context.Background() + client := newOrderNotFoundTestClient(t) + + svc := &PaymentService{ + entClient: client, + providersLoaded: true, + } + + notification := &payment.PaymentNotification{ + OrderID: "sub2_does_not_exist_12345", + TradeNo: "stripe_evt_test_xyz", + Status: payment.NotificationStatusSuccess, + Amount: 1000, + } + + err := svc.HandlePaymentNotification(ctx, notification, payment.TypeStripe) + require.Error(t, err, "unknown out_trade_no should surface an error") + require.ErrorIs(t, err, ErrOrderNotFound, + "webhook handler relies on errors.Is(err, ErrOrderNotFound) to downgrade to 200") + + // Sanity: the wrapped error message should still include the out_trade_no + // for operator diagnostics. + require.Contains(t, err.Error(), notification.OrderID) +} + +// TestHandlePaymentNotification_NonSuccessStatus_Skips documents the +// short-circuit that precedes the DB lookup: when the notification is not a +// success event (e.g. Stripe non-payment events that reach us via the webhook +// route), we return nil without touching the DB and the handler responds 200. +func TestHandlePaymentNotification_NonSuccessStatus_Skips(t *testing.T) { + ctx := context.Background() + client := newOrderNotFoundTestClient(t) + + svc := &PaymentService{ + entClient: client, + providersLoaded: true, + } + + notification := &payment.PaymentNotification{ + OrderID: "sub2_does_not_exist_12345", + Status: "failed", // any value other than NotificationStatusSuccess + } + + err := svc.HandlePaymentNotification(ctx, notification, payment.TypeStripe) + require.NoError(t, err, + "non-success notifications must short-circuit before the DB lookup") +} + +// TestErrOrderNotFound_DistinctFromOtherErrors guards against an accidental +// collapse where a generic wrapped error would start matching ErrOrderNotFound +// (which would silently mask real DB failures). +func TestErrOrderNotFound_DistinctFromOtherErrors(t *testing.T) { + genericErr := errors.New("some other failure") + require.False(t, errors.Is(genericErr, ErrOrderNotFound)) + require.False(t, errors.Is(ErrOrderNotFound, genericErr)) + + wrappedLookupErr := errors.New("lookup order failed for out_trade_no sub2_42: connection refused") + require.False(t, errors.Is(wrappedLookupErr, ErrOrderNotFound), + "DB connection failures must not masquerade as order-not-found") +} diff --git a/backend/internal/service/setting_service.go b/backend/internal/service/setting_service.go index df7c86e7..c79d8949 100644 --- a/backend/internal/service/setting_service.go +++ b/backend/internal/service/setting_service.go @@ -450,6 +450,9 @@ func (s *SettingService) GetPublicSettings(ctx context.Context) (*PublicSettings SettingKeyBalanceLowNotifyThreshold, SettingKeyBalanceLowNotifyRechargeURL, SettingKeyAccountQuotaNotifyEnabled, + SettingKeyChannelMonitorEnabled, + SettingKeyChannelMonitorDefaultIntervalSeconds, + SettingKeyAvailableChannelsEnabled, } settings, err := s.settingRepo.GetMultiple(ctx, keys) @@ -532,9 +535,88 @@ func (s *SettingService) GetPublicSettings(ctx context.Context) (*PublicSettings AccountQuotaNotifyEnabled: settings[SettingKeyAccountQuotaNotifyEnabled] == "true", BalanceLowNotifyThreshold: balanceLowNotifyThreshold, BalanceLowNotifyRechargeURL: settings[SettingKeyBalanceLowNotifyRechargeURL], + + ChannelMonitorEnabled: !isFalseSettingValue(settings[SettingKeyChannelMonitorEnabled]), + ChannelMonitorDefaultIntervalSeconds: parseChannelMonitorInterval(settings[SettingKeyChannelMonitorDefaultIntervalSeconds]), + + AvailableChannelsEnabled: settings[SettingKeyAvailableChannelsEnabled] == "true", }, nil } +// channelMonitorIntervalMin / channelMonitorIntervalMax bound the default interval +// (mirrors the monitor-level constraint but lives here so setting_service stays decoupled). +const ( + channelMonitorIntervalMin = 15 + channelMonitorIntervalMax = 3600 + channelMonitorIntervalFallback = 60 +) + +// parseChannelMonitorInterval parses the stored string and clamps to [15, 3600]. +// Empty / invalid input falls back to channelMonitorIntervalFallback. +func parseChannelMonitorInterval(raw string) int { + v, err := strconv.Atoi(strings.TrimSpace(raw)) + if err != nil { + return channelMonitorIntervalFallback + } + return clampChannelMonitorInterval(v) +} + +// clampChannelMonitorInterval clamps v to the allowed range. 0 means "not provided". +func clampChannelMonitorInterval(v int) int { + if v <= 0 { + return 0 + } + if v < channelMonitorIntervalMin { + return channelMonitorIntervalMin + } + if v > channelMonitorIntervalMax { + return channelMonitorIntervalMax + } + return v +} + +// ChannelMonitorRuntime is the lightweight view of the channel monitor feature +// consumed by the runner and user-facing handlers. +type ChannelMonitorRuntime struct { + Enabled bool + DefaultIntervalSeconds int +} + +// GetChannelMonitorRuntime reads the channel monitor feature flags directly from +// the settings store. Fail-open: on error returns Enabled=true with the default interval. +func (s *SettingService) GetChannelMonitorRuntime(ctx context.Context) ChannelMonitorRuntime { + vals, err := s.settingRepo.GetMultiple(ctx, []string{ + SettingKeyChannelMonitorEnabled, + SettingKeyChannelMonitorDefaultIntervalSeconds, + }) + if err != nil { + return ChannelMonitorRuntime{Enabled: true, DefaultIntervalSeconds: channelMonitorIntervalFallback} + } + return ChannelMonitorRuntime{ + Enabled: !isFalseSettingValue(vals[SettingKeyChannelMonitorEnabled]), + DefaultIntervalSeconds: parseChannelMonitorInterval(vals[SettingKeyChannelMonitorDefaultIntervalSeconds]), + } +} + +// AvailableChannelsRuntime is the lightweight view of the available-channels feature +// switch consumed by the user-facing handler. +type AvailableChannelsRuntime struct { + Enabled bool +} + +// GetAvailableChannelsRuntime reads the available-channels feature switch directly +// from the settings store. Fail-closed: on error returns Enabled=false, matching +// the opt-in default (unknown ↔ disabled). +func (s *SettingService) GetAvailableChannelsRuntime(ctx context.Context) AvailableChannelsRuntime { + vals, err := s.settingRepo.GetMultiple(ctx, []string{SettingKeyAvailableChannelsEnabled}) + if err != nil { + return AvailableChannelsRuntime{Enabled: false} + } + return AvailableChannelsRuntime{ + Enabled: vals[SettingKeyAvailableChannelsEnabled] == "true", + } +} + // SetOnUpdateCallback sets a callback function to be called when settings are updated // This is used for cache invalidation (e.g., HTML cache in frontend server) func (s *SettingService) SetOnUpdateCallback(callback func()) { @@ -546,54 +628,75 @@ func (s *SettingService) SetVersion(version string) { s.version = version } -// GetPublicSettingsForInjection returns public settings in a format suitable for HTML injection -// This implements the web.PublicSettingsProvider interface +// PublicSettingsInjectionPayload is the JSON shape embedded into HTML as +// `window.__APP_CONFIG__` so the frontend can hydrate feature flags & site +// config before the first XHR finishes. +// +// INVARIANT: every `json` tag here MUST also exist on handler/dto.PublicSettings. +// If you forget a feature-flag field here, the frontend's +// `cachedPublicSettings.xxx_enabled` will be `undefined` on refresh until the +// async `/api/v1/settings/public` call returns — which causes opt-in menus +// (strict `=== true`) to flicker off/on. See +// frontend/src/utils/featureFlags.ts for the matching registry. +// +// A unit test diffs this struct's JSON keys against dto.PublicSettings to catch +// drift automatically (see setting_service_injection_test.go). +type PublicSettingsInjectionPayload struct { + RegistrationEnabled bool `json:"registration_enabled"` + EmailVerifyEnabled bool `json:"email_verify_enabled"` + RegistrationEmailSuffixWhitelist []string `json:"registration_email_suffix_whitelist"` + PromoCodeEnabled bool `json:"promo_code_enabled"` + PasswordResetEnabled bool `json:"password_reset_enabled"` + InvitationCodeEnabled bool `json:"invitation_code_enabled"` + TotpEnabled bool `json:"totp_enabled"` + TurnstileEnabled bool `json:"turnstile_enabled"` + TurnstileSiteKey string `json:"turnstile_site_key"` + SiteName string `json:"site_name"` + SiteLogo string `json:"site_logo"` + SiteSubtitle string `json:"site_subtitle"` + APIBaseURL string `json:"api_base_url"` + ContactInfo string `json:"contact_info"` + DocURL string `json:"doc_url"` + HomeContent string `json:"home_content"` + HideCcsImportButton bool `json:"hide_ccs_import_button"` + PurchaseSubscriptionEnabled bool `json:"purchase_subscription_enabled"` + PurchaseSubscriptionURL string `json:"purchase_subscription_url"` + TableDefaultPageSize int `json:"table_default_page_size"` + TablePageSizeOptions []int `json:"table_page_size_options"` + CustomMenuItems json.RawMessage `json:"custom_menu_items"` + CustomEndpoints json.RawMessage `json:"custom_endpoints"` + LinuxDoOAuthEnabled bool `json:"linuxdo_oauth_enabled"` + WeChatOAuthEnabled bool `json:"wechat_oauth_enabled"` + WeChatOAuthOpenEnabled bool `json:"wechat_oauth_open_enabled"` + WeChatOAuthMPEnabled bool `json:"wechat_oauth_mp_enabled"` + WeChatOAuthMobileEnabled bool `json:"wechat_oauth_mobile_enabled"` + OIDCOAuthEnabled bool `json:"oidc_oauth_enabled"` + OIDCOAuthProviderName string `json:"oidc_oauth_provider_name"` + BackendModeEnabled bool `json:"backend_mode_enabled"` + PaymentEnabled bool `json:"payment_enabled"` + Version string `json:"version"` + BalanceLowNotifyEnabled bool `json:"balance_low_notify_enabled"` + AccountQuotaNotifyEnabled bool `json:"account_quota_notify_enabled"` + BalanceLowNotifyThreshold float64 `json:"balance_low_notify_threshold"` + BalanceLowNotifyRechargeURL string `json:"balance_low_notify_recharge_url"` + + // Feature flags — MUST match the opt-in/opt-out registry in + // frontend/src/utils/featureFlags.ts. Missing a field here is the bug + // that hid the "可用渠道" menu on page refresh. + ChannelMonitorEnabled bool `json:"channel_monitor_enabled"` + ChannelMonitorDefaultIntervalSeconds int `json:"channel_monitor_default_interval_seconds"` + AvailableChannelsEnabled bool `json:"available_channels_enabled"` +} + +// GetPublicSettingsForInjection returns public settings in a format suitable for HTML injection. +// This implements the web.PublicSettingsProvider interface. func (s *SettingService) GetPublicSettingsForInjection(ctx context.Context) (any, error) { settings, err := s.GetPublicSettings(ctx) if err != nil { return nil, err } - // Return a struct that matches the frontend's expected format - return &struct { - RegistrationEnabled bool `json:"registration_enabled"` - EmailVerifyEnabled bool `json:"email_verify_enabled"` - RegistrationEmailSuffixWhitelist []string `json:"registration_email_suffix_whitelist"` - PromoCodeEnabled bool `json:"promo_code_enabled"` - PasswordResetEnabled bool `json:"password_reset_enabled"` - InvitationCodeEnabled bool `json:"invitation_code_enabled"` - TotpEnabled bool `json:"totp_enabled"` - TurnstileEnabled bool `json:"turnstile_enabled"` - TurnstileSiteKey string `json:"turnstile_site_key,omitempty"` - SiteName string `json:"site_name"` - SiteLogo string `json:"site_logo,omitempty"` - SiteSubtitle string `json:"site_subtitle,omitempty"` - APIBaseURL string `json:"api_base_url,omitempty"` - ContactInfo string `json:"contact_info,omitempty"` - DocURL string `json:"doc_url,omitempty"` - HomeContent string `json:"home_content,omitempty"` - HideCcsImportButton bool `json:"hide_ccs_import_button"` - PurchaseSubscriptionEnabled bool `json:"purchase_subscription_enabled"` - PurchaseSubscriptionURL string `json:"purchase_subscription_url,omitempty"` - TableDefaultPageSize int `json:"table_default_page_size"` - TablePageSizeOptions []int `json:"table_page_size_options"` - CustomMenuItems json.RawMessage `json:"custom_menu_items"` - CustomEndpoints json.RawMessage `json:"custom_endpoints"` - LinuxDoOAuthEnabled bool `json:"linuxdo_oauth_enabled"` - WeChatOAuthEnabled bool `json:"wechat_oauth_enabled"` - WeChatOAuthOpenEnabled bool `json:"wechat_oauth_open_enabled"` - WeChatOAuthMPEnabled bool `json:"wechat_oauth_mp_enabled"` - WeChatOAuthMobileEnabled bool `json:"wechat_oauth_mobile_enabled"` - BackendModeEnabled bool `json:"backend_mode_enabled"` - PaymentEnabled bool `json:"payment_enabled"` - OIDCOAuthEnabled bool `json:"oidc_oauth_enabled"` - OIDCOAuthProviderName string `json:"oidc_oauth_provider_name"` - Version string `json:"version,omitempty"` - BalanceLowNotifyEnabled bool `json:"balance_low_notify_enabled"` - AccountQuotaNotifyEnabled bool `json:"account_quota_notify_enabled"` - BalanceLowNotifyThreshold float64 `json:"balance_low_notify_threshold"` - BalanceLowNotifyRechargeURL string `json:"balance_low_notify_recharge_url"` - }{ + return &PublicSettingsInjectionPayload{ RegistrationEnabled: settings.RegistrationEnabled, EmailVerifyEnabled: settings.EmailVerifyEnabled, RegistrationEmailSuffixWhitelist: settings.RegistrationEmailSuffixWhitelist, @@ -622,15 +725,19 @@ func (s *SettingService) GetPublicSettingsForInjection(ctx context.Context) (any WeChatOAuthOpenEnabled: settings.WeChatOAuthOpenEnabled, WeChatOAuthMPEnabled: settings.WeChatOAuthMPEnabled, WeChatOAuthMobileEnabled: settings.WeChatOAuthMobileEnabled, - BackendModeEnabled: settings.BackendModeEnabled, - PaymentEnabled: settings.PaymentEnabled, OIDCOAuthEnabled: settings.OIDCOAuthEnabled, OIDCOAuthProviderName: settings.OIDCOAuthProviderName, + BackendModeEnabled: settings.BackendModeEnabled, + PaymentEnabled: settings.PaymentEnabled, Version: s.version, BalanceLowNotifyEnabled: settings.BalanceLowNotifyEnabled, AccountQuotaNotifyEnabled: settings.AccountQuotaNotifyEnabled, BalanceLowNotifyThreshold: settings.BalanceLowNotifyThreshold, BalanceLowNotifyRechargeURL: settings.BalanceLowNotifyRechargeURL, + + ChannelMonitorEnabled: settings.ChannelMonitorEnabled, + ChannelMonitorDefaultIntervalSeconds: settings.ChannelMonitorDefaultIntervalSeconds, + AvailableChannelsEnabled: settings.AvailableChannelsEnabled, }, nil } @@ -1086,6 +1193,15 @@ func (s *SettingService) buildSystemSettingsUpdates(ctx context.Context, setting updates[SettingKeyOpsMetricsIntervalSeconds] = strconv.Itoa(settings.OpsMetricsIntervalSeconds) } + // Channel monitor feature switch + updates[SettingKeyChannelMonitorEnabled] = strconv.FormatBool(settings.ChannelMonitorEnabled) + if v := clampChannelMonitorInterval(settings.ChannelMonitorDefaultIntervalSeconds); v > 0 { + updates[SettingKeyChannelMonitorDefaultIntervalSeconds] = strconv.Itoa(v) + } + + // Available channels feature switch + updates[SettingKeyAvailableChannelsEnabled] = strconv.FormatBool(settings.AvailableChannelsEnabled) + // Claude Code version check updates[SettingKeyMinClaudeCodeVersion] = settings.MinClaudeCodeVersion updates[SettingKeyMaxClaudeCodeVersion] = settings.MaxClaudeCodeVersion @@ -1644,6 +1760,13 @@ func (s *SettingService) InitializeDefaultSettings(ctx context.Context) error { SettingKeyOpsQueryModeDefault: "auto", SettingKeyOpsMetricsIntervalSeconds: "60", + // Channel monitor defaults (enabled, 60s) + SettingKeyChannelMonitorEnabled: "true", + SettingKeyChannelMonitorDefaultIntervalSeconds: "60", + + // Available channels feature (default disabled; opt-in) + SettingKeyAvailableChannelsEnabled: "false", + // Claude Code version check (default: empty = disabled) SettingKeyMinClaudeCodeVersion: "", SettingKeyMaxClaudeCodeVersion: "", @@ -1950,6 +2073,15 @@ func (s *SettingService) parseSettings(settings map[string]string) *SystemSettin } } + // Channel monitor feature (default: enabled, 60s) + result.ChannelMonitorEnabled = !isFalseSettingValue(settings[SettingKeyChannelMonitorEnabled]) + result.ChannelMonitorDefaultIntervalSeconds = parseChannelMonitorInterval( + settings[SettingKeyChannelMonitorDefaultIntervalSeconds], + ) + + // Available channels feature (default: disabled; strict true) + result.AvailableChannelsEnabled = settings[SettingKeyAvailableChannelsEnabled] == "true" + // Claude Code version check result.MinClaudeCodeVersion = settings[SettingKeyMinClaudeCodeVersion] result.MaxClaudeCodeVersion = settings[SettingKeyMaxClaudeCodeVersion] diff --git a/backend/internal/service/settings_view.go b/backend/internal/service/settings_view.go index a9de5eee..ddd4fff6 100644 --- a/backend/internal/service/settings_view.go +++ b/backend/internal/service/settings_view.go @@ -126,6 +126,13 @@ type SystemSettings struct { OpsQueryModeDefault string OpsMetricsIntervalSeconds int + // Channel Monitor feature + ChannelMonitorEnabled bool `json:"channel_monitor_enabled"` + ChannelMonitorDefaultIntervalSeconds int `json:"channel_monitor_default_interval_seconds"` + + // Available Channels feature (user-facing aggregate view) + AvailableChannelsEnabled bool `json:"available_channels_enabled"` + // Claude Code version check MinClaudeCodeVersion string MaxClaudeCodeVersion string @@ -210,6 +217,13 @@ type PublicSettings struct { AccountQuotaNotifyEnabled bool BalanceLowNotifyThreshold float64 BalanceLowNotifyRechargeURL string + + // Channel Monitor feature + ChannelMonitorEnabled bool `json:"channel_monitor_enabled"` + ChannelMonitorDefaultIntervalSeconds int `json:"channel_monitor_default_interval_seconds"` + + // Available Channels feature (user-facing aggregate view) + AvailableChannelsEnabled bool `json:"available_channels_enabled"` } type WeChatConnectOAuthConfig struct { diff --git a/backend/internal/service/wire.go b/backend/internal/service/wire.go index 6b405724..86bfc327 100644 --- a/backend/internal/service/wire.go +++ b/backend/internal/service/wire.go @@ -269,13 +269,16 @@ func ProvideOpsAlertEvaluatorService( } // ProvideOpsCleanupService creates and starts OpsCleanupService (cron scheduled). +// channelMonitorSvc 让维护任务(聚合 + 历史/聚合软删)跟随 ops 清理 cron 一起跑, +// 共享 leader lock + heartbeat。 func ProvideOpsCleanupService( opsRepo OpsRepository, db *sql.DB, redisClient *redis.Client, cfg *config.Config, + channelMonitorSvc *ChannelMonitorService, ) *OpsCleanupService { - svc := NewOpsCleanupService(opsRepo, db, redisClient, cfg) + svc := NewOpsCleanupService(opsRepo, db, redisClient, cfg, channelMonitorSvc) svc.Start() return svc } @@ -487,6 +490,9 @@ var ProviderSet = wire.NewSet( NewPaymentService, ProvidePaymentOrderExpiryService, ProvideBalanceNotifyService, + ProvideChannelMonitorService, + ProvideChannelMonitorRunner, + NewChannelMonitorRequestTemplateService, ) // ProvidePaymentConfigService wraps NewPaymentConfigService to accept the named @@ -506,3 +512,23 @@ func ProvidePaymentOrderExpiryService(paymentSvc *PaymentService) *PaymentOrderE svc.Start() return svc } + +// ProvideChannelMonitorService 创建渠道监控服务(CRUD + RunCheck + 用户视图聚合)。 +// 加密器复用 wire 中已注入的 SecretEncryptor(AES-256-GCM)。 +func ProvideChannelMonitorService( + repo ChannelMonitorRepository, + encryptor SecretEncryptor, +) *ChannelMonitorService { + return NewChannelMonitorService(repo, encryptor) +} + +// ProvideChannelMonitorRunner 创建并启动渠道监控调度器。 +// 通过 SetScheduler 注入回 service 后再 Start,确保启动时加载所有 enabled monitor, +// 后续 CRUD 也能即时同步任务表。Runner.Stop 由 cleanup function 调用。 +// settingService 用于 runner 每次 fire 读取功能开关。 +func ProvideChannelMonitorRunner(svc *ChannelMonitorService, settingService *SettingService) *ChannelMonitorRunner { + r := NewChannelMonitorRunner(svc, settingService) + svc.SetScheduler(r) + r.Start() + return r +} diff --git a/backend/migrations/125_add_channel_monitors.sql b/backend/migrations/125_add_channel_monitors.sql new file mode 100644 index 00000000..5ec327da --- /dev/null +++ b/backend/migrations/125_add_channel_monitors.sql @@ -0,0 +1,58 @@ +-- Migration: 125_add_channel_monitors +-- 渠道监控 MVP:周期性对外部 provider/endpoint/api_key 做模型心跳测试。 +-- +-- 表结构说明: +-- - channel_monitors 渠道配置表(一行 = 一个监控对象) +-- - channel_monitor_histories 检测历史明细表(一次检测一个模型 = 一行) +-- +-- 设计要点: +-- - api_key_encrypted 列存放 AES-256-GCM 密文(base64),由 service 层加密。 +-- - extra_models 用 JSONB 存储字符串数组,便于扩展(后续可加权重等元数据)。 +-- - history 表通过 ON DELETE CASCADE 自动清理已删除监控的历史。 +-- - (enabled, last_checked_at) 索引服务于调度器扫描“到期需要检测”的监控。 +-- - histories 上 (monitor_id, model, checked_at DESC) 服务用户视图聚合查询; +-- 单独的 (checked_at) 索引服务定期清理 30 天前数据的 DELETE。 + +CREATE TABLE IF NOT EXISTS channel_monitors ( + id BIGSERIAL PRIMARY KEY, + name VARCHAR(100) NOT NULL, + provider VARCHAR(20) NOT NULL, -- openai / anthropic / gemini + endpoint VARCHAR(500) NOT NULL, -- base origin + api_key_encrypted TEXT NOT NULL, -- AES-256-GCM (base64) + primary_model VARCHAR(200) NOT NULL, + extra_models JSONB NOT NULL DEFAULT '[]'::jsonb, + group_name VARCHAR(100) NOT NULL DEFAULT '', + enabled BOOLEAN NOT NULL DEFAULT TRUE, + interval_seconds INT NOT NULL, + last_checked_at TIMESTAMPTZ, + created_by BIGINT NOT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + CONSTRAINT channel_monitors_provider_check CHECK (provider IN ('openai', 'anthropic', 'gemini')), + CONSTRAINT channel_monitors_interval_check CHECK (interval_seconds BETWEEN 15 AND 3600) +); + +CREATE INDEX IF NOT EXISTS idx_channel_monitors_enabled_last_checked + ON channel_monitors (enabled, last_checked_at); +CREATE INDEX IF NOT EXISTS idx_channel_monitors_provider + ON channel_monitors (provider); +CREATE INDEX IF NOT EXISTS idx_channel_monitors_group_name + ON channel_monitors (group_name); + +CREATE TABLE IF NOT EXISTS channel_monitor_histories ( + id BIGSERIAL PRIMARY KEY, + monitor_id BIGINT NOT NULL REFERENCES channel_monitors(id) ON DELETE CASCADE, + model VARCHAR(200) NOT NULL, + status VARCHAR(20) NOT NULL, + latency_ms INT, + ping_latency_ms INT, + message VARCHAR(500) NOT NULL DEFAULT '', + checked_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + CONSTRAINT channel_monitor_histories_status_check + CHECK (status IN ('operational', 'degraded', 'failed', 'error')) +); + +CREATE INDEX IF NOT EXISTS idx_channel_monitor_histories_monitor_model_checked + ON channel_monitor_histories (monitor_id, model, checked_at DESC); +CREATE INDEX IF NOT EXISTS idx_channel_monitor_histories_checked_at + ON channel_monitor_histories (checked_at); diff --git a/backend/migrations/126_add_channel_monitor_aggregation.sql b/backend/migrations/126_add_channel_monitor_aggregation.sql new file mode 100644 index 00000000..e643763c --- /dev/null +++ b/backend/migrations/126_add_channel_monitor_aggregation.sql @@ -0,0 +1,60 @@ +-- Migration: 126_add_channel_monitor_aggregation +-- 渠道监控日聚合:把 channel_monitor_histories 的明细按天聚合,明细只保留 1 天, +-- 聚合保留 30 天。明细和聚合表都用软删除(deleted_at),由 ops cleanup 任务每天 +-- 凌晨随运维监控清理一起跑(共享 cron)。 +-- +-- 设计要点: +-- - channel_monitor_histories 加 deleted_at 软删除字段(SoftDeleteMixin 全局 +-- Hook 会把 DELETE 自动改写成 UPDATE deleted_at = NOW())。 +-- - channel_monitor_daily_rollups 按 (monitor_id, model, bucket_date) 唯一, +-- 用 ON CONFLICT DO UPDATE 实现幂等回填,状态分布和延迟分子分母都保留, +-- 方便后续按窗口任意求加权可用率和均值。 +-- - watermark 表只有一行(id=1),记录最近一次聚合到达的日期,避免重启后重复 +-- 扫全表。 +-- - rollup 上 (bucket_date) 索引服务清理任务的 DELETE WHERE bucket_date < cutoff。 + +-- 1) 给历史明细表加软删除字段 +ALTER TABLE channel_monitor_histories + ADD COLUMN IF NOT EXISTS deleted_at TIMESTAMPTZ; + +CREATE INDEX IF NOT EXISTS idx_channel_monitor_histories_deleted_at + ON channel_monitor_histories (deleted_at); + +-- 2) 创建日聚合表 +CREATE TABLE IF NOT EXISTS channel_monitor_daily_rollups ( + id BIGSERIAL PRIMARY KEY, + monitor_id BIGINT NOT NULL REFERENCES channel_monitors(id) ON DELETE CASCADE, + model VARCHAR(200) NOT NULL, + bucket_date DATE NOT NULL, + total_checks INT NOT NULL DEFAULT 0, + ok_count INT NOT NULL DEFAULT 0, + operational_count INT NOT NULL DEFAULT 0, + degraded_count INT NOT NULL DEFAULT 0, + failed_count INT NOT NULL DEFAULT 0, + error_count INT NOT NULL DEFAULT 0, + sum_latency_ms BIGINT NOT NULL DEFAULT 0, + count_latency INT NOT NULL DEFAULT 0, + sum_ping_latency_ms BIGINT NOT NULL DEFAULT 0, + count_ping_latency INT NOT NULL DEFAULT 0, + computed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + deleted_at TIMESTAMPTZ +); + +CREATE UNIQUE INDEX IF NOT EXISTS idx_channel_monitor_daily_rollups_unique + ON channel_monitor_daily_rollups (monitor_id, model, bucket_date); +CREATE INDEX IF NOT EXISTS idx_channel_monitor_daily_rollups_bucket + ON channel_monitor_daily_rollups (bucket_date); +CREATE INDEX IF NOT EXISTS idx_channel_monitor_daily_rollups_deleted_at + ON channel_monitor_daily_rollups (deleted_at); + +-- 3) 创建 watermark 表(单行:id=1) +CREATE TABLE IF NOT EXISTS channel_monitor_aggregation_watermark ( + id INT PRIMARY KEY DEFAULT 1, + last_aggregated_date DATE, + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + CONSTRAINT channel_monitor_aggregation_watermark_singleton CHECK (id = 1) +); + +INSERT INTO channel_monitor_aggregation_watermark (id, last_aggregated_date, updated_at) +VALUES (1, NULL, NOW()) +ON CONFLICT (id) DO NOTHING; diff --git a/backend/migrations/127_drop_channel_monitor_deleted_at.sql b/backend/migrations/127_drop_channel_monitor_deleted_at.sql new file mode 100644 index 00000000..2260f06b --- /dev/null +++ b/backend/migrations/127_drop_channel_monitor_deleted_at.sql @@ -0,0 +1,16 @@ +-- Migration: 127_drop_channel_monitor_deleted_at +-- 纠正 110 引入的 SoftDeleteMixin:日志/聚合表无恢复需求,软删会让行和索引只增不减, +-- 徒增磁盘和查询开销。改回分批物理删(由 OpsCleanupService 每天凌晨统一调度, +-- deleteOldRowsByID 模板,batch=5000)。 +-- +-- 110 尚未跑过聚合/清理(首次 maintenance 在次日 02:00),所以此处不担心业务数据。 +-- 直接 DROP 列 + 索引;对应的 Go 侧 ent schema 已移除 SoftDeleteMixin、repo 的 +-- raw SQL 已移除 deleted_at IS NULL 过滤。 + +DROP INDEX IF EXISTS idx_channel_monitor_histories_deleted_at; +ALTER TABLE channel_monitor_histories + DROP COLUMN IF EXISTS deleted_at; + +DROP INDEX IF EXISTS idx_channel_monitor_daily_rollups_deleted_at; +ALTER TABLE channel_monitor_daily_rollups + DROP COLUMN IF EXISTS deleted_at; diff --git a/backend/migrations/128_add_channel_monitor_request_templates.sql b/backend/migrations/128_add_channel_monitor_request_templates.sql new file mode 100644 index 00000000..2db8fef6 --- /dev/null +++ b/backend/migrations/128_add_channel_monitor_request_templates.sql @@ -0,0 +1,70 @@ +-- Migration: 128_add_channel_monitor_request_templates +-- 加请求模板表 + 给 channel_monitors 加 4 个快照字段(template_id 关联引用 + extra_headers / +-- body_override_mode / body_override 三个真正运行时使用的快照)。 +-- +-- 设计要点: +-- 1) 模板与监控之间是「应用即拷贝」的快照语义,运行时 checker 不再回查模板表。 +-- 模板 UPDATE 不会自动影响监控;只有用户主动「应用到关联监控」才会刷新快照。 +-- 2) ON DELETE SET NULL:模板删除不级联清理监控;监控保留快照继续工作。 +-- 3) extra_headers / body_override 都是 JSONB;body_override_mode 用 varchar(不是 enum) +-- 便于将来加新模式无需 ALTER TYPE。 +-- 4) 同一 provider 内模板 name 唯一(允许 Anthropic + OpenAI 重名 "伪装官方客户端")。 + +CREATE TABLE IF NOT EXISTS channel_monitor_request_templates ( + id BIGSERIAL PRIMARY KEY, + name VARCHAR(100) NOT NULL, + provider VARCHAR(20) NOT NULL, + description VARCHAR(500) NOT NULL DEFAULT '', + extra_headers JSONB NOT NULL DEFAULT '{}'::jsonb, + body_override_mode VARCHAR(10) NOT NULL DEFAULT 'off', + body_override JSONB NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + CONSTRAINT channel_monitor_request_templates_provider_check + CHECK (provider IN ('openai', 'anthropic', 'gemini')), + CONSTRAINT channel_monitor_request_templates_body_mode_check + CHECK (body_override_mode IN ('off', 'merge', 'replace')) +); + +CREATE UNIQUE INDEX IF NOT EXISTS channel_monitor_request_templates_provider_name + ON channel_monitor_request_templates (provider, name); + +-- channel_monitors 加 4 列(ADD COLUMN IF NOT EXISTS 需要 PG 9.6+,生产使用 PG 16) +ALTER TABLE channel_monitors + ADD COLUMN IF NOT EXISTS template_id BIGINT NULL; +ALTER TABLE channel_monitors + ADD COLUMN IF NOT EXISTS extra_headers JSONB NOT NULL DEFAULT '{}'::jsonb; +ALTER TABLE channel_monitors + ADD COLUMN IF NOT EXISTS body_override_mode VARCHAR(10) NOT NULL DEFAULT 'off'; +ALTER TABLE channel_monitors + ADD COLUMN IF NOT EXISTS body_override JSONB NULL; + +-- 约束 + 外键(DO 块里 IF NOT EXISTS 判断,保证幂等) +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.table_constraints + WHERE constraint_name = 'channel_monitors_body_mode_check' + AND table_name = 'channel_monitors' + ) THEN + ALTER TABLE channel_monitors + ADD CONSTRAINT channel_monitors_body_mode_check + CHECK (body_override_mode IN ('off', 'merge', 'replace')); + END IF; + + IF NOT EXISTS ( + SELECT 1 FROM information_schema.table_constraints + WHERE constraint_name = 'channel_monitors_template_id_fkey' + AND table_name = 'channel_monitors' + ) THEN + ALTER TABLE channel_monitors + ADD CONSTRAINT channel_monitors_template_id_fkey + FOREIGN KEY (template_id) + REFERENCES channel_monitor_request_templates (id) + ON DELETE SET NULL; + END IF; +END $$; + +CREATE INDEX IF NOT EXISTS idx_channel_monitors_template_id + ON channel_monitors (template_id) + WHERE template_id IS NOT NULL; diff --git a/backend/migrations/129_seed_claude_code_template.sql b/backend/migrations/129_seed_claude_code_template.sql new file mode 100644 index 00000000..d9b062c9 --- /dev/null +++ b/backend/migrations/129_seed_claude_code_template.sql @@ -0,0 +1,38 @@ +-- Migration: 129_seed_claude_code_template +-- 内置「Claude Code 伪装」请求模板,覆盖 Anthropic 上游对官方 CLI 客户端的所有验证项: +-- 1) User-Agent / X-App / anthropic-beta / anthropic-version 等头 +-- 2) system 数组首项与官方 system prompt 字面一致(Dice >= 0.5) +-- 3) metadata.user_id 满足 ParseMetadataUserID — 这里用 legacy 格式(user_<64hex>_account__session_<36char>) +-- 避免新版 JSON 字符串内嵌 JSON 在编辑器里出现一长串 \" 转义,便于用户阅读。 +-- +-- ON CONFLICT DO NOTHING:已部署环境(手动建过模板)跑此 migration 不会重复 / 覆盖。 +-- 用户可自行编辑后续覆盖此 seed;CC 升大版时再起一条 migration 提供新模板,不动用户的旧模板。 + +INSERT INTO channel_monitor_request_templates ( + name, provider, description, extra_headers, body_override_mode, body_override +) +VALUES ( + 'Claude Code 伪装', + 'anthropic', + '完整模拟 Claude Code 2.1.114 客户端:UA + anthropic-beta + system + metadata.user_id 全部对齐,绕过 Anthropic 上游 ''Claude Code only'' 限制(如 Max 套餐)。', + '{ + "User-Agent": "claude-cli/2.1.114 (external, sdk-cli)", + "X-App": "cli", + "anthropic-version": "2023-06-01", + "anthropic-beta": "claude-code-20250219,interleaved-thinking-2025-05-14,context-management-2025-06-27,prompt-caching-scope-2026-01-05,advisor-tool-2026-03-01", + "anthropic-dangerous-direct-browser-access": "true" + }'::jsonb, + 'merge', + '{ + "system": [ + { + "type": "text", + "text": "You are Claude Code, Anthropic''s official CLI for Claude." + } + ], + "metadata": { + "user_id": "user_0000000000000000000000000000000000000000000000000000000000000000_account_00000000-0000-0000-0000-000000000000_session_00000000-0000-0000-0000-000000000000" + } + }'::jsonb +) +ON CONFLICT (provider, name) DO NOTHING; diff --git a/frontend/src/api/admin/channelMonitor.ts b/frontend/src/api/admin/channelMonitor.ts new file mode 100644 index 00000000..949c4bc8 --- /dev/null +++ b/frontend/src/api/admin/channelMonitor.ts @@ -0,0 +1,202 @@ +/** + * Admin Channel Monitor API endpoints + * Handles channel monitor (uptime/health) management for administrators + */ + +import { apiClient } from '../client' + +export type Provider = 'openai' | 'anthropic' | 'gemini' +export type MonitorStatus = 'operational' | 'degraded' | 'failed' | 'error' +export type BodyOverrideMode = 'off' | 'merge' | 'replace' + +export interface ChannelMonitor { + id: number + name: string + provider: Provider + endpoint: string + api_key_masked: string + /** + * True when the stored encrypted API key cannot be decrypted (e.g. the + * encryption key has changed). Admin must re-edit the monitor to provide + * a fresh key. Backend skips checks for these monitors. + */ + api_key_decrypt_failed?: boolean + primary_model: string + extra_models: string[] + group_name: string + enabled: boolean + interval_seconds: number + last_checked_at: string | null + created_by: number + created_at: string + updated_at: string + /** Latest status of the primary model (empty when no history yet) */ + primary_status: MonitorStatus | '' + /** Latest latency of the primary model in ms (null when no history yet) */ + primary_latency_ms: number | null + /** Primary model 7-day availability percentage (0-100) */ + availability_7d: number + /** Latest status per extra model (used for hover tooltip) */ + extra_models_status: ExtraModelStatus[] + /** 请求自定义快照字段(高级设置) */ + template_id: number | null + extra_headers: Record + body_override_mode: BodyOverrideMode + body_override: Record | null +} + +export interface ExtraModelStatus { + model: string + status: MonitorStatus | '' + latency_ms: number | null +} + +export interface ListParams { + page?: number + page_size?: number + provider?: Provider + enabled?: boolean + search?: string +} + +export interface ListResponse { + items: ChannelMonitor[] + total: number + page: number + page_size: number + pages: number +} + +export interface CreateParams { + name: string + provider: Provider + endpoint: string + api_key: string + primary_model: string + extra_models?: string[] + group_name?: string + enabled?: boolean + interval_seconds: number + template_id?: number | null + extra_headers?: Record + body_override_mode?: BodyOverrideMode + body_override?: Record | null +} + +// Update request: api_key 空串 = 不修改;clear_template=true 时把 template_id 置空 +export type UpdateParams = Partial & { + clear_template?: boolean +} + +export interface CheckResult { + model: string + status: MonitorStatus + latency_ms: number | null + ping_latency_ms: number | null + message: string + checked_at: string +} + +export interface RunNowResponse { + results: CheckResult[] +} + +export interface HistoryItem { + id: number + model: string + status: MonitorStatus + latency_ms: number | null + ping_latency_ms: number | null + message: string + checked_at: string +} + +export interface HistoryParams { + model?: string + limit?: number +} + +export interface HistoryResponse { + items: HistoryItem[] +} + +/** + * List channel monitors with pagination and filters + */ +export async function list( + params: ListParams = {}, + options?: { signal?: AbortSignal } +): Promise { + const { data } = await apiClient.get('/admin/channel-monitors', { + params, + signal: options?.signal, + }) + return data +} + +/** + * Get a channel monitor by ID + */ +export async function get(id: number): Promise { + const { data } = await apiClient.get(`/admin/channel-monitors/${id}`) + return data +} + +/** + * Create a new channel monitor + */ +export async function create(params: CreateParams): Promise { + const { data } = await apiClient.post('/admin/channel-monitors', params) + return data +} + +/** + * Update an existing channel monitor. + * api_key field: empty string means "do not modify". + */ +export async function update(id: number, params: UpdateParams): Promise { + const { data } = await apiClient.put(`/admin/channel-monitors/${id}`, params) + return data +} + +/** + * Delete a channel monitor + */ +export async function del(id: number): Promise { + await apiClient.delete(`/admin/channel-monitors/${id}`) +} + +/** + * Trigger an immediate manual check for a channel monitor. + * Returns the latest check results for primary + extra models. + */ +export async function runNow(id: number): Promise { + const { data } = await apiClient.post(`/admin/channel-monitors/${id}/run`) + return data +} + +/** + * List historical check results for a monitor. + */ +export async function listHistory( + id: number, + params: HistoryParams = {} +): Promise { + const { data } = await apiClient.get( + `/admin/channel-monitors/${id}/history`, + { params } + ) + return data +} + +export const channelMonitorAPI = { + list, + get, + create, + update, + del, + runNow, + listHistory, +} + +export default channelMonitorAPI diff --git a/frontend/src/api/admin/channelMonitorTemplate.ts b/frontend/src/api/admin/channelMonitorTemplate.ts new file mode 100644 index 00000000..01b3c2d0 --- /dev/null +++ b/frontend/src/api/admin/channelMonitorTemplate.ts @@ -0,0 +1,132 @@ +/** + * Admin Channel Monitor Request Template API. + * + * 模板 = 一组可复用的 headers + 可选 body 覆盖配置。 + * 应用到监控 = 拷贝快照;模板后续变动不自动同步,需手动点「应用到关联监控」刷新。 + */ + +import { apiClient } from '../client' +import type { BodyOverrideMode, Provider } from './channelMonitor' + +export interface ChannelMonitorTemplate { + id: number + name: string + provider: Provider + description: string + extra_headers: Record + body_override_mode: BodyOverrideMode + body_override: Record | null + created_at: string + updated_at: string + /** 关联的监控数量(快照来自此模板,仅 template_id 匹配即可) */ + associated_monitors: number +} + +export interface ListParams { + provider?: Provider +} + +export interface ListResponse { + items: ChannelMonitorTemplate[] +} + +export interface CreateParams { + name: string + provider: Provider + description?: string + extra_headers?: Record + body_override_mode?: BodyOverrideMode + body_override?: Record | null +} + +export interface UpdateParams { + name?: string + description?: string + extra_headers?: Record + body_override_mode?: BodyOverrideMode + body_override?: Record | null +} + +export interface ApplyResponse { + affected: number +} + +export interface AssociatedMonitorBrief { + id: number + name: string + provider: Provider + enabled: boolean +} + +export interface AssociatedMonitorsResponse { + items: AssociatedMonitorBrief[] +} + +export async function list(params: ListParams = {}): Promise { + const { data } = await apiClient.get('/admin/channel-monitor-templates', { + params, + }) + return data +} + +export async function get(id: number): Promise { + const { data } = await apiClient.get( + `/admin/channel-monitor-templates/${id}`, + ) + return data +} + +export async function create(params: CreateParams): Promise { + const { data } = await apiClient.post( + '/admin/channel-monitor-templates', + params, + ) + return data +} + +export async function update(id: number, params: UpdateParams): Promise { + const { data } = await apiClient.put( + `/admin/channel-monitor-templates/${id}`, + params, + ) + return data +} + +export async function del(id: number): Promise { + await apiClient.delete(`/admin/channel-monitor-templates/${id}`) +} + +/** + * Apply the template to the specified associated monitors (overwrite snapshot fields). + * monitorIds must be a non-empty subset of the template's associated monitors. + * Returns count of actually affected monitors. + */ +export async function apply(id: number, monitorIds: number[]): Promise { + const { data } = await apiClient.post( + `/admin/channel-monitor-templates/${id}/apply`, + { monitor_ids: monitorIds }, + ) + return data +} + +/** + * List monitors currently associated to this template (used by apply picker). + */ +export async function listAssociatedMonitors(id: number): Promise { + const { data } = await apiClient.get( + `/admin/channel-monitor-templates/${id}/monitors`, + ) + return data +} + +export const channelMonitorTemplateAPI = { + list, + get, + create, + update, + del, + apply, + listAssociatedMonitors, +} + +export default channelMonitorTemplateAPI diff --git a/frontend/src/api/admin/channels.ts b/frontend/src/api/admin/channels.ts index f129ceaa..9d430134 100644 --- a/frontend/src/api/admin/channels.ts +++ b/frontend/src/api/admin/channels.ts @@ -4,8 +4,9 @@ */ import { apiClient } from '../client' +import type { BillingMode, ChannelStatus, BillingModelSource } from '@/constants/channel' -export type BillingMode = 'token' | 'per_request' | 'image' +export type { BillingMode } from '@/constants/channel' export interface PricingInterval { id?: number @@ -46,8 +47,8 @@ export interface Channel { id: number name: string description: string - status: string - billing_model_source: string // "requested" | "upstream" + status: ChannelStatus + billing_model_source: BillingModelSource restrict_models: boolean features_config?: Record group_ids: number[] diff --git a/frontend/src/api/admin/index.ts b/frontend/src/api/admin/index.ts index 72597365..9cda5814 100644 --- a/frontend/src/api/admin/index.ts +++ b/frontend/src/api/admin/index.ts @@ -26,6 +26,8 @@ import scheduledTestsAPI from './scheduledTests' import backupAPI from './backup' import tlsFingerprintProfileAPI from './tlsFingerprintProfile' import channelsAPI from './channels' +import channelMonitorAPI from './channelMonitor' +import channelMonitorTemplateAPI from './channelMonitorTemplate' import adminPaymentAPI from './payment' /** @@ -55,6 +57,8 @@ export const adminAPI = { backup: backupAPI, tlsFingerprintProfiles: tlsFingerprintProfileAPI, channels: channelsAPI, + channelMonitor: channelMonitorAPI, + channelMonitorTemplate: channelMonitorTemplateAPI, payment: adminPaymentAPI } @@ -82,6 +86,8 @@ export { backupAPI, tlsFingerprintProfileAPI, channelsAPI, + channelMonitorAPI, + channelMonitorTemplateAPI, adminPaymentAPI } diff --git a/frontend/src/api/admin/settings.ts b/frontend/src/api/admin/settings.ts index c7b9031e..b9f24663 100644 --- a/frontend/src/api/admin/settings.ts +++ b/frontend/src/api/admin/settings.ts @@ -470,6 +470,13 @@ export interface SystemSettings { balance_low_notify_recharge_url: string; account_quota_notify_enabled: boolean; account_quota_notify_emails: NotifyEmailEntry[]; + + // Channel Monitor feature switch + channel_monitor_enabled: boolean; + channel_monitor_default_interval_seconds: number; + + // Available Channels feature switch + available_channels_enabled: boolean; } export interface UpdateSettingsRequest { @@ -620,6 +627,13 @@ export interface UpdateSettingsRequest { balance_low_notify_recharge_url?: string; account_quota_notify_enabled?: boolean; account_quota_notify_emails?: NotifyEmailEntry[]; + + // Channel Monitor feature switch + channel_monitor_enabled?: boolean; + channel_monitor_default_interval_seconds?: number; + + // Available Channels feature switch + available_channels_enabled?: boolean; } /** diff --git a/frontend/src/api/channelMonitor.ts b/frontend/src/api/channelMonitor.ts new file mode 100644 index 00000000..38dd0c99 --- /dev/null +++ b/frontend/src/api/channelMonitor.ts @@ -0,0 +1,83 @@ +/** + * User-facing Channel Monitor API endpoints + * Read-only views for end users to inspect channel availability/status. + */ + +import { apiClient } from './client' +import type { Provider, MonitorStatus } from './admin/channelMonitor' + +export type { Provider, MonitorStatus } from './admin/channelMonitor' + +export interface UserMonitorExtraModel { + model: string + status: MonitorStatus + latency_ms: number | null +} + +export interface MonitorTimelinePoint { + status: MonitorStatus + latency_ms: number | null + ping_latency_ms: number | null + checked_at: string +} + +export interface UserMonitorView { + id: number + name: string + provider: Provider + group_name: string + primary_model: string + primary_status: MonitorStatus + primary_latency_ms: number | null + primary_ping_latency_ms: number | null + availability_7d: number + extra_models: UserMonitorExtraModel[] + timeline: MonitorTimelinePoint[] +} + +export interface UserMonitorListResponse { + items: UserMonitorView[] +} + +export interface UserMonitorModelDetail { + model: string + latest_status: MonitorStatus + latest_latency_ms: number | null + availability_7d: number + availability_15d: number + availability_30d: number + avg_latency_7d_ms: number | null +} + +export interface UserMonitorDetail { + id: number + name: string + provider: Provider + group_name: string + models: UserMonitorModelDetail[] +} + +/** + * List all monitor views available to the current user. + */ +export async function list(options?: { signal?: AbortSignal }): Promise { + const { data } = await apiClient.get('/channel-monitors', { + signal: options?.signal, + }) + return data +} + +/** + * Get detailed status (multi-window availability + latency) for a single monitor. + */ +export async function status(id: number): Promise { + const { data } = await apiClient.get(`/channel-monitors/${id}/status`) + return data +} + +export const channelMonitorUserAPI = { + list, + status, +} + +export default channelMonitorUserAPI diff --git a/frontend/src/api/channels.ts b/frontend/src/api/channels.ts new file mode 100644 index 00000000..8962af2c --- /dev/null +++ b/frontend/src/api/channels.ts @@ -0,0 +1,76 @@ +/** + * User Channels API endpoints (non-admin) + * 用户侧「可用渠道」聚合查询:渠道 + 用户可访问的分组 + 支持模型(含定价)。 + */ + +import { apiClient } from './client' +import type { BillingMode } from '@/constants/channel' + +export interface UserAvailableGroup { + id: number + name: string + platform: string + /** 'standard' | 'subscription' — 订阅分组视觉加深,和 API 密钥页保持一致。 */ + subscription_type: string + /** 分组默认倍率。用户专属倍率(若有)通过 /groups/rates 获取后在前端 join。 */ + rate_multiplier: number + /** true = 专属分组(小范围授权);false = 公开分组。 */ + is_exclusive: boolean +} + +export interface UserPricingInterval { + min_tokens: number + max_tokens: number | null + tier_label?: string + input_price: number | null + output_price: number | null + cache_write_price: number | null + cache_read_price: number | null + per_request_price: number | null +} + +export interface UserSupportedModelPricing { + billing_mode: BillingMode + input_price: number | null + output_price: number | null + cache_write_price: number | null + cache_read_price: number | null + image_output_price: number | null + per_request_price: number | null + intervals: UserPricingInterval[] +} + +export interface UserSupportedModel { + name: string + platform: string + pricing: UserSupportedModelPricing | null +} + +/** + * 渠道下单个平台的子视图:用户可访问的分组 + 该平台支持的模型。 + * 后端把一个渠道按平台聚合成 sections,前端可以把渠道名作为 row-group + * 一次渲染,后面按 sections 顺序用 rowspan 铺开。 + */ +export interface UserChannelPlatformSection { + platform: string + groups: UserAvailableGroup[] + supported_models: UserSupportedModel[] +} + +export interface UserAvailableChannel { + name: string + description: string + platforms: UserChannelPlatformSection[] +} + +/** 列出当前用户可见的「可用渠道」(与 /groups/available 保持一致,返回平数组)。 */ +export async function getAvailable(options?: { signal?: AbortSignal }): Promise { + const { data } = await apiClient.get('/channels/available', { + signal: options?.signal + }) + return data +} + +export const userChannelsAPI = { getAvailable } + +export default userChannelsAPI diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts index 6b3ef174..6702468d 100644 --- a/frontend/src/api/index.ts +++ b/frontend/src/api/index.ts @@ -16,8 +16,10 @@ export { userAPI } from './user' export { redeemAPI, type RedeemHistoryItem } from './redeem' export { paymentAPI } from './payment' export { userGroupsAPI } from './groups' +export { userChannelsAPI } from './channels' export { totpAPI } from './totp' export { default as announcementsAPI } from './announcements' +export { channelMonitorUserAPI } from './channelMonitor' // Admin APIs export { adminAPI } from './admin' diff --git a/frontend/src/components/admin/channel/ModelTagInput.vue b/frontend/src/components/admin/channel/ModelTagInput.vue index a1ce4022..b91aa119 100644 --- a/frontend/src/components/admin/channel/ModelTagInput.vue +++ b/frontend/src/components/admin/channel/ModelTagInput.vue @@ -27,6 +27,7 @@ @keydown.tab.prevent="addModel" @keydown.delete="handleBackspace" @paste="handlePaste" + @blur="addModel" />

diff --git a/frontend/src/components/admin/channel/types.ts b/frontend/src/components/admin/channel/types.ts index b3966289..955b6487 100644 --- a/frontend/src/components/admin/channel/types.ts +++ b/frontend/src/components/admin/channel/types.ts @@ -187,3 +187,14 @@ export function getPlatformTagClass(platform: string): string { default: return 'bg-gray-100 text-gray-700 dark:bg-gray-900/30 dark:text-gray-400' } } + +/** 平台对应的模型文字色(仅 text-*,用于 input/text 场景)— 与 getPlatformTagClass 同色系 */ +export function getPlatformTextClass(platform: string): string { + switch (platform) { + case 'anthropic': return 'text-orange-700 dark:text-orange-400' + case 'openai': return 'text-emerald-700 dark:text-emerald-400' + case 'gemini': return 'text-blue-700 dark:text-blue-400' + case 'antigravity': return 'text-purple-700 dark:text-purple-400' + default: return '' + } +} diff --git a/frontend/src/components/admin/monitor/MonitorActionsCell.vue b/frontend/src/components/admin/monitor/MonitorActionsCell.vue new file mode 100644 index 00000000..74aa4017 --- /dev/null +++ b/frontend/src/components/admin/monitor/MonitorActionsCell.vue @@ -0,0 +1,45 @@ + + + diff --git a/frontend/src/components/admin/monitor/MonitorAdvancedRequestConfig.vue b/frontend/src/components/admin/monitor/MonitorAdvancedRequestConfig.vue new file mode 100644 index 00000000..0d6b4ace --- /dev/null +++ b/frontend/src/components/admin/monitor/MonitorAdvancedRequestConfig.vue @@ -0,0 +1,301 @@ +