core/internal/domain/version.go

359 lines
6.5 KiB
Go

package domain
import (
"fmt"
"net/url"
)
type Version struct {
code string
name string
host string
timezone string
}
var versionModelName = "Version"
// UnmarshalVersionFromDatabase unmarshals Version from the database.
//
// It should be used only for unmarshalling from the database!
// You can't use UnmarshalVersionFromDatabase as constructor - It may put domain into the invalid state!
func UnmarshalVersionFromDatabase(
code string,
name string,
host string,
timezone string,
) (Version, error) {
if code == "" {
return Version{}, ValidationError{
Model: versionModelName,
Field: "code",
Err: ErrRequired,
}
}
if name == "" {
return Version{}, ValidationError{
Model: versionModelName,
Field: "name",
Err: ErrRequired,
}
}
if host == "" {
return Version{}, ValidationError{
Model: versionModelName,
Field: "host",
Err: ErrRequired,
}
}
if timezone == "" {
return Version{}, ValidationError{
Model: versionModelName,
Field: "timezone",
Err: ErrRequired,
}
}
return Version{
code: code,
name: name,
host: host,
timezone: timezone,
}, nil
}
func (v Version) Code() string {
return v.code
}
func (v Version) Name() string {
return v.name
}
func (v Version) Host() string {
return v.host
}
func (v Version) Timezone() string {
return v.timezone
}
func (v Version) URL() *url.URL {
return &url.URL{
Scheme: "https",
Host: v.host,
}
}
func (v Version) ToCursor() (VersionCursor, error) {
return NewVersionCursor(v.code)
}
func (v Version) IsZero() bool {
return v == Version{}
}
type Versions []Version
type VersionSort uint8
const (
VersionSortCodeASC VersionSort = iota + 1
VersionSortCodeDESC
)
// IsInConflict returns true if two sorts can't be used together (e.g. VersionSortCodeASC and VersionSortCodeDESC).
func (s VersionSort) IsInConflict(s2 VersionSort) bool {
return isSortInConflict(s, s2)
}
func (s VersionSort) String() string {
switch s {
case VersionSortCodeASC:
return "code:ASC"
case VersionSortCodeDESC:
return "code:DESC"
default:
return "unknown version sort"
}
}
type VersionCursor struct {
code string
}
const versionCursorModelName = "VersionCursor"
func NewVersionCursor(code string) (VersionCursor, error) {
if err := validateVersionCode(code); err != nil {
return VersionCursor{}, ValidationError{
Model: versionCursorModelName,
Field: "code",
Err: err,
}
}
return VersionCursor{
code: code,
}, nil
}
func decodeVersionCursor(encoded string) (VersionCursor, error) {
m, err := decodeCursor(encoded)
if err != nil {
return VersionCursor{}, err
}
code, err := m.string("code")
if err != nil {
return VersionCursor{}, ErrInvalidCursor
}
vc, err := NewVersionCursor(code)
if err != nil {
return VersionCursor{}, ErrInvalidCursor
}
return vc, nil
}
func (vc VersionCursor) Code() string {
return vc.code
}
func (vc VersionCursor) IsZero() bool {
return vc == VersionCursor{}
}
func (vc VersionCursor) Encode() string {
if vc.IsZero() {
return ""
}
return encodeCursor([]keyValuePair{
{"code", vc.code},
})
}
type ListVersionsParams struct {
codes []string
sort []VersionSort
cursor VersionCursor
limit int
}
const (
VersionListMaxLimit = 500
listVersionsParamsModelName = "ListVersionsParams"
)
func NewListVersionsParams() ListVersionsParams {
return ListVersionsParams{
sort: []VersionSort{VersionSortCodeASC},
limit: VersionListMaxLimit,
}
}
func (params *ListVersionsParams) Codes() []string {
return params.codes
}
func (params *ListVersionsParams) SetCodes(codes []string) error {
for i, c := range codes {
if err := validateVersionCode(c); err != nil {
return SliceElementValidationError{
Model: listVersionsParamsModelName,
Field: "codes",
Index: i,
Err: err,
}
}
}
params.codes = codes
return nil
}
const (
versionSortMinLength = 0
versionSortMaxLength = 1
)
func (params *ListVersionsParams) Sort() []VersionSort {
return params.sort
}
func (params *ListVersionsParams) SetSort(sort []VersionSort) error {
if err := validateSort(sort, versionSortMinLength, versionSortMaxLength); err != nil {
return ValidationError{
Model: listVersionsParamsModelName,
Field: "sort",
Err: err,
}
}
params.sort = sort
return nil
}
func (params *ListVersionsParams) Cursor() VersionCursor {
return params.cursor
}
func (params *ListVersionsParams) SetCursor(vc VersionCursor) error {
params.cursor = vc
return nil
}
func (params *ListVersionsParams) SetEncodedCursor(encoded string) error {
decoded, err := decodeVersionCursor(encoded)
if err != nil {
return ValidationError{
Model: listVersionsParamsModelName,
Field: "cursor",
Err: err,
}
}
params.cursor = decoded
return nil
}
func (params *ListVersionsParams) Limit() int {
return params.limit
}
func (params *ListVersionsParams) SetLimit(limit int) error {
if err := validateIntInRange(limit, 1, VersionListMaxLimit); err != nil {
return ValidationError{
Model: listVersionsParamsModelName,
Field: "limit",
Err: err,
}
}
params.limit = limit
return nil
}
type ListVersionsResult struct {
versions Versions
self VersionCursor
next VersionCursor
}
const listVersionsResultModelName = "ListVersionsResult"
func NewListVersionsResult(versions Versions, next Version) (ListVersionsResult, error) {
var err error
res := ListVersionsResult{
versions: versions,
}
if len(versions) > 0 {
res.self, err = versions[0].ToCursor()
if err != nil {
return ListVersionsResult{}, ValidationError{
Model: listVersionsResultModelName,
Field: "self",
Err: err,
}
}
}
if !next.IsZero() {
res.next, err = next.ToCursor()
if err != nil {
return ListVersionsResult{}, ValidationError{
Model: listVersionsResultModelName,
Field: "next",
Err: err,
}
}
}
return res, nil
}
func (res ListVersionsResult) Versions() Versions {
return res.versions
}
func (res ListVersionsResult) Self() VersionCursor {
return res.self
}
func (res ListVersionsResult) Next() VersionCursor {
return res.next
}
type VersionNotFoundError struct {
VersionCode string
}
func (e VersionNotFoundError) Error() string {
return fmt.Sprintf("version with code %s not found", e.VersionCode)
}
func (e VersionNotFoundError) Type() ErrorType {
return ErrorTypeNotFound
}
const errorCodeVersionNotFound = "version-not-found"
func (e VersionNotFoundError) Code() string {
return errorCodeVersionNotFound
}
func (e VersionNotFoundError) Params() map[string]any {
return map[string]any{
"Code": e.VersionCode,
}
}