embulk 0.8.35-java → 0.8.36-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -0
- data/build.gradle +1 -1
- data/embulk-cli/src/main/java/org/embulk/cli/EmbulkExample.java +5 -1
- data/embulk-cli/src/main/java/org/embulk/cli/EmbulkRun.java +12 -0
- data/embulk-core/src/main/java/org/embulk/EmbulkRunner.java +2 -2
- data/embulk-core/src/main/java/org/embulk/plugin/PluginClassLoader.java +802 -17
- data/embulk-core/src/main/java/org/embulk/plugin/PluginClassLoaderFactory.java +8 -1
- data/embulk-core/src/main/java/org/embulk/plugin/PluginClassLoaderModule.java +33 -2
- data/embulk-core/src/main/java/org/embulk/plugin/jar/JarPluginLoader.java +32 -5
- data/embulk-core/src/main/java/org/embulk/spi/ExecSession.java +1 -6
- data/embulk-core/src/main/java/org/embulk/spi/json/RubyValueApi.java +39 -1
- data/embulk-core/src/main/java/org/embulk/spi/time/Timestamp.java +21 -0
- data/embulk-core/src/main/java/org/embulk/spi/time/TimestampFormat.java +21 -0
- data/embulk-core/src/main/java/org/embulk/spi/util/DynamicColumnSetterFactory.java +43 -9
- data/embulk-core/src/main/java/org/embulk/spi/util/DynamicPageBuilder.java +46 -8
- data/embulk-core/src/main/java/org/embulk/spi/util/PagePrinter.java +19 -1
- data/embulk-core/src/main/java/org/embulk/spi/util/dynamic/AbstractDynamicColumnSetter.java +11 -0
- data/embulk-core/src/main/java/org/embulk/spi/util/dynamic/SkipColumnSetter.java +12 -1
- data/embulk-core/src/main/resources/embulk/parent_first_packages.properties +1 -0
- data/embulk-docs/build.gradle +8 -0
- data/embulk-docs/src/built-in.rst +47 -35
- data/embulk-docs/src/index.rst +9 -1
- data/embulk-docs/src/release.rst +1 -0
- data/embulk-docs/src/release/release-0.8.36.rst +32 -0
- data/embulk-standards/src/main/java/org/embulk/standards/CsvParserPlugin.java +22 -0
- data/embulk-standards/src/main/java/org/embulk/standards/CsvTokenizer.java +34 -1
- data/embulk-standards/src/main/java/org/embulk/standards/StdoutOutputPlugin.java +8 -2
- data/embulk-standards/src/test/java/org/embulk/standards/TestCsvTokenizer.java +76 -0
- data/lib/embulk/guess/schema_guess.rb +1 -1
- data/lib/embulk/input_plugin.rb +8 -1
- data/lib/embulk/page_builder.rb +38 -5
- data/lib/embulk/schema.rb +5 -6
- data/lib/embulk/version.rb +1 -1
- data/test/guess/test_schema_guess.rb +18 -0
- metadata +7 -6
@@ -5,5 +5,12 @@ import java.net.URL;
|
|
5
5
|
|
6
6
|
public interface PluginClassLoaderFactory
|
7
7
|
{
|
8
|
-
PluginClassLoader create(Collection<URL>
|
8
|
+
PluginClassLoader create(Collection<URL> flatJarUrls, ClassLoader parentClassLoader);
|
9
|
+
PluginClassLoader createForNestedJar(
|
10
|
+
final ClassLoader parentClassLoader,
|
11
|
+
final URL oneNestedJarUrl);
|
12
|
+
PluginClassLoader createForNestedJar(
|
13
|
+
final ClassLoader parentClassLoader,
|
14
|
+
final URL oneNestedJarUrl,
|
15
|
+
final Collection<String> embeddedJarPathsInNestedJar);
|
9
16
|
}
|
@@ -61,10 +61,41 @@ public class PluginClassLoaderModule
|
|
61
61
|
|
62
62
|
private class Factory implements PluginClassLoaderFactory
|
63
63
|
{
|
64
|
+
@Override
|
64
65
|
public PluginClassLoader create(Collection<URL> urls, ClassLoader parentClassLoader)
|
65
66
|
{
|
66
|
-
return
|
67
|
-
|
67
|
+
return PluginClassLoader.createForFlatJars(
|
68
|
+
parentClassLoader,
|
69
|
+
urls,
|
70
|
+
parentFirstPackages,
|
71
|
+
parentFirstResources);
|
72
|
+
}
|
73
|
+
|
74
|
+
@Override
|
75
|
+
public PluginClassLoader createForNestedJar(
|
76
|
+
final ClassLoader parentClassLoader,
|
77
|
+
final URL oneNestedJarUrl)
|
78
|
+
{
|
79
|
+
return PluginClassLoader.createForNestedJar(
|
80
|
+
parentClassLoader,
|
81
|
+
oneNestedJarUrl,
|
82
|
+
null,
|
83
|
+
parentFirstPackages,
|
84
|
+
parentFirstResources);
|
85
|
+
}
|
86
|
+
|
87
|
+
@Override
|
88
|
+
public PluginClassLoader createForNestedJar(
|
89
|
+
final ClassLoader parentClassLoader,
|
90
|
+
final URL oneNestedJarUrl,
|
91
|
+
final Collection<String> embeddedJarPathsInNestedJar)
|
92
|
+
{
|
93
|
+
return PluginClassLoader.createForNestedJar(
|
94
|
+
parentClassLoader,
|
95
|
+
oneNestedJarUrl,
|
96
|
+
embeddedJarPathsInNestedJar,
|
97
|
+
parentFirstPackages,
|
98
|
+
parentFirstResources);
|
68
99
|
}
|
69
100
|
}
|
70
101
|
}
|
@@ -1,6 +1,5 @@
|
|
1
1
|
package org.embulk.plugin.jar;
|
2
2
|
|
3
|
-
import com.google.common.collect.ImmutableList;
|
4
3
|
import java.io.IOError;
|
5
4
|
import java.io.IOException;
|
6
5
|
import java.net.JarURLConnection;
|
@@ -8,6 +7,9 @@ import java.net.MalformedURLException;
|
|
8
7
|
import java.net.URI;
|
9
8
|
import java.net.URL;
|
10
9
|
import java.nio.file.Path;
|
10
|
+
import java.util.ArrayList;
|
11
|
+
import java.util.Collections;
|
12
|
+
import java.util.List;
|
11
13
|
import java.util.jar.Attributes;
|
12
14
|
import java.util.jar.Manifest;
|
13
15
|
import org.embulk.plugin.PluginClassLoader;
|
@@ -24,6 +26,7 @@ public class JarPluginLoader
|
|
24
26
|
{
|
25
27
|
public static final String MANIFEST_PLUGIN_MAIN_CLASS = "Embulk-Plugin-Main-Class";
|
26
28
|
public static final String MANIFEST_PLUGIN_SPI_VERSION = "Embulk-Plugin-Spi-Version";
|
29
|
+
public static final String MANIFEST_PLUGIN_CLASS_PATH = "Embulk-Plugin-Class-Path";
|
27
30
|
|
28
31
|
private JarPluginLoader(final Manifest pluginManifest,
|
29
32
|
final Attributes pluginManifestAttributes,
|
@@ -44,7 +47,8 @@ public class JarPluginLoader
|
|
44
47
|
|
45
48
|
if (spiVersion == 0) {
|
46
49
|
final String mainClassName = getPluginMainClassNameFromManifest(manifestAttributes);
|
47
|
-
final
|
50
|
+
final List<String> pluginClassPath = getPluginClassPathFromManifest(manifestAttributes);
|
51
|
+
final Class mainClass = loadJarPluginMainClass(jarPath, mainClassName, pluginClassPath, classLoaderFactory);
|
48
52
|
return new JarPluginLoader(manifest, manifestAttributes, mainClass);
|
49
53
|
}
|
50
54
|
|
@@ -108,6 +112,7 @@ public class JarPluginLoader
|
|
108
112
|
|
109
113
|
private static Class loadJarPluginMainClass(final Path jarPath,
|
110
114
|
final String pluginMainClassName,
|
115
|
+
final List<String> pluginClassPath,
|
111
116
|
final PluginClassLoaderFactory pluginClassLoaderFactory)
|
112
117
|
throws InvalidJarPluginException
|
113
118
|
{
|
@@ -138,9 +143,15 @@ public class JarPluginLoader
|
|
138
143
|
throw new InvalidJarPluginException("JAR plugin path specified is invalid: " + jarPath.toString(), ex);
|
139
144
|
}
|
140
145
|
|
141
|
-
|
142
|
-
|
143
|
-
pluginClassLoaderFactory.
|
146
|
+
final PluginClassLoader pluginClassLoader;
|
147
|
+
if (pluginClassPath.isEmpty()) {
|
148
|
+
pluginClassLoader = pluginClassLoaderFactory.createForNestedJar(
|
149
|
+
JarPluginLoader.class.getClassLoader(), fileUrlJar);
|
150
|
+
}
|
151
|
+
else {
|
152
|
+
pluginClassLoader = pluginClassLoaderFactory.createForNestedJar(
|
153
|
+
JarPluginLoader.class.getClassLoader(), fileUrlJar, pluginClassPath);
|
154
|
+
}
|
144
155
|
|
145
156
|
final Class pluginMainClass;
|
146
157
|
try {
|
@@ -185,6 +196,22 @@ public class JarPluginLoader
|
|
185
196
|
return pluginMainClassName;
|
186
197
|
}
|
187
198
|
|
199
|
+
private static List<String> getPluginClassPathFromManifest(final Attributes manifestAttributes)
|
200
|
+
throws InvalidJarPluginException
|
201
|
+
{
|
202
|
+
final String pluginClassPathJoined = getAttributeFromManifest(manifestAttributes, MANIFEST_PLUGIN_CLASS_PATH);
|
203
|
+
|
204
|
+
if (pluginClassPathJoined == null) {
|
205
|
+
return Collections.<String>emptyList();
|
206
|
+
}
|
207
|
+
|
208
|
+
final List<String> pluginClassPath = new ArrayList<String>();
|
209
|
+
for (final String splitPluginClassPath : pluginClassPathJoined.split(" +", 0)) {
|
210
|
+
pluginClassPath.add(splitPluginClassPath);
|
211
|
+
}
|
212
|
+
return pluginClassPath;
|
213
|
+
}
|
214
|
+
|
188
215
|
private static String getAttributeFromManifest(final Attributes manifestAttributes, final String attributeName)
|
189
216
|
throws InvalidJarPluginException
|
190
217
|
{
|
@@ -20,7 +20,6 @@ import org.embulk.plugin.PluginType;
|
|
20
20
|
import org.embulk.plugin.PluginManager;
|
21
21
|
import org.embulk.spi.time.Timestamp;
|
22
22
|
import org.embulk.spi.time.TimestampFormatter;
|
23
|
-
import org.embulk.spi.time.TimestampFormatter.FormatterTask;
|
24
23
|
|
25
24
|
public class ExecSession
|
26
25
|
{
|
@@ -201,11 +200,7 @@ public class ExecSession
|
|
201
200
|
|
202
201
|
public TimestampFormatter newTimestampFormatter(String format, DateTimeZone timezone)
|
203
202
|
{
|
204
|
-
|
205
|
-
config.set("timezone", timezone.getID());
|
206
|
-
// TODO: Stop creating the |FormatterTask| as |TimestampFormater.FormatterTask| is deprecated since v0.6.14.
|
207
|
-
FormatterTask formatterTask = config.loadConfig(FormatterTask.class);
|
208
|
-
return new TimestampFormatter(format, formatterTask.getTimeZone());
|
203
|
+
return new TimestampFormatter(format, timezone);
|
209
204
|
}
|
210
205
|
|
211
206
|
public TempFileSpace getTempFileSpace()
|
@@ -13,9 +13,24 @@ import org.jruby.runtime.builtin.IRubyObject;
|
|
13
13
|
import org.jruby.util.ByteList;
|
14
14
|
import org.jcodings.specific.ASCIIEncoding;
|
15
15
|
|
16
|
+
@Deprecated
|
16
17
|
public class RubyValueApi
|
17
18
|
{
|
19
|
+
@Deprecated
|
18
20
|
public static Value fromMessagePack(RubyString content)
|
21
|
+
{
|
22
|
+
if (!fromMessagePackDeprecationWarned) {
|
23
|
+
System.err.println("[WARN] Plugin uses deprecated org.embulk.spi.json.RubyValueApi.fromMessagePack");
|
24
|
+
System.err.println("[WARN] Report plugins in your config at: https://github.com/embulk/embulk/issues/802");
|
25
|
+
// The |fromMessagePackDeprecationWarned| flag is used only for warning messages.
|
26
|
+
// Even in case of race conditions, messages are just duplicated -- should be acceptable.
|
27
|
+
fromMessagePackDeprecationWarned = true;
|
28
|
+
}
|
29
|
+
|
30
|
+
return fromMessagePackInternal(content);
|
31
|
+
}
|
32
|
+
|
33
|
+
private static Value fromMessagePackInternal(RubyString content)
|
19
34
|
{
|
20
35
|
ByteList list = content.getByteList();
|
21
36
|
try {
|
@@ -40,8 +55,17 @@ public class RubyValueApi
|
|
40
55
|
}
|
41
56
|
}
|
42
57
|
|
58
|
+
@Deprecated
|
43
59
|
public static RubyString toMessagePack(Ruby runtime, Value value)
|
44
60
|
{
|
61
|
+
if (!toMessagePackDeprecationWarned) {
|
62
|
+
System.err.println("[WARN] Plugin uses deprecated org.embulk.spi.json.RubyValueApi.toMessagePack");
|
63
|
+
System.err.println("[WARN] Report plugins in your config at: https://github.com/embulk/embulk/issues/802");
|
64
|
+
// The |toMessagePackDeprecationWarned| flag is used only for warning messages.
|
65
|
+
// Even in case of race conditions, messages are just duplicated -- should be acceptable.
|
66
|
+
toMessagePackDeprecationWarned = true;
|
67
|
+
}
|
68
|
+
|
45
69
|
try {
|
46
70
|
MessageBufferPacker packer = MessagePack.newDefaultBufferPacker();
|
47
71
|
packer.packValue(value);
|
@@ -54,9 +78,23 @@ public class RubyValueApi
|
|
54
78
|
}
|
55
79
|
}
|
56
80
|
|
81
|
+
@Deprecated
|
57
82
|
public static Value toValue(Ruby runtime, IRubyObject object)
|
58
83
|
{
|
84
|
+
if (!toValueDeprecationWarned) {
|
85
|
+
System.err.println("[WARN] Plugin uses deprecated org.embulk.spi.json.RubyValueApi.toValue");
|
86
|
+
System.err.println("[WARN] Report plugins in your config at: https://github.com/embulk/embulk/issues/802");
|
87
|
+
// The |toValueDeprecationWarned| flag is used only for warning messages.
|
88
|
+
// Even in case of race conditions, messages are just duplicated -- should be acceptable.
|
89
|
+
toValueDeprecationWarned = true;
|
90
|
+
}
|
91
|
+
|
59
92
|
RubyString string = (RubyString) object.callMethod(runtime.getCurrentContext(), "to_msgpack");
|
60
|
-
return
|
93
|
+
return fromMessagePackInternal(string);
|
61
94
|
}
|
95
|
+
|
96
|
+
private static boolean fromMessagePackDeprecationWarned = false;
|
97
|
+
private static boolean toMessagePackDeprecationWarned = false;
|
98
|
+
private static boolean toValueDeprecationWarned = false;
|
99
|
+
|
62
100
|
}
|
@@ -88,15 +88,33 @@ public class Timestamp
|
|
88
88
|
}
|
89
89
|
}
|
90
90
|
|
91
|
+
@Deprecated
|
91
92
|
public RubyTime getRubyTime(Ruby runtime)
|
92
93
|
{
|
94
|
+
if (!getRubyTimeDeprecationWarned) {
|
95
|
+
System.err.println("[WARN] Plugin uses deprecated org.embulk.spi.time.Timestamp.getRubyTime");
|
96
|
+
System.err.println("[WARN] Report plugins in your config at: https://github.com/embulk/embulk/issues/820");
|
97
|
+
// The |getRubyTimeDeprecationWarned| flag is used only for warning messages.
|
98
|
+
// Even in case of race conditions, messages are just duplicated -- should be acceptable.
|
99
|
+
getRubyTimeDeprecationWarned = true;
|
100
|
+
}
|
101
|
+
|
93
102
|
RubyTime time = new RubyTime(runtime, runtime.getClass("Time"), new DateTime(toEpochMilli())).gmtime();
|
94
103
|
time.setNSec(nano % 1000000);
|
95
104
|
return time;
|
96
105
|
}
|
97
106
|
|
107
|
+
@Deprecated
|
98
108
|
public static Timestamp fromRubyTime(RubyTime time)
|
99
109
|
{
|
110
|
+
if (!fromRubyTimeDeprecationWarned) {
|
111
|
+
System.err.println("[WARN] Plugin uses deprecated org.embulk.spi.time.Timestamp.fromRubyTime");
|
112
|
+
System.err.println("[WARN] Report plugins in your config at: https://github.com/embulk/embulk/issues/820");
|
113
|
+
// The |fromRubyTimeDeprecationWarned| flag is used only for warning messages.
|
114
|
+
// Even in case of race conditions, messages are just duplicated -- should be acceptable.
|
115
|
+
fromRubyTimeDeprecationWarned = true;
|
116
|
+
}
|
117
|
+
|
100
118
|
long msec = time.getDateTime().getMillis();
|
101
119
|
long sec = msec / 1000;
|
102
120
|
long nsec = time.getNSec() + (msec % 1000) * 1000000;
|
@@ -156,4 +174,7 @@ public class Timestamp
|
|
156
174
|
|
157
175
|
return new Timestamp(seconds, nano);
|
158
176
|
}
|
177
|
+
|
178
|
+
private static boolean getRubyTimeDeprecationWarned = false;
|
179
|
+
private static boolean fromRubyTimeDeprecationWarned = false;
|
159
180
|
}
|
@@ -26,12 +26,30 @@ public class TimestampFormat
|
|
26
26
|
@Deprecated
|
27
27
|
public TimestampFormatter newFormatter(TimestampFormatter.FormatterTask task)
|
28
28
|
{
|
29
|
+
// NOTE: Its deprecation is not actually from ScriptingContainer, though.
|
30
|
+
// TODO: Notify users about deprecated calls through the notification reporter.
|
31
|
+
if (!newFormatterDeprecationWarned) {
|
32
|
+
System.err.println("[WARN] Plugin uses deprecated method org.embulk.spi.time.TimestampFormat.newFormatter");
|
33
|
+
System.err.println("[WARN] Report plugins in your config at: https://github.com/embulk/embulk/issues/828");
|
34
|
+
// The |newFormatterDeprecationWarned| flag is used only for warning messages.
|
35
|
+
// Even in case of race conditions, messages are just duplicated -- should be acceptable.
|
36
|
+
newFormatterDeprecationWarned = true;
|
37
|
+
}
|
29
38
|
return new TimestampFormatter(format, task.getTimeZone());
|
30
39
|
}
|
31
40
|
|
32
41
|
@Deprecated
|
33
42
|
public TimestampParser newParser(TimestampParser.ParserTask task)
|
34
43
|
{
|
44
|
+
// NOTE: Its deprecation is not actually from ScriptingContainer, though.
|
45
|
+
// TODO: Notify users about deprecated calls through the notification reporter.
|
46
|
+
if (!newParserDeprecationWarned) {
|
47
|
+
System.err.println("[WARN] Plugin uses deprecated method org.embulk.spi.time.TimestampFormat.newParser");
|
48
|
+
System.err.println("[WARN] Report plugins in your config at: https://github.com/embulk/embulk/issues/828");
|
49
|
+
// The |newParserDeprecationWarned| flag is used only for warning messages.
|
50
|
+
// Even in case of race conditions, messages are just duplicated -- should be acceptable.
|
51
|
+
newParserDeprecationWarned = true;
|
52
|
+
}
|
35
53
|
return new TimestampParser(format, task.getDefaultTimeZone());
|
36
54
|
}
|
37
55
|
|
@@ -69,6 +87,9 @@ public class TimestampFormat
|
|
69
87
|
}
|
70
88
|
}
|
71
89
|
|
90
|
+
private static boolean newFormatterDeprecationWarned = false;
|
91
|
+
private static boolean newParserDeprecationWarned = false;
|
92
|
+
|
72
93
|
//// Java standard TimeZone
|
73
94
|
//static TimeZone parseDateTimeZone(String s)
|
74
95
|
//{
|
@@ -24,17 +24,34 @@ import org.embulk.spi.Column;
|
|
24
24
|
import org.embulk.spi.PageBuilder;
|
25
25
|
import org.embulk.config.ConfigException;
|
26
26
|
|
27
|
-
|
27
|
+
class DynamicColumnSetterFactory
|
28
28
|
{
|
29
29
|
private final DefaultValueSetter defaultValue;
|
30
30
|
private final DynamicPageBuilder.BuilderTask task;
|
31
|
+
private final boolean useColumnForTimestampMetadata;
|
31
32
|
|
32
|
-
DynamicColumnSetterFactory(
|
33
|
-
DynamicPageBuilder.BuilderTask task,
|
34
|
-
DefaultValueSetter defaultValue
|
33
|
+
private DynamicColumnSetterFactory(
|
34
|
+
final DynamicPageBuilder.BuilderTask task,
|
35
|
+
final DefaultValueSetter defaultValue,
|
36
|
+
final boolean useColumnForTimestampMetadata)
|
35
37
|
{
|
36
38
|
this.defaultValue = defaultValue;
|
37
39
|
this.task = task;
|
40
|
+
this.useColumnForTimestampMetadata = useColumnForTimestampMetadata;
|
41
|
+
}
|
42
|
+
|
43
|
+
static DynamicColumnSetterFactory createWithTimestampMetadataFromBuilderTask(
|
44
|
+
final DynamicPageBuilder.BuilderTask task,
|
45
|
+
final DefaultValueSetter defaultValue)
|
46
|
+
{
|
47
|
+
return new DynamicColumnSetterFactory(task, defaultValue, false);
|
48
|
+
}
|
49
|
+
|
50
|
+
static DynamicColumnSetterFactory createWithTimestampMetadataFromColumn(
|
51
|
+
final DynamicPageBuilder.BuilderTask task,
|
52
|
+
final DefaultValueSetter defaultValue)
|
53
|
+
{
|
54
|
+
return new DynamicColumnSetterFactory(task, defaultValue, true);
|
38
55
|
}
|
39
56
|
|
40
57
|
public static DefaultValueSetter nullDefaultValue()
|
@@ -53,22 +70,29 @@ public class DynamicColumnSetterFactory
|
|
53
70
|
return new DoubleColumnSetter(pageBuilder, column, defaultValue);
|
54
71
|
} else if (type instanceof StringType) {
|
55
72
|
TimestampFormatter formatter = new TimestampFormatter(
|
56
|
-
|
73
|
+
getTimestampFormatForFormatter(column).getFormat(), getTimeZone(column));
|
57
74
|
return new StringColumnSetter(pageBuilder, column, defaultValue, formatter);
|
58
75
|
} else if (type instanceof TimestampType) {
|
59
76
|
// TODO use flexible time format like Ruby's Time.parse
|
60
|
-
TimestampParser parser
|
61
|
-
|
77
|
+
final TimestampParser parser;
|
78
|
+
if (this.useColumnForTimestampMetadata) {
|
79
|
+
final TimestampType timestampType = (TimestampType) type;
|
80
|
+
parser = new TimestampParser(timestampType.getFormat(), getTimeZone(column));
|
81
|
+
}
|
82
|
+
else {
|
83
|
+
parser = new TimestampParser(
|
84
|
+
getTimestampFormatForParser(column).getFormat(), getTimeZone(column));
|
85
|
+
}
|
62
86
|
return new TimestampColumnSetter(pageBuilder, column, defaultValue, parser);
|
63
87
|
} else if (type instanceof JsonType) {
|
64
88
|
TimestampFormatter formatter = new TimestampFormatter(
|
65
|
-
|
89
|
+
getTimestampFormatForFormatter(column).getFormat(), getTimeZone(column));
|
66
90
|
return new JsonColumnSetter(pageBuilder, column, defaultValue, formatter);
|
67
91
|
}
|
68
92
|
throw new ConfigException("Unknown column type: "+type);
|
69
93
|
}
|
70
94
|
|
71
|
-
private TimestampFormat
|
95
|
+
private TimestampFormat getTimestampFormatForFormatter(Column column)
|
72
96
|
{
|
73
97
|
DynamicPageBuilder.ColumnOption option = getColumnOption(column);
|
74
98
|
if (option != null) {
|
@@ -78,6 +102,16 @@ public class DynamicColumnSetterFactory
|
|
78
102
|
}
|
79
103
|
}
|
80
104
|
|
105
|
+
private TimestampFormat getTimestampFormatForParser(Column column)
|
106
|
+
{
|
107
|
+
DynamicPageBuilder.ColumnOption option = getColumnOption(column);
|
108
|
+
if (option != null) {
|
109
|
+
return option.getTimestampFormat();
|
110
|
+
} else {
|
111
|
+
return new TimestampFormat("%Y-%m-%d %H:%M:%S.%N");
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
81
115
|
private DateTimeZone getTimeZone(Column column)
|
82
116
|
{
|
83
117
|
DynamicPageBuilder.ColumnOption option = getColumnOption(column);
|
@@ -50,8 +50,10 @@ public class DynamicPageBuilder
|
|
50
50
|
public static interface ColumnOption
|
51
51
|
extends Task
|
52
52
|
{
|
53
|
+
// DynamicPageBuilder is used for inputs, then datetime parsing.
|
54
|
+
// Ruby's strptime does not accept numeric prefixes in specifiers such as "%6N".
|
53
55
|
@Config("timestamp_format")
|
54
|
-
@ConfigDefault("\"%Y-%m-%d %H:%M:%S.%
|
56
|
+
@ConfigDefault("\"%Y-%m-%d %H:%M:%S.%N\"")
|
55
57
|
public TimestampFormat getTimestampFormat();
|
56
58
|
|
57
59
|
@Config("timezone")
|
@@ -59,16 +61,14 @@ public class DynamicPageBuilder
|
|
59
61
|
public Optional<DateTimeZone> getTimeZone();
|
60
62
|
}
|
61
63
|
|
62
|
-
|
63
|
-
|
64
|
+
private DynamicPageBuilder(
|
65
|
+
final DynamicColumnSetterFactory factory,
|
66
|
+
final BufferAllocator allocator,
|
67
|
+
final Schema schema,
|
68
|
+
final PageOutput output)
|
64
69
|
{
|
65
70
|
this.pageBuilder = new PageBuilder(allocator, schema, output);
|
66
71
|
this.schema = schema;
|
67
|
-
|
68
|
-
// TODO configurable default value
|
69
|
-
DynamicColumnSetterFactory factory = new DynamicColumnSetterFactory(task,
|
70
|
-
DynamicColumnSetterFactory.nullDefaultValue());
|
71
|
-
|
72
72
|
ImmutableList.Builder<DynamicColumnSetter> setters = ImmutableList.builder();
|
73
73
|
ImmutableMap.Builder<String, DynamicColumnSetter> lookup = ImmutableMap.builder();
|
74
74
|
for (Column c : schema.getColumns()) {
|
@@ -80,6 +80,44 @@ public class DynamicPageBuilder
|
|
80
80
|
this.columnLookup = lookup.build();
|
81
81
|
}
|
82
82
|
|
83
|
+
@Deprecated // The static creator method "createWithTimestampMetadataFromBuilderTask" is preferred.
|
84
|
+
public DynamicPageBuilder(
|
85
|
+
BuilderTask task,
|
86
|
+
BufferAllocator allocator,
|
87
|
+
Schema schema,
|
88
|
+
PageOutput output)
|
89
|
+
{
|
90
|
+
this(DynamicColumnSetterFactory.createWithTimestampMetadataFromBuilderTask(
|
91
|
+
task, DynamicColumnSetterFactory.nullDefaultValue()), // TODO configurable default value
|
92
|
+
allocator,
|
93
|
+
schema,
|
94
|
+
output);
|
95
|
+
}
|
96
|
+
|
97
|
+
public static DynamicPageBuilder createWithTimestampMetadataFromBuilderTask(
|
98
|
+
BuilderTask task,
|
99
|
+
BufferAllocator allocator,
|
100
|
+
Schema schema,
|
101
|
+
PageOutput output)
|
102
|
+
{
|
103
|
+
// TODO configurable default value
|
104
|
+
DynamicColumnSetterFactory factory = DynamicColumnSetterFactory.createWithTimestampMetadataFromBuilderTask(
|
105
|
+
task, DynamicColumnSetterFactory.nullDefaultValue());
|
106
|
+
return new DynamicPageBuilder(factory, allocator, schema, output);
|
107
|
+
}
|
108
|
+
|
109
|
+
public static DynamicPageBuilder createWithTimestampMetadataFromColumn(
|
110
|
+
BuilderTask task,
|
111
|
+
BufferAllocator allocator,
|
112
|
+
Schema schema,
|
113
|
+
PageOutput output)
|
114
|
+
{
|
115
|
+
// TODO configurable default value
|
116
|
+
DynamicColumnSetterFactory factory = DynamicColumnSetterFactory.createWithTimestampMetadataFromColumn(
|
117
|
+
task, DynamicColumnSetterFactory.nullDefaultValue());
|
118
|
+
return new DynamicPageBuilder(factory, allocator, schema, output);
|
119
|
+
}
|
120
|
+
|
83
121
|
public List<Column> getColumns()
|
84
122
|
{
|
85
123
|
return schema.getColumns();
|