package persistence import ( domain "RenewCMS/internal/domain/entry" "RenewCMS/internal/infrastructure/persistence/mappers" entity "RenewCMS/internal/infrastructure/persistence/models" "gorm.io/gorm" ) var _ domain.Repository = &EntryRepository{} type EntryRepository struct { db *gorm.DB } func NewEntryRepository(db *gorm.DB) *EntryRepository { return &EntryRepository{db} } var entrySortColumns = map[domain.SortField]string{ domain.SortByID: "id", domain.SortByCreatedAt: "created_at", domain.SortByUpdatedAt: "updated_at", } var entrySortDirections = map[domain.SortDirection]string{ domain.SortAsc: "ASC", domain.SortDesc: "DESC", } func EntryOrderClause(sort domain.Sort) (string, error) { column, columnKnown := entrySortColumns[sort.Field] direction, directionKnown := entrySortDirections[sort.Direction] if !columnKnown || !directionKnown || !sort.Valid() { return "", domain.ErrInvalidSort } if sort.Field == domain.SortByID { return column + " " + direction, nil } return column + " " + direction + ", id DESC", nil } func (e *EntryRepository) Create(record domain.Entry) (domain.Entry, error) { model, err := mappers.EntryToModel(record) if err != nil { return domain.Entry{}, err } if err := e.db.Create(&model).Error; err != nil { return domain.Entry{}, err } return mappers.EntryToDomain(model) } func (e *EntryRepository) Get(contentTypeID uint32, id uint32) (domain.Entry, error) { var model entity.Entry if err := e.db.Where("content_type_id = ? AND id = ?", contentTypeID, id).First(&model).Error; err != nil { return domain.Entry{}, mapNotFoundErr(err, domain.ErrEntryNotFound) } return mappers.EntryToDomain(model) } func (e *EntryRepository) ListPage(filters domain.Filters) (domain.PageResult, error) { order, err := EntryOrderClause(filters.Sort) if err != nil { return domain.PageResult{}, err } if err := domain.ValidatePage(filters.Page, filters.Size); err != nil { return domain.PageResult{}, err } filters.Page = max(filters.Page, 1) filters.Size = max(filters.Size, 0) scoped := func() *gorm.DB { return e.db.Model(&entity.Entry{}).Where("content_type_id = ?", filters.ContentTypeID) } var total int64 if err := scoped().Count(&total).Error; err != nil { return domain.PageResult{}, err } ordered := scoped().Order(order) if !filters.Unpaged { ordered = ordered.Limit(filters.Size).Offset((filters.Page - 1) * filters.Size) } var models []entity.Entry if err := ordered.Find(&models).Error; err != nil { return domain.PageResult{}, err } items, err := entriesToDomain(models) if err != nil { return domain.PageResult{}, err } return domain.PageResult{Items: items, Total: int(total)}, nil } func (e *EntryRepository) Update(record domain.Entry) (domain.Entry, error) { model, err := mappers.EntryToModel(record) if err != nil { return domain.Entry{}, err } result := e.db.Model(&entity.Entry{}).Where("id = ?", model.ID).Select("Data", "UpdatedBy", "UpdatedAt").Updates(&model) if err := deleteOrNotFound(result, domain.ErrEntryNotFound); err != nil { return domain.Entry{}, err } return record, nil } func (e *EntryRepository) Delete(contentTypeID uint32, id uint32) error { result := e.db.Where("content_type_id = ? AND id = ?", contentTypeID, id).Delete(&entity.Entry{}) return deleteOrNotFound(result, domain.ErrEntryNotFound) } func (e *EntryRepository) DeleteByContentType(contentTypeID uint32) error { return e.db.Where("content_type_id = ?", contentTypeID).Delete(&entity.Entry{}).Error } func (e *EntryRepository) CountByContentType(contentTypeID uint32) (int, error) { var total int64 if err := e.db.Model(&entity.Entry{}).Where("content_type_id = ?", contentTypeID).Count(&total).Error; err != nil { return 0, err } return int(total), nil } func (e *EntryRepository) FindByFieldValue(contentTypeID uint32, fieldKey string, value any, excludeID uint32) ([]domain.Entry, error) { var models []entity.Entry if err := e.db.Where("content_type_id = ? AND id <> ?", contentTypeID, excludeID).Find(&models).Error; err != nil { return nil, err } candidates, err := entriesToDomain(models) if err != nil { return nil, err } matching := []domain.Entry{} for _, candidate := range candidates { if domain.SameValue(candidate.Data[fieldKey], value) { matching = append(matching, candidate) } } return matching, nil } func entriesToDomain(models []entity.Entry) ([]domain.Entry, error) { items := make([]domain.Entry, 0, len(models)) for _, model := range models { item, err := mappers.EntryToDomain(model) if err != nil { return nil, err } items = append(items, item) } return items, nil }