346 lines
7.8 KiB
Go
346 lines
7.8 KiB
Go
package repo
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"log"
|
|
"time"
|
|
"voltaserve/errorpkg"
|
|
"voltaserve/infra"
|
|
"voltaserve/model"
|
|
|
|
"gorm.io/datatypes"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type SnapshotUpdateOptions struct {
|
|
Original *model.S3Object
|
|
Preview *model.S3Object
|
|
Text *model.S3Object
|
|
Thumbnail *model.Thumbnail
|
|
Status string
|
|
}
|
|
|
|
type SnapshotRepo interface {
|
|
Find(id string) (model.Snapshot, error)
|
|
Save(snapshot model.Snapshot) error
|
|
Update(id string, opts SnapshotUpdateOptions) error
|
|
MapWithFile(id string, fileID string) error
|
|
DeleteMappingsForFile(fileID string) error
|
|
FindAllDangling() ([]model.Snapshot, error)
|
|
DeleteAllDangling() error
|
|
GetLatestVersionForFile(fileID string) (int64, error)
|
|
}
|
|
|
|
func NewSnapshotRepo() SnapshotRepo {
|
|
return newSnapshotRepo()
|
|
}
|
|
|
|
func NewSnapshot() model.Snapshot {
|
|
return &snapshotEntity{}
|
|
}
|
|
|
|
type snapshotEntity struct {
|
|
ID string `json:"id" gorm:"column:id;size:36"`
|
|
Version int64 `json:"version" gorm:"column:version"`
|
|
Original datatypes.JSON `json:"original,omitempty" gorm:"column:original"`
|
|
Preview datatypes.JSON `json:"preview,omitempty" gorm:"column:preview"`
|
|
Text datatypes.JSON `json:"text,omitempty" gorm:"column:text"`
|
|
Thumbnail datatypes.JSON `json:"thumbnail,omitempty" gorm:"column:thumbnail"`
|
|
Status string `json:"status,omitempty" gorm:"column,status"`
|
|
CreateTime string `json:"createTime" gorm:"column:create_time"`
|
|
UpdateTime *string `json:"updateTime,omitempty" gorm:"column:update_time"`
|
|
}
|
|
|
|
func (*snapshotEntity) TableName() string {
|
|
return "snapshot"
|
|
}
|
|
|
|
func (s *snapshotEntity) BeforeCreate(*gorm.DB) (err error) {
|
|
s.CreateTime = time.Now().UTC().Format(time.RFC3339)
|
|
return nil
|
|
}
|
|
|
|
func (s *snapshotEntity) BeforeSave(*gorm.DB) (err error) {
|
|
timeNow := time.Now().UTC().Format(time.RFC3339)
|
|
s.UpdateTime = &timeNow
|
|
return nil
|
|
}
|
|
|
|
func (s *snapshotEntity) GetID() string {
|
|
return s.ID
|
|
}
|
|
|
|
func (s *snapshotEntity) GetVersion() int64 {
|
|
return s.Version
|
|
}
|
|
|
|
func (s *snapshotEntity) GetOriginal() *model.S3Object {
|
|
if s.Original.String() == "" {
|
|
return nil
|
|
}
|
|
var res = model.S3Object{}
|
|
if err := json.Unmarshal([]byte(s.Original.String()), &res); err != nil {
|
|
log.Fatal(err)
|
|
return nil
|
|
}
|
|
return &res
|
|
}
|
|
|
|
func (s *snapshotEntity) GetPreview() *model.S3Object {
|
|
if s.Preview.String() == "" {
|
|
return nil
|
|
}
|
|
var res = model.S3Object{}
|
|
if err := json.Unmarshal([]byte(s.Preview.String()), &res); err != nil {
|
|
log.Fatal(err)
|
|
return nil
|
|
}
|
|
return &res
|
|
}
|
|
|
|
func (s *snapshotEntity) GetText() *model.S3Object {
|
|
if s.Text.String() == "" {
|
|
return nil
|
|
}
|
|
var res = model.S3Object{}
|
|
if err := json.Unmarshal([]byte(s.Text.String()), &res); err != nil {
|
|
log.Fatal(err)
|
|
return nil
|
|
}
|
|
return &res
|
|
}
|
|
|
|
func (s *snapshotEntity) GetThumbnail() *model.Thumbnail {
|
|
if s.Thumbnail.String() == "" {
|
|
return nil
|
|
}
|
|
var res = model.Thumbnail{}
|
|
if err := json.Unmarshal([]byte(s.Thumbnail.String()), &res); err != nil {
|
|
log.Fatal(err)
|
|
return nil
|
|
}
|
|
return &res
|
|
}
|
|
|
|
func (s *snapshotEntity) GetStatus() string {
|
|
return s.Status
|
|
}
|
|
|
|
func (s *snapshotEntity) SetID(id string) {
|
|
s.ID = id
|
|
}
|
|
|
|
func (s *snapshotEntity) SetVersion(version int64) {
|
|
s.Version = version
|
|
}
|
|
|
|
func (s *snapshotEntity) SetOriginal(m *model.S3Object) {
|
|
if m == nil {
|
|
s.Original = nil
|
|
} else {
|
|
b, err := json.Marshal(m)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
return
|
|
}
|
|
if err := s.Original.UnmarshalJSON(b); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *snapshotEntity) SetPreview(m *model.S3Object) {
|
|
if m == nil {
|
|
s.Preview = nil
|
|
} else {
|
|
b, err := json.Marshal(m)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
return
|
|
}
|
|
if err := s.Preview.UnmarshalJSON(b); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *snapshotEntity) SetText(m *model.S3Object) {
|
|
if m == nil {
|
|
s.Text = nil
|
|
} else {
|
|
b, err := json.Marshal(m)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
return
|
|
}
|
|
if err := s.Text.UnmarshalJSON(b); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *snapshotEntity) SetThumbnail(m *model.Thumbnail) {
|
|
if m == nil {
|
|
s.Thumbnail = nil
|
|
} else {
|
|
b, err := json.Marshal(m)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
return
|
|
}
|
|
if err := s.Thumbnail.UnmarshalJSON(b); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *snapshotEntity) SetStatus(status string) {
|
|
s.Status = status
|
|
}
|
|
|
|
func (s *snapshotEntity) HasOriginal() bool {
|
|
return s.Original != nil
|
|
}
|
|
|
|
func (s *snapshotEntity) HasPreview() bool {
|
|
return s.Preview != nil
|
|
}
|
|
|
|
func (s *snapshotEntity) HasText() bool {
|
|
return s.Text != nil
|
|
}
|
|
|
|
func (s *snapshotEntity) HasThumbnail() bool {
|
|
return s.Thumbnail != nil
|
|
}
|
|
|
|
func (s *snapshotEntity) GetCreateTime() string {
|
|
return s.CreateTime
|
|
}
|
|
|
|
func (s *snapshotEntity) GetUpdateTime() *string {
|
|
return s.UpdateTime
|
|
}
|
|
|
|
type snapshotRepo struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
func newSnapshotRepo() *snapshotRepo {
|
|
return &snapshotRepo{
|
|
db: infra.GetDb(),
|
|
}
|
|
}
|
|
|
|
func (repo *snapshotRepo) find(id string) (*snapshotEntity, error) {
|
|
var res snapshotEntity
|
|
if db := repo.db.Where("id = ?", id).First(&res); db.Error != nil {
|
|
if errors.Is(db.Error, gorm.ErrRecordNotFound) {
|
|
return nil, errorpkg.NewSnapshotNotFoundError(db.Error)
|
|
} else {
|
|
return nil, errorpkg.NewInternalServerError(db.Error)
|
|
}
|
|
}
|
|
return &res, nil
|
|
}
|
|
|
|
func (repo *snapshotRepo) Find(id string) (model.Snapshot, error) {
|
|
res, err := repo.find(id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
func (repo *snapshotRepo) Save(snapshot model.Snapshot) error {
|
|
if db := repo.db.Save(snapshot); db.Error != nil {
|
|
return db.Error
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (repo *snapshotRepo) Update(id string, opts SnapshotUpdateOptions) error {
|
|
snapshot, err := repo.find(id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if opts.Thumbnail != nil {
|
|
snapshot.SetThumbnail(opts.Thumbnail)
|
|
}
|
|
if opts.Original != nil {
|
|
snapshot.SetOriginal(opts.Original)
|
|
}
|
|
if opts.Preview != nil {
|
|
snapshot.SetPreview(opts.Preview)
|
|
}
|
|
if opts.Text != nil {
|
|
snapshot.SetText(opts.Text)
|
|
}
|
|
if opts.Status != "" {
|
|
snapshot.SetStatus(opts.Status)
|
|
}
|
|
if db := repo.db.Save(&snapshot); db.Error != nil {
|
|
return db.Error
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (repo *snapshotRepo) MapWithFile(id string, fileID string) error {
|
|
if db := repo.db.Exec("INSERT INTO snapshot_file (snapshot_id, file_id) VALUES (?, ?)", id, fileID); db.Error != nil {
|
|
return db.Error
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (repo *snapshotRepo) DeleteMappingsForFile(fileID string) error {
|
|
if db := repo.db.Exec("DELETE FROM snapshot_file WHERE file_id = ?", fileID); db.Error != nil {
|
|
return db.Error
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (repo *snapshotRepo) findAllForFile(fileID string) ([]*snapshotEntity, error) {
|
|
var res []*snapshotEntity
|
|
db := repo.db.
|
|
Raw("SELECT * FROM snapshot s LEFT JOIN snapshot_file sf ON s.id = sf.snapshot_id WHERE sf.file_id = ? ORDER BY s.version", fileID).
|
|
Scan(&res)
|
|
if db.Error != nil {
|
|
return nil, db.Error
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
func (repo *snapshotRepo) FindAllDangling() ([]model.Snapshot, error) {
|
|
var snapshots []*snapshotEntity
|
|
db := repo.db.Raw("SELECT * FROM snapshot s LEFT JOIN snapshot_file sf ON s.id = sf.snapshot_id WHERE sf.snapshot_id IS NULL").Scan(&snapshots)
|
|
if db.Error != nil {
|
|
return nil, db.Error
|
|
}
|
|
var res []model.Snapshot
|
|
for _, s := range snapshots {
|
|
res = append(res, s)
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
func (repo *snapshotRepo) DeleteAllDangling() error {
|
|
if db := repo.db.Exec("DELETE FROM snapshot WHERE id IN (SELECT s.id FROM (SELECT * FROM snapshot) s LEFT JOIN snapshot_file sf ON s.id = sf.snapshot_id WHERE sf.snapshot_id IS NULL)"); db.Error != nil {
|
|
return db.Error
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (repo *snapshotRepo) GetLatestVersionForFile(fileID string) (int64, error) {
|
|
type Result struct {
|
|
Result int64
|
|
}
|
|
var res Result
|
|
if db := repo.db.
|
|
Raw("SELECT coalesce(max(s.version), 0) + 1 result FROM snapshot s LEFT JOIN snapshot_file map ON s.id = map.snapshot_id WHERE map.file_id = ?", fileID).
|
|
Scan(&res); db.Error != nil {
|
|
return 0, db.Error
|
|
}
|
|
return res.Result, nil
|
|
}
|