Skip to content

Commit 9bc4dd2

Browse files
committed
cmd/achcli: setup internal package to share read/write logic
1 parent 19f7fff commit 9bc4dd2

File tree

7 files changed

+149
-38
lines changed

7 files changed

+149
-38
lines changed

cmd/achcli/fix/fix.go

Lines changed: 6 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@ package fix
22

33
import (
44
"bytes"
5-
"encoding/json"
65
"fmt"
76
"os"
87

98
"github.com/moov-io/ach"
9+
"github.com/moov-io/ach/cmd/achcli/internal/read"
10+
"github.com/moov-io/ach/cmd/achcli/internal/write"
1011
)
1112

12-
func Perform(path string, validateOpts *ach.ValidateOpts, conf Config) (string, error) {
13-
file, err := readFile(path, validateOpts)
13+
func Perform(path string, validateOptsPath *string, skipAll *bool, conf Config) (string, error) {
14+
file, format, err := read.Filepath(path, validateOptsPath, skipAll)
1415
if err != nil {
1516
return "", fmt.Errorf("reading %s failed: %w", path, err)
1617
}
@@ -38,9 +39,9 @@ func Perform(path string, validateOpts *ach.ValidateOpts, conf Config) (string,
3839
newpath := path + ".fix"
3940

4041
var buf bytes.Buffer
41-
err = ach.NewWriter(&buf).Write(file)
42+
err = write.File(&buf, file, format)
4243
if err != nil {
43-
return "", fmt.Errorf("encoding fixed file: %w", err)
44+
return "", fmt.Errorf("encoding fixed file as %s: %w", format, err)
4445
}
4546

4647
err = os.WriteFile(newpath, buf.Bytes(), 0644)
@@ -51,33 +52,4 @@ func Perform(path string, validateOpts *ach.ValidateOpts, conf Config) (string,
5152
return newpath, nil
5253
}
5354

54-
func readFile(path string, validateOpts *ach.ValidateOpts) (*ach.File, error) {
55-
bs, err := os.ReadFile(path)
56-
if err != nil {
57-
return nil, err
58-
}
59-
if json.Valid(bs) {
60-
return readJsonFile(bs, validateOpts)
61-
}
62-
return readACHFile(bs, validateOpts)
63-
}
64-
65-
func readACHFile(input []byte, validateOpts *ach.ValidateOpts) (*ach.File, error) {
66-
r := ach.NewReader(bytes.NewReader(input))
67-
r.SetValidation(validateOpts)
68-
f, err := r.Read()
69-
return &f, err
70-
}
71-
72-
func readJsonFile(input []byte, validateOpts *ach.ValidateOpts) (*ach.File, error) {
73-
return ach.FileFromJSONWith(input, validateOpts)
74-
}
75-
7655
type batchHeaderFixer func(bh *ach.BatchHeader) error
77-
78-
// TODO(adam): process file batch by batch
79-
// TODO(adam): fix funcs take a file header, batch, entry, etc
80-
81-
// TODO(adam): updateEED()
82-
83-
// TODO(adam): write output to disk

cmd/achcli/fix/fix_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"path/filepath"
77
"testing"
88

9-
"github.com/moov-io/ach"
109
"github.com/moov-io/ach/cmd/achcli/fix"
1110

1211
"github.com/stretchr/testify/require"
@@ -15,7 +14,8 @@ import (
1514
func TestPerform(t *testing.T) {
1615
cases := []struct {
1716
inputFilepath string
18-
validateOpts *ach.ValidateOpts
17+
validateOptsPath *string
18+
skipAll *bool
1919
config fix.Config
2020
expectedFilepath string
2121
}{
@@ -31,7 +31,7 @@ func TestPerform(t *testing.T) {
3131
_, filename := filepath.Split(tc.inputFilepath)
3232

3333
t.Run(filename, func(t *testing.T) {
34-
newpath, err := fix.Perform(tc.inputFilepath, tc.validateOpts, tc.config)
34+
newpath, err := fix.Perform(tc.inputFilepath, tc.validateOptsPath, tc.skipAll, tc.config)
3535
require.NoError(t, err)
3636

3737
got, err := os.ReadFile(newpath)
@@ -47,3 +47,5 @@ func TestPerform(t *testing.T) {
4747
})
4848
}
4949
}
50+
51+
func ptr[T any](in T) *T { return &in }

cmd/achcli/internal/read/read.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package read
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"fmt"
7+
"os"
8+
9+
"github.com/moov-io/ach"
10+
)
11+
12+
type Format string
13+
14+
var (
15+
FormatUnknown Format = "unknown"
16+
FormatNacha Format = "nacha"
17+
FormatJSON Format = "json"
18+
)
19+
20+
func Filepath(path string, validateOptsPath *string, skipAll *bool) (*ach.File, Format, error) {
21+
validateOpts := readValidationOpts(validateOptsPath, skipAll)
22+
23+
return readFile(path, validateOpts)
24+
}
25+
26+
func readValidationOpts(path *string, skipAll *bool) *ach.ValidateOpts {
27+
var opts ach.ValidateOpts
28+
29+
if skipAll != nil && *skipAll {
30+
opts.SkipAll = true
31+
return &opts
32+
}
33+
34+
if path != nil && *path != "" {
35+
// read config file
36+
bs, readErr := os.ReadFile(*path)
37+
if readErr != nil {
38+
fmt.Printf("ERROR: reading %s for validate opts failed: %v\n", *path, readErr)
39+
os.Exit(1)
40+
}
41+
42+
if err := json.Unmarshal(bs, &opts); err != nil {
43+
fmt.Printf("ERROR: unmarshal of validate opts failed: %v\n", err)
44+
os.Exit(1)
45+
}
46+
return &opts
47+
}
48+
return nil
49+
}
50+
51+
func readFile(path string, validateOpts *ach.ValidateOpts) (*ach.File, Format, error) {
52+
bs, err := os.ReadFile(path)
53+
if err != nil {
54+
return nil, FormatUnknown, err
55+
}
56+
if json.Valid(bs) {
57+
return readJsonFile(bs, validateOpts)
58+
}
59+
return readACHFile(bs, validateOpts)
60+
}
61+
62+
func readACHFile(input []byte, validateOpts *ach.ValidateOpts) (*ach.File, Format, error) {
63+
r := ach.NewReader(bytes.NewReader(input))
64+
r.SetValidation(validateOpts)
65+
66+
f, err := r.Read()
67+
68+
return &f, FormatNacha, err
69+
}
70+
71+
func readJsonFile(input []byte, validateOpts *ach.ValidateOpts) (*ach.File, Format, error) {
72+
file, err := ach.FileFromJSONWith(input, validateOpts)
73+
return file, FormatJSON, err
74+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package read_test
2+
3+
import (
4+
"path/filepath"
5+
"testing"
6+
7+
"github.com/moov-io/ach/cmd/achcli/internal/read"
8+
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
func TestRead(t *testing.T) {
13+
cases := []struct {
14+
inputFilepath string
15+
validateOptsPath *string
16+
skipAll *bool
17+
18+
expectedFormat read.Format
19+
}{
20+
{
21+
inputFilepath: filepath.Join("..", "..", "..", "..", "test", "testdata", "ppd-debit-invalid-entryDetail-checkDigit.ach"),
22+
validateOptsPath: ptr(filepath.Join("..", "..", "..", "..", "test", "testdata", "ppd-debit-invalid-entryDetail-checkDigit.json")),
23+
expectedFormat: read.FormatNacha,
24+
},
25+
{
26+
inputFilepath: filepath.Join("..", "..", "..", "..", "test", "testdata", "ppd-valid-preserve-spaces.json"),
27+
expectedFormat: read.FormatJSON,
28+
},
29+
}
30+
for _, tc := range cases {
31+
_, filename := filepath.Split(tc.inputFilepath)
32+
33+
t.Run(filename, func(t *testing.T) {
34+
file, format, err := read.Filepath(tc.inputFilepath, tc.validateOptsPath, tc.skipAll)
35+
require.NoError(t, err)
36+
require.Equal(t, tc.expectedFormat, format)
37+
require.NotNil(t, file)
38+
})
39+
}
40+
}
41+
42+
func ptr[T any](in T) *T { return &in }

cmd/achcli/internal/write/write.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package write
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"io"
7+
8+
"github.com/moov-io/ach"
9+
"github.com/moov-io/ach/cmd/achcli/internal/read"
10+
)
11+
12+
func File(w io.Writer, file *ach.File, format read.Format) error {
13+
switch format {
14+
case read.FormatNacha:
15+
return ach.NewWriter(w).Write(file)
16+
case read.FormatJSON:
17+
return json.NewEncoder(w).Encode(file)
18+
}
19+
return fmt.Errorf("unknown format %v", format)
20+
}

cmd/achcli/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ func main() {
9191
conf := fix.Config{
9292
UpdateEED: *flagUpdateEED,
9393
}
94-
newpath, err := fix.Perform(args[0], validateOpts, conf)
94+
newpath, err := fix.Perform(args[0], flagValidateOpts, flagSkipValidation, conf)
9595
if err != nil {
9696
fmt.Printf("ERROR: %v\n", err)
9797
os.Exit(1)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"allowInvalidCheckDigit": true}

0 commit comments

Comments
 (0)