embulk-filter-typecast 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e8a2482d0bd6fc6109bb8763f9a1f9db6b0733db
4
- data.tar.gz: b80c4d01e823e3a4b59594002277fc78e1ee0ef9
3
+ metadata.gz: 0ced2804053187863055f59aa064418cd0b8d7aa
4
+ data.tar.gz: 447a4328482d178a479b404bfb7af62c61a2c1f3
5
5
  SHA512:
6
- metadata.gz: 7473b57b158d8936e14015358dcd21d3bfe852f0b7c33de10da4ad38aa4553b3ddf39e5b41c9ed11df32713c42a33506aba22820b2236590ab124035a1056783
7
- data.tar.gz: 354bf8ab52c2ee5ba124af046abea9e311213c4ebaa03991f432504cc87094a0e1d4815c3c94434ee843de836f6e2146331540fd23b286071c000011bb64c55a
6
+ metadata.gz: 2833a31678457b155864532d95de1af40594ffa7d5ffee4d489bcc4d993b444dacd18adbbcac444b2ad6b2fe85b2fbb837fa559abbdadd13010a98009894ec1d
7
+ data.tar.gz: f668410813b7109c96a6277b6ecd0b576334f74261f2c5ce5d941ddc0b6b6e2b4e84d4daeedde49b3a86abc140cc99481fa7a5a0e0b330a9494efccd0cd5eaaf
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ # 0.1.3 (2016-05-19)
2
+
3
+ Enhancements:
4
+
5
+ * Support JSONPath array wildcard
6
+
1
7
  # 0.1.2 (2016-04-28)
2
8
 
3
9
  Enhancements:
data/README.md CHANGED
@@ -19,6 +19,18 @@ A filter plugin for Embulk to cast column type.
19
19
 
20
20
  See [example.csv](./example/example.csv) and [example.yml](./example/example.yml).
21
21
 
