159 lines
5.8 KiB
Go
159 lines
5.8 KiB
Go
package repository
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"strings"
|
|
"time"
|
|
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/clause"
|
|
"infinite-canvas/backend/internal/model"
|
|
)
|
|
|
|
var ErrCreationConflict = errors.New("数据已被更新,请刷新后重试")
|
|
|
|
func (r *Repository) CreationStorageUsage(userID string) (int64, int64, error) {
|
|
var usage struct {
|
|
Count int64
|
|
Bytes int64
|
|
}
|
|
query := `SELECT (SELECT COUNT(*) FROM creation_runs WHERE user_id = ?) AS count,
|
|
(SELECT COALESCE(SUM(length(CAST(COALESCE(state_json,'') AS BLOB))+length(CAST(COALESCE(approved_operations_json,'') AS BLOB))+length(CAST(COALESCE(approved_canvas_json,'') AS BLOB))),0) FROM creation_runs WHERE user_id = ?)
|
|
+ (SELECT COALESCE(SUM(length(CAST(COALESCE(request_json,'') AS BLOB))+length(CAST(COALESCE(quote_json,'') AS BLOB))+length(CAST(COALESCE(price_signature,'') AS BLOB))),0) FROM creation_submissions WHERE user_id = ?) AS bytes`
|
|
if r.Dialect() == "postgres" {
|
|
query = strings.ReplaceAll(query, "length(CAST(COALESCE(", "octet_length(COALESCE(")
|
|
query = strings.ReplaceAll(query, ",'') AS BLOB))", ",''))")
|
|
}
|
|
err := r.db.Raw(query, userID, userID, userID).Scan(&usage).Error
|
|
return usage.Count, usage.Bytes, err
|
|
}
|
|
|
|
func (r *Repository) CreationRun(userID, id string) (*model.CreationRun, error) {
|
|
var run model.CreationRun
|
|
err := r.db.First(&run, "id = ? AND user_id = ?", id, userID).Error
|
|
return &run, err
|
|
}
|
|
|
|
func (r *Repository) CreationRunByClientKey(userID, key string) (*model.CreationRun, error) {
|
|
var run model.CreationRun
|
|
err := r.db.First(&run, "user_id = ? AND client_key = ?", userID, key).Error
|
|
return &run, err
|
|
}
|
|
func (r *Repository) CreationRuns(userID string) ([]model.CreationRun, error) {
|
|
items := []model.CreationRun{}
|
|
err := r.db.Where("user_id = ?", userID).Order("updated_at DESC").Limit(100).Find(&items).Error
|
|
return items, err
|
|
}
|
|
func (r *Repository) CreateCreationRun(run *model.CreationRun) error {
|
|
var old model.CreationRun
|
|
if err := r.db.First(&old, "user_id = ? AND client_key = ?", run.UserID, run.ClientKey).Error; err == nil {
|
|
if old.CreateHash != run.CreateHash {
|
|
return ErrCreationConflict
|
|
}
|
|
*run = old
|
|
return nil
|
|
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return err
|
|
}
|
|
if err := r.db.Create(run).Error; err != nil {
|
|
if e := r.db.First(&old, "user_id = ? AND client_key = ?", run.UserID, run.ClientKey).Error; e == nil && old.CreateHash == run.CreateHash {
|
|
*run = old
|
|
return nil
|
|
}
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// A conditional write obtains the run row's write lock in both SQLite and PostgreSQL.
|
|
// All submission consumption and task reservation use the returned transaction repository.
|
|
func (r *Repository) MutateCreationRun(userID, id string, fn func(*model.CreationRun, *Repository) error) error {
|
|
return r.db.Transaction(func(tx *gorm.DB) error {
|
|
result := tx.Model(&model.CreationRun{}).Where("id = ? AND user_id = ?", id, userID).UpdateColumn("revision", gorm.Expr("revision"))
|
|
if result.Error != nil {
|
|
return result.Error
|
|
}
|
|
if result.RowsAffected != 1 {
|
|
return gorm.ErrRecordNotFound
|
|
}
|
|
scoped := New(tx)
|
|
run, err := scoped.CreationRun(userID, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := fn(run, scoped); err != nil {
|
|
return err
|
|
}
|
|
return tx.Save(run).Error
|
|
})
|
|
}
|
|
func (r *Repository) CreationSubmissions(userID, runID string) ([]model.CreationSubmission, error) {
|
|
items := []model.CreationSubmission{}
|
|
err := r.db.Where("user_id = ? AND run_id = ?", userID, runID).Order("created_at").Find(&items).Error
|
|
return items, err
|
|
}
|
|
func (r *Repository) CreationSubmission(userID, runID, id string) (*model.CreationSubmission, error) {
|
|
var item model.CreationSubmission
|
|
err := r.db.First(&item, "id = ? AND user_id = ? AND run_id = ?", id, userID, runID).Error
|
|
return &item, err
|
|
}
|
|
func (r *Repository) SaveCreationSubmission(item *model.CreationSubmission) error {
|
|
return r.db.Save(item).Error
|
|
}
|
|
func (r *Repository) RevokeCreationSubmissions(runID string) error {
|
|
return r.db.Model(&model.CreationSubmission{}).Where("run_id = ? AND task_id IS NULL AND revoked_at IS NULL", runID).Update("revoked_at", time.Now()).Error
|
|
}
|
|
func (r *Repository) CreateCreationCanvas(canvas *model.CanvasProject) error {
|
|
return r.UpsertCanvasProject(canvas)
|
|
}
|
|
|
|
// Capture server-side configuration versions, never channel credentials.
|
|
func (r *Repository) CreationPriceSignature(task *model.Task, channelID, modelKey string) (string, error) {
|
|
db := r.db.Clauses(clause.Locking{Strength: "SHARE"}).Session(&gorm.Session{})
|
|
values := map[string]any{}
|
|
var cm model.ChannelModel
|
|
query := db.Where("channel_id = ? AND model_key = ?", channelID, modelKey)
|
|
if task.ChannelModelID != "" {
|
|
query = db.Where("id = ?", task.ChannelModelID)
|
|
}
|
|
if err := query.First(&cm).Error; err != nil {
|
|
return "", err
|
|
}
|
|
values["channelModel"] = cm
|
|
values["capabilityConfig"] = cm.CapabilityConfigJSON
|
|
var channel struct {
|
|
ID string
|
|
Enabled bool
|
|
UpdatedAt time.Time
|
|
}
|
|
if err := db.Model(&model.ModelChannel{}).Select("id, enabled, updated_at").First(&channel, "id = ?", cm.ChannelID).Error; err != nil {
|
|
return "", err
|
|
}
|
|
values["channel"] = channel
|
|
var tiers []model.ChannelModelPriceTier
|
|
if err := db.Where("channel_model_id = ?", cm.ID).Order("id").Find(&tiers).Error; err != nil {
|
|
return "", err
|
|
}
|
|
values["tiers"] = tiers
|
|
if task.LogicalModelID != "" {
|
|
var logical model.LogicalModel
|
|
if err := db.First(&logical, "id = ?", task.LogicalModelID).Error; err != nil {
|
|
return "", err
|
|
}
|
|
values["logical"] = logical
|
|
var route model.LogicalModelRoute
|
|
if err := db.First(&route, "id = ?", task.RouteID).Error; err != nil {
|
|
return "", err
|
|
}
|
|
values["route"] = route
|
|
}
|
|
var settings []model.SystemSetting
|
|
if err := db.Where("key IN ?", []string{"credit_policy", "feature_availability"}).Order("key").Find(&settings).Error; err != nil {
|
|
return "", err
|
|
}
|
|
values["pricingSettings"] = settings
|
|
b, err := json.Marshal(values)
|
|
return string(b), err
|
|
}
|