30
30
import org .slf4j .LoggerFactory ;
31
31
32
32
import java .util .HashMap ;
33
- import java .util .LinkedHashMap ;
33
+ import java .util .List ;
34
34
import java .util .Map ;
35
+ import java .util .stream .Collectors ;
35
36
36
37
public abstract class ChangeCase <R extends ConnectRecord <R >> extends BaseTransformation <R > {
37
38
private static final Logger log = LoggerFactory .getLogger (ChangeCase .class );
38
39
39
- class State {
40
- public final Map <String , String > columnMapping ;
41
- public final Schema schema ;
42
-
43
- State (Map <String , String > columnMapping , Schema schema ) {
44
- this .columnMapping = columnMapping ;
45
- this .schema = schema ;
46
- }
47
- }
48
-
49
40
private ChangeCaseConfig config ;
50
41
51
42
@ Override
@@ -63,39 +54,89 @@ public void configure(Map<String, ?> map) {
63
54
this .config = new ChangeCaseConfig (map );
64
55
}
65
56
66
- Map <Schema , State > schemaState = new HashMap <>();
57
+ Map <Schema , Schema > schemaState = new HashMap <>();
67
58
68
59
@ Override
69
60
protected SchemaAndValue processStruct (R record , Schema inputSchema , Struct input ) {
70
- final State state = this .schemaState .computeIfAbsent (inputSchema , schema -> {
71
- final SchemaBuilder builder = SchemaBuilder .struct ();
72
- if (!Strings .isNullOrEmpty (schema .name ())) {
73
- builder .name (schema .name ());
74
- }
75
- if (schema .isOptional ()) {
76
- builder .optional ();
77
- }
61
+ final Schema outputSchema = this .schemaState .computeIfAbsent (inputSchema , schema -> convertSchema (schema ));
62
+ final Struct outputStruct = convertStruct (inputSchema , outputSchema , input );
63
+ return new SchemaAndValue (outputSchema , outputStruct );
64
+ }
78
65
79
- final Map <String , String > columnMapping = new LinkedHashMap <>();
66
+ private Struct convertStruct (Schema inputSchema , Schema outputSchema , Struct input ) {
67
+ final Struct struct = new Struct (outputSchema );
68
+ for (Field inputField : inputSchema .fields ()) {
69
+ final int index = inputField .index ();
70
+ final Field outputField = outputSchema .fields ().get (index );
71
+ final Schema inputFieldSchema = inputField .schema ();
72
+ final Schema outputFieldSchema = outputField .schema ();
73
+ final Object value = convertValue (inputFieldSchema , outputFieldSchema , input .get (inputField ));
74
+ struct .put (outputField , value );
75
+ }
76
+ return struct ;
77
+ }
80
78
81
- for (Field field : schema .fields ()) {
82
- final String newFieldName = this .config .from .to (this .config .to , field .name ());
83
- log .trace ("processStruct() - Mapped '{}' to '{}'" , field .name (), newFieldName );
84
- columnMapping .put (field .name (), newFieldName );
85
- builder .field (newFieldName , field .schema ());
79
+ private Object convertValue (Schema inputFieldSchema , Schema outputFieldSchema , Object value ) {
80
+ switch (outputFieldSchema .type ()) {
81
+ case STRUCT : {
82
+ return convertStruct (inputFieldSchema , outputFieldSchema , (Struct ) value );
86
83
}
84
+ case ARRAY : {
85
+ return convertArray (inputFieldSchema , outputFieldSchema , (List <Object >) value );
86
+ }
87
+ }
88
+ return value ;
89
+ }
87
90
88
- return new State (columnMapping , builder .build ());
89
- });
90
-
91
- final Struct outputStruct = new Struct (state .schema );
92
-
93
- for (Map .Entry <String , String > kvp : state .columnMapping .entrySet ()) {
94
- final Object value = input .get (kvp .getKey ());
95
- outputStruct .put (kvp .getValue (), value );
91
+ private Object convertArray (Schema inputFieldSchema , Schema outputFieldSchema , List <Object > value ) {
92
+ final Schema inputSchema = inputFieldSchema .valueSchema ();
93
+ final Schema outputSchema = outputFieldSchema .valueSchema ();
94
+ switch (outputSchema .type ()) {
95
+ case STRUCT : {
96
+ return value .stream ().map (entry -> convertStruct (
97
+ inputSchema ,
98
+ outputSchema ,
99
+ (Struct ) entry
100
+ )).collect (Collectors .toList ());
101
+ }
102
+ case ARRAY : {
103
+ return value .stream ().map (entry -> convertArray (
104
+ inputSchema ,
105
+ outputSchema ,
106
+ (List <Object >) entry
107
+ )).collect (Collectors .toList ());
108
+ }
96
109
}
110
+ return value ;
111
+ }
97
112
98
- return new SchemaAndValue (state .schema , outputStruct );
113
+ private Schema convertSchema (Schema inputSchema ) {
114
+ switch (inputSchema .type ()) {
115
+ case ARRAY : {
116
+ log .trace ("convertSchema() - Recurse into array" );
117
+ final SchemaBuilder builder = SchemaBuilder .array (convertSchema (inputSchema .valueSchema ()));
118
+ if (inputSchema .isOptional ()) {
119
+ builder .optional ();
120
+ }
121
+ return builder .build ();
122
+ }
123
+ case STRUCT : {
124
+ final SchemaBuilder builder = SchemaBuilder .struct ();
125
+ if (!Strings .isNullOrEmpty (inputSchema .name ())) {
126
+ builder .name (inputSchema .name ());
127
+ }
128
+ if (inputSchema .isOptional ()) {
129
+ builder .optional ();
130
+ }
131
+ for (Field field : inputSchema .fields ()) {
132
+ final String newFieldName = this .config .from .to (this .config .to , field .name ());
133
+ log .trace ("convertSchema() - Mapped '{}' to '{}'" , field .name (), newFieldName );
134
+ builder .field (newFieldName , convertSchema (field .schema ()));
135
+ }
136
+ return builder .build ();
137
+ }
138
+ }
139
+ return inputSchema ;
99
140
}
100
141
101
142
@ Title ("ChangeCase(Key)" )
0 commit comments