22
+ ## JSONPath (like) name
23
+
24
+ For `type: json` column, you can specify [JSONPath](http://goessner.net/articles/JsonPath/) for column's name as:
25
+
26
+ ```
27
+ $.payload.key1
28
+ $.payload.array[0]
29
+ $.payload.array[*]
30
+ ```
31
+
32
+ NOTE: JSONPath syntax is not fully supported
33
+
22
34
  ## ToDo
23
35
 
24
36
  * Write test
data/build.gradle CHANGED
@@ -13,7 +13,7 @@ configurations {
13
13
  provided
14
14
  }
15
15
 
16
- version = "0.1.2"
16
+ version = "0.1.3"
17
17
  sourceCompatibility = 1.7
18
18
  targetCompatibility = 1.7
19
19
 
data/example/empty.yml ADDED
@@ -0,0 +1,24 @@
1
+ in:
2
+ type: file
3
+ path_prefix: example/example.csv
4
+ parser:
5
+ type: csv
6
+ charset: UTF-8
7
+ newline: CRLF
8
+ null_string: 'NULL'
9
+ skip_header_lines: 1
10
+ comment_line_marker: '#'
11
+ columns:
12
+ - {name: timestamp, type: timestamp, format: "%Y-%m-%d %H:%M:%S.%N", timezone: "+09:00"}
13
+ - {name: "null", type: string}
14
+ - {name: long, type: long}
15
+ - {name: string, type: string}
16
+ - {name: double, type: double}
17
+ - {name: json1, type: json}
18
+ - {name: json2, type: json}
19
+ - {name: ignore, type: timestamp, format: "%Y-%m-%d", timezone: "+09:00"}
20
+ - {name: boolean, type: boolean}
21
+ filters:
22
+ - type: typecast
23
+ out:
24
+ type: "null"
data/example/example.csv CHANGED
@@ -1,11 +1,11 @@
1
- timestamp,null,long,string,double,json1,json2,boolean
2
- 2015-07-13 00:00:00.100000,,90,l6lTsvxd,903.4,{"string":"0"},{"long":0},true
3
- 2015-07-13 00:00:00.100000,,91,XoALSEQg,394.5,{"string":"1"},{"long":1},true
4
- 2015-07-13 00:00:00.100000,,92,0hgDRI_m,810.9,{"string":"2"},{"long":2},true
5
- 2015-07-13 00:00:00.100000,,93,KjCRAc-A,477.4,{"string":"3"},{"long":3},true
6
- 2015-07-13 00:00:00.100000,,94,fyQVGlT8,725.3,{"string":"4"},{"long":4},true
7
- 2015-07-13 00:00:00.100000,,95,FpBYRPWK,316.6,{"string":"5"},{"long":5},false
8
- 2015-07-13 00:00:00.100000,,96,9ikvnUqp,369.5,{"string":"6"},{"long":6},false
9
- 2015-07-13 00:00:00.100000,,97,RRNYDAzK,506.5,{"string":"7"},{"long":7},false
10
- 2015-07-13 00:00:00.100000,,90,l6lTsvxd,903.4,{"string":"8"},{"long":8},false
11
- 2015-07-13 00:00:00.100000,,91,XoALSEQg,394.5,{"string":"9"},{"long":9},false
1
+ timestamp,null,long,string,double,json1,json2,array_str,array_int,ignore,boolean
2
+ 2015-07-13 00:00:00.100000,,90,l6lTsvxd,903.4,{"string":"0"},{"long":0},["0"],[0],2015-07-13,true
3
+ 2015-07-13 00:00:00.100000,,91,XoALSEQg,394.5,{"string":"1"},{"long":1},["1"],[1],2015-07-13,true
4
+ 2015-07-13 00:00:00.100000,,92,0hgDRI_m,810.9,{"string":"2"},{"long":2},["2"],[2],2015-07-13,true
5
+ 2015-07-13 00:00:00.100000,,93,KjCRAc-A,477.4,{"string":"3"},{"long":3},["3"],[3],2015-07-13,true
6
+ 2015-07-13 00:00:00.100000,,94,fyQVGlT8,725.3,{"string":"4"},{"long":4},["4"],[4],2015-07-13,true
7
+ 2015-07-13 00:00:00.100000,,95,FpBYRPWK,316.6,{"string":"5"},{"long":5},["5"],[5],2015-07-13,false
8
+ 2015-07-13 00:00:00.100000,,96,9ikvnUqp,369.5,{"string":"6"},{"long":6},["6"],[6],2015-07-13,false
9
+ 2015-07-13 00:00:00.100000,,97,RRNYDAzK,506.5,{"string":"7"},{"long":7},["7"],[7],2015-07-13,false
10
+ 2015-07-13 00:00:00.100000,,90,l6lTsvxd,903.4,{"string":"8"},{"long":8},["8"],[8],2015-07-13,false
11
+ 2015-07-13 00:00:00.100000,,91,XoALSEQg,394.5,{"string":"9"},{"long":9},["9"],[9],2015-07-13,false
data/example/example.yml CHANGED
@@ -16,6 +16,9 @@ in:
16
16
  - {name: double, type: double}
17
17
  - {name: json1, type: json}
18
18
  - {name: json2, type: json}
19
+ - {name: array_str, type: json}
20
+ - {name: array_int, type: json}
21
+ - {name: ignore, type: timestamp, format: "%Y-%m-%d", timezone: "+09:00"}
19
22
  - {name: boolean, type: boolean}
20
23
  filters:
21
24
  - type: typecast
@@ -29,5 +32,7 @@ filters:
29
32
  - {name: boolean, type: string}
30
33
  - {name: "$.json1.string", type: string}
31
34
  - {name: "$.json2.long", type: string}
35
+ - {name: "$.array_str[0]", type: long}
36
+ - {name: "$.array_int[*]", type: string}
32
37
  out:
33
38
  type: "null"
data/settings.gradle ADDED
@@ -0,0 +1 @@
1
+ rootProject.name = 'embulk-filter-typecast'
@@ -1,11 +1,15 @@
1
1
  package org.embulk.filter.typecast;
2
2
 
3
- import org.embulk.filter.typecast.cast.*;
4
-
3
+ import org.embulk.filter.typecast.TypecastFilterPlugin.ColumnConfig;
5
4
  import org.embulk.filter.typecast.TypecastFilterPlugin.PluginTask;
6
5
 
6
+ import org.embulk.filter.typecast.cast.BooleanCast;
7
+ import org.embulk.filter.typecast.cast.DoubleCast;
8
+ import org.embulk.filter.typecast.cast.JsonCast;
9
+ import org.embulk.filter.typecast.cast.LongCast;
10
+ import org.embulk.filter.typecast.cast.StringCast;
11
+ import org.embulk.filter.typecast.cast.TimestampCast;
7
12
  import org.embulk.spi.Column;
8
- import org.embulk.spi.DataException;
9
13
  import org.embulk.spi.Exec;
10
14
  import org.embulk.spi.PageBuilder;
11
15
  import org.embulk.spi.PageReader;
@@ -13,11 +17,19 @@ import org.embulk.spi.Schema;
13
17
  import org.embulk.spi.time.Timestamp;
14
18
  import org.embulk.spi.time.TimestampFormatter;
15
19
  import org.embulk.spi.time.TimestampParser;
16
- import org.embulk.spi.type.*;
20
+ import org.embulk.spi.type.BooleanType;
21
+ import org.embulk.spi.type.DoubleType;
22
+ import org.embulk.spi.type.JsonType;
23
+ import org.embulk.spi.type.LongType;
24
+ import org.embulk.spi.type.StringType;
25
+ import org.embulk.spi.type.TimestampType;
26
+ import org.embulk.spi.type.Type;
27
+ import org.joda.time.DateTimeZone;
17
28
  import org.msgpack.value.Value;
18
29
 
19
30
  import org.slf4j.Logger;
20
31
 
32
+ import java.util.HashMap;
21
33
 
22
34
  class ColumnCaster
23
35
  {
@@ -27,6 +39,8 @@ class ColumnCaster
27
39
  private final Schema outputSchema;
28
40
  private final PageReader pageReader;
29
41
  private final PageBuilder pageBuilder;
42
+ private final HashMap<String, TimestampParser> timestampParserMap = new HashMap<>();
43
+ private final HashMap<String, TimestampFormatter> timestampFormatterMap = new HashMap<>();
30
44
  private final JsonVisitor jsonVisitor;
31
45
 
32
46
  ColumnCaster(TypecastFilterPlugin.PluginTask task, Schema inputSchema, Schema outputSchema,
@@ -37,24 +51,78 @@ class ColumnCaster
37
51
  this.outputSchema = outputSchema;
38
52
  this.pageReader = pageReader;
39
53
  this.pageBuilder = pageBuilder;
54
+
55
+ buildTimestampParserMap();
56
+ buildTimestampFormatterMap();
40
57
  this.jsonVisitor = new JsonVisitor(task, inputSchema, outputSchema);
41
58
  }
42
59
 
43
- public void setFromBoolean(Column outputColumn, boolean value) {
60
+ private void buildTimestampParserMap()
61
+ {
62
+ // columnName => TimestampParser
63
+ for (ColumnConfig columnConfig : task.getColumns()) {
64
+ if (columnConfig.getName().startsWith("$.")) {
65
+ continue; // type: json columns do not support type: timestamp
66
+ }
67
+ Column inputColumn = inputSchema.lookupColumn(columnConfig.getName());
68
+ if (inputColumn.getType() instanceof StringType && columnConfig.getType() instanceof TimestampType) {
69
+ TimestampParser parser = getTimestampParser(columnConfig, task);
70
+ this.timestampParserMap.put(columnConfig.getName(), parser);
71
+ }
72
+ }
73
+ }
74
+
75
+ private void buildTimestampFormatterMap()
76
+ {
77
+ // columnName => TimestampFormatter
78
+ for (ColumnConfig columnConfig : task.getColumns()) {
79
+ if (columnConfig.getName().startsWith("$.")) {
80
+ continue; // type: json columns do not have type: timestamp
81
+ }
82
+ Column inputColumn = inputSchema.lookupColumn(columnConfig.getName());
83
+ if (inputColumn.getType() instanceof TimestampType && columnConfig.getType() instanceof StringType) {
84
+ TimestampFormatter parser = getTimestampFormatter(columnConfig, task);
85
+ this.timestampFormatterMap.put(columnConfig.getName(), parser);
86
+ }
87
+ }
88
+ }
89
+
90
+ private TimestampParser getTimestampParser(ColumnConfig columnConfig, PluginTask task)
91
+ {
92
+ DateTimeZone timezone = columnConfig.getTimeZone().or(task.getDefaultTimeZone());
93
+ String format = columnConfig.getFormat().or(task.getDefaultTimestampFormat());
94
+ return new TimestampParser(task.getJRuby(), format, timezone);
95
+ }
96
+
97
+ private TimestampFormatter getTimestampFormatter(ColumnConfig columnConfig, PluginTask task)
98
+ {
99
+ String format = columnConfig.getFormat().or(task.getDefaultTimestampFormat());
100
+ DateTimeZone timezone = columnConfig.getTimeZone().or(task.getDefaultTimeZone());
101
+ return new TimestampFormatter(task.getJRuby(), format, timezone);
102
+ }
103
+
104
+ public void setFromBoolean(Column outputColumn, boolean value)
105
+ {
44
106
  Type outputType = outputColumn.getType();
45
107
  if (outputType instanceof BooleanType) {
46
108
  pageBuilder.setBoolean(outputColumn, BooleanCast.asBoolean(value));
47
- } else if (outputType instanceof LongType) {
109
+ }
110
+ else if (outputType instanceof LongType) {
48
111
  pageBuilder.setLong(outputColumn, BooleanCast.asLong(value));
49
- } else if (outputType instanceof DoubleType) {
112
+ }
113
+ else if (outputType instanceof DoubleType) {
50
114
  pageBuilder.setDouble(outputColumn, BooleanCast.asDouble(value));
51
- } else if (outputType instanceof StringType) {
115
+ }
116
+ else if (outputType instanceof StringType) {
52
117
  pageBuilder.setString(outputColumn, BooleanCast.asString(value));
53
- } else if (outputType instanceof TimestampType) {
118
+ }
119
+ else if (outputType instanceof TimestampType) {
54
120
  pageBuilder.setTimestamp(outputColumn, BooleanCast.asTimestamp(value));
55
- } else if (outputType instanceof JsonType) {
121
+ }
122
+ else if (outputType instanceof JsonType) {
56
123
  pageBuilder.setJson(outputColumn, BooleanCast.asJson(value));
57
- } else {
124
+ }
125
+ else {
58
126
  assert (false);
59
127
  }
60
128
  }
@@ -64,86 +132,107 @@ class ColumnCaster
64
132
  Type outputType = outputColumn.getType();
65
133
  if (outputType instanceof BooleanType) {
66
134
  pageBuilder.setBoolean(outputColumn, LongCast.asBoolean(value));
67
- } else if (outputType instanceof LongType) {
135
+ }
136
+ else if (outputType instanceof LongType) {
68
137
  pageBuilder.setLong(outputColumn, LongCast.asLong(value));
69
- } else if (outputType instanceof DoubleType) {
138
+ }
139
+ else if (outputType instanceof DoubleType) {
70
140
  pageBuilder.setDouble(outputColumn, LongCast.asDouble(value));
71
- } else if (outputType instanceof StringType) {
141
+ }
142
+ else if (outputType instanceof StringType) {
72
143
  pageBuilder.setString(outputColumn, LongCast.asString(value));
73
- } else if (outputType instanceof TimestampType) {
144
+ }
145
+ else if (outputType instanceof TimestampType) {
74
146
  pageBuilder.setTimestamp(outputColumn, LongCast.asTimestamp(value));
75
- } else if (outputType instanceof JsonType) {
147
+ }
148
+ else if (outputType instanceof JsonType) {
76
149
  pageBuilder.setJson(outputColumn, LongCast.asJson(value));
77
- } else {
78
- assert(false);
150
+ }
151
+ else {
152
+ assert false;
79
153
  }
80
154
  }
81
155
 
82
156
  public void setFromDouble(Column outputColumn, double value)
83
157
  {
84
- try {
85
- Type outputType = outputColumn.getType();
86
- if (outputType instanceof BooleanType) {
87
- pageBuilder.setBoolean(outputColumn, DoubleCast.asBoolean(value));
88
- } else if (outputType instanceof LongType) {
89
- pageBuilder.setLong(outputColumn, DoubleCast.asLong(value));
90
- } else if (outputType instanceof DoubleType) {
91
- pageBuilder.setDouble(outputColumn, DoubleCast.asDouble(value));
92
- } else if (outputType instanceof StringType) {
93
- pageBuilder.setString(outputColumn, DoubleCast.asString(value));
94
- } else if (outputType instanceof TimestampType) {
95
- pageBuilder.setTimestamp(outputColumn, DoubleCast.asTimestamp(value));
96
- } else if (outputType instanceof JsonType) {
97
- pageBuilder.setJson(outputColumn, DoubleCast.asJson(value));
98
- } else {
99
- assert (false);
100
- }
158
+ Type outputType = outputColumn.getType();
159
+ if (outputType instanceof BooleanType) {
160
+ pageBuilder.setBoolean(outputColumn, DoubleCast.asBoolean(value));
101
161
  }
102
- catch (DataException ex) {
103
-
162
+ else if (outputType instanceof LongType) {
163
+ pageBuilder.setLong(outputColumn, DoubleCast.asLong(value));
164
+ }
165
+ else if (outputType instanceof DoubleType) {
166
+ pageBuilder.setDouble(outputColumn, DoubleCast.asDouble(value));
167
+ }
168
+ else if (outputType instanceof StringType) {
169
+ pageBuilder.setString(outputColumn, DoubleCast.asString(value));
170
+ }
171
+ else if (outputType instanceof TimestampType) {
172
+ pageBuilder.setTimestamp(outputColumn, DoubleCast.asTimestamp(value));
173
+ }
174
+ else if (outputType instanceof JsonType) {
175
+ pageBuilder.setJson(outputColumn, DoubleCast.asJson(value));
176
+ }
177
+ else {
178
+ assert false;
104
179
  }
105
180
  }
106
181
 
107
- public void setFromString(Column outputColumn, String value, TimestampParser timestampParser)
182
+ public void setFromString(Column outputColumn, String value)
108
183
  {
109
184
  Type outputType = outputColumn.getType();
110
185
  if (outputType instanceof BooleanType) {
111
186
  pageBuilder.setBoolean(outputColumn, StringCast.asBoolean(value));
112
- } else if (outputType instanceof LongType) {
187
+ }
188
+ else if (outputType instanceof LongType) {
113
189
  pageBuilder.setLong(outputColumn, StringCast.asLong(value));
114
- } else if (outputType instanceof DoubleType) {
190
+ }
191
+ else if (outputType instanceof DoubleType) {
115
192
  pageBuilder.setDouble(outputColumn, StringCast.asDouble(value));
116
- } else if (outputType instanceof StringType) {
193
+ }
194
+ else if (outputType instanceof StringType) {
117
195
  pageBuilder.setString(outputColumn, StringCast.asString(value));
118
- } else if (outputType instanceof TimestampType) {
196
+ }
197
+ else if (outputType instanceof TimestampType) {
198
+ TimestampParser timestampParser = timestampParserMap.get(outputColumn.getName());
119
199
  pageBuilder.setTimestamp(outputColumn, StringCast.asTimestamp(value, timestampParser));
120
- } else if (outputType instanceof JsonType) {
200
+ }
201
+ else if (outputType instanceof JsonType) {
121
202
  Value jsonValue = StringCast.asJson(value);
122
203
  String jsonPath = new StringBuilder("$.").append(outputColumn.getName()).toString();
123
204
  Value castedValue = jsonVisitor.visit(jsonPath, jsonValue);
124
205
  pageBuilder.setJson(outputColumn, castedValue);
125
- } else {
126
- assert(false);
206
+ }
207
+ else {
208
+ assert false;
127
209
  }
128
210
  }
129
211
 
130
- public void setFromTimestamp(Column outputColumn, Timestamp value, TimestampFormatter timestampFormatter)
212
+ public void setFromTimestamp(Column outputColumn, Timestamp value)
131
213
  {
132
214
  Type outputType = outputColumn.getType();
133
215
  if (outputType instanceof BooleanType) {
134
216
  pageBuilder.setBoolean(outputColumn, TimestampCast.asBoolean(value));
135
- } else if (outputType instanceof LongType) {
217
+ }
218
+ else if (outputType instanceof LongType) {
136
219
  pageBuilder.setLong(outputColumn, TimestampCast.asLong(value));
137
- } else if (outputType instanceof DoubleType) {
220
+ }
221
+ else if (outputType instanceof DoubleType) {
138
222
  pageBuilder.setDouble(outputColumn, TimestampCast.asDouble(value));
139
- } else if (outputType instanceof StringType) {
223
+ }
224
+ else if (outputType instanceof StringType) {
225
+ TimestampFormatter timestampFormatter = timestampFormatterMap.get(outputColumn.getName());
140
226
  pageBuilder.setString(outputColumn, TimestampCast.asString(value, timestampFormatter));
141
- } else if (outputType instanceof TimestampType) {
227
+ }
228
+ else if (outputType instanceof TimestampType) {
142
229
  pageBuilder.setTimestamp(outputColumn, TimestampCast.asTimestamp(value));
143
- } else if (outputType instanceof JsonType) {
230
+ }
231
+ else if (outputType instanceof JsonType) {
144
232
  pageBuilder.setJson(outputColumn, TimestampCast.asJson(value));
145
- } else {
146
- assert(false);
233
+ }
234
+ else {
235
+ assert false;
147
236
  }
148
237
  }
149
238
 
@@ -154,18 +243,24 @@ class ColumnCaster
154
243
  Type outputType = outputColumn.getType();
155
244
  if (outputType instanceof BooleanType) {
156
245
  pageBuilder.setBoolean(outputColumn, JsonCast.asBoolean(castedValue));
157
- } else if (outputType instanceof LongType) {
246
+ }
247
+ else if (outputType instanceof LongType) {
158
248
  pageBuilder.setLong(outputColumn, JsonCast.asLong(castedValue));
159
- } else if (outputType instanceof DoubleType) {
249
+ }
250
+ else if (outputType instanceof DoubleType) {
160
251
  pageBuilder.setDouble(outputColumn, JsonCast.asDouble(castedValue));
161
- } else if (outputType instanceof StringType) {
252
+ }
253
+ else if (outputType instanceof StringType) {
162
254
  pageBuilder.setString(outputColumn, JsonCast.asString(castedValue));
163
- } else if (outputType instanceof TimestampType) {
255
+ }
256
+ else if (outputType instanceof TimestampType) {
164
257
  pageBuilder.setTimestamp(outputColumn, JsonCast.asTimestamp(castedValue));
165
- } else if (outputType instanceof JsonType) {
258
+ }
259
+ else if (outputType instanceof JsonType) {
166
260
  pageBuilder.setJson(outputColumn, JsonCast.asJson(castedValue));
167
- } else {
168
- assert(false);
261
+ }
262
+ else {
263
+ assert false;
169
264
  }
170
265
  }
171
266
  }
@@ -1,21 +1,19 @@
1
1
  package org.embulk.filter.typecast;
2
2
 
3
- import org.embulk.spi.*;
4
- import org.embulk.spi.type.StringType;
5
- import org.embulk.spi.type.TimestampType;
6
-
7
- import org.embulk.filter.typecast.TypecastFilterPlugin.ColumnConfig;
8
3
  import org.embulk.filter.typecast.TypecastFilterPlugin.PluginTask;
9
4
 
10
- import org.embulk.spi.time.TimestampFormatter;
11
- import org.embulk.spi.time.TimestampParser;
12
- import org.joda.time.DateTimeZone;
5
+ import org.embulk.spi.Column;
6
+ import org.embulk.spi.ColumnVisitor;
7
+ import org.embulk.spi.DataException;
8
+ import org.embulk.spi.Exec;
9
+ import org.embulk.spi.PageBuilder;
10
+ import org.embulk.spi.PageReader;
11
+ import org.embulk.spi.Schema;
13
12
  import org.slf4j.Logger;
14
13
 
15
14
  import java.util.HashMap;
16
15
 
17
- public class ColumnVisitorImpl
18
- implements ColumnVisitor
16
+ class ColumnVisitorImpl implements ColumnVisitor
19
17
  {
20
18
  private static final Logger logger = Exec.getLogger(TypecastFilterPlugin.class);
21
19
  private final PluginTask task;
@@ -24,8 +22,6 @@ public class ColumnVisitorImpl
24
22
  private final PageReader pageReader;
25
23
  private final PageBuilder pageBuilder;
26
24
  private final HashMap<String, Column> outputColumnMap = new HashMap<>();
27
- private final HashMap<String, TimestampParser> timestampParserMap = new HashMap<>();
28
- private final HashMap<String, TimestampFormatter> timestampFormatterMap = new HashMap<>();
29
25
  private final ColumnCaster columnCaster;
30
26
 
31
27
  ColumnVisitorImpl(PluginTask task, Schema inputSchema, Schema outputSchema,
@@ -40,8 +36,6 @@ public class ColumnVisitorImpl
40
36
  this.columnCaster = new ColumnCaster(task, inputSchema, outputSchema, pageReader, pageBuilder);
41
37
 
42
38
  buildOutputColumnMap();
43
- buildTimestampParserMap();
44
- buildTimestampFormatterMap();
45
39
  }
46
40
 
47
41
  private void buildOutputColumnMap()
@@ -52,66 +46,26 @@ public class ColumnVisitorImpl
52
46
  }
53
47
  }
54
48
 
55
- private void buildTimestampParserMap()
56
- {
57
- // columnName => TimestampParser
58
- for (ColumnConfig columnConfig : task.getColumns()) {
59
- if (columnConfig.getName().startsWith("$.")) {
60
- continue; // type: json columns do not support type: timestamp
61
- }
62
- Column inputColumn = inputSchema.lookupColumn(columnConfig.getName());
63
- if (inputColumn.getType() instanceof StringType && columnConfig.getType() instanceof TimestampType) {
64
- TimestampParser parser = getTimestampParser(columnConfig, task);
65
- this.timestampParserMap.put(columnConfig.getName(), parser);
66
- }
67
- }
68
- }
69
-
70
- private void buildTimestampFormatterMap()
71
- {
72
- // columnName => TimestampFormatter
73
- for (ColumnConfig columnConfig : task.getColumns()) {
74
- if (columnConfig.getName().startsWith("$.")) {
75
- continue; // type: json columns do not have type: timestamp
76
- }
77
- Column inputColumn = inputSchema.lookupColumn(columnConfig.getName());
78
- if (inputColumn.getType() instanceof TimestampType && columnConfig.getType() instanceof StringType) {
79
- TimestampFormatter parser = getTimestampFormatter(columnConfig, task);
80
- this.timestampFormatterMap.put(columnConfig.getName(), parser);
81
- }
82
- }
83
- }
84
-
85
- private TimestampParser getTimestampParser(ColumnConfig columnConfig, PluginTask task)
86
- {
87
- DateTimeZone timezone = columnConfig.getTimeZone().or(task.getDefaultTimeZone());
88
- String format = columnConfig.getFormat().or(task.getDefaultTimestampFormat());
89
- return new TimestampParser(task.getJRuby(), format, timezone);
90
- }
91
-
92
- private TimestampFormatter getTimestampFormatter(ColumnConfig columnConfig, PluginTask task)
93
- {
94
- String format = columnConfig.getFormat().or(task.getDefaultTimestampFormat());
95
- DateTimeZone timezone = columnConfig.getTimeZone().or(task.getDefaultTimeZone());
96
- return new TimestampFormatter(task.getJRuby(), format, timezone);
97
- }
98
-
99
49
  private interface PageBuildable
100
50
  {
101
- public void run() throws DataException;
51
+ void run() throws DataException;
102
52
  }
103
53
 
104
- private void withStopOnInvalidRecord(final PageBuildable op, final Column inputColumn, final Column outputColumn) throws DataException {
54
+ private void withStopOnInvalidRecord(final PageBuildable op, final Column inputColumn, final Column outputColumn)
55
+ throws DataException
56
+ {
105
57
  if (pageReader.isNull(inputColumn)) {
106
58
  pageBuilder.setNull(outputColumn);
107
59
  }
108
60
  else {
109
61
  if (task.getStopOnInvalidRecord()) {
110
62
  op.run();
111
- } else {
63
+ }
64
+ else {
112
65
  try {
113
66
  op.run();
114
- } catch (final DataException ex) {
67
+ }
68
+ catch (final DataException ex) {
115
69
  logger.warn(ex.getMessage());
116
70
  pageBuilder.setNull(outputColumn);
117
71
  }
@@ -124,7 +78,8 @@ public class ColumnVisitorImpl
124
78
  {
125
79
  final Column outputColumn = outputColumnMap.get(inputColumn.getName());
126
80
  PageBuildable op = new PageBuildable() {
127
- public void run() throws DataException {
81
+ public void run() throws DataException
82
+ {
128
83
  columnCaster.setFromBoolean(outputColumn, pageReader.getBoolean(inputColumn));
129
84
  }
130
85
  };
@@ -136,7 +91,8 @@ public class ColumnVisitorImpl
136
91
  {
137
92
  final Column outputColumn = outputColumnMap.get(inputColumn.getName());
138
93
  PageBuildable op = new PageBuildable() {
139
- public void run() throws DataException {
94
+ public void run() throws DataException
95
+ {
140
96
  columnCaster.setFromLong(outputColumn, pageReader.getLong(inputColumn));
141
97
  }
142
98
  };
@@ -148,7 +104,8 @@ public class ColumnVisitorImpl
148
104
  {
149
105
  final Column outputColumn = outputColumnMap.get(inputColumn.getName());
150
106
  PageBuildable op = new PageBuildable() {
151
- public void run() throws DataException {
107
+ public void run() throws DataException
108
+ {
152
109
  columnCaster.setFromDouble(outputColumn, pageReader.getDouble(inputColumn));
153
110
  }
154
111
  };
@@ -159,10 +116,10 @@ public class ColumnVisitorImpl
159
116
  public void stringColumn(final Column inputColumn)
160
117
  {
161
118
  final Column outputColumn = outputColumnMap.get(inputColumn.getName());
162
- final TimestampParser timestampParser = timestampParserMap.get(inputColumn.getName());
163
119
  PageBuildable op = new PageBuildable() {
164
- public void run() throws DataException {
165
- columnCaster.setFromString(outputColumn, pageReader.getString(inputColumn), timestampParser);
120
+ public void run() throws DataException
121
+ {
122
+ columnCaster.setFromString(outputColumn, pageReader.getString(inputColumn));
166
123
  }
167
124
  };
168
125
  withStopOnInvalidRecord(op, inputColumn, outputColumn);
@@ -172,10 +129,10 @@ public class ColumnVisitorImpl
172
129
  public void timestampColumn(final Column inputColumn)
173
130
  {
174
131
  final Column outputColumn = outputColumnMap.get(inputColumn.getName());
175
- final TimestampFormatter timestampFormatter = timestampFormatterMap.get(inputColumn.getName());
176
132
  PageBuildable op = new PageBuildable() {
177
- public void run() throws DataException {
178
- columnCaster.setFromTimestamp(outputColumn, pageReader.getTimestamp(inputColumn), timestampFormatter);
133
+ public void run() throws DataException
134
+ {
135
+ columnCaster.setFromTimestamp(outputColumn, pageReader.getTimestamp(inputColumn));
179
136
  }
180
137
  };
181
138
  withStopOnInvalidRecord(op, inputColumn, outputColumn);
@@ -186,7 +143,8 @@ public class ColumnVisitorImpl
186
143
  {
187
144
  final Column outputColumn = outputColumnMap.get(inputColumn.getName());
188
145
  PageBuildable op = new PageBuildable() {
189
- public void run() throws DataException {
146
+ public void run() throws DataException
147
+ {
190
148
  columnCaster.setFromJson(outputColumn, pageReader.getJson(inputColumn));
191
149
  }
192
150
  };
@@ -1,34 +1,45 @@
1
1
  package org.embulk.filter.typecast;
2
2
 
3
- import org.embulk.filter.typecast.cast.*;
4
-
3
+ import org.embulk.filter.typecast.cast.BooleanCast;
4
+ import org.embulk.filter.typecast.cast.DoubleCast;
5
+ import org.embulk.filter.typecast.cast.LongCast;
6
+ import org.embulk.filter.typecast.cast.StringCast;
5
7
  import org.embulk.spi.DataException;
6
- import org.embulk.spi.type.*;
8
+ import org.embulk.spi.type.BooleanType;
9
+ import org.embulk.spi.type.DoubleType;
10
+ import org.embulk.spi.type.JsonType;
11
+ import org.embulk.spi.type.LongType;
12
+ import org.embulk.spi.type.StringType;
13
+ import org.embulk.spi.type.Type;
7
14
  import org.msgpack.value.BooleanValue;
8
- import org.msgpack.value.IntegerValue;
9
15
  import org.msgpack.value.FloatValue;
16
+ import org.msgpack.value.IntegerValue;
10
17
  import org.msgpack.value.StringValue;
11
18
  import org.msgpack.value.Value;
12
19
  import org.msgpack.value.ValueFactory;
13
20
 
14
21
  class JsonCaster
15
22
  {
16
- public JsonCaster()
17
- {
18
- }
23
+ public JsonCaster() {}
19
24
 
20
- public Value fromBoolean(Type outputType, BooleanValue value) {
25
+ public Value fromBoolean(Type outputType, BooleanValue value)
26
+ {
21
27
  if (outputType instanceof BooleanType) {
22
28
  return value;
23
- } else if (outputType instanceof LongType) {
29
+ }
30
+ else if (outputType instanceof LongType) {
24
31
  return ValueFactory.newInteger(BooleanCast.asLong(value.getBoolean()));
25
- } else if (outputType instanceof DoubleType) {
32
+ }
33
+ else if (outputType instanceof DoubleType) {
26
34
  return ValueFactory.newFloat(BooleanCast.asDouble(value.getBoolean()));
27
- } else if (outputType instanceof StringType) {
35
+ }
36
+ else if (outputType instanceof StringType) {
28
37
  return ValueFactory.newString(BooleanCast.asString(value.getBoolean()));
29
- } else if (outputType instanceof JsonType) {
38
+ }
39
+ else if (outputType instanceof JsonType) {
30
40
  throw new DataException(String.format("cannot cast boolean to json: \"%s\"", value));
31
- } else {
41
+ }
42
+ else {
32
43
  assert (false);
33
44
  return null;
34
45
  }
@@ -38,16 +49,21 @@ class JsonCaster
38
49
  {
39
50
  if (outputType instanceof BooleanType) {
40
51
  return ValueFactory.newBoolean(LongCast.asBoolean(value.asLong()));
41
- } else if (outputType instanceof LongType) {
52
+ }
53
+ else if (outputType instanceof LongType) {
42
54
  return value;
43
- } else if (outputType instanceof DoubleType) {
55
+ }
56
+ else if (outputType instanceof DoubleType) {
44
57
  return ValueFactory.newFloat(LongCast.asDouble(value.asLong()));
45
- } else if (outputType instanceof StringType) {
58
+ }
59
+ else if (outputType instanceof StringType) {
46
60
  return ValueFactory.newString(LongCast.asString(value.asLong()));
47
- } else if (outputType instanceof JsonType) {
61
+ }
62
+ else if (outputType instanceof JsonType) {
48
63
  throw new DataException(String.format("cannot cast long to json:: \"%s\"", value));
49
- } else {
50
- assert(false);
64
+ }
65
+ else {
66
+ assert false;
51
67
  return null;
52
68
  }
53
69
  }
@@ -56,15 +72,20 @@ class JsonCaster
56
72
  {
57
73
  if (outputType instanceof BooleanType) {
58
74
  return ValueFactory.newBoolean(DoubleCast.asBoolean(value.toDouble()));
59
- } else if (outputType instanceof LongType) {
75
+ }
76
+ else if (outputType instanceof LongType) {
60
77
  return ValueFactory.newInteger(DoubleCast.asLong(value.toDouble()));
61
- } else if (outputType instanceof DoubleType) {
78
+ }
79
+ else if (outputType instanceof DoubleType) {
62
80
  return value;
63
- } else if (outputType instanceof StringType) {
81
+ }
82
+ else if (outputType instanceof StringType) {
64
83
  return ValueFactory.newString(DoubleCast.asString(value.toDouble()));
65
- } else if (outputType instanceof JsonType) {
84
+ }
85
+ else if (outputType instanceof JsonType) {
66
86
  throw new DataException(String.format("cannot cast double to json:: \"%s\"", value));
67
- } else {
87
+ }
88
+ else {
68
89
  assert (false);
69
90
  return null;
70
91
  }
@@ -74,16 +95,21 @@ class JsonCaster
74
95
  {
75
96
  if (outputType instanceof BooleanType) {
76
97
  return ValueFactory.newBoolean(StringCast.asBoolean(value.asString()));
77
- } else if (outputType instanceof LongType) {
98
+ }
99
+ else if (outputType instanceof LongType) {
78
100
  return ValueFactory.newInteger(StringCast.asLong(value.asString()));
79
- } else if (outputType instanceof DoubleType) {
101
+ }
102
+ else if (outputType instanceof DoubleType) {
80
103
  return ValueFactory.newFloat(StringCast.asDouble(value.asString()));
81
- } else if (outputType instanceof StringType) {
104
+ }
105
+ else if (outputType instanceof StringType) {
82
106
  return value;
83
- } else if (outputType instanceof JsonType) {
107
+ }
108
+ else if (outputType instanceof JsonType) {
84
109
  return StringCast.asJson(value.asString());
85
- } else {
86
- assert(false);
110
+ }
111
+ else {
112
+ assert false;
87
113
  return null;
88
114
  }
89
115
  }
@@ -1,15 +1,16 @@
1
1
  package org.embulk.filter.typecast;
2
2
 
3
- import org.embulk.spi.*;
3
+ import org.embulk.filter.typecast.TypecastFilterPlugin.ColumnConfig;
4
+ import org.embulk.filter.typecast.TypecastFilterPlugin.PluginTask;
5
+
6
+ import org.embulk.spi.Exec;
7
+ import org.embulk.spi.Schema;
4
8
  import org.embulk.spi.type.Type;
5
9
  import org.msgpack.value.ArrayValue;
6
10
  import org.msgpack.value.MapValue;
7
11
  import org.msgpack.value.Value;
8
12
  import org.msgpack.value.ValueFactory;
9
13
 
10
- import org.embulk.filter.typecast.TypecastFilterPlugin.ColumnConfig;
11
- import org.embulk.filter.typecast.TypecastFilterPlugin.PluginTask;
12
-
13
14
  import org.slf4j.Logger;
14
15
 
15
16
  import java.util.HashMap;
@@ -65,6 +66,7 @@ public class JsonVisitor
65
66
  partialPath.append(".").append(arrayParts[0]);
66
67
  this.shouldVisitSet.add(partialPath.toString());
67
68
  for (int j = 1; j < arrayParts.length; j++) {
69
+ // Supports both [0] and [*]
68
70
  partialPath.append("[").append(arrayParts[j]);
69
71
  this.shouldVisitSet.add(partialPath.toString());
70
72
  }
@@ -93,6 +95,9 @@ public class JsonVisitor
93
95
  Value[] newValue = new Value[size];
94
96
  for (int i = 0; i < size; i++) {
95
97
  String k = new StringBuilder(jsonPath).append("[").append(Integer.toString(i)).append("]").toString();
98
+ if (!shouldVisit(k)) {
99
+ k = new StringBuilder(jsonPath).append("[*]").toString(); // try [*] too
100
+ }
96
101
  Value v = arrayValue.get(i);
97
102
  newValue[i] = visit(k, v);
98
103
  }
@@ -10,11 +10,14 @@ import org.embulk.config.ConfigSource;
10
10
  import org.embulk.config.Task;
11
11
  import org.embulk.config.TaskSource;
12
12
 
13
- import org.embulk.spi.*;
14
- import org.embulk.spi.time.Timestamp;
15
- import org.embulk.spi.time.TimestampFormatter;
16
- import org.embulk.spi.time.TimestampParser;
17
-
13
+ import org.embulk.spi.Column;
14
+ import org.embulk.spi.Exec;
15
+ import org.embulk.spi.FilterPlugin;
16
+ import org.embulk.spi.Page;
17
+ import org.embulk.spi.PageBuilder;
18
+ import org.embulk.spi.PageOutput;
19
+ import org.embulk.spi.PageReader;
20
+ import org.embulk.spi.Schema;
18
21
  import org.embulk.spi.type.TimestampType;
19
22
  import org.embulk.spi.type.Type;
20
23
  import org.joda.time.DateTimeZone;
@@ -59,7 +62,6 @@ public class TypecastFilterPlugin implements FilterPlugin
59
62
  @ConfigDefault("false")
60
63
  Boolean getStopOnInvalidRecord();
61
64
 
62
-
63
65
  @Config("default_timezone")
64
66
  @ConfigDefault("\"UTC\"")
65
67
  public DateTimeZone getDefaultTimeZone();
@@ -91,7 +93,8 @@ public class TypecastFilterPlugin implements FilterPlugin
91
93
  String name = columnConfig.getName();
92
94
  if (name.startsWith("$.")) { // check only top level column name
93
95
  String firstName = name.split("\\.", 3)[1];
94
- inputSchema.lookupColumn(firstName);
96
+ String firstNameWithoutArray = firstName.split("\\[")[0];
97
+ inputSchema.lookupColumn(firstNameWithoutArray);
95
98
  }
96
99
  else {
97
100
  inputSchema.lookupColumn(name);
@@ -137,7 +140,7 @@ public class TypecastFilterPlugin implements FilterPlugin
137
140
 
138
141
  @Override
139
142
  public PageOutput open(final TaskSource taskSource, final Schema inputSchema,
140
- final Schema outputSchema, final PageOutput output)
143
+ final Schema outputSchema, final PageOutput output)
141
144
  {
142
145
  final PluginTask task = taskSource.loadTask(PluginTask.class);
143
146
 
@@ -1,13 +1,16 @@
1
1
  package org.embulk.filter.typecast.cast;
2
2
 
3
- import org.embulk.spi.time.Timestamp;
4
3
  import org.embulk.spi.DataException;
4
+ import org.embulk.spi.time.Timestamp;
5
5
  import org.msgpack.value.Value;
6
6
 
7
- public class BooleanCast {
7
+ public class BooleanCast
8
+ {
9
+ private BooleanCast() {}
10
+
8
11
  private static String buildErrorMessage(String as, boolean value)
9
12
  {
10
- return String.format("cannot cast double to %s: \"%s\"", as, value);
13
+ return String.format("cannot cast boolean to %s: \"%s\"", as, value);
11
14
  }
12
15
 
13
16
  public static boolean asBoolean(boolean value) throws DataException
@@ -1,10 +1,13 @@
1
1
  package org.embulk.filter.typecast.cast;
2
2
 
3
- import org.embulk.spi.time.Timestamp;
4
3
  import org.embulk.spi.DataException;
4
+ import org.embulk.spi.time.Timestamp;
5
5
  import org.msgpack.value.Value;
6
6
 
7
- public class DoubleCast {
7
+ public class DoubleCast
8
+ {
9
+ private DoubleCast() {}
10
+
8
11
  private static String buildErrorMessage(String as, double value)
9
12
  {
10
13
  return String.format("cannot cast double to %s: \"%s\"", as, value);
@@ -17,7 +20,7 @@ public class DoubleCast {
17
20
 
18
21
  public static long asLong(double value) throws DataException
19
22
  {
20
- return (long)value;
23
+ return (long) value;
21
24
  }
22
25
 
23
26
  public static double asDouble(double value) throws DataException
@@ -37,7 +40,7 @@ public class DoubleCast {
37
40
 
38
41
  public static Timestamp asTimestamp(double value) throws DataException
39
42
  {
40
- long epochSecond = (long)value;
43
+ long epochSecond = (long) value;
41
44
  long nanoAdjustMent = (long) ((value - epochSecond) * 1000000000);
42
45
  return Timestamp.ofEpochSecond(epochSecond, nanoAdjustMent);
43
46
  }
@@ -4,10 +4,13 @@ import org.embulk.spi.DataException;
4
4
  import org.embulk.spi.time.Timestamp;
5
5
  import org.msgpack.value.Value;
6
6
 
7
- public class JsonCast {
7
+ public class JsonCast
8
+ {
9
+ private JsonCast() {}
10
+
8
11
  private static String buildErrorMessage(String as, Value value)
9
12
  {
10
- return String.format("cannot cast String to %s: \"%s\"", as, value);
13
+ return String.format("cannot cast Json to %s: \"%s\"", as, value);
11
14
  }
12
15
 
13
16
  public static boolean asBoolean(Value value) throws DataException
@@ -1,10 +1,13 @@
1
1
  package org.embulk.filter.typecast.cast;
2
2
 
3
- import org.embulk.spi.time.Timestamp;
4
3
  import org.embulk.spi.DataException;
4
+ import org.embulk.spi.time.Timestamp;
5
5
  import org.msgpack.value.Value;
6
6
 
7
- public class LongCast {
7
+ public class LongCast
8
+ {
9
+ private LongCast() {}
10
+
8
11
  private static String buildErrorMessage(String as, long value)
9
12
  {
10
13
  return String.format("cannot cast long to %s: \"%s\"", as, value);
@@ -30,7 +33,7 @@ public class LongCast {
30
33
 
31
34
  public static double asDouble(long value) throws DataException
32
35
  {
33
- return (double)value;
36
+ return (double) value;
34
37
  }
35
38
 
36
39
  public static String asString(long value) throws DataException
@@ -2,14 +2,15 @@ package org.embulk.filter.typecast.cast;
2
2
 
3
3
  import com.google.common.collect.ImmutableSet;
4
4
  import org.embulk.spi.DataException;
5
- import org.embulk.spi.json.JsonParser;
6
5
  import org.embulk.spi.json.JsonParseException;
6
+ import org.embulk.spi.json.JsonParser;
7
7
  import org.embulk.spi.time.Timestamp;
8
- import org.embulk.spi.time.TimestampParser;
9
8
  import org.embulk.spi.time.TimestampParseException;
9
+ import org.embulk.spi.time.TimestampParser;
10
10
  import org.msgpack.value.Value;
11
11
 
12
- public class StringCast {
12
+ public class StringCast
13
+ {
13
14
  private static final JsonParser jsonParser = new JsonParser();
14
15
 
15
16
  // copy from csv plugin
@@ -29,6 +30,7 @@ public class StringCast {
29
30
  "off", "Off", "OFF",
30
31
  "0");
31
32
 
33
+ private StringCast() {}
32
34
 
33
35
  private static String buildErrorMessage(String as, String value)
34
36
  {
@@ -5,7 +5,10 @@ import org.embulk.spi.time.Timestamp;
5
5
  import org.embulk.spi.time.TimestampFormatter;
6
6
  import org.msgpack.value.Value;
7
7
 
8
- public class TimestampCast {
8
+ public class TimestampCast
9
+ {
10
+ private TimestampCast() {}
11
+
9
12
  private static String buildErrorMessage(String as, Timestamp value)
10
13
  {
11
14
  return String.format("cannot cast Timestamp to %s: \"%s\"", as, value);
@@ -25,7 +28,7 @@ public class TimestampCast {
25
28
  {
26
29
  long epochSecond = value.getEpochSecond();
27
30
  long nano = value.getNano();
28
- return epochSecond + ((double)nano / 1000000000.0);
31
+ return epochSecond + ((double) nano / 1000000000.0);
29
32
  }
30
33
 
31
34
  public static String asString(Timestamp value, TimestampFormatter formatter) throws DataException
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: embulk-filter-typecast
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Naotoshi Seo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-28 00:00:00.000000000 Z
11
+ date: 2016-05-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,6 +52,7 @@ files:
52
52
  - README.md
53
53
  - build.gradle
54
54
  - config/checkstyle/checkstyle.xml
55
+ - example/empty.yml
55
56
  - example/example.csv
56
57
  - example/example.yml
57
58
  - example/example2.yml
@@ -60,6 +61,7 @@ files:
60
61
  - gradlew
61
62
  - gradlew.bat
62
63
  - lib/embulk/filter/typecast.rb
64
+ - settings.gradle
63
65
  - src/main/java/org/embulk/filter/typecast/ColumnCaster.java
64
66
  - src/main/java/org/embulk/filter/typecast/ColumnVisitorImpl.java
65
67
  - src/main/java/org/embulk/filter/typecast/JsonCaster.java
@@ -72,7 +74,7 @@ files:
72
74
  - src/main/java/org/embulk/filter/typecast/cast/StringCast.java
73
75
  - src/main/java/org/embulk/filter/typecast/cast/TimestampCast.java
74
76
  - src/test/java/org/embulk/filter/TestTypecastFilterPlugin.java
75
- - classpath/embulk-filter-typecast-0.1.2.jar
77
+ - classpath/embulk-filter-typecast-0.1.3.jar
76
78
  homepage: https://github.com/sonots/embulk-filter-typecast
77
79
  licenses:
78
80
  - MIT