embulk-input-postgresql 0.6.4 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b6b89fe67e85773011e8d1d3f4ae745ecbe13f36
4
- data.tar.gz: a2ab692201c8e013f217fc32b5229bad05dc2475
3
+ metadata.gz: a8a52d399d27705849e5c548b2a4a2e26d3f8db4
4
+ data.tar.gz: ae9c01752906c2132c4dea6acdd47e49cedae5ae
5
5
  SHA512:
6
- metadata.gz: c75a5dd2ad7b25a58d902b170e1a853be93e168b0699fa821a80e8068456a104d4aaf90348d7f15800e294e1e0bdcba22a8eda9d50aeb0a5b9a876cdee5a7d80
7
- data.tar.gz: 0514090f496d88be229ed4a2299dedb88c745be2028b03a364d45b4332fe377364e71ca15245936b9b6f14fe87c00fbb61b89b7f2f5dd41fa05c85609b0ebe44
6
+ metadata.gz: 97da962ac8166bfb6929fdd4c375d1e8c24348a4c9ae0fd865435cc68974b7acff222fa5617bcc3ccacc71afe74cea3710da423903290011233dc178e9c6e173
7
+ data.tar.gz: cdf01ea2f741ceea6948202d56e241cb05430af539bba10574afb3918bcef3329e855c5ee7ca66cf90a56c7392526e69e478b08600c51b979c023edb7b978b22
data/README.md CHANGED
@@ -29,13 +29,31 @@ PostgreSQL input plugins for Embulk loads records from PostgreSQL.
29
29
  - **default_timezone**: If the sql type of a column is `date`/`time`/`datetime` and the embulk type is `string`, column values are formatted int this default_timezone. You can overwrite timezone for each columns using column_options option. (string, default: `UTC`)
30
30
  - **column_options**: advanced: a key-value pairs where key is a column name and value is options for the column.
31
31
  - **value_type**: embulk get values from database as this value_type. Typically, the value_type determines `getXXX` method of `java.sql.PreparedStatement`.
32
- (string, default: depends on the sql type of the column. Available values options are: `long`, `double`, `float`, `decimal`, `boolean`, `string`, `date`, `time`, `timestamp`)
32
+ (string, default: depends on the sql type of the column. Available values options are: `long`, `double`, `float`, `decimal`, `boolean`, `string`, `json`, `date`, `time`, `timestamp`)
33
+ See below for `hstore` column.
33
34
  - **type**: Column values are converted to this embulk type.
34
- Available values options are: `boolean`, `long`, `double`, `string`, `timestamp`).
35
+ Available values options are: `boolean`, `long`, `double`, `string`, `json`, `timestamp`).
35
36
  By default, the embulk type is determined according to the sql type of the column (or value_type if specified).
37
+ See below for `hstore` column.
36
38
  - **timestamp_format**: If the sql type of the column is `date`/`time`/`datetime` and the embulk type is `string`, column values are formatted by this timestamp_format. And if the embulk type is `timestamp`, this timestamp_format may be used in the output plugin. For example, stdout plugin use the timestamp_format, but *csv formatter plugin doesn't use*. (string, default : `%Y-%m-%d` for `date`, `%H:%M:%S` for `time`, `%Y-%m-%d %H:%M:%S` for `timestamp`)
37
39
  - **timezone**: If the sql type of the column is `date`/`time`/`datetime` and the embulk type is `string`, column values are formatted in this timezone.
38
40
  (string, value of default_timezone option is used by default)
41
+ - **after_select**: if set, this SQL will be executed after the SELECT query in the same transaction.
42
+
43
+ ### hstore column support
44
+
45
+ By default, `type` of `column_options` for `hstore` column is `string`, and output will be as follows.
46
+ ```
47
+ "key1"=>"value1", "key2"=>"value2"
48
+ ```
49
+
50
+ In addition, `json` type is supported for `hstore` column, and output will be as follows.
51
+ ```
52
+ {"key1": "value1", "key2": "value2"}
53
+ ```
54
+
55
+ `value_type` is ignored.
56
+
39
57
 
40
58
  ## Example
41
59
 
@@ -82,6 +100,7 @@ in:
82
100
  column_options:
83
101
  col1: {type: long}
84
102
  col3: {type: string, timestamp_format: "%Y/%m/%d", timezone: "+0900"}
103
+ after_select: "update my_table set col5 = '1' where col4 != 'a'"
85
104
 
