101 lines
2.1 KiB
Go
101 lines
2.1 KiB
Go
package sqlite
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
|
|
"cmroubao/backend-api/internal/domain"
|
|
"cmroubao/backend-api/internal/usecase"
|
|
)
|
|
|
|
const assetUploadOperation = "UPLOAD_TASK_REFERENCE"
|
|
|
|
func (s *Store) CreateAssetIdempotent(
|
|
ctx context.Context,
|
|
candidate domain.Asset,
|
|
idempotencyKey string,
|
|
requestHash string,
|
|
) (domain.Asset, bool, error) {
|
|
tx, err := s.db.BeginTx(ctx, nil)
|
|
if err != nil {
|
|
return domain.Asset{}, false, repositoryFailure(err)
|
|
}
|
|
defer func() { _ = tx.Rollback() }()
|
|
|
|
existingHash, resourceID, found, err := lookupIdempotency(
|
|
ctx,
|
|
tx,
|
|
candidate.CreatorSubject,
|
|
assetUploadOperation,
|
|
idempotencyKey,
|
|
)
|
|
if err != nil {
|
|
return domain.Asset{}, false, err
|
|
}
|
|
if found {
|
|
if existingHash != requestHash {
|
|
return domain.Asset{}, false, usecase.ErrIdempotencyConflict
|
|
}
|
|
existing, err := getAssetByID(
|
|
ctx,
|
|
tx,
|
|
candidate.CreatorSubject,
|
|
resourceID,
|
|
)
|
|
if err != nil {
|
|
return domain.Asset{}, false, err
|
|
}
|
|
if err := tx.Commit(); err != nil {
|
|
return domain.Asset{}, false, repositoryFailure(err)
|
|
}
|
|
return existing, false, nil
|
|
}
|
|
|
|
_, err = tx.ExecContext(
|
|
ctx,
|
|
`INSERT INTO assets (
|
|
id, creator_subject, purpose, media_type, size_bytes,
|
|
sha256, storage_key, created_at
|
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
candidate.ID,
|
|
candidate.CreatorSubject,
|
|
candidate.Purpose,
|
|
candidate.MediaType,
|
|
candidate.SizeBytes,
|
|
candidate.SHA256,
|
|
candidate.StorageKey,
|
|
formatTimestamp(candidate.CreatedAt),
|
|
)
|
|
if err != nil {
|
|
return domain.Asset{}, false, repositoryFailure(err)
|
|
}
|
|
if err := insertIdempotency(
|
|
ctx,
|
|
tx,
|
|
candidate.CreatorSubject,
|
|
assetUploadOperation,
|
|
idempotencyKey,
|
|
requestHash,
|
|
"ASSET",
|
|
candidate.ID,
|
|
candidate.CreatedAt,
|
|
); err != nil {
|
|
return domain.Asset{}, false, err
|
|
}
|
|
if err := tx.Commit(); err != nil {
|
|
return domain.Asset{}, false, repositoryFailure(err)
|
|
}
|
|
return candidate, true, nil
|
|
}
|
|
|
|
func (s *Store) GetAsset(
|
|
ctx context.Context,
|
|
creatorSubject string,
|
|
assetID string,
|
|
) (domain.Asset, error) {
|
|
return getAssetByID(ctx, s.db, creatorSubject, assetID)
|
|
}
|
|
|
|
var _ usecase.AssetRepository = (*Store)(nil)
|
|
var _ queryRower = (*sql.Tx)(nil)
|