Skip to content

Commit 4b63e42

Browse files
longbui98berkaykrc
authored andcommitted
Add solution for Challenge 12 by longbui98 (RezaSi#297)
1 parent ff24b63 commit 4b63e42

File tree

1 file changed

+297
-0
lines changed

1 file changed

+297
-0
lines changed
Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
// Package challenge12 contains the solution for Challenge 12.
2+
package challenge12
3+
4+
import (
5+
"bytes"
6+
"context"
7+
"encoding/json"
8+
"errors"
9+
"fmt"
10+
"os"
11+
// Add any necessary imports here
12+
)
13+
14+
// Reader defines an interface for data sources
15+
type Reader interface {
16+
Read(ctx context.Context) ([]byte, error)
17+
}
18+
19+
// Validator defines an interface for data validation
20+
type Validator interface {
21+
Validate(data []byte) error
22+
}
23+
24+
// Transformer defines an interface for data transformation
25+
type Transformer interface {
26+
Transform(data []byte) ([]byte, error)
27+
}
28+
29+
// Writer defines an interface for data destinations
30+
type Writer interface {
31+
Write(ctx context.Context, data []byte) error
32+
}
33+
34+
// ValidationError represents an error during data validation
35+
type ValidationError struct {
36+
Field string
37+
Message string
38+
Err error
39+
}
40+
41+
// Error returns a string representation of the ValidationError
42+
func (e *ValidationError) Error() string {
43+
// TODO: Implement error message formatting
44+
return fmt.Sprintf("%s: %s error : %s", e.Field, e.Message, e.Err.Error())
45+
}
46+
47+
// Unwrap returns the underlying error
48+
func (e *ValidationError) Unwrap() error {
49+
// TODO: Implement error unwrapping
50+
return e.Err
51+
}
52+
53+
// TransformError represents an error during data transformation
54+
type TransformError struct {
55+
Stage string
56+
Err error
57+
}
58+
59+
// Error returns a string representation of the TransformError
60+
func (e *TransformError) Error() string {
61+
// TODO: Implement error message formatting
62+
return fmt.Sprintf("%s: error %s", e.Stage, e.Err.Error())
63+
}
64+
65+
// Unwrap returns the underlying error
66+
func (e *TransformError) Unwrap() error {
67+
return e.Err
68+
}
69+
70+
// PipelineError represents an error in the processing pipeline
71+
type PipelineError struct {
72+
Stage string
73+
Err error
74+
}
75+
76+
// Error returns a string representation of the PipelineError
77+
func (e *PipelineError) Error() string {
78+
// TODO: Implement error message formatting
79+
return fmt.Sprintf("%s: error %s", e.Stage, e.Err.Error())
80+
}
81+
82+
// Unwrap returns the underlying error
83+
func (e *PipelineError) Unwrap() error {
84+
// TODO: Implement error unwrapping
85+
return e.Err
86+
}
87+
88+
// Sentinel errors for common error conditions
89+
var (
90+
ErrInvalidFormat = errors.New("invalid data format")
91+
ErrMissingField = errors.New("required field missing")
92+
ErrProcessingFailed = errors.New("processing failed")
93+
ErrDestinationFull = errors.New("destination is full")
94+
)
95+
96+
// Pipeline orchestrates the data processing flow
97+
type Pipeline struct {
98+
Reader Reader
99+
Validators []Validator
100+
Transformers []Transformer
101+
Writer Writer
102+
}
103+
104+
// NewPipeline creates a new processing pipeline with specified components
105+
func NewPipeline(r Reader, v []Validator, t []Transformer, w Writer) *Pipeline {
106+
// TODO: Implement pipeline initialization
107+
if r == nil {
108+
return nil
109+
}
110+
if w == nil {
111+
return nil
112+
}
113+
return &Pipeline{
114+
Reader: r,
115+
Validators: v,
116+
Transformers: t,
117+
Writer: w,
118+
}
119+
}
120+
121+
// Process runs the complete pipeline
122+
func (p *Pipeline) Process(ctx context.Context) error {
123+
// TODO: Implement the complete pipeline process
124+
data, err := p.Reader.Read(ctx)
125+
if err != nil {
126+
return err
127+
}
128+
for _, validator := range p.Validators {
129+
if err = validator.Validate(data); err != nil {
130+
return err
131+
}
132+
}
133+
for _, transformer := range p.Transformers {
134+
if data, err = transformer.Transform(data); err != nil {
135+
return err
136+
}
137+
if data == nil {
138+
return errors.New("error while transform")
139+
}
140+
}
141+
142+
if err = p.Writer.Write(ctx, nil); err != nil {
143+
return err
144+
}
145+
146+
return nil
147+
}
148+
149+
// handleErrors consolidates errors from concurrent operations
150+
func (p *Pipeline) handleErrors(ctx context.Context, errs <-chan error) error {
151+
// TODO: Implement concurrent error handling
152+
for {
153+
select {
154+
case <-ctx.Done():
155+
return ctx.Err()
156+
case err, ok := <-errs:
157+
if !ok {
158+
return nil
159+
}
160+
if err != nil {
161+
return err
162+
}
163+
}
164+
}
165+
}
166+
167+
// FileReader implements the Reader interface for file sources
168+
type FileReader struct {
169+
Filename string
170+
}
171+
172+
// NewFileReader creates a new file reader
173+
func NewFileReader(filename string) *FileReader {
174+
// TODO: Implement file reader initialization
175+
return &FileReader{filename}
176+
}
177+
178+
// Read reads data from a file
179+
func (fr *FileReader) Read(ctx context.Context) ([]byte, error) {
180+
// TODO: Implement file reading with context support
181+
resultChan := make(chan []byte)
182+
errChan := make(chan error)
183+
184+
go func() {
185+
data, err := os.ReadFile(fr.Filename)
186+
if err != nil {
187+
errChan <- err
188+
return
189+
}
190+
resultChan <- data
191+
}()
192+
193+
select {
194+
case <-ctx.Done():
195+
return nil, ctx.Err()
196+
case err := <-errChan:
197+
return nil, err
198+
case data := <-resultChan:
199+
return data, nil
200+
}
201+
}
202+
203+
// JSONValidator implements the Validator interface for JSON validation
204+
type JSONValidator struct{}
205+
206+
// NewJSONValidator creates a new JSON validator
207+
func NewJSONValidator() *JSONValidator {
208+
// TODO: Implement JSON validator initialization
209+
return &JSONValidator{}
210+
}
211+
212+
// Validate validates JSON data
213+
func (jv *JSONValidator) Validate(data []byte) error {
214+
// TODO: Implement JSON validation
215+
if !json.Valid(data) {
216+
return ErrInvalidFormat
217+
}
218+
return nil
219+
}
220+
221+
// SchemaValidator implements the Validator interface for schema validation
222+
type SchemaValidator struct {
223+
Schema []byte
224+
}
225+
226+
// NewSchemaValidator creates a new schema validator
227+
func NewSchemaValidator(schema []byte) *SchemaValidator {
228+
// TODO: Implement schema validator initialization
229+
return &SchemaValidator{Schema: schema}
230+
}
231+
232+
// Validate validates data against a schema
233+
func (sv *SchemaValidator) Validate(data []byte) error {
234+
res := bytes.Equal(sv.Schema, data)
235+
if !res {
236+
return fmt.Errorf("%w: %s", ErrInvalidFormat, string(data))
237+
}
238+
return nil
239+
}
240+
241+
// FieldTransformer implements the Transformer interface for field transformations
242+
type FieldTransformer struct {
243+
FieldName string
244+
TransformFunc func(string) string
245+
}
246+
247+
// NewFieldTransformer creates a new field transformer
248+
func NewFieldTransformer(fieldName string, transformFunc func(string) string) *FieldTransformer {
249+
// TODO: Implement field transformer initialization
250+
return &FieldTransformer{fieldName, transformFunc}
251+
}
252+
253+
// Transform transforms a specific field in the data
254+
func (ft *FieldTransformer) Transform(data []byte) ([]byte, error) {
255+
payload := make(map[string]interface{})
256+
if err := json.Unmarshal(data, &payload); err != nil {
257+
return nil, err
258+
}
259+
260+
val, ok := payload[ft.FieldName]
261+
if !ok {
262+
return nil, fmt.Errorf("field '%s' not found in input", ft.FieldName)
263+
}
264+
265+
strVal, ok := val.(string)
266+
if !ok {
267+
return nil, errors.New("field value is not a string")
268+
}
269+
270+
payload[ft.FieldName] = ft.TransformFunc(strVal)
271+
data, err := json.Marshal(payload)
272+
if err != nil {
273+
return nil, err
274+
}
275+
276+
return data, nil
277+
}
278+
279+
// FileWriter implements the Writer interface for file destinations
280+
type FileWriter struct {
281+
Filename string
282+
}
283+
284+
// NewFileWriter creates a new file writer
285+
func NewFileWriter(filename string) *FileWriter {
286+
// TODO: Implement file writer initialization
287+
return &FileWriter{Filename: filename}
288+
}
289+
290+
// Write writes data to a file
291+
func (fw *FileWriter) Write(ctx context.Context, data []byte) error {
292+
err := os.WriteFile(fw.Filename, data, 0644)
293+
if err != nil {
294+
return err
295+
}
296+
return nil
297+
}

0 commit comments

Comments
 (0)