86
105
  ```
87
106
 
data/build.gradle CHANGED
@@ -3,5 +3,6 @@ dependencies {
3
3
 
4
4
  compile 'org.postgresql:postgresql:9.4-1205-jdbc41'
5
5
 
6
+ testCompile 'org.embulk:embulk-standards:0.8.8'
6
7
  testCompile project(':embulk-input-jdbc').sourceSets.test.output
7
8
  }
@@ -1,13 +1,20 @@
1
1
  package org.embulk.input;
2
2
 
3
+ import java.util.Map;
3
4
  import java.util.Properties;
4
5
  import java.sql.Connection;
5
6
  import java.sql.Driver;
6
7
  import java.sql.SQLException;
8
+
7
9
  import org.embulk.config.Config;
8
10
  import org.embulk.config.ConfigDefault;
9
11
  import org.embulk.input.jdbc.AbstractJdbcInputPlugin;
12
+ import org.embulk.input.jdbc.JdbcColumnOption;
13
+ import org.embulk.input.jdbc.getter.ColumnGetterFactory;
10
14
  import org.embulk.input.postgresql.PostgreSQLInputConnection;
15
+ import org.embulk.input.postgresql.getter.PostgreSQLColumnGetterFactory;
16
+ import org.embulk.spi.PageBuilder;
17
+ import org.joda.time.DateTimeZone;
11
18
 
12
19
  public class PostgreSQLInputPlugin
13
20
  extends AbstractJdbcInputPlugin
@@ -88,4 +95,10 @@ public class PostgreSQLInputPlugin
88
95
  }
89
96
  }
90
97
  }
98
+
99
+ @Override
100
+ protected ColumnGetterFactory newColumnGetterFactory(PageBuilder pageBuilder, DateTimeZone dateTimeZone)
101
+ {
102
+ return new PostgreSQLColumnGetterFactory(pageBuilder, dateTimeZone);
103
+ }
91
104
  }
@@ -0,0 +1,63 @@
1
+ package org.embulk.input.postgresql.getter;
2
+
3
+ import com.fasterxml.jackson.core.JsonProcessingException;
4
+ import com.fasterxml.jackson.databind.ObjectMapper;
5
+ import org.embulk.input.jdbc.getter.AbstractColumnGetter;
6
+ import org.embulk.spi.Column;
7
+ import org.embulk.spi.PageBuilder;
8
+ import org.embulk.spi.json.JsonParseException;
9
+ import org.embulk.spi.json.JsonParser;
10
+ import org.embulk.spi.type.Type;
11
+ import org.embulk.spi.type.Types;
12
+ import org.msgpack.value.Value;
13
+ import org.postgresql.util.HStoreConverter;
14
+
15
+ import java.sql.ResultSet;
16
+ import java.sql.SQLException;
17
+ import java.util.Map;
18
+
19
+ public class HstoreColumnGetter
20
+ extends AbstractColumnGetter
21
+ {
22
+ private final JsonParser parser = new JsonParser();
23
+ private final ObjectMapper mapper = new ObjectMapper();
24
+
25
+ private String value;
26
+
27
+ public HstoreColumnGetter(PageBuilder to, Type toType)
28
+ {
29
+ super(to, toType);
30
+ }
31
+
32
+ @Override
33
+ protected void fetch(ResultSet from, int fromIndex) throws SQLException
34
+ {
35
+ value = from.getString(fromIndex);
36
+ }
37
+
38
+ @Override
39
+ protected Type getDefaultToType()
40
+ {
41
+ return Types.STRING;
42
+ }
43
+
44
+ @Override
45
+ public void jsonColumn(Column column)
46
+ {
47
+ Value v;
48
+ try {
49
+ Map map = HStoreConverter.fromString(value);
50
+ v = parser.parse(mapper.writeValueAsString(map));
51
+ } catch (JsonProcessingException | JsonParseException e) {
52
+ super.jsonColumn(column);
53
+ return;
54
+ }
55
+ to.setJson(column, v);
56
+ }
57
+
58
+ @Override
59
+ public void stringColumn(Column column)
60
+ {
61
+ to.setString(column, value);
62
+ }
63
+ }
@@ -0,0 +1,36 @@
1
+ package org.embulk.input.postgresql.getter;
2
+
3
+ import org.embulk.input.jdbc.JdbcColumn;
4
+ import org.embulk.input.jdbc.JdbcColumnOption;
5
+ import org.embulk.input.jdbc.getter.ColumnGetter;
6
+ import org.embulk.input.jdbc.getter.ColumnGetterFactory;
7
+ import org.embulk.spi.PageBuilder;
8
+ import org.joda.time.DateTimeZone;
9
+
10
+ public class PostgreSQLColumnGetterFactory extends ColumnGetterFactory
11
+ {
12
+ public PostgreSQLColumnGetterFactory(PageBuilder to, DateTimeZone defaultTimeZone)
13
+ {
14
+ super(to, defaultTimeZone);
15
+ }
16
+
17
+ @Override
18
+ public ColumnGetter newColumnGetter(JdbcColumn column, JdbcColumnOption option)
19
+ {
20
+ if (column.getTypeName().equals("hstore")) {
21
+ return new HstoreColumnGetter(to, getToType(option));
22
+ } else {
23
+ return super.newColumnGetter(column, option);
24
+ }
25
+ }
26
+
27
+ @Override
28
+ protected String sqlTypeToValueType(JdbcColumn column, int sqlType)
29
+ {
30
+ if (column.getTypeName().equals("json") || column.getTypeName().equals("jsonb")) {
31
+ return "json";
32
+ } else {
33
+ return super.sqlTypeToValueType(column, sqlType);
34
+ }
35
+ }
36
+ }
@@ -0,0 +1,126 @@
1
+ package org.embulk.input.postgresql;
2
+
3
+ import static org.junit.Assert.assertEquals;
4
+
5
+ import java.io.BufferedReader;
6
+ import java.io.File;
7
+ import java.io.IOException;
8
+ import java.io.InputStreamReader;
9
+ import java.net.URISyntaxException;
10
+ import java.nio.charset.Charset;
11
+ import java.nio.file.FileSystem;
12
+ import java.nio.file.FileSystems;
13
+ import java.nio.file.Files;
14
+ import java.sql.Connection;
15
+ import java.sql.DriverManager;
16
+ import java.sql.Statement;
17
+ import java.util.Arrays;
18
+ import java.util.List;
19
+
20
+ import org.embulk.input.EmbulkPluginTester;
21
+ import org.embulk.input.PostgreSQLInputPlugin;
22
+ import org.embulk.spi.InputPlugin;
23
+ import org.junit.AfterClass;
24
+ import org.junit.BeforeClass;
25
+ import org.junit.Test;
26
+
27
+ public class PostgreSQLInputPluginTest
28
+ {
29
+ private static final String DATABASE = "test_db";
30
+ private static final String USER = "test_user";
31
+ private static final String PASSWORD = "test_pw";
32
+ private static final String URL = "jdbc:postgresql://localhost:5432/" + DATABASE;
33
+
34
+ private static boolean prepared = false;
35
+ private static EmbulkPluginTester tester = new EmbulkPluginTester(InputPlugin.class, "postgresql", PostgreSQLInputPlugin.class);
36
+
37
+ @BeforeClass
38
+ public static void prepare() throws Exception
39
+ {
40
+ try {
41
+ // Create User and Database
42
+ psql(String.format("DROP DATABASE IF EXISTS %s;", DATABASE));
43
+ psql(String.format("DROP USER IF EXISTS %s;", USER));
44
+ psql(String.format("CREATE USER %s WITH SUPERUSER PASSWORD '%s';", USER, PASSWORD));
45
+ psql(String.format("CREATE DATABASE %s WITH OWNER %s;", DATABASE, USER));
46
+ } catch (IOException e) {
47
+ System.err.println(e);
48
+ System.err.println("Warning: cannot prepare a database for testing embulk-input-postgresql.");
49
+ // 1. install postgresql.
50
+ // 2. add bin directory to path.
51
+ // 3. set environment variable PGPASSWORD
52
+ return;
53
+ }
54
+
55
+ prepared = true;
56
+
57
+ // Insert Data
58
+ try(Connection connection = DriverManager.getConnection(URL, USER, PASSWORD)) {
59
+ try (Statement statement = connection.createStatement()) {
60
+ String sql = "";
61
+ sql += "DROP TABLE IF EXISTS input_hstore;";
62
+ sql += "CREATE EXTENSION IF NOT EXISTS hstore WITH SCHEMA public;";
63
+ sql += "CREATE TABLE input_hstore (c1 hstore);";
64
+ sql += "INSERT INTO input_hstore (c1) VALUES('\"a\" => \"b\"');";
65
+ statement.execute(sql);
66
+ }
67
+ }
68
+ }
69
+
70
+ @AfterClass
71
+ public static void dispose()
72
+ {
73
+ tester.destroy();
74
+ }
75
+
76
+ @Test
77
+ public void testHstoreAsString() throws Exception
78
+ {
79
+ if (prepared) {
80
+ tester.run(convertPath("/yml/input_hstore.yml"));
81
+ assertEquals(Arrays.asList("c1", "\"\"\"a\"\"=>\"\"b\"\"\""),
82
+ read("postgresql-input000.00.csv"));
83
+ }
84
+ }
85
+
86
+ @Test
87
+ public void testHstoreAsJson() throws Exception
88
+ {
89
+ if (prepared) {
90
+ tester.run(convertPath("/yml/input_hstore2.yml"));
91
+ assertEquals(Arrays.asList("c1", "\"{\"\"a\"\":\"\"b\"\"}\""),
92
+ read("postgresql-input000.00.csv"));
93
+ }
94
+ }
95
+
96
+ private List<String> read(String path) throws IOException
97
+ {
98
+ FileSystem fs = FileSystems.getDefault();
99
+ return Files.readAllLines(fs.getPath(path), Charset.defaultCharset());
100
+ }
101
+
102
+ private String convertPath(String name) throws URISyntaxException
103
+ {
104
+ if (getClass().getResource(name) == null) {
105
+ return name;
106
+ }
107
+ return new File(getClass().getResource(name).toURI()).getAbsolutePath();
108
+ }
109
+
110
+ private static void psql(String sql) throws IOException, InterruptedException {
111
+ ProcessBuilder pb = new ProcessBuilder("psql", "-w", "-c", sql);
112
+ System.out.println("PSQL: " + pb.command().toString());
113
+ final Process process = pb.start();
114
+ final int code = process.waitFor();
115
+ if (code != 0) {
116
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
117
+ String line;
118
+ while ((line = reader.readLine()) != null) {
119
+ System.err.println(line);
120
+ }
121
+ }
122
+ throw new IOException(String.format(
123
+ "Command finished with non-zero exit code. Exit code is %d.", code));
124
+ }
125
+ }
126
+ }
@@ -0,0 +1,14 @@
1
+ in:
2
+ type: postgresql
3
+ host: localhost
4
+ database: test_db
5
+ user: test_user
6
+ password: test_pw
7
+ table: input_hstore
8
+ select: "*"
9
+ out:
10
+ type: file
11
+ path_prefix: postgresql-input
12
+ file_ext: csv
13
+ formatter:
14
+ type: csv
@@ -0,0 +1,16 @@
1
+ in:
2
+ type: postgresql
3
+ host: localhost
4
+ database: test_db
5
+ user: test_user
6
+ password: test_pw
7
+ table: input_hstore
8
+ select: "*"
9
+ column_options:
10
+ c1: {type: json}
11
+ out:
12
+ type: file
13
+ path_prefix: postgresql-input
14
+ file_ext: csv
15
+ formatter:
16
+ type: csv
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: embulk-input-postgresql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.4
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sadayuki Furuhashi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-15 00:00:00.000000000 Z
11
+ date: 2016-03-29 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Selects records from a table.
14
14
  email:
@@ -22,8 +22,13 @@ files:
22
22
  - lib/embulk/input/postgresql.rb
23
23
  - src/main/java/org/embulk/input/PostgreSQLInputPlugin.java
24
24
  - src/main/java/org/embulk/input/postgresql/PostgreSQLInputConnection.java
25
- - classpath/embulk-input-jdbc-0.6.4.jar
26
- - classpath/embulk-input-postgresql-0.6.4.jar
25
+ - src/main/java/org/embulk/input/postgresql/getter/HstoreColumnGetter.java
26
+ - src/main/java/org/embulk/input/postgresql/getter/PostgreSQLColumnGetterFactory.java
27
+ - src/test/java/org/embulk/input/postgresql/PostgreSQLInputPluginTest.java
28
+ - src/test/resources/yml/input_hstore.yml
29
+ - src/test/resources/yml/input_hstore2.yml
30
+ - classpath/embulk-input-jdbc-0.7.0.jar
31
+ - classpath/embulk-input-postgresql-0.7.0.jar
27
32
  - classpath/postgresql-9.4-1205-jdbc41.jar
28
33
  homepage: https://github.com/embulk/embulk-input-jdbc
29
34
  licenses: