diff options
author | Michael Muré <batolettre@gmail.com> | 2021-05-03 11:45:15 +0200 |
---|---|---|
committer | Michael Muré <batolettre@gmail.com> | 2022-08-22 13:25:26 +0200 |
commit | 45b04351d8d02e53b3401b0ee23f7cbe750b63cd (patch) | |
tree | 59d203ef6c0f6a497b7074cd5617c8869cac3b14 /entity/id_interleaved.go | |
parent | 43026fc53669d462a60feec7d22aec090959be72 (diff) | |
download | git-bug-45b04351d8d02e53b3401b0ee23f7cbe750b63cd.tar.gz |
bug: have a type for combined ids, fix https://github.com/MichaelMure/git-bug/issues/653
Diffstat (limited to 'entity/id_interleaved.go')
-rw-r--r-- | entity/id_interleaved.go | 84 |
1 files changed, 81 insertions, 3 deletions
diff --git a/entity/id_interleaved.go b/entity/id_interleaved.go index 0ce2ba00..28c59a42 100644 --- a/entity/id_interleaved.go +++ b/entity/id_interleaved.go @@ -1,13 +1,91 @@ package entity import ( + "fmt" + "io" "strings" + + "github.com/pkg/errors" ) +const UnsetCombinedId = CombinedId("unset") + +// CombinedId is an Id holding information from both a primary Id and a secondary Id. +// While it looks like a regular Id, do not just cast from one to another. +// Instead, use CombineIds and SeparateIds to create it and split it. +type CombinedId string + +// String return the identifier as a string +func (ci CombinedId) String() string { + return string(ci) +} + +// Human return the identifier, shortened for human consumption +func (ci CombinedId) Human() string { + format := fmt.Sprintf("%%.%ds", humanIdLength) + return fmt.Sprintf(format, ci) +} + +func (ci CombinedId) HasPrefix(prefix string) bool { + return strings.HasPrefix(string(ci), prefix) +} + +// UnmarshalGQL implement the Unmarshaler interface for gqlgen +func (ci *CombinedId) UnmarshalGQL(v interface{}) error { + _, ok := v.(string) + if !ok { + return fmt.Errorf("CombinedIds must be strings") + } + + *ci = v.(CombinedId) + + if err := ci.Validate(); err != nil { + return errors.Wrap(err, "invalid CombinedId") + } + + return nil +} + +// MarshalGQL implement the Marshaler interface for gqlgen +func (ci CombinedId) MarshalGQL(w io.Writer) { + _, _ = w.Write([]byte(`"` + ci.String() + `"`)) +} + +// Validate tell if the Id is valid +func (ci CombinedId) Validate() error { + // Special case to detect outdated repo + if len(ci) == 40 { + return fmt.Errorf("outdated repository format, please use https://github.com/MichaelMure/git-bug-migration to upgrade") + } + if len(ci) != idLength { + return fmt.Errorf("invalid length") + } + for _, r := range ci { + if (r < 'a' || r > 'z') && (r < '0' || r > '9') { + return fmt.Errorf("invalid character") + } + } + return nil +} + +// PrimaryPrefix is a helper to extract the primary prefix. +// If practical, use SeparateIds instead. +func (ci CombinedId) PrimaryPrefix() string { + primaryPrefix, _ := SeparateIds(string(ci)) + return primaryPrefix +} + +// SecondaryPrefix is a helper to extract the secondary prefix. +// If practical, use SeparateIds instead. +func (ci CombinedId) SecondaryPrefix() string { + _, secondaryPrefix := SeparateIds(string(ci)) + return secondaryPrefix +} + // CombineIds compute a merged Id holding information from both the primary Id // and the secondary Id. // -// This allow to later find efficiently a secondary element because we can access +// This allows to later find efficiently a secondary element because we can access // the primary one directly instead of searching for a primary that has a // secondary matching the Id. // @@ -32,7 +110,7 @@ import ( // 7: 4P, 3S // 10: 6P, 4S // 16: 11P, 5S -func CombineIds(primary Id, secondary Id) Id { +func CombineIds(primary Id, secondary Id) CombinedId { var id strings.Builder for i := 0; i < idLength; i++ { @@ -46,7 +124,7 @@ func CombineIds(primary Id, secondary Id) Id { } } - return Id(id.String()) + return CombinedId(id.String()) } // SeparateIds extract primary and secondary prefix from an arbitrary length prefix |