Skip to content

Commit 34cd8d3

Browse files
committed
add copyIndexers
1 parent 4015355 commit 34cd8d3

File tree

2 files changed

+89
-29
lines changed

2 files changed

+89
-29
lines changed

orbit/copier.go

+33-6
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import (
2020
var ErrNotPtr = errors.New("must provide a pointer to a non-nil value")
2121

2222
// Copy is an easy way to copy one data structure to another.
23-
func Copy(src interface{}, dst interface{}) error {
23+
func Copy(src, dst any) error {
2424
if src == nil || reflect.TypeOf(src).Kind() != reflect.Ptr {
2525
return fmt.Errorf("copy source: %w", ErrNotPtr)
2626
} else if dst == nil || reflect.TypeOf(dst).Kind() != reflect.Ptr {
@@ -41,18 +41,45 @@ func Copy(src interface{}, dst interface{}) error {
4141

4242
// IndexerInput represents all possible Indexer inputs.
4343
type IndexerInput interface {
44-
*lidarr.IndexerInput | *prowlarr.IndexerInput | *radarr.IndexerInput |
45-
*readarr.IndexerInput | *sonarr.IndexerInput
44+
lidarr.IndexerInput | prowlarr.IndexerInput | radarr.IndexerInput |
45+
readarr.IndexerInput | sonarr.IndexerInput
4646
}
4747

4848
// IndexerOutput represents all possible Indexer outputs.
4949
type IndexerOutput interface {
50-
*lidarr.IndexerOutput | *prowlarr.IndexerOutput | *radarr.IndexerOutput |
51-
*readarr.IndexerOutput | *sonarr.IndexerOutput
50+
lidarr.IndexerOutput | prowlarr.IndexerOutput | radarr.IndexerOutput |
51+
readarr.IndexerOutput | sonarr.IndexerOutput
52+
}
53+
54+
// CopyIndexers copies a slice of indexers from one type to another, so you may copy them among instances.
55+
// The destination must be a pointer to a slice, so it can be updated in place.
56+
// The destination slice may be empty but not nil.
57+
func CopyIndexers[S IndexerInput | IndexerOutput, D IndexerInput](src []*S, dst *[]*D, keepTags bool) ([]*D, error) {
58+
if dst == nil {
59+
return nil, ErrNotPtr
60+
}
61+
62+
var err error
63+
64+
for idx, indexer := range src {
65+
if len(*dst)-1 >= idx { // The destination slice location exists, so update it in place.
66+
_, err = CopyIndexer(indexer, (*dst)[idx], keepTags)
67+
} else { // The destination slice is shorter than the source, so append to it.
68+
newIndexer := new(D)
69+
newIndexer, err = CopyIndexer(indexer, newIndexer, keepTags)
70+
*dst = append(*dst, newIndexer) // This happens before checking the error.
71+
}
72+
73+
if err != nil {
74+
break
75+
}
76+
}
77+
78+
return *dst, err
5279
}
5380

5481
// CopyIndexer copies an indexer from one type to another, so you may copy them among instances.
55-
func CopyIndexer[S IndexerInput | IndexerOutput, D IndexerInput](src S, dst D, keepTags bool) (D, error) {
82+
func CopyIndexer[S IndexerInput | IndexerOutput, D IndexerInput](src *S, dst *D, keepTags bool) (*D, error) {
5683
if err := Copy(src, dst); err != nil {
5784
return dst, err
5885
}

orbit/copier_test.go

+56-23
Original file line numberDiff line numberDiff line change
@@ -11,33 +11,66 @@ import (
1111
"golift.io/starr/sonarr"
1212
)
1313

14-
func TestCopyIndexer(t *testing.T) {
14+
func TestCopyIndexers(t *testing.T) {
1515
t.Parallel()
16+
src1, dst1 := copyData(t)
17+
src2, dst2 := copyData(t)
18+
src3, dst3 := copyData(t)
19+
src4, _ := copyData(t)
20+
src5, _ := copyData(t)
21+
// We test for these.
22+
src1.Priority = 1
23+
src2.Priority = 2
24+
src3.Priority = 3
25+
src4.Priority = 4
26+
src5.Priority = 5
27+
// Make two lists.
28+
srcs := append([]*prowlarr.IndexerOutput{}, src1, src2, src3, src4, src5)
29+
dsts := append([]*sonarr.IndexerInput{}, dst1, dst2, dst3) // short by 2.
30+
// Copy the lists.
31+
dsts2, err := orbit.CopyIndexers(srcs, &dsts, false)
32+
require.NoError(t, err)
33+
// Make sure both outputs have a length matching the input.
34+
assert.Len(t, dsts, len(srcs))
35+
assert.Len(t, dsts2, len(srcs))
36+
// Test that values got copied.
37+
for idx, src := range srcs {
38+
assert.Equal(t, src.Priority, dsts[idx].Priority)
39+
}
40+
}
41+
42+
func copyData(t *testing.T) (*prowlarr.IndexerOutput, *sonarr.IndexerInput) {
43+
t.Helper()
1644

17-
src := &prowlarr.IndexerOutput{
18-
ID: 2,
19-
Priority: 3,
20-
Name: "yes",
21-
Protocol: "usenet",
22-
Implementation: "core",
23-
ConfigContract: "hancock",
24-
Tags: []int{1, 2, 5},
25-
Fields: []*starr.FieldOutput{
26-
{Name: "One", Value: "one"},
27-
{Name: "Two", Value: 2.0},
28-
{Name: "Three", Value: uint(3)},
29-
{Name: "Five", Value: 5},
45+
return &prowlarr.IndexerOutput{
46+
ID: 2,
47+
Priority: 3,
48+
Name: "yes",
49+
Protocol: "usenet",
50+
Implementation: "core",
51+
ConfigContract: "hancock",
52+
Tags: []int{1, 2, 5},
53+
Fields: []*starr.FieldOutput{
54+
{Name: "One", Value: "one"},
55+
{Name: "Two", Value: 2.0},
56+
{Name: "Three", Value: uint(3)},
57+
{Name: "Five", Value: 5},
58+
},
3059
},
31-
}
32-
// This is a real example of how you'd copy an indexer from Prowlarr to Sonarr.
33-
dst := &sonarr.IndexerInput{
34-
// These are not part of the used input, so set them before copying.
35-
EnableAutomaticSearch: true,
36-
EnableInteractiveSearch: true,
37-
EnableRss: true,
38-
DownloadClientID: 15,
39-
}
60+
// This is a real example of how you'd copy an indexer from Prowlarr to Sonarr.
61+
&sonarr.IndexerInput{
62+
// These are not part of the used input, so set them before copying.
63+
EnableAutomaticSearch: true,
64+
EnableInteractiveSearch: true,
65+
EnableRss: true,
66+
DownloadClientID: 15,
67+
}
68+
}
69+
70+
func TestCopyIndexer(t *testing.T) {
71+
t.Parallel()
4072

73+
src, dst := copyData(t)
4174
// Verify everything copies over.
4275
_, err := orbit.CopyIndexer(src, dst, true)
4376
require.NoError(t, err)

0 commit comments

Comments
 (0)