Merge pull request #1850 from touwaeriol/feat/channel-insights
feat(monitor): channel monitor with available channels & feature flags
This commit is contained in:
commit
ac11473833
@ -97,6 +97,7 @@ func provideCleanup(
|
|||||||
scheduledTestRunner *service.ScheduledTestRunnerService,
|
scheduledTestRunner *service.ScheduledTestRunnerService,
|
||||||
backupSvc *service.BackupService,
|
backupSvc *service.BackupService,
|
||||||
paymentOrderExpiry *service.PaymentOrderExpiryService,
|
paymentOrderExpiry *service.PaymentOrderExpiryService,
|
||||||
|
channelMonitorRunner *service.ChannelMonitorRunner,
|
||||||
) func() {
|
) func() {
|
||||||
return func() {
|
return func() {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
@ -239,6 +240,12 @@ func provideCleanup(
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}},
|
}},
|
||||||
|
{"ChannelMonitorRunner", func() error {
|
||||||
|
if channelMonitorRunner != nil {
|
||||||
|
channelMonitorRunner.Stop()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}},
|
||||||
}
|
}
|
||||||
|
|
||||||
infraSteps := []cleanupStep{
|
infraSteps := []cleanupStep{
|
||||||
|
|||||||
@ -176,7 +176,7 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
|
|||||||
claudeTokenProvider := service.ProvideClaudeTokenProvider(accountRepository, geminiTokenCache, oAuthService, oAuthRefreshAPI)
|
claudeTokenProvider := service.ProvideClaudeTokenProvider(accountRepository, geminiTokenCache, oAuthService, oAuthRefreshAPI)
|
||||||
digestSessionStore := service.NewDigestSessionStore()
|
digestSessionStore := service.NewDigestSessionStore()
|
||||||
channelRepository := repository.NewChannelRepository(db)
|
channelRepository := repository.NewChannelRepository(db)
|
||||||
channelService := service.NewChannelService(channelRepository, apiKeyAuthCacheInvalidator)
|
channelService := service.NewChannelService(channelRepository, groupRepository, apiKeyAuthCacheInvalidator, pricingService)
|
||||||
modelPricingResolver := service.NewModelPricingResolver(channelService, billingService)
|
modelPricingResolver := service.NewModelPricingResolver(channelService, billingService)
|
||||||
balanceNotifyService := service.ProvideBalanceNotifyService(emailService, settingRepository, accountRepository)
|
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)
|
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)
|
scheduledTestService := service.ProvideScheduledTestService(scheduledTestPlanRepository, scheduledTestResultRepository)
|
||||||
scheduledTestHandler := admin.NewScheduledTestHandler(scheduledTestService)
|
scheduledTestHandler := admin.NewScheduledTestHandler(scheduledTestService)
|
||||||
channelHandler := admin.NewChannelHandler(channelService, billingService)
|
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)
|
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)
|
usageRecordWorkerPool := service.NewUsageRecordWorkerPool(configConfig)
|
||||||
userMsgQueueCache := repository.NewUserMsgQueueCache(redisClient)
|
userMsgQueueCache := repository.NewUserMsgQueueCache(redisClient)
|
||||||
userMessageQueueService := service.ProvideUserMessageQueueService(userMsgQueueCache, rpmCache, configConfig)
|
userMessageQueueService := service.ProvideUserMessageQueueService(userMsgQueueCache, rpmCache, configConfig)
|
||||||
@ -234,7 +247,7 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
|
|||||||
paymentWebhookHandler := handler.NewPaymentWebhookHandler(paymentService, registry)
|
paymentWebhookHandler := handler.NewPaymentWebhookHandler(paymentService, registry)
|
||||||
idempotencyCoordinator := service.ProvideIdempotencyCoordinator(idempotencyRepository, configConfig)
|
idempotencyCoordinator := service.ProvideIdempotencyCoordinator(idempotencyRepository, configConfig)
|
||||||
idempotencyCleanupService := service.ProvideIdempotencyCleanupService(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)
|
jwtAuthMiddleware := middleware.NewJWTAuthMiddleware(authService, userService)
|
||||||
adminAuthMiddleware := middleware.NewAdminAuthMiddleware(authService, userService, settingService)
|
adminAuthMiddleware := middleware.NewAdminAuthMiddleware(authService, userService, settingService)
|
||||||
apiKeyAuthMiddleware := middleware.NewAPIKeyAuthMiddleware(apiKeyService, subscriptionService, configConfig)
|
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)
|
opsMetricsCollector := service.ProvideOpsMetricsCollector(opsRepository, settingRepository, accountRepository, concurrencyService, db, redisClient, configConfig)
|
||||||
opsAggregationService := service.ProvideOpsAggregationService(opsRepository, settingRepository, db, redisClient, configConfig)
|
opsAggregationService := service.ProvideOpsAggregationService(opsRepository, settingRepository, db, redisClient, configConfig)
|
||||||
opsAlertEvaluatorService := service.ProvideOpsAlertEvaluatorService(opsService, opsRepository, emailService, 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)
|
opsScheduledReportService := service.ProvideOpsScheduledReportService(opsService, userService, emailService, redisClient, configConfig)
|
||||||
tokenRefreshService := service.ProvideTokenRefreshService(accountRepository, oAuthService, openAIOAuthService, geminiOAuthService, antigravityOAuthService, compositeTokenCacheInvalidator, schedulerCache, configConfig, tempUnschedCache, privacyClientFactory, proxyRepository, oAuthRefreshAPI)
|
tokenRefreshService := service.ProvideTokenRefreshService(accountRepository, oAuthService, openAIOAuthService, geminiOAuthService, antigravityOAuthService, compositeTokenCacheInvalidator, schedulerCache, configConfig, tempUnschedCache, privacyClientFactory, proxyRepository, oAuthRefreshAPI)
|
||||||
accountExpiryService := service.ProvideAccountExpiryService(accountRepository)
|
accountExpiryService := service.ProvideAccountExpiryService(accountRepository)
|
||||||
subscriptionExpiryService := service.ProvideSubscriptionExpiryService(userSubscriptionRepository)
|
subscriptionExpiryService := service.ProvideSubscriptionExpiryService(userSubscriptionRepository)
|
||||||
scheduledTestRunnerService := service.ProvideScheduledTestRunnerService(scheduledTestPlanRepository, scheduledTestService, accountTestService, rateLimitService, configConfig)
|
scheduledTestRunnerService := service.ProvideScheduledTestRunnerService(scheduledTestPlanRepository, scheduledTestService, accountTestService, rateLimitService, configConfig)
|
||||||
paymentOrderExpiryService := service.ProvidePaymentOrderExpiryService(paymentService)
|
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{
|
application := &Application{
|
||||||
Server: httpServer,
|
Server: httpServer,
|
||||||
Cleanup: v,
|
Cleanup: v,
|
||||||
@ -304,6 +317,7 @@ func provideCleanup(
|
|||||||
scheduledTestRunner *service.ScheduledTestRunnerService,
|
scheduledTestRunner *service.ScheduledTestRunnerService,
|
||||||
backupSvc *service.BackupService,
|
backupSvc *service.BackupService,
|
||||||
paymentOrderExpiry *service.PaymentOrderExpiryService,
|
paymentOrderExpiry *service.PaymentOrderExpiryService,
|
||||||
|
channelMonitorRunner *service.ChannelMonitorRunner,
|
||||||
) func() {
|
) func() {
|
||||||
return func() {
|
return func() {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
@ -445,6 +459,12 @@ func provideCleanup(
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}},
|
}},
|
||||||
|
{"ChannelMonitorRunner", func() error {
|
||||||
|
if channelMonitorRunner != nil {
|
||||||
|
channelMonitorRunner.Stop()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}},
|
||||||
}
|
}
|
||||||
|
|
||||||
infraSteps := []cleanupStep{
|
infraSteps := []cleanupStep{
|
||||||
|
|||||||
@ -76,6 +76,7 @@ func TestProvideCleanup_WithMinimalDependencies_NoPanic(t *testing.T) {
|
|||||||
nil, // scheduledTestRunner
|
nil, // scheduledTestRunner
|
||||||
nil, // backupSvc
|
nil, // backupSvc
|
||||||
nil, // paymentOrderExpiry
|
nil, // paymentOrderExpiry
|
||||||
|
nil, // channelMonitorRunner
|
||||||
)
|
)
|
||||||
|
|
||||||
require.NotPanics(t, func() {
|
require.NotPanics(t, func() {
|
||||||
|
|||||||
359
backend/ent/channelmonitor.go
Normal file
359
backend/ent/channelmonitor.go
Normal file
@ -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=<sensitive>")
|
||||||
|
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
|
||||||
304
backend/ent/channelmonitor/channelmonitor.go
Normal file
304
backend/ent/channelmonitor/channelmonitor.go
Normal file
@ -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),
|
||||||
|
)
|
||||||
|
}
|
||||||
885
backend/ent/channelmonitor/where.go
Normal file
885
backend/ent/channelmonitor/where.go
Normal file
@ -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))
|
||||||
|
}
|
||||||
1610
backend/ent/channelmonitor_create.go
Normal file
1610
backend/ent/channelmonitor_create.go
Normal file
File diff suppressed because it is too large
Load Diff
88
backend/ent/channelmonitor_delete.go
Normal file
88
backend/ent/channelmonitor_delete.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
797
backend/ent/channelmonitor_query.go
Normal file
797
backend/ent/channelmonitor_query.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
1328
backend/ent/channelmonitor_update.go
Normal file
1328
backend/ent/channelmonitor_update.go
Normal file
File diff suppressed because it is too large
Load Diff
278
backend/ent/channelmonitordailyrollup.go
Normal file
278
backend/ent/channelmonitordailyrollup.go
Normal file
@ -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
|
||||||
@ -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),
|
||||||
|
)
|
||||||
|
}
|
||||||
729
backend/ent/channelmonitordailyrollup/where.go
Normal file
729
backend/ent/channelmonitordailyrollup/where.go
Normal file
@ -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))
|
||||||
|
}
|
||||||
1509
backend/ent/channelmonitordailyrollup_create.go
Normal file
1509
backend/ent/channelmonitordailyrollup_create.go
Normal file
File diff suppressed because it is too large
Load Diff
88
backend/ent/channelmonitordailyrollup_delete.go
Normal file
88
backend/ent/channelmonitordailyrollup_delete.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
643
backend/ent/channelmonitordailyrollup_query.go
Normal file
643
backend/ent/channelmonitordailyrollup_query.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
961
backend/ent/channelmonitordailyrollup_update.go
Normal file
961
backend/ent/channelmonitordailyrollup_update.go
Normal file
@ -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
|
||||||
|
}
|
||||||
207
backend/ent/channelmonitorhistory.go
Normal file
207
backend/ent/channelmonitorhistory.go
Normal file
@ -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
|
||||||
158
backend/ent/channelmonitorhistory/channelmonitorhistory.go
Normal file
158
backend/ent/channelmonitorhistory/channelmonitorhistory.go
Normal file
@ -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),
|
||||||
|
)
|
||||||
|
}
|
||||||
444
backend/ent/channelmonitorhistory/where.go
Normal file
444
backend/ent/channelmonitorhistory/where.go
Normal file
@ -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))
|
||||||
|
}
|
||||||
947
backend/ent/channelmonitorhistory_create.go
Normal file
947
backend/ent/channelmonitorhistory_create.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
88
backend/ent/channelmonitorhistory_delete.go
Normal file
88
backend/ent/channelmonitorhistory_delete.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
643
backend/ent/channelmonitorhistory_query.go
Normal file
643
backend/ent/channelmonitorhistory_query.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
635
backend/ent/channelmonitorhistory_update.go
Normal file
635
backend/ent/channelmonitorhistory_update.go
Normal file
@ -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
|
||||||
|
}
|
||||||
216
backend/ent/channelmonitorrequesttemplate.go
Normal file
216
backend/ent/channelmonitorrequesttemplate.go
Normal file
@ -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
|
||||||
@ -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),
|
||||||
|
)
|
||||||
|
}
|
||||||
434
backend/ent/channelmonitorrequesttemplate/where.go
Normal file
434
backend/ent/channelmonitorrequesttemplate/where.go
Normal file
@ -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))
|
||||||
|
}
|
||||||
942
backend/ent/channelmonitorrequesttemplate_create.go
Normal file
942
backend/ent/channelmonitorrequesttemplate_create.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
88
backend/ent/channelmonitorrequesttemplate_delete.go
Normal file
88
backend/ent/channelmonitorrequesttemplate_delete.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
648
backend/ent/channelmonitorrequesttemplate_query.go
Normal file
648
backend/ent/channelmonitorrequesttemplate_query.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
639
backend/ent/channelmonitorrequesttemplate_update.go
Normal file
639
backend/ent/channelmonitorrequesttemplate_update.go
Normal file
@ -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
|
||||||
|
}
|
||||||
@ -22,6 +22,10 @@ import (
|
|||||||
"github.com/Wei-Shaw/sub2api/ent/apikey"
|
"github.com/Wei-Shaw/sub2api/ent/apikey"
|
||||||
"github.com/Wei-Shaw/sub2api/ent/authidentity"
|
"github.com/Wei-Shaw/sub2api/ent/authidentity"
|
||||||
"github.com/Wei-Shaw/sub2api/ent/authidentitychannel"
|
"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/errorpassthroughrule"
|
||||||
"github.com/Wei-Shaw/sub2api/ent/group"
|
"github.com/Wei-Shaw/sub2api/ent/group"
|
||||||
"github.com/Wei-Shaw/sub2api/ent/idempotencyrecord"
|
"github.com/Wei-Shaw/sub2api/ent/idempotencyrecord"
|
||||||
@ -68,6 +72,14 @@ type Client struct {
|
|||||||
AuthIdentity *AuthIdentityClient
|
AuthIdentity *AuthIdentityClient
|
||||||
// AuthIdentityChannel is the client for interacting with the AuthIdentityChannel builders.
|
// AuthIdentityChannel is the client for interacting with the AuthIdentityChannel builders.
|
||||||
AuthIdentityChannel *AuthIdentityChannelClient
|
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 is the client for interacting with the ErrorPassthroughRule builders.
|
||||||
ErrorPassthroughRule *ErrorPassthroughRuleClient
|
ErrorPassthroughRule *ErrorPassthroughRuleClient
|
||||||
// Group is the client for interacting with the Group builders.
|
// Group is the client for interacting with the Group builders.
|
||||||
@ -132,6 +144,10 @@ func (c *Client) init() {
|
|||||||
c.AnnouncementRead = NewAnnouncementReadClient(c.config)
|
c.AnnouncementRead = NewAnnouncementReadClient(c.config)
|
||||||
c.AuthIdentity = NewAuthIdentityClient(c.config)
|
c.AuthIdentity = NewAuthIdentityClient(c.config)
|
||||||
c.AuthIdentityChannel = NewAuthIdentityChannelClient(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.ErrorPassthroughRule = NewErrorPassthroughRuleClient(c.config)
|
||||||
c.Group = NewGroupClient(c.config)
|
c.Group = NewGroupClient(c.config)
|
||||||
c.IdempotencyRecord = NewIdempotencyRecordClient(c.config)
|
c.IdempotencyRecord = NewIdempotencyRecordClient(c.config)
|
||||||
@ -245,38 +261,42 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) {
|
|||||||
cfg := c.config
|
cfg := c.config
|
||||||
cfg.driver = tx
|
cfg.driver = tx
|
||||||
return &Tx{
|
return &Tx{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
config: cfg,
|
config: cfg,
|
||||||
APIKey: NewAPIKeyClient(cfg),
|
APIKey: NewAPIKeyClient(cfg),
|
||||||
Account: NewAccountClient(cfg),
|
Account: NewAccountClient(cfg),
|
||||||
AccountGroup: NewAccountGroupClient(cfg),
|
AccountGroup: NewAccountGroupClient(cfg),
|
||||||
Announcement: NewAnnouncementClient(cfg),
|
Announcement: NewAnnouncementClient(cfg),
|
||||||
AnnouncementRead: NewAnnouncementReadClient(cfg),
|
AnnouncementRead: NewAnnouncementReadClient(cfg),
|
||||||
AuthIdentity: NewAuthIdentityClient(cfg),
|
AuthIdentity: NewAuthIdentityClient(cfg),
|
||||||
AuthIdentityChannel: NewAuthIdentityChannelClient(cfg),
|
AuthIdentityChannel: NewAuthIdentityChannelClient(cfg),
|
||||||
ErrorPassthroughRule: NewErrorPassthroughRuleClient(cfg),
|
ChannelMonitor: NewChannelMonitorClient(cfg),
|
||||||
Group: NewGroupClient(cfg),
|
ChannelMonitorDailyRollup: NewChannelMonitorDailyRollupClient(cfg),
|
||||||
IdempotencyRecord: NewIdempotencyRecordClient(cfg),
|
ChannelMonitorHistory: NewChannelMonitorHistoryClient(cfg),
|
||||||
IdentityAdoptionDecision: NewIdentityAdoptionDecisionClient(cfg),
|
ChannelMonitorRequestTemplate: NewChannelMonitorRequestTemplateClient(cfg),
|
||||||
PaymentAuditLog: NewPaymentAuditLogClient(cfg),
|
ErrorPassthroughRule: NewErrorPassthroughRuleClient(cfg),
|
||||||
PaymentOrder: NewPaymentOrderClient(cfg),
|
Group: NewGroupClient(cfg),
|
||||||
PaymentProviderInstance: NewPaymentProviderInstanceClient(cfg),
|
IdempotencyRecord: NewIdempotencyRecordClient(cfg),
|
||||||
PendingAuthSession: NewPendingAuthSessionClient(cfg),
|
IdentityAdoptionDecision: NewIdentityAdoptionDecisionClient(cfg),
|
||||||
PromoCode: NewPromoCodeClient(cfg),
|
PaymentAuditLog: NewPaymentAuditLogClient(cfg),
|
||||||
PromoCodeUsage: NewPromoCodeUsageClient(cfg),
|
PaymentOrder: NewPaymentOrderClient(cfg),
|
||||||
Proxy: NewProxyClient(cfg),
|
PaymentProviderInstance: NewPaymentProviderInstanceClient(cfg),
|
||||||
RedeemCode: NewRedeemCodeClient(cfg),
|
PendingAuthSession: NewPendingAuthSessionClient(cfg),
|
||||||
SecuritySecret: NewSecuritySecretClient(cfg),
|
PromoCode: NewPromoCodeClient(cfg),
|
||||||
Setting: NewSettingClient(cfg),
|
PromoCodeUsage: NewPromoCodeUsageClient(cfg),
|
||||||
SubscriptionPlan: NewSubscriptionPlanClient(cfg),
|
Proxy: NewProxyClient(cfg),
|
||||||
TLSFingerprintProfile: NewTLSFingerprintProfileClient(cfg),
|
RedeemCode: NewRedeemCodeClient(cfg),
|
||||||
UsageCleanupTask: NewUsageCleanupTaskClient(cfg),
|
SecuritySecret: NewSecuritySecretClient(cfg),
|
||||||
UsageLog: NewUsageLogClient(cfg),
|
Setting: NewSettingClient(cfg),
|
||||||
User: NewUserClient(cfg),
|
SubscriptionPlan: NewSubscriptionPlanClient(cfg),
|
||||||
UserAllowedGroup: NewUserAllowedGroupClient(cfg),
|
TLSFingerprintProfile: NewTLSFingerprintProfileClient(cfg),
|
||||||
UserAttributeDefinition: NewUserAttributeDefinitionClient(cfg),
|
UsageCleanupTask: NewUsageCleanupTaskClient(cfg),
|
||||||
UserAttributeValue: NewUserAttributeValueClient(cfg),
|
UsageLog: NewUsageLogClient(cfg),
|
||||||
UserSubscription: NewUserSubscriptionClient(cfg),
|
User: NewUserClient(cfg),
|
||||||
|
UserAllowedGroup: NewUserAllowedGroupClient(cfg),
|
||||||
|
UserAttributeDefinition: NewUserAttributeDefinitionClient(cfg),
|
||||||
|
UserAttributeValue: NewUserAttributeValueClient(cfg),
|
||||||
|
UserSubscription: NewUserSubscriptionClient(cfg),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,38 +314,42 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error)
|
|||||||
cfg := c.config
|
cfg := c.config
|
||||||
cfg.driver = &txDriver{tx: tx, drv: c.driver}
|
cfg.driver = &txDriver{tx: tx, drv: c.driver}
|
||||||
return &Tx{
|
return &Tx{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
config: cfg,
|
config: cfg,
|
||||||
APIKey: NewAPIKeyClient(cfg),
|
APIKey: NewAPIKeyClient(cfg),
|
||||||
Account: NewAccountClient(cfg),
|
Account: NewAccountClient(cfg),
|
||||||
AccountGroup: NewAccountGroupClient(cfg),
|
AccountGroup: NewAccountGroupClient(cfg),
|
||||||
Announcement: NewAnnouncementClient(cfg),
|
Announcement: NewAnnouncementClient(cfg),
|
||||||
AnnouncementRead: NewAnnouncementReadClient(cfg),
|
AnnouncementRead: NewAnnouncementReadClient(cfg),
|
||||||
AuthIdentity: NewAuthIdentityClient(cfg),
|
AuthIdentity: NewAuthIdentityClient(cfg),
|
||||||
AuthIdentityChannel: NewAuthIdentityChannelClient(cfg),
|
AuthIdentityChannel: NewAuthIdentityChannelClient(cfg),
|
||||||
ErrorPassthroughRule: NewErrorPassthroughRuleClient(cfg),
|
ChannelMonitor: NewChannelMonitorClient(cfg),
|
||||||
Group: NewGroupClient(cfg),
|
ChannelMonitorDailyRollup: NewChannelMonitorDailyRollupClient(cfg),
|
||||||
IdempotencyRecord: NewIdempotencyRecordClient(cfg),
|
ChannelMonitorHistory: NewChannelMonitorHistoryClient(cfg),
|
||||||
IdentityAdoptionDecision: NewIdentityAdoptionDecisionClient(cfg),
|
ChannelMonitorRequestTemplate: NewChannelMonitorRequestTemplateClient(cfg),
|
||||||
PaymentAuditLog: NewPaymentAuditLogClient(cfg),
|
ErrorPassthroughRule: NewErrorPassthroughRuleClient(cfg),
|
||||||
PaymentOrder: NewPaymentOrderClient(cfg),
|
Group: NewGroupClient(cfg),
|
||||||
PaymentProviderInstance: NewPaymentProviderInstanceClient(cfg),
|
IdempotencyRecord: NewIdempotencyRecordClient(cfg),
|
||||||
PendingAuthSession: NewPendingAuthSessionClient(cfg),
|
IdentityAdoptionDecision: NewIdentityAdoptionDecisionClient(cfg),
|
||||||
PromoCode: NewPromoCodeClient(cfg),
|
PaymentAuditLog: NewPaymentAuditLogClient(cfg),
|
||||||
PromoCodeUsage: NewPromoCodeUsageClient(cfg),
|
PaymentOrder: NewPaymentOrderClient(cfg),
|
||||||
Proxy: NewProxyClient(cfg),
|
PaymentProviderInstance: NewPaymentProviderInstanceClient(cfg),
|
||||||
RedeemCode: NewRedeemCodeClient(cfg),
|
PendingAuthSession: NewPendingAuthSessionClient(cfg),
|
||||||
SecuritySecret: NewSecuritySecretClient(cfg),
|
PromoCode: NewPromoCodeClient(cfg),
|
||||||
Setting: NewSettingClient(cfg),
|
PromoCodeUsage: NewPromoCodeUsageClient(cfg),
|
||||||
SubscriptionPlan: NewSubscriptionPlanClient(cfg),
|
Proxy: NewProxyClient(cfg),
|
||||||
TLSFingerprintProfile: NewTLSFingerprintProfileClient(cfg),
|
RedeemCode: NewRedeemCodeClient(cfg),
|
||||||
UsageCleanupTask: NewUsageCleanupTaskClient(cfg),
|
SecuritySecret: NewSecuritySecretClient(cfg),
|
||||||
UsageLog: NewUsageLogClient(cfg),
|
Setting: NewSettingClient(cfg),
|
||||||
User: NewUserClient(cfg),
|
SubscriptionPlan: NewSubscriptionPlanClient(cfg),
|
||||||
UserAllowedGroup: NewUserAllowedGroupClient(cfg),
|
TLSFingerprintProfile: NewTLSFingerprintProfileClient(cfg),
|
||||||
UserAttributeDefinition: NewUserAttributeDefinitionClient(cfg),
|
UsageCleanupTask: NewUsageCleanupTaskClient(cfg),
|
||||||
UserAttributeValue: NewUserAttributeValueClient(cfg),
|
UsageLog: NewUsageLogClient(cfg),
|
||||||
UserSubscription: NewUserSubscriptionClient(cfg),
|
User: NewUserClient(cfg),
|
||||||
|
UserAllowedGroup: NewUserAllowedGroupClient(cfg),
|
||||||
|
UserAttributeDefinition: NewUserAttributeDefinitionClient(cfg),
|
||||||
|
UserAttributeValue: NewUserAttributeValueClient(cfg),
|
||||||
|
UserSubscription: NewUserSubscriptionClient(cfg),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,7 +380,9 @@ func (c *Client) Close() error {
|
|||||||
func (c *Client) Use(hooks ...Hook) {
|
func (c *Client) Use(hooks ...Hook) {
|
||||||
for _, n := range []interface{ Use(...Hook) }{
|
for _, n := range []interface{ Use(...Hook) }{
|
||||||
c.APIKey, c.Account, c.AccountGroup, c.Announcement, c.AnnouncementRead,
|
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.IdempotencyRecord, c.IdentityAdoptionDecision, c.PaymentAuditLog,
|
||||||
c.PaymentOrder, c.PaymentProviderInstance, c.PendingAuthSession, c.PromoCode,
|
c.PaymentOrder, c.PaymentProviderInstance, c.PendingAuthSession, c.PromoCode,
|
||||||
c.PromoCodeUsage, c.Proxy, c.RedeemCode, c.SecuritySecret, c.Setting,
|
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) {
|
func (c *Client) Intercept(interceptors ...Interceptor) {
|
||||||
for _, n := range []interface{ Intercept(...Interceptor) }{
|
for _, n := range []interface{ Intercept(...Interceptor) }{
|
||||||
c.APIKey, c.Account, c.AccountGroup, c.Announcement, c.AnnouncementRead,
|
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.IdempotencyRecord, c.IdentityAdoptionDecision, c.PaymentAuditLog,
|
||||||
c.PaymentOrder, c.PaymentProviderInstance, c.PendingAuthSession, c.PromoCode,
|
c.PaymentOrder, c.PaymentProviderInstance, c.PendingAuthSession, c.PromoCode,
|
||||||
c.PromoCodeUsage, c.Proxy, c.RedeemCode, c.SecuritySecret, c.Setting,
|
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)
|
return c.AuthIdentity.mutate(ctx, m)
|
||||||
case *AuthIdentityChannelMutation:
|
case *AuthIdentityChannelMutation:
|
||||||
return c.AuthIdentityChannel.mutate(ctx, m)
|
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:
|
case *ErrorPassthroughRuleMutation:
|
||||||
return c.ErrorPassthroughRule.mutate(ctx, m)
|
return c.ErrorPassthroughRule.mutate(ctx, m)
|
||||||
case *GroupMutation:
|
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.
|
// ErrorPassthroughRuleClient is a client for the ErrorPassthroughRule schema.
|
||||||
type ErrorPassthroughRuleClient struct {
|
type ErrorPassthroughRuleClient struct {
|
||||||
config
|
config
|
||||||
@ -5355,21 +6019,23 @@ func (c *UserSubscriptionClient) mutate(ctx context.Context, m *UserSubscription
|
|||||||
type (
|
type (
|
||||||
hooks struct {
|
hooks struct {
|
||||||
APIKey, Account, AccountGroup, Announcement, AnnouncementRead, AuthIdentity,
|
APIKey, Account, AccountGroup, Announcement, AnnouncementRead, AuthIdentity,
|
||||||
AuthIdentityChannel, ErrorPassthroughRule, Group, IdempotencyRecord,
|
AuthIdentityChannel, ChannelMonitor, ChannelMonitorDailyRollup,
|
||||||
IdentityAdoptionDecision, PaymentAuditLog, PaymentOrder,
|
ChannelMonitorHistory, ChannelMonitorRequestTemplate, ErrorPassthroughRule,
|
||||||
PaymentProviderInstance, PendingAuthSession, PromoCode, PromoCodeUsage, Proxy,
|
Group, IdempotencyRecord, IdentityAdoptionDecision, PaymentAuditLog,
|
||||||
RedeemCode, SecuritySecret, Setting, SubscriptionPlan, TLSFingerprintProfile,
|
PaymentOrder, PaymentProviderInstance, PendingAuthSession, PromoCode,
|
||||||
UsageCleanupTask, UsageLog, User, UserAllowedGroup, UserAttributeDefinition,
|
PromoCodeUsage, Proxy, RedeemCode, SecuritySecret, Setting, SubscriptionPlan,
|
||||||
UserAttributeValue, UserSubscription []ent.Hook
|
TLSFingerprintProfile, UsageCleanupTask, UsageLog, User, UserAllowedGroup,
|
||||||
|
UserAttributeDefinition, UserAttributeValue, UserSubscription []ent.Hook
|
||||||
}
|
}
|
||||||
inters struct {
|
inters struct {
|
||||||
APIKey, Account, AccountGroup, Announcement, AnnouncementRead, AuthIdentity,
|
APIKey, Account, AccountGroup, Announcement, AnnouncementRead, AuthIdentity,
|
||||||
AuthIdentityChannel, ErrorPassthroughRule, Group, IdempotencyRecord,
|
AuthIdentityChannel, ChannelMonitor, ChannelMonitorDailyRollup,
|
||||||
IdentityAdoptionDecision, PaymentAuditLog, PaymentOrder,
|
ChannelMonitorHistory, ChannelMonitorRequestTemplate, ErrorPassthroughRule,
|
||||||
PaymentProviderInstance, PendingAuthSession, PromoCode, PromoCodeUsage, Proxy,
|
Group, IdempotencyRecord, IdentityAdoptionDecision, PaymentAuditLog,
|
||||||
RedeemCode, SecuritySecret, Setting, SubscriptionPlan, TLSFingerprintProfile,
|
PaymentOrder, PaymentProviderInstance, PendingAuthSession, PromoCode,
|
||||||
UsageCleanupTask, UsageLog, User, UserAllowedGroup, UserAttributeDefinition,
|
PromoCodeUsage, Proxy, RedeemCode, SecuritySecret, Setting, SubscriptionPlan,
|
||||||
UserAttributeValue, UserSubscription []ent.Interceptor
|
TLSFingerprintProfile, UsageCleanupTask, UsageLog, User, UserAllowedGroup,
|
||||||
|
UserAttributeDefinition, UserAttributeValue, UserSubscription []ent.Interceptor
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -19,6 +19,10 @@ import (
|
|||||||
"github.com/Wei-Shaw/sub2api/ent/apikey"
|
"github.com/Wei-Shaw/sub2api/ent/apikey"
|
||||||
"github.com/Wei-Shaw/sub2api/ent/authidentity"
|
"github.com/Wei-Shaw/sub2api/ent/authidentity"
|
||||||
"github.com/Wei-Shaw/sub2api/ent/authidentitychannel"
|
"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/errorpassthroughrule"
|
||||||
"github.com/Wei-Shaw/sub2api/ent/group"
|
"github.com/Wei-Shaw/sub2api/ent/group"
|
||||||
"github.com/Wei-Shaw/sub2api/ent/idempotencyrecord"
|
"github.com/Wei-Shaw/sub2api/ent/idempotencyrecord"
|
||||||
@ -102,36 +106,40 @@ var (
|
|||||||
func checkColumn(t, c string) error {
|
func checkColumn(t, c string) error {
|
||||||
initCheck.Do(func() {
|
initCheck.Do(func() {
|
||||||
columnCheck = sql.NewColumnCheck(map[string]func(string) bool{
|
columnCheck = sql.NewColumnCheck(map[string]func(string) bool{
|
||||||
apikey.Table: apikey.ValidColumn,
|
apikey.Table: apikey.ValidColumn,
|
||||||
account.Table: account.ValidColumn,
|
account.Table: account.ValidColumn,
|
||||||
accountgroup.Table: accountgroup.ValidColumn,
|
accountgroup.Table: accountgroup.ValidColumn,
|
||||||
announcement.Table: announcement.ValidColumn,
|
announcement.Table: announcement.ValidColumn,
|
||||||
announcementread.Table: announcementread.ValidColumn,
|
announcementread.Table: announcementread.ValidColumn,
|
||||||
authidentity.Table: authidentity.ValidColumn,
|
authidentity.Table: authidentity.ValidColumn,
|
||||||
authidentitychannel.Table: authidentitychannel.ValidColumn,
|
authidentitychannel.Table: authidentitychannel.ValidColumn,
|
||||||
errorpassthroughrule.Table: errorpassthroughrule.ValidColumn,
|
channelmonitor.Table: channelmonitor.ValidColumn,
|
||||||
group.Table: group.ValidColumn,
|
channelmonitordailyrollup.Table: channelmonitordailyrollup.ValidColumn,
|
||||||
idempotencyrecord.Table: idempotencyrecord.ValidColumn,
|
channelmonitorhistory.Table: channelmonitorhistory.ValidColumn,
|
||||||
identityadoptiondecision.Table: identityadoptiondecision.ValidColumn,
|
channelmonitorrequesttemplate.Table: channelmonitorrequesttemplate.ValidColumn,
|
||||||
paymentauditlog.Table: paymentauditlog.ValidColumn,
|
errorpassthroughrule.Table: errorpassthroughrule.ValidColumn,
|
||||||
paymentorder.Table: paymentorder.ValidColumn,
|
group.Table: group.ValidColumn,
|
||||||
paymentproviderinstance.Table: paymentproviderinstance.ValidColumn,
|
idempotencyrecord.Table: idempotencyrecord.ValidColumn,
|
||||||
pendingauthsession.Table: pendingauthsession.ValidColumn,
|
identityadoptiondecision.Table: identityadoptiondecision.ValidColumn,
|
||||||
promocode.Table: promocode.ValidColumn,
|
paymentauditlog.Table: paymentauditlog.ValidColumn,
|
||||||
promocodeusage.Table: promocodeusage.ValidColumn,
|
paymentorder.Table: paymentorder.ValidColumn,
|
||||||
proxy.Table: proxy.ValidColumn,
|
paymentproviderinstance.Table: paymentproviderinstance.ValidColumn,
|
||||||
redeemcode.Table: redeemcode.ValidColumn,
|
pendingauthsession.Table: pendingauthsession.ValidColumn,
|
||||||
securitysecret.Table: securitysecret.ValidColumn,
|
promocode.Table: promocode.ValidColumn,
|
||||||
setting.Table: setting.ValidColumn,
|
promocodeusage.Table: promocodeusage.ValidColumn,
|
||||||
subscriptionplan.Table: subscriptionplan.ValidColumn,
|
proxy.Table: proxy.ValidColumn,
|
||||||
tlsfingerprintprofile.Table: tlsfingerprintprofile.ValidColumn,
|
redeemcode.Table: redeemcode.ValidColumn,
|
||||||
usagecleanuptask.Table: usagecleanuptask.ValidColumn,
|
securitysecret.Table: securitysecret.ValidColumn,
|
||||||
usagelog.Table: usagelog.ValidColumn,
|
setting.Table: setting.ValidColumn,
|
||||||
user.Table: user.ValidColumn,
|
subscriptionplan.Table: subscriptionplan.ValidColumn,
|
||||||
userallowedgroup.Table: userallowedgroup.ValidColumn,
|
tlsfingerprintprofile.Table: tlsfingerprintprofile.ValidColumn,
|
||||||
userattributedefinition.Table: userattributedefinition.ValidColumn,
|
usagecleanuptask.Table: usagecleanuptask.ValidColumn,
|
||||||
userattributevalue.Table: userattributevalue.ValidColumn,
|
usagelog.Table: usagelog.ValidColumn,
|
||||||
usersubscription.Table: usersubscription.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)
|
return columnCheck(t, c)
|
||||||
|
|||||||
@ -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)
|
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
|
// The ErrorPassthroughRuleFunc type is an adapter to allow the use of ordinary
|
||||||
// function as ErrorPassthroughRule mutator.
|
// function as ErrorPassthroughRule mutator.
|
||||||
type ErrorPassthroughRuleFunc func(context.Context, *ent.ErrorPassthroughRuleMutation) (ent.Value, error)
|
type ErrorPassthroughRuleFunc func(context.Context, *ent.ErrorPassthroughRuleMutation) (ent.Value, error)
|
||||||
|
|||||||
@ -15,6 +15,10 @@ import (
|
|||||||
"github.com/Wei-Shaw/sub2api/ent/apikey"
|
"github.com/Wei-Shaw/sub2api/ent/apikey"
|
||||||
"github.com/Wei-Shaw/sub2api/ent/authidentity"
|
"github.com/Wei-Shaw/sub2api/ent/authidentity"
|
||||||
"github.com/Wei-Shaw/sub2api/ent/authidentitychannel"
|
"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/errorpassthroughrule"
|
||||||
"github.com/Wei-Shaw/sub2api/ent/group"
|
"github.com/Wei-Shaw/sub2api/ent/group"
|
||||||
"github.com/Wei-Shaw/sub2api/ent/idempotencyrecord"
|
"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)
|
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.
|
// 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)
|
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
|
return &query[*ent.AuthIdentityQuery, predicate.AuthIdentity, authidentity.OrderOption]{typ: ent.TypeAuthIdentity, tq: q}, nil
|
||||||
case *ent.AuthIdentityChannelQuery:
|
case *ent.AuthIdentityChannelQuery:
|
||||||
return &query[*ent.AuthIdentityChannelQuery, predicate.AuthIdentityChannel, authidentitychannel.OrderOption]{typ: ent.TypeAuthIdentityChannel, tq: q}, nil
|
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:
|
case *ent.ErrorPassthroughRuleQuery:
|
||||||
return &query[*ent.ErrorPassthroughRuleQuery, predicate.ErrorPassthroughRule, errorpassthroughrule.OrderOption]{typ: ent.TypeErrorPassthroughRule, tq: q}, nil
|
return &query[*ent.ErrorPassthroughRuleQuery, predicate.ErrorPassthroughRule, errorpassthroughrule.OrderOption]{typ: ent.TypeErrorPassthroughRule, tq: q}, nil
|
||||||
case *ent.GroupQuery:
|
case *ent.GroupQuery:
|
||||||
|
|||||||
@ -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 holds the columns for the "error_passthrough_rules" table.
|
||||||
ErrorPassthroughRulesColumns = []*schema.Column{
|
ErrorPassthroughRulesColumns = []*schema.Column{
|
||||||
{Name: "id", Type: field.TypeInt64, Increment: true},
|
{Name: "id", Type: field.TypeInt64, Increment: true},
|
||||||
@ -1522,6 +1685,10 @@ var (
|
|||||||
AnnouncementReadsTable,
|
AnnouncementReadsTable,
|
||||||
AuthIdentitiesTable,
|
AuthIdentitiesTable,
|
||||||
AuthIdentityChannelsTable,
|
AuthIdentityChannelsTable,
|
||||||
|
ChannelMonitorsTable,
|
||||||
|
ChannelMonitorDailyRollupsTable,
|
||||||
|
ChannelMonitorHistoriesTable,
|
||||||
|
ChannelMonitorRequestTemplatesTable,
|
||||||
ErrorPassthroughRulesTable,
|
ErrorPassthroughRulesTable,
|
||||||
GroupsTable,
|
GroupsTable,
|
||||||
IdempotencyRecordsTable,
|
IdempotencyRecordsTable,
|
||||||
@ -1579,6 +1746,21 @@ func init() {
|
|||||||
AuthIdentityChannelsTable.Annotation = &entsql.Annotation{
|
AuthIdentityChannelsTable.Annotation = &entsql.Annotation{
|
||||||
Table: "auth_identity_channels",
|
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{
|
ErrorPassthroughRulesTable.Annotation = &entsql.Annotation{
|
||||||
Table: "error_passthrough_rules",
|
Table: "error_passthrough_rules",
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -27,6 +27,18 @@ type AuthIdentity func(*sql.Selector)
|
|||||||
// AuthIdentityChannel is the predicate function for authidentitychannel builders.
|
// AuthIdentityChannel is the predicate function for authidentitychannel builders.
|
||||||
type AuthIdentityChannel func(*sql.Selector)
|
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.
|
// ErrorPassthroughRule is the predicate function for errorpassthroughrule builders.
|
||||||
type ErrorPassthroughRule func(*sql.Selector)
|
type ErrorPassthroughRule func(*sql.Selector)
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,10 @@ import (
|
|||||||
"github.com/Wei-Shaw/sub2api/ent/apikey"
|
"github.com/Wei-Shaw/sub2api/ent/apikey"
|
||||||
"github.com/Wei-Shaw/sub2api/ent/authidentity"
|
"github.com/Wei-Shaw/sub2api/ent/authidentity"
|
||||||
"github.com/Wei-Shaw/sub2api/ent/authidentitychannel"
|
"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/errorpassthroughrule"
|
||||||
"github.com/Wei-Shaw/sub2api/ent/group"
|
"github.com/Wei-Shaw/sub2api/ent/group"
|
||||||
"github.com/Wei-Shaw/sub2api/ent/idempotencyrecord"
|
"github.com/Wei-Shaw/sub2api/ent/idempotencyrecord"
|
||||||
@ -427,6 +431,252 @@ func init() {
|
|||||||
authidentitychannelDescMetadata := authidentitychannelFields[6].Descriptor()
|
authidentitychannelDescMetadata := authidentitychannelFields[6].Descriptor()
|
||||||
// authidentitychannel.DefaultMetadata holds the default value on creation for the metadata field.
|
// authidentitychannel.DefaultMetadata holds the default value on creation for the metadata field.
|
||||||
authidentitychannel.DefaultMetadata = authidentitychannelDescMetadata.Default.(func() map[string]interface{})
|
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()
|
errorpassthroughruleMixin := schema.ErrorPassthroughRule{}.Mixin()
|
||||||
errorpassthroughruleMixinFields0 := errorpassthroughruleMixin[0].Fields()
|
errorpassthroughruleMixinFields0 := errorpassthroughruleMixin[0].Fields()
|
||||||
_ = errorpassthroughruleMixinFields0
|
_ = errorpassthroughruleMixinFields0
|
||||||
|
|||||||
110
backend/ent/schema/channel_monitor.go
Normal file
110
backend/ent/schema/channel_monitor.go
Normal file
@ -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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
66
backend/ent/schema/channel_monitor_daily_rollup.go
Normal file
66
backend/ent/schema/channel_monitor_daily_rollup.go
Normal file
@ -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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
66
backend/ent/schema/channel_monitor_history.go
Normal file
66
backend/ent/schema/channel_monitor_history.go
Normal file
@ -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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
80
backend/ent/schema/channel_monitor_request_template.go
Normal file
80
backend/ent/schema/channel_monitor_request_template.go
Normal file
@ -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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -28,6 +28,14 @@ type Tx struct {
|
|||||||
AuthIdentity *AuthIdentityClient
|
AuthIdentity *AuthIdentityClient
|
||||||
// AuthIdentityChannel is the client for interacting with the AuthIdentityChannel builders.
|
// AuthIdentityChannel is the client for interacting with the AuthIdentityChannel builders.
|
||||||
AuthIdentityChannel *AuthIdentityChannelClient
|
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 is the client for interacting with the ErrorPassthroughRule builders.
|
||||||
ErrorPassthroughRule *ErrorPassthroughRuleClient
|
ErrorPassthroughRule *ErrorPassthroughRuleClient
|
||||||
// Group is the client for interacting with the Group builders.
|
// Group is the client for interacting with the Group builders.
|
||||||
@ -212,6 +220,10 @@ func (tx *Tx) init() {
|
|||||||
tx.AnnouncementRead = NewAnnouncementReadClient(tx.config)
|
tx.AnnouncementRead = NewAnnouncementReadClient(tx.config)
|
||||||
tx.AuthIdentity = NewAuthIdentityClient(tx.config)
|
tx.AuthIdentity = NewAuthIdentityClient(tx.config)
|
||||||
tx.AuthIdentityChannel = NewAuthIdentityChannelClient(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.ErrorPassthroughRule = NewErrorPassthroughRuleClient(tx.config)
|
||||||
tx.Group = NewGroupClient(tx.config)
|
tx.Group = NewGroupClient(tx.config)
|
||||||
tx.IdempotencyRecord = NewIdempotencyRecordClient(tx.config)
|
tx.IdempotencyRecord = NewIdempotencyRecordClient(tx.config)
|
||||||
|
|||||||
@ -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/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 h1:LMTUjNRUybUkTPn8oJDq8Kg3JRBOBTcnDhKu7mzupKI=
|
||||||
github.com/imroc/req/v3 v3.57.0/go.mod h1:JL62ey1nvSLq81HORNcosvlf7SxZStONNqOprg0Pz00=
|
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 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||||
|
|||||||
@ -158,9 +158,6 @@ func channelToResponse(ch *service.Channel) *channelResponse {
|
|||||||
UpdatedAt: ch.UpdatedAt.Format("2006-01-02T15:04:05Z"),
|
UpdatedAt: ch.UpdatedAt.Format("2006-01-02T15:04:05Z"),
|
||||||
}
|
}
|
||||||
resp.BillingModelSource = ch.BillingModelSource
|
resp.BillingModelSource = ch.BillingModelSource
|
||||||
if resp.BillingModelSource == "" {
|
|
||||||
resp.BillingModelSource = service.BillingModelSourceChannelMapped
|
|
||||||
}
|
|
||||||
if resp.GroupIDs == nil {
|
if resp.GroupIDs == nil {
|
||||||
resp.GroupIDs = []int64{}
|
resp.GroupIDs = []int64{}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -91,7 +91,7 @@ func TestChannelToResponse_EmptyDefaults(t *testing.T) {
|
|||||||
ch := &service.Channel{
|
ch := &service.Channel{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
Name: "ch",
|
Name: "ch",
|
||||||
BillingModelSource: "",
|
BillingModelSource: service.BillingModelSourceChannelMapped,
|
||||||
CreatedAt: now,
|
CreatedAt: now,
|
||||||
UpdatedAt: now,
|
UpdatedAt: now,
|
||||||
GroupIDs: nil,
|
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)
|
resp := channelToResponse(ch)
|
||||||
require.Equal(t, "channel_mapped", resp.BillingModelSource)
|
require.Equal(t, "channel_mapped", resp.BillingModelSource)
|
||||||
require.NotNil(t, resp.GroupIDs)
|
require.NotNil(t, resp.GroupIDs)
|
||||||
@ -117,6 +120,19 @@ func TestChannelToResponse_EmptyDefaults(t *testing.T) {
|
|||||||
require.Equal(t, "token", resp.ModelPricing[0].BillingMode)
|
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) {
|
func TestChannelToResponse_NilModels(t *testing.T) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
ch := &service.Channel{
|
ch := &service.Channel{
|
||||||
|
|||||||
427
backend/internal/handler/admin/channel_monitor_handler.go
Normal file
427
backend/internal/handler/admin/channel_monitor_handler.go
Normal file
@ -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
|
||||||
|
}
|
||||||
@ -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})
|
||||||
|
}
|
||||||
@ -236,6 +236,11 @@ func (h *SettingHandler) GetSettings(c *gin.Context) {
|
|||||||
PaymentCancelRateLimitWindow: paymentCfg.CancelRateLimitWindow,
|
PaymentCancelRateLimitWindow: paymentCfg.CancelRateLimitWindow,
|
||||||
PaymentCancelRateLimitUnit: paymentCfg.CancelRateLimitUnit,
|
PaymentCancelRateLimitUnit: paymentCfg.CancelRateLimitUnit,
|
||||||
PaymentCancelRateLimitMode: paymentCfg.CancelRateLimitMode,
|
PaymentCancelRateLimitMode: paymentCfg.CancelRateLimitMode,
|
||||||
|
|
||||||
|
ChannelMonitorEnabled: settings.ChannelMonitorEnabled,
|
||||||
|
ChannelMonitorDefaultIntervalSeconds: settings.ChannelMonitorDefaultIntervalSeconds,
|
||||||
|
|
||||||
|
AvailableChannelsEnabled: settings.AvailableChannelsEnabled,
|
||||||
}
|
}
|
||||||
response.Success(c, systemSettingsResponseData(payload, authSourceDefaults))
|
response.Success(c, systemSettingsResponseData(payload, authSourceDefaults))
|
||||||
}
|
}
|
||||||
@ -427,6 +432,13 @@ type UpdateSettingsRequest struct {
|
|||||||
PaymentCancelRateLimitWindow *int `json:"payment_cancel_rate_limit_window"`
|
PaymentCancelRateLimitWindow *int `json:"payment_cancel_rate_limit_window"`
|
||||||
PaymentCancelRateLimitUnit *string `json:"payment_cancel_rate_limit_unit"`
|
PaymentCancelRateLimitUnit *string `json:"payment_cancel_rate_limit_unit"`
|
||||||
PaymentCancelRateLimitMode *string `json:"payment_cancel_rate_limit_window_mode"`
|
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 更新系统设置
|
// UpdateSettings 更新系统设置
|
||||||
@ -1222,6 +1234,24 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
return previousSettings.AccountQuotaNotifyEmails
|
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{
|
authSourceDefaults := &service.AuthSourceDefaultSettings{
|
||||||
@ -1453,6 +1483,11 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
|
|||||||
PaymentCancelRateLimitWindow: updatedPaymentCfg.CancelRateLimitWindow,
|
PaymentCancelRateLimitWindow: updatedPaymentCfg.CancelRateLimitWindow,
|
||||||
PaymentCancelRateLimitUnit: updatedPaymentCfg.CancelRateLimitUnit,
|
PaymentCancelRateLimitUnit: updatedPaymentCfg.CancelRateLimitUnit,
|
||||||
PaymentCancelRateLimitMode: updatedPaymentCfg.CancelRateLimitMode,
|
PaymentCancelRateLimitMode: updatedPaymentCfg.CancelRateLimitMode,
|
||||||
|
|
||||||
|
ChannelMonitorEnabled: updatedSettings.ChannelMonitorEnabled,
|
||||||
|
ChannelMonitorDefaultIntervalSeconds: updatedSettings.ChannelMonitorDefaultIntervalSeconds,
|
||||||
|
|
||||||
|
AvailableChannelsEnabled: updatedSettings.AvailableChannelsEnabled,
|
||||||
}
|
}
|
||||||
response.Success(c, systemSettingsResponseData(payload, updatedAuthSourceDefaults))
|
response.Success(c, systemSettingsResponseData(payload, updatedAuthSourceDefaults))
|
||||||
}
|
}
|
||||||
@ -1809,6 +1844,15 @@ func diffSettings(before *service.SystemSettings, after *service.SystemSettings,
|
|||||||
if !equalNotifyEmailEntries(before.AccountQuotaNotifyEmails, after.AccountQuotaNotifyEmails) {
|
if !equalNotifyEmailEntries(before.AccountQuotaNotifyEmails, after.AccountQuotaNotifyEmails) {
|
||||||
changed = append(changed, "account_quota_notify_emails")
|
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)
|
changed = appendAuthSourceDefaultChanges(changed, beforeAuthSourceDefaults, afterAuthSourceDefaults)
|
||||||
return changed
|
return changed
|
||||||
}
|
}
|
||||||
|
|||||||
283
backend/internal/handler/available_channel_handler.go
Normal file
283
backend/internal/handler/available_channel_handler.go
Normal file
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
157
backend/internal/handler/available_channel_handler_test.go
Normal file
157
backend/internal/handler/available_channel_handler_test.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
176
backend/internal/handler/channel_monitor_user_handler.go
Normal file
176
backend/internal/handler/channel_monitor_user_handler.go
Normal file
@ -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))
|
||||||
|
}
|
||||||
10
backend/internal/handler/dto/channel_monitor.go
Normal file
10
backend/internal/handler/dto/channel_monitor.go
Normal file
@ -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"`
|
||||||
|
}
|
||||||
@ -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
|
||||||
|
}
|
||||||
@ -184,6 +184,13 @@ type SystemSettings struct {
|
|||||||
BalanceLowNotifyRechargeURL string `json:"balance_low_notify_recharge_url"`
|
BalanceLowNotifyRechargeURL string `json:"balance_low_notify_recharge_url"`
|
||||||
AccountQuotaNotifyEnabled bool `json:"account_quota_notify_enabled"`
|
AccountQuotaNotifyEnabled bool `json:"account_quota_notify_enabled"`
|
||||||
AccountQuotaNotifyEmails []NotifyEmailEntry `json:"account_quota_notify_emails"`
|
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 {
|
type DefaultSubscriptionSetting struct {
|
||||||
@ -231,6 +238,11 @@ type PublicSettings struct {
|
|||||||
AccountQuotaNotifyEnabled bool `json:"account_quota_notify_enabled"`
|
AccountQuotaNotifyEnabled bool `json:"account_quota_notify_enabled"`
|
||||||
BalanceLowNotifyThreshold float64 `json:"balance_low_notify_threshold"`
|
BalanceLowNotifyThreshold float64 `json:"balance_low_notify_threshold"`
|
||||||
BalanceLowNotifyRechargeURL string `json:"balance_low_notify_recharge_url"`
|
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
|
// OverloadCooldownSettings 529过载冷却配置 DTO
|
||||||
|
|||||||
@ -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 不使用会话限制
|
selection, err := h.gatewayService.SelectAccountWithLoadAwareness(c.Request.Context(), apiKey.GroupID, sessionKey, reqModel, fs.FailedAccountIDs, "", int64(0)) // Gemini 不使用会话限制
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if len(fs.FailedAccountIDs) == 0 {
|
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)
|
h.handleStreamingAwareError(c, http.StatusServiceUnavailable, "api_error", "No available accounts: "+err.Error(), streamStarted)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -347,6 +353,11 @@ func (h *GatewayHandler) Messages(c *gin.Context) {
|
|||||||
accountReleaseFunc := selection.ReleaseFunc
|
accountReleaseFunc := selection.ReleaseFunc
|
||||||
if !selection.Acquired {
|
if !selection.Acquired {
|
||||||
if selection.WaitPlan == nil {
|
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)
|
h.handleStreamingAwareError(c, http.StatusServiceUnavailable, "api_error", "No available accounts", streamStarted)
|
||||||
return
|
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)
|
selection, err := h.gatewayService.SelectAccountWithLoadAwareness(c.Request.Context(), currentAPIKey.GroupID, sessionKey, reqModel, fs.FailedAccountIDs, parsedReq.MetadataUserID, subject.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if len(fs.FailedAccountIDs) == 0 {
|
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)
|
h.handleStreamingAwareError(c, http.StatusServiceUnavailable, "api_error", "No available accounts: "+err.Error(), streamStarted)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -571,6 +589,11 @@ func (h *GatewayHandler) Messages(c *gin.Context) {
|
|||||||
accountReleaseFunc := selection.ReleaseFunc
|
accountReleaseFunc := selection.ReleaseFunc
|
||||||
if !selection.Acquired {
|
if !selection.Acquired {
|
||||||
if selection.WaitPlan == nil {
|
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)
|
h.handleStreamingAwareError(c, http.StatusServiceUnavailable, "api_error", "No available accounts", streamStarted)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,50 +6,54 @@ import (
|
|||||||
|
|
||||||
// AdminHandlers contains all admin-related HTTP handlers
|
// AdminHandlers contains all admin-related HTTP handlers
|
||||||
type AdminHandlers struct {
|
type AdminHandlers struct {
|
||||||
Dashboard *admin.DashboardHandler
|
Dashboard *admin.DashboardHandler
|
||||||
User *admin.UserHandler
|
User *admin.UserHandler
|
||||||
Group *admin.GroupHandler
|
Group *admin.GroupHandler
|
||||||
Account *admin.AccountHandler
|
Account *admin.AccountHandler
|
||||||
Announcement *admin.AnnouncementHandler
|
Announcement *admin.AnnouncementHandler
|
||||||
DataManagement *admin.DataManagementHandler
|
DataManagement *admin.DataManagementHandler
|
||||||
Backup *admin.BackupHandler
|
Backup *admin.BackupHandler
|
||||||
OAuth *admin.OAuthHandler
|
OAuth *admin.OAuthHandler
|
||||||
OpenAIOAuth *admin.OpenAIOAuthHandler
|
OpenAIOAuth *admin.OpenAIOAuthHandler
|
||||||
GeminiOAuth *admin.GeminiOAuthHandler
|
GeminiOAuth *admin.GeminiOAuthHandler
|
||||||
AntigravityOAuth *admin.AntigravityOAuthHandler
|
AntigravityOAuth *admin.AntigravityOAuthHandler
|
||||||
Proxy *admin.ProxyHandler
|
Proxy *admin.ProxyHandler
|
||||||
Redeem *admin.RedeemHandler
|
Redeem *admin.RedeemHandler
|
||||||
Promo *admin.PromoHandler
|
Promo *admin.PromoHandler
|
||||||
Setting *admin.SettingHandler
|
Setting *admin.SettingHandler
|
||||||
Ops *admin.OpsHandler
|
Ops *admin.OpsHandler
|
||||||
System *admin.SystemHandler
|
System *admin.SystemHandler
|
||||||
Subscription *admin.SubscriptionHandler
|
Subscription *admin.SubscriptionHandler
|
||||||
Usage *admin.UsageHandler
|
Usage *admin.UsageHandler
|
||||||
UserAttribute *admin.UserAttributeHandler
|
UserAttribute *admin.UserAttributeHandler
|
||||||
ErrorPassthrough *admin.ErrorPassthroughHandler
|
ErrorPassthrough *admin.ErrorPassthroughHandler
|
||||||
TLSFingerprintProfile *admin.TLSFingerprintProfileHandler
|
TLSFingerprintProfile *admin.TLSFingerprintProfileHandler
|
||||||
APIKey *admin.AdminAPIKeyHandler
|
APIKey *admin.AdminAPIKeyHandler
|
||||||
ScheduledTest *admin.ScheduledTestHandler
|
ScheduledTest *admin.ScheduledTestHandler
|
||||||
Channel *admin.ChannelHandler
|
Channel *admin.ChannelHandler
|
||||||
Payment *admin.PaymentHandler
|
ChannelMonitor *admin.ChannelMonitorHandler
|
||||||
|
ChannelMonitorTemplate *admin.ChannelMonitorRequestTemplateHandler
|
||||||
|
Payment *admin.PaymentHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handlers contains all HTTP handlers
|
// Handlers contains all HTTP handlers
|
||||||
type Handlers struct {
|
type Handlers struct {
|
||||||
Auth *AuthHandler
|
Auth *AuthHandler
|
||||||
User *UserHandler
|
User *UserHandler
|
||||||
APIKey *APIKeyHandler
|
APIKey *APIKeyHandler
|
||||||
Usage *UsageHandler
|
Usage *UsageHandler
|
||||||
Redeem *RedeemHandler
|
Redeem *RedeemHandler
|
||||||
Subscription *SubscriptionHandler
|
Subscription *SubscriptionHandler
|
||||||
Announcement *AnnouncementHandler
|
Announcement *AnnouncementHandler
|
||||||
Admin *AdminHandlers
|
ChannelMonitor *ChannelMonitorUserHandler
|
||||||
Gateway *GatewayHandler
|
Admin *AdminHandlers
|
||||||
OpenAIGateway *OpenAIGatewayHandler
|
Gateway *GatewayHandler
|
||||||
Setting *SettingHandler
|
OpenAIGateway *OpenAIGatewayHandler
|
||||||
Totp *TotpHandler
|
Setting *SettingHandler
|
||||||
Payment *PaymentHandler
|
Totp *TotpHandler
|
||||||
PaymentWebhook *PaymentWebhookHandler
|
Payment *PaymentHandler
|
||||||
|
PaymentWebhook *PaymentWebhookHandler
|
||||||
|
AvailableChannel *AvailableChannelHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildInfo contains build-time information
|
// BuildInfo contains build-time information
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package handler
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log/slog"
|
"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 {
|
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)
|
slog.Error("[Payment Webhook] handle notification failed", "provider", resolvedProviderKey, "error", err)
|
||||||
c.String(http.StatusInternalServerError, "handle failed")
|
c.String(http.StatusInternalServerError, "handle failed")
|
||||||
return
|
return
|
||||||
|
|||||||
@ -6,11 +6,13 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/Wei-Shaw/sub2api/internal/payment"
|
"github.com/Wei-Shaw/sub2api/internal/payment"
|
||||||
|
"github.com/Wei-Shaw/sub2api/internal/service"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"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) {
|
func TestWebhookConstants(t *testing.T) {
|
||||||
t.Run("maxWebhookBodySize is 1MB", func(t *testing.T) {
|
t.Run("maxWebhookBodySize is 1MB", func(t *testing.T) {
|
||||||
assert.Equal(t, int64(1<<20), int64(maxWebhookBodySize))
|
assert.Equal(t, int64(1<<20), int64(maxWebhookBodySize))
|
||||||
|
|||||||
@ -70,5 +70,10 @@ func (h *SettingHandler) GetPublicSettings(c *gin.Context) {
|
|||||||
AccountQuotaNotifyEnabled: settings.AccountQuotaNotifyEnabled,
|
AccountQuotaNotifyEnabled: settings.AccountQuotaNotifyEnabled,
|
||||||
BalanceLowNotifyThreshold: settings.BalanceLowNotifyThreshold,
|
BalanceLowNotifyThreshold: settings.BalanceLowNotifyThreshold,
|
||||||
BalanceLowNotifyRechargeURL: settings.BalanceLowNotifyRechargeURL,
|
BalanceLowNotifyRechargeURL: settings.BalanceLowNotifyRechargeURL,
|
||||||
|
|
||||||
|
ChannelMonitorEnabled: settings.ChannelMonitorEnabled,
|
||||||
|
ChannelMonitorDefaultIntervalSeconds: settings.ChannelMonitorDefaultIntervalSeconds,
|
||||||
|
|
||||||
|
AvailableChannelsEnabled: settings.AvailableChannelsEnabled,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,35 +34,39 @@ func ProvideAdminHandlers(
|
|||||||
apiKeyHandler *admin.AdminAPIKeyHandler,
|
apiKeyHandler *admin.AdminAPIKeyHandler,
|
||||||
scheduledTestHandler *admin.ScheduledTestHandler,
|
scheduledTestHandler *admin.ScheduledTestHandler,
|
||||||
channelHandler *admin.ChannelHandler,
|
channelHandler *admin.ChannelHandler,
|
||||||
|
channelMonitorHandler *admin.ChannelMonitorHandler,
|
||||||
|
channelMonitorTemplateHandler *admin.ChannelMonitorRequestTemplateHandler,
|
||||||
paymentHandler *admin.PaymentHandler,
|
paymentHandler *admin.PaymentHandler,
|
||||||
) *AdminHandlers {
|
) *AdminHandlers {
|
||||||
return &AdminHandlers{
|
return &AdminHandlers{
|
||||||
Dashboard: dashboardHandler,
|
Dashboard: dashboardHandler,
|
||||||
User: userHandler,
|
User: userHandler,
|
||||||
Group: groupHandler,
|
Group: groupHandler,
|
||||||
Account: accountHandler,
|
Account: accountHandler,
|
||||||
Announcement: announcementHandler,
|
Announcement: announcementHandler,
|
||||||
DataManagement: dataManagementHandler,
|
DataManagement: dataManagementHandler,
|
||||||
Backup: backupHandler,
|
Backup: backupHandler,
|
||||||
OAuth: oauthHandler,
|
OAuth: oauthHandler,
|
||||||
OpenAIOAuth: openaiOAuthHandler,
|
OpenAIOAuth: openaiOAuthHandler,
|
||||||
GeminiOAuth: geminiOAuthHandler,
|
GeminiOAuth: geminiOAuthHandler,
|
||||||
AntigravityOAuth: antigravityOAuthHandler,
|
AntigravityOAuth: antigravityOAuthHandler,
|
||||||
Proxy: proxyHandler,
|
Proxy: proxyHandler,
|
||||||
Redeem: redeemHandler,
|
Redeem: redeemHandler,
|
||||||
Promo: promoHandler,
|
Promo: promoHandler,
|
||||||
Setting: settingHandler,
|
Setting: settingHandler,
|
||||||
Ops: opsHandler,
|
Ops: opsHandler,
|
||||||
System: systemHandler,
|
System: systemHandler,
|
||||||
Subscription: subscriptionHandler,
|
Subscription: subscriptionHandler,
|
||||||
Usage: usageHandler,
|
Usage: usageHandler,
|
||||||
UserAttribute: userAttributeHandler,
|
UserAttribute: userAttributeHandler,
|
||||||
ErrorPassthrough: errorPassthroughHandler,
|
ErrorPassthrough: errorPassthroughHandler,
|
||||||
TLSFingerprintProfile: tlsFingerprintProfileHandler,
|
TLSFingerprintProfile: tlsFingerprintProfileHandler,
|
||||||
APIKey: apiKeyHandler,
|
APIKey: apiKeyHandler,
|
||||||
ScheduledTest: scheduledTestHandler,
|
ScheduledTest: scheduledTestHandler,
|
||||||
Channel: channelHandler,
|
Channel: channelHandler,
|
||||||
Payment: paymentHandler,
|
ChannelMonitor: channelMonitorHandler,
|
||||||
|
ChannelMonitorTemplate: channelMonitorTemplateHandler,
|
||||||
|
Payment: paymentHandler,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,6 +89,7 @@ func ProvideHandlers(
|
|||||||
redeemHandler *RedeemHandler,
|
redeemHandler *RedeemHandler,
|
||||||
subscriptionHandler *SubscriptionHandler,
|
subscriptionHandler *SubscriptionHandler,
|
||||||
announcementHandler *AnnouncementHandler,
|
announcementHandler *AnnouncementHandler,
|
||||||
|
channelMonitorUserHandler *ChannelMonitorUserHandler,
|
||||||
adminHandlers *AdminHandlers,
|
adminHandlers *AdminHandlers,
|
||||||
gatewayHandler *GatewayHandler,
|
gatewayHandler *GatewayHandler,
|
||||||
openaiGatewayHandler *OpenAIGatewayHandler,
|
openaiGatewayHandler *OpenAIGatewayHandler,
|
||||||
@ -92,24 +97,27 @@ func ProvideHandlers(
|
|||||||
totpHandler *TotpHandler,
|
totpHandler *TotpHandler,
|
||||||
paymentHandler *PaymentHandler,
|
paymentHandler *PaymentHandler,
|
||||||
paymentWebhookHandler *PaymentWebhookHandler,
|
paymentWebhookHandler *PaymentWebhookHandler,
|
||||||
|
availableChannelHandler *AvailableChannelHandler,
|
||||||
_ *service.IdempotencyCoordinator,
|
_ *service.IdempotencyCoordinator,
|
||||||
_ *service.IdempotencyCleanupService,
|
_ *service.IdempotencyCleanupService,
|
||||||
) *Handlers {
|
) *Handlers {
|
||||||
return &Handlers{
|
return &Handlers{
|
||||||
Auth: authHandler,
|
Auth: authHandler,
|
||||||
User: userHandler,
|
User: userHandler,
|
||||||
APIKey: apiKeyHandler,
|
APIKey: apiKeyHandler,
|
||||||
Usage: usageHandler,
|
Usage: usageHandler,
|
||||||
Redeem: redeemHandler,
|
Redeem: redeemHandler,
|
||||||
Subscription: subscriptionHandler,
|
Subscription: subscriptionHandler,
|
||||||
Announcement: announcementHandler,
|
Announcement: announcementHandler,
|
||||||
Admin: adminHandlers,
|
ChannelMonitor: channelMonitorUserHandler,
|
||||||
Gateway: gatewayHandler,
|
Admin: adminHandlers,
|
||||||
OpenAIGateway: openaiGatewayHandler,
|
Gateway: gatewayHandler,
|
||||||
Setting: settingHandler,
|
OpenAIGateway: openaiGatewayHandler,
|
||||||
Totp: totpHandler,
|
Setting: settingHandler,
|
||||||
Payment: paymentHandler,
|
Totp: totpHandler,
|
||||||
PaymentWebhook: paymentWebhookHandler,
|
Payment: paymentHandler,
|
||||||
|
PaymentWebhook: paymentWebhookHandler,
|
||||||
|
AvailableChannel: availableChannelHandler,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,12 +131,14 @@ var ProviderSet = wire.NewSet(
|
|||||||
NewRedeemHandler,
|
NewRedeemHandler,
|
||||||
NewSubscriptionHandler,
|
NewSubscriptionHandler,
|
||||||
NewAnnouncementHandler,
|
NewAnnouncementHandler,
|
||||||
|
NewChannelMonitorUserHandler,
|
||||||
NewGatewayHandler,
|
NewGatewayHandler,
|
||||||
NewOpenAIGatewayHandler,
|
NewOpenAIGatewayHandler,
|
||||||
NewTotpHandler,
|
NewTotpHandler,
|
||||||
ProvideSettingHandler,
|
ProvideSettingHandler,
|
||||||
NewPaymentHandler,
|
NewPaymentHandler,
|
||||||
NewPaymentWebhookHandler,
|
NewPaymentWebhookHandler,
|
||||||
|
NewAvailableChannelHandler,
|
||||||
|
|
||||||
// Admin handlers
|
// Admin handlers
|
||||||
admin.NewDashboardHandler,
|
admin.NewDashboardHandler,
|
||||||
@ -156,6 +166,8 @@ var ProviderSet = wire.NewSet(
|
|||||||
admin.NewAdminAPIKeyHandler,
|
admin.NewAdminAPIKeyHandler,
|
||||||
admin.NewScheduledTestHandler,
|
admin.NewScheduledTestHandler,
|
||||||
admin.NewChannelHandler,
|
admin.NewChannelHandler,
|
||||||
|
admin.NewChannelMonitorHandler,
|
||||||
|
admin.NewChannelMonitorRequestTemplateHandler,
|
||||||
admin.NewPaymentHandler,
|
admin.NewPaymentHandler,
|
||||||
|
|
||||||
// AdminHandlers and Handlers constructors
|
// AdminHandlers and Handlers constructors
|
||||||
|
|||||||
755
backend/internal/repository/channel_monitor_repo.go
Normal file
755
backend/internal/repository/channel_monitor_repo.go
Normal file
@ -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
|
||||||
|
}
|
||||||
195
backend/internal/repository/channel_monitor_template_repo.go
Normal file
195
backend/internal/repository/channel_monitor_template_repo.go
Normal file
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -89,6 +89,8 @@ var ProviderSet = wire.NewSet(
|
|||||||
NewErrorPassthroughRepository,
|
NewErrorPassthroughRepository,
|
||||||
NewTLSFingerprintProfileRepository,
|
NewTLSFingerprintProfileRepository,
|
||||||
NewChannelRepository,
|
NewChannelRepository,
|
||||||
|
NewChannelMonitorRepository,
|
||||||
|
NewChannelMonitorRequestTemplateRepository,
|
||||||
|
|
||||||
// Cache implementations
|
// Cache implementations
|
||||||
NewGatewayCache,
|
NewGatewayCache,
|
||||||
|
|||||||
@ -771,6 +771,9 @@ func TestAPIContracts(t *testing.T) {
|
|||||||
"balance_low_notify_threshold": 0,
|
"balance_low_notify_threshold": 0,
|
||||||
"balance_low_notify_recharge_url": "",
|
"balance_low_notify_recharge_url": "",
|
||||||
"account_quota_notify_emails": [],
|
"account_quota_notify_emails": [],
|
||||||
|
"channel_monitor_enabled": true,
|
||||||
|
"channel_monitor_default_interval_seconds": 60,
|
||||||
|
"available_channels_enabled": false,
|
||||||
"wechat_connect_enabled": false,
|
"wechat_connect_enabled": false,
|
||||||
"wechat_connect_app_id": "",
|
"wechat_connect_app_id": "",
|
||||||
"wechat_connect_app_secret_configured": false,
|
"wechat_connect_app_secret_configured": false,
|
||||||
@ -943,6 +946,9 @@ func TestAPIContracts(t *testing.T) {
|
|||||||
"balance_low_notify_threshold": 0,
|
"balance_low_notify_threshold": 0,
|
||||||
"balance_low_notify_recharge_url": "",
|
"balance_low_notify_recharge_url": "",
|
||||||
"account_quota_notify_emails": [],
|
"account_quota_notify_emails": [],
|
||||||
|
"channel_monitor_enabled": true,
|
||||||
|
"channel_monitor_default_interval_seconds": 60,
|
||||||
|
"available_channels_enabled": false,
|
||||||
"wechat_connect_enabled": true,
|
"wechat_connect_enabled": true,
|
||||||
"wechat_connect_app_id": "wx-open-config",
|
"wechat_connect_app_id": "wx-open-config",
|
||||||
"wechat_connect_app_secret_configured": true,
|
"wechat_connect_app_secret_configured": true,
|
||||||
|
|||||||
@ -88,6 +88,9 @@ func RegisterAdminRoutes(
|
|||||||
|
|
||||||
// 渠道管理
|
// 渠道管理
|
||||||
registerChannelRoutes(admin, h)
|
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)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -68,6 +68,12 @@ func RegisterUserRoutes(
|
|||||||
groups.GET("/rates", h.APIKey.GetUserGroupRates)
|
groups.GET("/rates", h.APIKey.GetUserGroupRates)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 用户可用渠道(非管理员接口)
|
||||||
|
channels := authenticated.Group("/channels")
|
||||||
|
{
|
||||||
|
channels.GET("/available", h.AvailableChannel.List)
|
||||||
|
}
|
||||||
|
|
||||||
// 使用记录
|
// 使用记录
|
||||||
usage := authenticated.Group("/usage")
|
usage := authenticated.Group("/usage")
|
||||||
{
|
{
|
||||||
@ -103,5 +109,12 @@ func RegisterUserRoutes(
|
|||||||
subscriptions.GET("/progress", h.Subscription.GetProgress)
|
subscriptions.GET("/progress", h.Subscription.GetProgress)
|
||||||
subscriptions.GET("/summary", h.Subscription.GetSummary)
|
subscriptions.GET("/summary", h.Subscription.GetSummary)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 渠道监控(用户只读)
|
||||||
|
monitors := authenticated.Group("/channel-monitors")
|
||||||
|
{
|
||||||
|
monitors.GET("", h.ChannelMonitor.List)
|
||||||
|
monitors.GET("/:id/status", h.ChannelMonitor.GetStatus)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -111,6 +111,18 @@ func (c *Channel) IsActive() bool {
|
|||||||
return c.Status == StatusActive
|
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。
|
// GetModelPricing 根据模型名查找渠道定价,未找到返回 nil。
|
||||||
// 精确匹配,大小写不敏感。返回值拷贝,不污染缓存。
|
// 精确匹配,大小写不敏感。返回值拷贝,不污染缓存。
|
||||||
func (c *Channel) GetModelPricing(model string) *ChannelModelPricing {
|
func (c *Channel) GetModelPricing(model string) *ChannelModelPricing {
|
||||||
@ -345,3 +357,209 @@ type ChannelUsageFields struct {
|
|||||||
BillingModelSource string // 计费模型来源:"requested" / "upstream" / "channel_mapped"
|
BillingModelSource string // 计费模型来源:"requested" / "upstream" / "channel_mapped"
|
||||||
ModelMappingChain string // 映射链描述,如 "a→b→c"
|
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
|
||||||
|
}
|
||||||
|
|||||||
149
backend/internal/service/channel_available.go
Normal file
149
backend/internal/service/channel_available.go
Normal file
@ -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
|
||||||
|
}
|
||||||
177
backend/internal/service/channel_available_test.go
Normal file
177
backend/internal/service/channel_available_test.go
Normal file
@ -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"])
|
||||||
|
}
|
||||||
292
backend/internal/service/channel_monitor_aggregator.go
Normal file
292
backend/internal/service/channel_monitor_aggregator.go
Normal file
@ -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
|
||||||
|
}
|
||||||
80
backend/internal/service/channel_monitor_challenge.go
Normal file
80
backend/internal/service/channel_monitor_challenge.go
Normal file
@ -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
|
||||||
|
}
|
||||||
443
backend/internal/service/channel_monitor_checker.go
Normal file
443
backend/internal/service/channel_monitor_checker.go
Normal file
@ -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
|
||||||
|
}
|
||||||
173
backend/internal/service/channel_monitor_checker_body_test.go
Normal file
173
backend/internal/service/channel_monitor_checker_body_test.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
142
backend/internal/service/channel_monitor_const.go
Normal file
142
backend/internal/service/channel_monitor_const.go
Normal file
@ -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 <status>: " 前缀留出余量,避免最终被 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",
|
||||||
|
)
|
||||||
|
)
|
||||||
291
backend/internal/service/channel_monitor_runner.go
Normal file
291
backend/internal/service/channel_monitor_runner.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
277
backend/internal/service/channel_monitor_runner_test.go
Normal file
277
backend/internal/service/channel_monitor_runner_test.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
539
backend/internal/service/channel_monitor_service.go
Normal file
539
backend/internal/service/channel_monitor_service.go
Normal file
@ -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
|
||||||
|
}
|
||||||
152
backend/internal/service/channel_monitor_ssrf.go
Normal file
152
backend/internal/service/channel_monitor_ssrf.go
Normal file
@ -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
|
||||||
|
}
|
||||||
251
backend/internal/service/channel_monitor_template_service.go
Normal file
251
backend/internal/service/channel_monitor_template_service.go
Normal file
@ -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
|
||||||
|
}
|
||||||
77
backend/internal/service/channel_monitor_template_types.go
Normal file
77
backend/internal/service/channel_monitor_template_types.go
Normal file
@ -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",
|
||||||
|
)
|
||||||
|
)
|
||||||
203
backend/internal/service/channel_monitor_types.go
Normal file
203
backend/internal/service/channel_monitor_types.go
Normal file
@ -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
|
||||||
|
}
|
||||||
99
backend/internal/service/channel_monitor_validate.go
Normal file
99
backend/internal/service/channel_monitor_validate.go
Normal file
@ -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
|
||||||
|
}
|
||||||
@ -141,17 +141,23 @@ const (
|
|||||||
// ChannelService 渠道管理服务
|
// ChannelService 渠道管理服务
|
||||||
type ChannelService struct {
|
type ChannelService struct {
|
||||||
repo ChannelRepository
|
repo ChannelRepository
|
||||||
|
groupRepo GroupRepository
|
||||||
authCacheInvalidator APIKeyAuthCacheInvalidator
|
authCacheInvalidator APIKeyAuthCacheInvalidator
|
||||||
|
pricingService *PricingService // 用于「可用渠道」展示时回落到全局定价;可为 nil(测试场景)
|
||||||
|
|
||||||
cache atomic.Value // *channelCache
|
cache atomic.Value // *channelCache
|
||||||
cacheSF singleflight.Group
|
cacheSF singleflight.Group
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewChannelService 创建渠道服务实例
|
// NewChannelService 创建渠道服务实例。
|
||||||
func NewChannelService(repo ChannelRepository, authCacheInvalidator APIKeyAuthCacheInvalidator) *ChannelService {
|
// pricingService 仅供 ListAvailable 在渠道未配置定价时回落到全局 LiteLLM 数据;
|
||||||
|
// 计费热路径走独立的 ModelPricingResolver,与此参数无关。可传 nil。
|
||||||
|
func NewChannelService(repo ChannelRepository, groupRepo GroupRepository, authCacheInvalidator APIKeyAuthCacheInvalidator, pricingService *PricingService) *ChannelService {
|
||||||
s := &ChannelService{
|
s := &ChannelService{
|
||||||
repo: repo,
|
repo: repo,
|
||||||
|
groupRepo: groupRepo,
|
||||||
authCacheInvalidator: authCacheInvalidator,
|
authCacheInvalidator: authCacheInvalidator,
|
||||||
|
pricingService: pricingService,
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
@ -299,6 +305,9 @@ func (s *ChannelService) fetchChannelData(ctx context.Context) ([]Channel, map[i
|
|||||||
}
|
}
|
||||||
|
|
||||||
// populateChannelCache 将渠道列表和分组平台映射填充到缓存快照中。
|
// populateChannelCache 将渠道列表和分组平台映射填充到缓存快照中。
|
||||||
|
// 装填时对每个 Channel 统一归一化 BillingModelSource,让缓存命中的所有下游
|
||||||
|
// (gateway routing / billing / 未来任何 cache-backed 读路径)都拿到已归一化的实体,
|
||||||
|
// 避免"每个出口各自记得 normalize"反模式。
|
||||||
func populateChannelCache(channels []Channel, groupPlatforms map[int64]string) *channelCache {
|
func populateChannelCache(channels []Channel, groupPlatforms map[int64]string) *channelCache {
|
||||||
cache := newEmptyChannelCache()
|
cache := newEmptyChannelCache()
|
||||||
cache.groupPlatform = groupPlatforms
|
cache.groupPlatform = groupPlatforms
|
||||||
@ -306,6 +315,7 @@ func populateChannelCache(channels []Channel, groupPlatforms map[int64]string) *
|
|||||||
cache.loadedAt = time.Now()
|
cache.loadedAt = time.Now()
|
||||||
|
|
||||||
for i := range channels {
|
for i := range channels {
|
||||||
|
channels[i].normalizeBillingModelSource()
|
||||||
ch := &channels[i]
|
ch := &channels[i]
|
||||||
cache.byID[ch.ID] = ch
|
cache.byID[ch.ID] = ch
|
||||||
for _, gid := range ch.GroupIDs {
|
for _, gid := range ch.GroupIDs {
|
||||||
@ -516,14 +526,13 @@ func (s *ChannelService) ResolveChannelMappingAndRestrict(ctx context.Context, g
|
|||||||
// resolveMapping 基于已查找的渠道信息解析模型映射。
|
// resolveMapping 基于已查找的渠道信息解析模型映射。
|
||||||
// antigravity 分组依次尝试所有匹配平台,确保跨平台同名映射各自独立。
|
// antigravity 分组依次尝试所有匹配平台,确保跨平台同名映射各自独立。
|
||||||
func resolveMapping(lk *channelLookup, groupID int64, model string) ChannelMappingResult {
|
func resolveMapping(lk *channelLookup, groupID int64, model string) ChannelMappingResult {
|
||||||
|
// lk.channel 来自已装填的缓存,BillingModelSource 已在 populateChannelCache 阶段归一化,
|
||||||
|
// 这里无需重复兜底。
|
||||||
result := ChannelMappingResult{
|
result := ChannelMappingResult{
|
||||||
MappedModel: model,
|
MappedModel: model,
|
||||||
ChannelID: lk.channel.ID,
|
ChannelID: lk.channel.ID,
|
||||||
BillingModelSource: lk.channel.BillingModelSource,
|
BillingModelSource: lk.channel.BillingModelSource,
|
||||||
}
|
}
|
||||||
if result.BillingModelSource == "" {
|
|
||||||
result.BillingModelSource = BillingModelSourceChannelMapped
|
|
||||||
}
|
|
||||||
|
|
||||||
modelLower := strings.ToLower(model)
|
modelLower := strings.ToLower(model)
|
||||||
if mapped := lookupMappingAcrossPlatforms(lk.cache, groupID, lk.platform, modelLower); mapped != "" {
|
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,
|
ApplyPricingToAccountStats: input.ApplyPricingToAccountStats,
|
||||||
AccountStatsPricingRules: input.AccountStatsPricingRules,
|
AccountStatsPricingRules: input.AccountStatsPricingRules,
|
||||||
}
|
}
|
||||||
if channel.BillingModelSource == "" {
|
channel.normalizeBillingModelSource()
|
||||||
channel.BillingModelSource = BillingModelSourceChannelMapped
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := validateChannelConfig(channel.ModelPricing, channel.ModelMapping); err != nil {
|
if err := validateChannelConfig(channel.ModelPricing, channel.ModelMapping); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -702,12 +709,23 @@ func (s *ChannelService) Create(ctx context.Context, input *CreateChannelInput)
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.invalidateCache()
|
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) {
|
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 更新渠道
|
// Update 更新渠道
|
||||||
@ -739,7 +757,12 @@ func (s *ChannelService) Update(ctx context.Context, id int64, input *UpdateChan
|
|||||||
s.invalidateCache()
|
s.invalidateCache()
|
||||||
s.invalidateAuthCacheForGroups(ctx, oldGroupIDs, channel.GroupIDs)
|
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 将更新请求的字段应用到渠道实体上。
|
// applyUpdateInput 将更新请求的字段应用到渠道实体上。
|
||||||
@ -857,7 +880,14 @@ func (s *ChannelService) Delete(ctx context.Context, id int64) error {
|
|||||||
|
|
||||||
// List 获取渠道列表
|
// List 获取渠道列表
|
||||||
func (s *ChannelService) List(ctx context.Context, params pagination.PaginationParams, status, search string) ([]Channel, *pagination.PaginationResult, error) {
|
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 表示一个模型模式条目(用于冲突检测)
|
// modelEntry 表示一个模型模式条目(用于冲突检测)
|
||||||
@ -884,12 +914,7 @@ func conflictsBetween(a, b modelEntry) bool {
|
|||||||
|
|
||||||
// toModelEntry 将模型名转换为 modelEntry
|
// toModelEntry 将模型名转换为 modelEntry
|
||||||
func toModelEntry(pattern string) modelEntry {
|
func toModelEntry(pattern string) modelEntry {
|
||||||
lower := strings.ToLower(pattern)
|
prefix, isWild := splitWildcardSuffix(strings.ToLower(pattern))
|
||||||
isWild := strings.HasSuffix(lower, "*")
|
|
||||||
prefix := lower
|
|
||||||
if isWild {
|
|
||||||
prefix = strings.TrimSuffix(lower, "*")
|
|
||||||
}
|
|
||||||
return modelEntry{pattern: pattern, prefix: prefix, wildcard: isWild}
|
return modelEntry{pattern: pattern, prefix: prefix, wildcard: isWild}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -189,11 +189,11 @@ func (m *mockChannelAuthCacheInvalidator) InvalidateAuthCacheByGroupID(_ context
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
func newTestChannelService(repo *mockChannelRepository) *ChannelService {
|
func newTestChannelService(repo *mockChannelRepository) *ChannelService {
|
||||||
return NewChannelService(repo, nil)
|
return NewChannelService(repo, nil, nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestChannelServiceWithAuth(repo *mockChannelRepository, auth *mockChannelAuthCacheInvalidator) *ChannelService {
|
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
|
// makeStandardRepo returns a repo that serves one active channel with anthropic pricing
|
||||||
|
|||||||
@ -433,3 +433,296 @@ func TestValidateIntervals_UnboundedNotLast(t *testing.T) {
|
|||||||
require.Contains(t, err.Error(), "unbounded")
|
require.Contains(t, err.Error(), "unbounded")
|
||||||
require.Contains(t, err.Error(), "last")
|
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)
|
||||||
|
}
|
||||||
|
|||||||
@ -243,6 +243,23 @@ const (
|
|||||||
// SettingKeyOpsRuntimeLogConfig stores JSON config for runtime log settings.
|
// SettingKeyOpsRuntimeLogConfig stores JSON config for runtime log settings.
|
||||||
SettingKeyOpsRuntimeLogConfig = "ops_runtime_log_config"
|
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)
|
// Overload Cooldown (529)
|
||||||
// =========================
|
// =========================
|
||||||
|
|||||||
@ -184,7 +184,7 @@ func newResolverWithChannel(t *testing.T, pricing []ChannelModelPricing) *ModelP
|
|||||||
return map[int64]string{groupID: "anthropic"}, nil
|
return map[int64]string{groupID: "anthropic"}, nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cs := NewChannelService(repo, nil)
|
cs := NewChannelService(repo, nil, nil, nil)
|
||||||
bs := newTestBillingServiceForResolver()
|
bs := newTestBillingServiceForResolver()
|
||||||
return NewModelPricingResolver(cs, bs)
|
return NewModelPricingResolver(cs, bs)
|
||||||
}
|
}
|
||||||
@ -517,7 +517,7 @@ func TestResolve_WithChannelOverride_CacheError(t *testing.T) {
|
|||||||
return nil, errors.New("database unavailable")
|
return nil, errors.New("database unavailable")
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cs := NewChannelService(repo, nil)
|
cs := NewChannelService(repo, nil, nil, nil)
|
||||||
bs := newTestBillingServiceForResolver()
|
bs := newTestBillingServiceForResolver()
|
||||||
r := NewModelPricingResolver(cs, bs)
|
r := NewModelPricingResolver(cs, bs)
|
||||||
|
|
||||||
|
|||||||
@ -36,11 +36,15 @@ return 0
|
|||||||
// - Scheduling: 5-field cron spec (minute hour dom month dow).
|
// - Scheduling: 5-field cron spec (minute hour dom month dow).
|
||||||
// - Multi-instance: best-effort Redis leader lock so only one node runs cleanup.
|
// - Multi-instance: best-effort Redis leader lock so only one node runs cleanup.
|
||||||
// - Safety: deletes in batches to avoid long transactions.
|
// - Safety: deletes in batches to avoid long transactions.
|
||||||
|
//
|
||||||
|
// 附带:在 runCleanupOnce 末尾调用 ChannelMonitorService.RunDailyMaintenance,
|
||||||
|
// 统一共享 cron schedule + leader lock + heartbeat,避免再引一套调度。
|
||||||
type OpsCleanupService struct {
|
type OpsCleanupService struct {
|
||||||
opsRepo OpsRepository
|
opsRepo OpsRepository
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
redisClient *redis.Client
|
redisClient *redis.Client
|
||||||
cfg *config.Config
|
cfg *config.Config
|
||||||
|
channelMonitorSvc *ChannelMonitorService
|
||||||
|
|
||||||
instanceID string
|
instanceID string
|
||||||
|
|
||||||
@ -57,13 +61,15 @@ func NewOpsCleanupService(
|
|||||||
db *sql.DB,
|
db *sql.DB,
|
||||||
redisClient *redis.Client,
|
redisClient *redis.Client,
|
||||||
cfg *config.Config,
|
cfg *config.Config,
|
||||||
|
channelMonitorSvc *ChannelMonitorService,
|
||||||
) *OpsCleanupService {
|
) *OpsCleanupService {
|
||||||
return &OpsCleanupService{
|
return &OpsCleanupService{
|
||||||
opsRepo: opsRepo,
|
opsRepo: opsRepo,
|
||||||
db: db,
|
db: db,
|
||||||
redisClient: redisClient,
|
redisClient: redisClient,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
instanceID: uuid.NewString(),
|
channelMonitorSvc: channelMonitorSvc,
|
||||||
|
instanceID: uuid.NewString(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,6 +254,15 @@ func (s *OpsCleanupService) runCleanupOnce(ctx context.Context) (opsCleanupDelet
|
|||||||
out.dailyPreagg = n
|
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
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"math"
|
"math"
|
||||||
@ -16,6 +17,14 @@ import (
|
|||||||
infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors"
|
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 ---
|
// --- Payment Notification & Fulfillment ---
|
||||||
|
|
||||||
func (s *PaymentService) HandlePaymentNotification(ctx context.Context, n *payment.PaymentNotification, pk string) error {
|
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 {
|
if oid, ok := parseLegacyPaymentOrderID(n.OrderID, err); ok {
|
||||||
return s.confirmPayment(ctx, oid, n.TradeNo, n.Amount, pk, n.Metadata)
|
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)
|
return s.confirmPayment(ctx, order.ID, n.TradeNo, n.Amount, pk, n.Metadata)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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")
|
||||||
|
}
|
||||||
@ -450,6 +450,9 @@ func (s *SettingService) GetPublicSettings(ctx context.Context) (*PublicSettings
|
|||||||
SettingKeyBalanceLowNotifyThreshold,
|
SettingKeyBalanceLowNotifyThreshold,
|
||||||
SettingKeyBalanceLowNotifyRechargeURL,
|
SettingKeyBalanceLowNotifyRechargeURL,
|
||||||
SettingKeyAccountQuotaNotifyEnabled,
|
SettingKeyAccountQuotaNotifyEnabled,
|
||||||
|
SettingKeyChannelMonitorEnabled,
|
||||||
|
SettingKeyChannelMonitorDefaultIntervalSeconds,
|
||||||
|
SettingKeyAvailableChannelsEnabled,
|
||||||
}
|
}
|
||||||
|
|
||||||
settings, err := s.settingRepo.GetMultiple(ctx, keys)
|
settings, err := s.settingRepo.GetMultiple(ctx, keys)
|
||||||
@ -532,9 +535,88 @@ func (s *SettingService) GetPublicSettings(ctx context.Context) (*PublicSettings
|
|||||||
AccountQuotaNotifyEnabled: settings[SettingKeyAccountQuotaNotifyEnabled] == "true",
|
AccountQuotaNotifyEnabled: settings[SettingKeyAccountQuotaNotifyEnabled] == "true",
|
||||||
BalanceLowNotifyThreshold: balanceLowNotifyThreshold,
|
BalanceLowNotifyThreshold: balanceLowNotifyThreshold,
|
||||||
BalanceLowNotifyRechargeURL: settings[SettingKeyBalanceLowNotifyRechargeURL],
|
BalanceLowNotifyRechargeURL: settings[SettingKeyBalanceLowNotifyRechargeURL],
|
||||||
|
|
||||||
|
ChannelMonitorEnabled: !isFalseSettingValue(settings[SettingKeyChannelMonitorEnabled]),
|
||||||
|
ChannelMonitorDefaultIntervalSeconds: parseChannelMonitorInterval(settings[SettingKeyChannelMonitorDefaultIntervalSeconds]),
|
||||||
|
|
||||||
|
AvailableChannelsEnabled: settings[SettingKeyAvailableChannelsEnabled] == "true",
|
||||||
}, nil
|
}, 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
|
// 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)
|
// This is used for cache invalidation (e.g., HTML cache in frontend server)
|
||||||
func (s *SettingService) SetOnUpdateCallback(callback func()) {
|
func (s *SettingService) SetOnUpdateCallback(callback func()) {
|
||||||
@ -546,54 +628,75 @@ func (s *SettingService) SetVersion(version string) {
|
|||||||
s.version = version
|
s.version = version
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPublicSettingsForInjection returns public settings in a format suitable for HTML injection
|
// PublicSettingsInjectionPayload is the JSON shape embedded into HTML as
|
||||||
// This implements the web.PublicSettingsProvider interface
|
// `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) {
|
func (s *SettingService) GetPublicSettingsForInjection(ctx context.Context) (any, error) {
|
||||||
settings, err := s.GetPublicSettings(ctx)
|
settings, err := s.GetPublicSettings(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a struct that matches the frontend's expected format
|
return &PublicSettingsInjectionPayload{
|
||||||
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"`
|
|
||||||
}{
|
|
||||||
RegistrationEnabled: settings.RegistrationEnabled,
|
RegistrationEnabled: settings.RegistrationEnabled,
|
||||||
EmailVerifyEnabled: settings.EmailVerifyEnabled,
|
EmailVerifyEnabled: settings.EmailVerifyEnabled,
|
||||||
RegistrationEmailSuffixWhitelist: settings.RegistrationEmailSuffixWhitelist,
|
RegistrationEmailSuffixWhitelist: settings.RegistrationEmailSuffixWhitelist,
|
||||||
@ -622,15 +725,19 @@ func (s *SettingService) GetPublicSettingsForInjection(ctx context.Context) (any
|
|||||||
WeChatOAuthOpenEnabled: settings.WeChatOAuthOpenEnabled,
|
WeChatOAuthOpenEnabled: settings.WeChatOAuthOpenEnabled,
|
||||||
WeChatOAuthMPEnabled: settings.WeChatOAuthMPEnabled,
|
WeChatOAuthMPEnabled: settings.WeChatOAuthMPEnabled,
|
||||||
WeChatOAuthMobileEnabled: settings.WeChatOAuthMobileEnabled,
|
WeChatOAuthMobileEnabled: settings.WeChatOAuthMobileEnabled,
|
||||||
BackendModeEnabled: settings.BackendModeEnabled,
|
|
||||||
PaymentEnabled: settings.PaymentEnabled,
|
|
||||||
OIDCOAuthEnabled: settings.OIDCOAuthEnabled,
|
OIDCOAuthEnabled: settings.OIDCOAuthEnabled,
|
||||||
OIDCOAuthProviderName: settings.OIDCOAuthProviderName,
|
OIDCOAuthProviderName: settings.OIDCOAuthProviderName,
|
||||||
|
BackendModeEnabled: settings.BackendModeEnabled,
|
||||||
|
PaymentEnabled: settings.PaymentEnabled,
|
||||||
Version: s.version,
|
Version: s.version,
|
||||||
BalanceLowNotifyEnabled: settings.BalanceLowNotifyEnabled,
|
BalanceLowNotifyEnabled: settings.BalanceLowNotifyEnabled,
|
||||||
AccountQuotaNotifyEnabled: settings.AccountQuotaNotifyEnabled,
|
AccountQuotaNotifyEnabled: settings.AccountQuotaNotifyEnabled,
|
||||||
BalanceLowNotifyThreshold: settings.BalanceLowNotifyThreshold,
|
BalanceLowNotifyThreshold: settings.BalanceLowNotifyThreshold,
|
||||||
BalanceLowNotifyRechargeURL: settings.BalanceLowNotifyRechargeURL,
|
BalanceLowNotifyRechargeURL: settings.BalanceLowNotifyRechargeURL,
|
||||||
|
|
||||||
|
ChannelMonitorEnabled: settings.ChannelMonitorEnabled,
|
||||||
|
ChannelMonitorDefaultIntervalSeconds: settings.ChannelMonitorDefaultIntervalSeconds,
|
||||||
|
AvailableChannelsEnabled: settings.AvailableChannelsEnabled,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1086,6 +1193,15 @@ func (s *SettingService) buildSystemSettingsUpdates(ctx context.Context, setting
|
|||||||
updates[SettingKeyOpsMetricsIntervalSeconds] = strconv.Itoa(settings.OpsMetricsIntervalSeconds)
|
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
|
// Claude Code version check
|
||||||
updates[SettingKeyMinClaudeCodeVersion] = settings.MinClaudeCodeVersion
|
updates[SettingKeyMinClaudeCodeVersion] = settings.MinClaudeCodeVersion
|
||||||
updates[SettingKeyMaxClaudeCodeVersion] = settings.MaxClaudeCodeVersion
|
updates[SettingKeyMaxClaudeCodeVersion] = settings.MaxClaudeCodeVersion
|
||||||
@ -1644,6 +1760,13 @@ func (s *SettingService) InitializeDefaultSettings(ctx context.Context) error {
|
|||||||
SettingKeyOpsQueryModeDefault: "auto",
|
SettingKeyOpsQueryModeDefault: "auto",
|
||||||
SettingKeyOpsMetricsIntervalSeconds: "60",
|
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)
|
// Claude Code version check (default: empty = disabled)
|
||||||
SettingKeyMinClaudeCodeVersion: "",
|
SettingKeyMinClaudeCodeVersion: "",
|
||||||
SettingKeyMaxClaudeCodeVersion: "",
|
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
|
// Claude Code version check
|
||||||
result.MinClaudeCodeVersion = settings[SettingKeyMinClaudeCodeVersion]
|
result.MinClaudeCodeVersion = settings[SettingKeyMinClaudeCodeVersion]
|
||||||
result.MaxClaudeCodeVersion = settings[SettingKeyMaxClaudeCodeVersion]
|
result.MaxClaudeCodeVersion = settings[SettingKeyMaxClaudeCodeVersion]
|
||||||
|
|||||||
@ -126,6 +126,13 @@ type SystemSettings struct {
|
|||||||
OpsQueryModeDefault string
|
OpsQueryModeDefault string
|
||||||
OpsMetricsIntervalSeconds int
|
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
|
// Claude Code version check
|
||||||
MinClaudeCodeVersion string
|
MinClaudeCodeVersion string
|
||||||
MaxClaudeCodeVersion string
|
MaxClaudeCodeVersion string
|
||||||
@ -210,6 +217,13 @@ type PublicSettings struct {
|
|||||||
AccountQuotaNotifyEnabled bool
|
AccountQuotaNotifyEnabled bool
|
||||||
BalanceLowNotifyThreshold float64
|
BalanceLowNotifyThreshold float64
|
||||||
BalanceLowNotifyRechargeURL string
|
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 {
|
type WeChatConnectOAuthConfig struct {
|
||||||
|
|||||||
@ -269,13 +269,16 @@ func ProvideOpsAlertEvaluatorService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ProvideOpsCleanupService creates and starts OpsCleanupService (cron scheduled).
|
// ProvideOpsCleanupService creates and starts OpsCleanupService (cron scheduled).
|
||||||
|
// channelMonitorSvc 让维护任务(聚合 + 历史/聚合软删)跟随 ops 清理 cron 一起跑,
|
||||||
|
// 共享 leader lock + heartbeat。
|
||||||
func ProvideOpsCleanupService(
|
func ProvideOpsCleanupService(
|
||||||
opsRepo OpsRepository,
|
opsRepo OpsRepository,
|
||||||
db *sql.DB,
|
db *sql.DB,
|
||||||
redisClient *redis.Client,
|
redisClient *redis.Client,
|
||||||
cfg *config.Config,
|
cfg *config.Config,
|
||||||
|
channelMonitorSvc *ChannelMonitorService,
|
||||||
) *OpsCleanupService {
|
) *OpsCleanupService {
|
||||||
svc := NewOpsCleanupService(opsRepo, db, redisClient, cfg)
|
svc := NewOpsCleanupService(opsRepo, db, redisClient, cfg, channelMonitorSvc)
|
||||||
svc.Start()
|
svc.Start()
|
||||||
return svc
|
return svc
|
||||||
}
|
}
|
||||||
@ -487,6 +490,9 @@ var ProviderSet = wire.NewSet(
|
|||||||
NewPaymentService,
|
NewPaymentService,
|
||||||
ProvidePaymentOrderExpiryService,
|
ProvidePaymentOrderExpiryService,
|
||||||
ProvideBalanceNotifyService,
|
ProvideBalanceNotifyService,
|
||||||
|
ProvideChannelMonitorService,
|
||||||
|
ProvideChannelMonitorRunner,
|
||||||
|
NewChannelMonitorRequestTemplateService,
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProvidePaymentConfigService wraps NewPaymentConfigService to accept the named
|
// ProvidePaymentConfigService wraps NewPaymentConfigService to accept the named
|
||||||
@ -506,3 +512,23 @@ func ProvidePaymentOrderExpiryService(paymentSvc *PaymentService) *PaymentOrderE
|
|||||||
svc.Start()
|
svc.Start()
|
||||||
return svc
|
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
|
||||||
|
}
|
||||||
|
|||||||
58
backend/migrations/125_add_channel_monitors.sql
Normal file
58
backend/migrations/125_add_channel_monitors.sql
Normal file
@ -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);
|
||||||
60
backend/migrations/126_add_channel_monitor_aggregation.sql
Normal file
60
backend/migrations/126_add_channel_monitor_aggregation.sql
Normal file
@ -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;
|
||||||
16
backend/migrations/127_drop_channel_monitor_deleted_at.sql
Normal file
16
backend/migrations/127_drop_channel_monitor_deleted_at.sql
Normal file
@ -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;
|
||||||
@ -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;
|
||||||
38
backend/migrations/129_seed_claude_code_template.sql
Normal file
38
backend/migrations/129_seed_claude_code_template.sql
Normal file
@ -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_<uuid>_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;
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user