embulk-output-mailchimp 0.3.28 → 0.3.31

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: b429373deb2a79bd444d223f70818c7a7517bd63
4
- data.tar.gz: 06fb08e83602804217e386754e39cd7cb542c2e8
3
+ metadata.gz: 37dfc8c615f96c0c1652b421bb1b716fbf44e578
4
+ data.tar.gz: 563dfbcf427399d4d78b4f1fd277d5eb8a437835
5
5
  SHA512:
6
- metadata.gz: b096372c93fcb6a0c2930d0b98ade33a1d52277f65fd1554e6d80178ee2179b300847c69c907d4e2cbb1279f7028e6eac3804d123f8e92681e1955182df5bc22
7
- data.tar.gz: efd31474670848d2457b2fdc5ea68b990902971543e884dd473fcb57064b34687a79beb95188bc06349e5448cac1a4919b91cadc90083a0fe39cca32d09c5c60
6
+ metadata.gz: 95ecae408533dbea06c19215d01e6a77842f5ee23a5948768352fed63470fea2ae486fc3c037c2a4bda6fe20b0d71144bc0eb087f7643768c80c0057ab59a758
7
+ data.tar.gz: c577620282aeb24d5c3c4bed48ded23338ae4f271637bd6b247a39c536c3a83ef7b3168db49fc734f15bdd879c1cc3ea0ec76dd04addd5b0e377170d8f528099
@@ -1,3 +1,16 @@
1
+ ## 0.3.31 - 2019-09-30
2
+
3
+ - Fix: retries always fail
4
+ - Fix: correct pagination
5
+
6
+ ## 0.3.30 - 2019-01-23
7
+
8
+ - Renamed some configurations
9
+
10
+ ## 0.3.29 - 2018-11-30
11
+
12
+ - Fix crashes when data schema doesn't contain all of the target Mailchimp list's groups
13
+
1
14
  ## 0.3.28 - 2018-10-29
2
15
 
3
16
  - Quick fix a typo
@@ -18,7 +18,7 @@ configurations {
18
18
  provided
19
19
  }
20
20
 
21
- version = "0.3.28"
21
+ version = "0.3.31"
22
22
 
23
23
  sourceCompatibility = 1.7
24
24
  targetCompatibility = 1.7
@@ -3,12 +3,10 @@ package org.embulk.output.mailchimp;
3
3
  import com.fasterxml.jackson.core.JsonParser;
4
4
  import com.fasterxml.jackson.core.JsonProcessingException;
5
5
  import com.fasterxml.jackson.databind.DeserializationFeature;
6
- import com.fasterxml.jackson.databind.JsonNode;
7
6
  import com.fasterxml.jackson.databind.ObjectMapper;
8
7
  import com.fasterxml.jackson.databind.node.ObjectNode;
9
8
  import com.google.common.base.Function;
10
9
  import com.google.common.collect.FluentIterable;
11
- import com.google.common.collect.ImmutableList;
12
10
  import com.google.common.collect.Maps;
13
11
  import org.eclipse.jetty.client.HttpResponseException;
14
12
  import org.embulk.base.restclient.jackson.StringJsonParser;
@@ -16,26 +14,27 @@ import org.embulk.config.ConfigException;
16
14
  import org.embulk.output.mailchimp.MailChimpOutputPluginDelegate.PluginTask;
17
15
  import org.embulk.output.mailchimp.helper.MailChimpHelper;
18
16
  import org.embulk.output.mailchimp.helper.MailChimpRetryable;
19
- import org.embulk.output.mailchimp.model.CategoriesResponse;
17
+ import org.embulk.output.mailchimp.model.Category;
20
18
  import org.embulk.output.mailchimp.model.ErrorResponse;
21
- import org.embulk.output.mailchimp.model.InterestCategoriesResponse;
22
- import org.embulk.output.mailchimp.model.InterestResponse;
23
- import org.embulk.output.mailchimp.model.InterestsResponse;
19
+ import org.embulk.output.mailchimp.model.Interest;
24
20
  import org.embulk.output.mailchimp.model.MergeField;
25
- import org.embulk.output.mailchimp.model.MergeFields;
26
21
  import org.embulk.output.mailchimp.model.ReportResponse;
27
22
  import org.embulk.spi.DataException;
28
23
  import org.embulk.spi.Exec;
24
+ import org.embulk.spi.Schema;
29
25
  import org.slf4j.Logger;
30
26
 
31
27
  import javax.annotation.Nullable;
32
28
 
33
- import java.text.MessageFormat;
34
29
  import java.util.ArrayList;
30
+ import java.util.Collections;
35
31
  import java.util.HashMap;
36
32
  import java.util.List;
37
33
  import java.util.Map;
38
34
 
35
+ import static java.text.MessageFormat.format;
36
+ import static java.util.Arrays.asList;
37
+
39
38
  /**
40
39
  * Created by thangnc on 4/25/17.
41
40
  */
@@ -68,7 +67,7 @@ public class MailChimpClient
68
67
  public ReportResponse push(final ObjectNode node, PluginTask task) throws JsonProcessingException
69
68
  {
70
69
  try (MailChimpRetryable retryable = new MailChimpRetryable(task)) {
71
- String response = retryable.post(MessageFormat.format("/lists/{0}", task.getListId()),
70
+ String response = retryable.post(format("/lists/{0}", task.getListId()),
72
71
  "application/json;utf-8",
73
72
  node.toString());
74
73
  if (response != null && !response.isEmpty()) {
@@ -90,7 +89,7 @@ public class MailChimpClient
90
89
  StringBuilder errorMessage = new StringBuilder();
91
90
 
92
91
  for (ErrorResponse errorResponse : errorResponses) {
93
- errorMessage.append(MessageFormat.format("`{0}` failed cause `{1}`\n",
92
+ errorMessage.append(format("`{0}` failed cause `{1}`\n",
94
93
  MailChimpHelper.maskEmail(errorResponse.getEmailAddress()),
95
94
  MailChimpHelper.maskEmail(errorResponse.getError())));
96
95
  }
@@ -104,130 +103,128 @@ public class MailChimpClient
104
103
  * Extract interest categories by group names. Loop via categories and fetch category details
105
104
  * Reference: https://developer.mailchimp.com/documentation/mailchimp/reference/lists/interest-categories/#read-get_lists_list_id_interest_categories
106
105
  * https://developer.mailchimp.com/documentation/mailchimp/reference/lists/interest-categories/#read-get_lists_list_id_interest_categories_interest_category_id
107
- *
108
- * @param task the task
109
- * @return the map
110
- * @throws JsonProcessingException the json processing exception
111
106
  */
112
- public Map<String, Map<String, InterestResponse>> extractInterestCategoriesByGroupNames(final PluginTask task)
113
- throws JsonProcessingException
107
+ Map<String, Map<String, Interest>> interestsByCategory(final PluginTask task, Schema schema) throws JsonProcessingException
114
108
  {
109
+ if (!task.getGroupingColumns().isPresent() || task.getGroupingColumns().get().isEmpty()) {
110
+ return Collections.emptyMap();
111
+ }
115
112
  try (MailChimpRetryable retryable = new MailChimpRetryable(task)) {
116
- Map<String, Map<String, InterestResponse>> categories = new HashMap<>();
117
- if (task.getGroupingColumns().isPresent() && !task.getGroupingColumns().get().isEmpty()) {
118
- List<String> interestCategoryNames = task.getGroupingColumns().get();
119
-
120
- int count = 100;
121
- int offset = 0;
122
- int page = 1;
123
- boolean hasMore = true;
124
- JsonNode response;
125
- List<CategoriesResponse> allCategoriesResponse = new ArrayList<>();
126
-
127
- while (hasMore) {
128
- String path = MessageFormat.format("/lists/{0}/interest-categories?count={1}&offset={2}",
129
- task.getListId(),
130
- count,
131
- offset);
132
- response = jsonParser.parseJsonObject(retryable.get(path));
133
- InterestCategoriesResponse interestCategoriesResponse = mapper.treeToValue(response,
134
- InterestCategoriesResponse.class);
135
-
136
- allCategoriesResponse.addAll(interestCategoriesResponse.getCategories());
137
- if (hasMorePage(interestCategoriesResponse.getTotalItems(), count, page)) {
138
- offset = count;
139
- page++;
140
- }
141
- else {
142
- hasMore = false;
143
- }
144
- }
145
-
146
- Function<CategoriesResponse, String> function = new Function<CategoriesResponse, String>()
147
- {
148
- @Override
149
- public String apply(CategoriesResponse input)
150
- {
151
- return input.getTitle().toLowerCase();
152
- }
153
- };
154
-
155
- // Transform to a list of available category names and validate with data that user input
156
- ImmutableList<String> availableCategories = FluentIterable
157
- .from(allCategoriesResponse)
158
- .transform(function)
159
- .toList();
160
-
161
- for (String category : interestCategoryNames) {
162
- if (!availableCategories.contains(category)) {
163
- throw new ConfigException("Invalid interest category name: '" + category + "'");
164
- }
113
+ List<Category> categories = fetchCategories(retryable, task.getListId(), task.getGroupingColumns().get());
114
+ Map<String, Map<String, Interest>> interestsByCategory = new HashMap<>();
115
+ for (Category category : categories) {
116
+ // Skip fetching interests if this category isn't specified in the task's grouping column.
117
+ // Assume task's grouping columns are always in lower case
118
+ if (!task.getGroupingColumns().get().contains(category.getTitle().toLowerCase())) {
119
+ continue;
165
120
  }
121
+ avoidFloodAPI("Fetching next category's interests", task.getSleepBetweenRequestsMillis());
122
+ interestsByCategory.put(
123
+ category.getTitle().toLowerCase(),
124
+ convertInterestCategoryToMap(fetchInterests(retryable, task.getListId(), category.getId())));
125
+ }
126
+ return interestsByCategory;
127
+ }
128
+ }
166
129
 
167
- for (CategoriesResponse categoriesResponse : allCategoriesResponse) {
168
- String detailPath = MessageFormat.format("/lists/{0}/interest-categories/{1}/interests",
169
- task.getListId(),
170
- categoriesResponse.getId());
171
- response = jsonParser.parseJsonObject(retryable.get(detailPath));
172
-
173
- // Avoid flood MailChimp API
174
- avoidFloodAPI("Fetching next category's interests", task.getSleepBetweenRequestsMillis());
175
- InterestsResponse interestsResponse = mapper.treeToValue(response, InterestsResponse.class);
176
- categories.put(categoriesResponse.getTitle().toLowerCase(),
177
- convertInterestCategoryToMap(interestsResponse.getInterests()));
130
+ /**
131
+ * @throws ConfigException if task having unexist category
132
+ */
133
+ private List<Category> fetchCategories(MailChimpRetryable retryable,
134
+ String listId,
135
+ List<String> taskCategories)
136
+ throws JsonProcessingException
137
+ {
138
+ List<Category> categories = fetch(
139
+ retryable,
140
+ "/lists/" + listId + "/interest-categories",
141
+ "categories",
142
+ Category[].class);
143
+ // Fail early if one of the task's categories is not exist
144
+ taskCategories:
145
+ for (String taskCategoryName : taskCategories) {
146
+ for (Category category : categories) {
147
+ // Tasks's configured categories are (implicitly?) case-sensitive
148
+ if (category.getTitle().toLowerCase().equals(taskCategoryName)) {
149
+ continue taskCategories;
178
150
  }
179
151
  }
180
-
181
- return categories;
152
+ throw new ConfigException("Invalid group category name: '" + taskCategoryName + "'");
182
153
  }
154
+ return categories;
183
155
  }
184
156
 
157
+ private List<Interest> fetchInterests(MailChimpRetryable retryable,
158
+ String listId,
159
+ String categoryId)
160
+ throws JsonProcessingException
161
+ {
162
+ return fetch(retryable,
163
+ "/lists/" + listId + "/interest-categories/" + categoryId + "/interests",
164
+ "interests",
165
+ Interest[].class);
166
+ }
185
167
  /**
186
168
  * Extract merge fields from the list, find correct merge fields from API and put into the map to use
187
169
  * Reference: https://developer.mailchimp.com/documentation/mailchimp/reference/lists/merge-fields/#read-get_lists_list_id_merge_fields
188
- *
189
- * @param task the task
190
- * @return the map
191
- * @throws JsonProcessingException the json processing exception
192
170
  */
193
- public Map<String, MergeField> extractMergeFieldsFromList(PluginTask task) throws JsonProcessingException
171
+ Map<String, MergeField> mergeFieldByTag(PluginTask task) throws JsonProcessingException
194
172
  {
195
- try (MailChimpRetryable retryable = new MailChimpRetryable(task)) {
196
- int count = 100;
197
- int offset = 0;
198
- int page = 1;
199
- boolean hasMore = true;
200
- List<MergeField> allMergeFields = new ArrayList<>();
201
-
202
- while (hasMore) {
203
- String path = MessageFormat.format("/lists/{0}/merge-fields?count={1}&offset={2}",
204
- task.getListId(),
205
- count,
206
- offset);
207
-
208
- JsonNode response = jsonParser.parseJsonObject(retryable.get(path));
209
- MergeFields mergeFields = mapper.treeToValue(response,
210
- MergeFields.class);
211
-
212
- allMergeFields.addAll(mergeFields.getMergeFields());
213
-
214
- if (hasMorePage(mergeFields.getTotalItems(), count, page)) {
215
- offset = count;
216
- page++;
217
- }
218
- else {
219
- hasMore = false;
220
- }
221
- }
173
+ return convertMergeFieldToMap(
174
+ fetch(task,
175
+ "/lists/" + task.getListId() + "/merge-fields",
176
+ "merge_fields",
177
+ MergeField[].class));
178
+ }
222
179
 
223
- return convertMergeFieldToMap(allMergeFields);
180
+ /**
181
+ * Like {@link MailChimpClient#fetch(MailChimpRetryable, String, String, Class)},
182
+ * with an automatically created MailchimpRetryable
183
+ */
184
+ private <T> List<T> fetch(PluginTask task,
185
+ String url,
186
+ String recordsAttribute,
187
+ Class<T[]> entitiesClass)
188
+ throws JsonProcessingException
189
+ {
190
+ try (MailChimpRetryable retryable = new MailChimpRetryable(task)) {
191
+ return fetch(retryable, url, recordsAttribute, entitiesClass);
192
+ }
193
+ }
194
+ /**
195
+ * Fetch all (by pagination) records at the target URL,
196
+ * Assume that endpoint handles `count` and `offset` parameter and have a response scheme of:
197
+ * {
198
+ * recordsAttribute}: [...],
199
+ * "total_items": 10
200
+ * }
201
+ * @param recordsAttribute name of the attribute to extract records inside the response's body.
202
+ * @param entitiesClass *Array* class of the entity to deserialize into
203
+ */
204
+ private <T> List<T> fetch(MailChimpRetryable retryable,
205
+ String url,
206
+ String recordsAttribute,
207
+ Class<T[]> entitiesClass)
208
+ throws JsonProcessingException
209
+ {
210
+ final int batchSize = 100;
211
+ int offset = 0;
212
+ List<T> entities = new ArrayList<>();
213
+ ObjectNode response;
214
+ do {
215
+ response = jsonParser.parseJsonObject(
216
+ retryable.get(url + "?count=" + batchSize + "&offset=" + offset));
217
+ entities.addAll(asList(mapper.treeToValue(response.get(recordsAttribute), entitiesClass)));
218
+ offset += batchSize;
224
219
  }
220
+ while (offset < response.get("total_items").asInt());
221
+ return entities;
225
222
  }
226
223
 
227
224
  private void findList(final PluginTask task)
228
225
  {
229
226
  try (MailChimpRetryable retryable = new MailChimpRetryable(task)) {
230
- jsonParser.parseJsonObject(retryable.get(MessageFormat.format("/lists/{0}",
227
+ jsonParser.parseJsonObject(retryable.get(format("/lists/{0}",
231
228
  task.getListId())));
232
229
  }
233
230
  catch (HttpResponseException hre) {
@@ -235,18 +232,18 @@ public class MailChimpClient
235
232
  }
236
233
  }
237
234
 
238
- private Map<String, InterestResponse> convertInterestCategoryToMap(final List<InterestResponse> interestResponseList)
235
+ private Map<String, Interest> convertInterestCategoryToMap(final List<Interest> interestList)
239
236
  {
240
- Function<InterestResponse, String> function = new Function<InterestResponse, String>()
237
+ Function<Interest, String> function = new Function<Interest, String>()
241
238
  {
242
239
  @Override
243
- public String apply(@Nullable InterestResponse input)
240
+ public String apply(@Nullable Interest input)
244
241
  {
245
242
  return input.getName();
246
243
  }
247
244
  };
248
245
 
249
- return Maps.uniqueIndex(FluentIterable.from(interestResponseList)
246
+ return Maps.uniqueIndex(FluentIterable.from(interestList)
250
247
  .toList(),
251
248
  function);
252
249
  }
@@ -19,9 +19,13 @@ import org.embulk.spi.Exec;
19
19
  import org.embulk.spi.Schema;
20
20
  import org.slf4j.Logger;
21
21
 
22
+ import java.util.HashSet;
22
23
  import java.util.List;
24
+ import java.util.Set;
23
25
 
26
+ import static com.google.common.base.Joiner.on;
24
27
  import static com.google.common.base.Strings.isNullOrEmpty;
28
+ import static org.embulk.output.mailchimp.helper.MailChimpHelper.caseInsensitiveColumnNames;
25
29
  import static org.embulk.output.mailchimp.validation.ColumnDataValidator.checkExistColumns;
26
30
 
27
31
  /**
@@ -39,17 +43,17 @@ public class MailChimpOutputPluginDelegate
39
43
  public interface PluginTask
40
44
  extends RestClientOutputTaskBase
41
45
  {
42
- @Config("maximum_retries")
46
+ @Config("retry_limit")
43
47
  @ConfigDefault("6")
44
- int getMaximumRetries();
48
+ int getRetryLimit();
45
49
 
46
- @Config("initial_retry_interval_millis")
50
+ @Config("retry_initial_wait_msec")
47
51
  @ConfigDefault("1000")
48
- int getInitialRetryIntervalMillis();
52
+ int getRetryInitialWaitMSec();
49
53
 
50
- @Config("maximum_retry_interval_millis")
54
+ @Config("max_retry_wait_msec")
51
55
  @ConfigDefault("32000")
52
- int getMaximumRetryIntervalMillis();
56
+ int getMaxRetryWaitMSec();
53
57
 
54
58
  @Config("timeout_millis")
55
59
  @ConfigDefault("60000")
@@ -155,6 +159,16 @@ public class MailChimpOutputPluginDelegate
155
159
  if (task.getAtomicUpsert()) {
156
160
  LOG.info(" Treating upsert as atomic operation");
157
161
  }
162
+
163
+ // Warn if schema doesn't have the task's grouping column (Group Category)
164
+ if (task.getGroupingColumns().isPresent()
165
+ && !task.getGroupingColumns().get().isEmpty()) {
166
+ Set<String> categoryNames = new HashSet<>(task.getGroupingColumns().get());
167
+ categoryNames.removeAll(caseInsensitiveColumnNames(schema));
168
+ if (categoryNames.size() > 0) {
169
+ LOG.warn("Data schema doesn't contain the task's grouping column(s): {}", on(", ").join(categoryNames));
170
+ }
171
+ }
158
172
  }
159
173
 
160
174
  @Override
@@ -17,7 +17,7 @@ import org.embulk.base.restclient.record.RecordBuffer;
17
17
  import org.embulk.base.restclient.record.ServiceRecord;
18
18
  import org.embulk.config.TaskReport;
19
19
  import org.embulk.output.mailchimp.model.AddressMergeFieldAttribute;
20
- import org.embulk.output.mailchimp.model.InterestResponse;
20
+ import org.embulk.output.mailchimp.model.Interest;
21
21
  import org.embulk.output.mailchimp.model.MergeField;
22
22
  import org.embulk.output.mailchimp.model.ReportResponse;
23
23
  import org.embulk.spi.Column;
@@ -26,8 +26,6 @@ import org.embulk.spi.Exec;
26
26
  import org.embulk.spi.Schema;
27
27
  import org.slf4j.Logger;
28
28
 
29
- import javax.annotation.Nullable;
30
-
31
29
  import java.io.IOException;
32
30
  import java.util.ArrayList;
33
31
  import java.util.Arrays;
@@ -37,9 +35,7 @@ import java.util.List;
37
35
  import java.util.Map;
38
36
  import java.util.Set;
39
37
  import java.util.TreeMap;
40
- import java.util.TreeSet;
41
38
 
42
- import static com.google.common.base.Joiner.on;
43
39
  import static java.lang.String.CASE_INSENSITIVE_ORDER;
44
40
  import static java.lang.String.format;
45
41
  import static org.embulk.output.mailchimp.MailChimpOutputPluginDelegate.PluginTask;
@@ -65,7 +61,7 @@ public class MailChimpRecordBuffer
65
61
  private int errorCount;
66
62
  private long totalCount;
67
63
  private List<JsonNode> records;
68
- private Map<String, Map<String, InterestResponse>> categories;
64
+ private Map<String, Map<String, Interest>> categories;
69
65
  private Map<String, MergeField> availableMergeFields;
70
66
  private List<JsonNode> uniqueRecords;
71
67
  private List<JsonNode> duplicatedRecords;
@@ -173,19 +169,12 @@ public class MailChimpRecordBuffer
173
169
  // Should loop the names and get the id of interest categories.
174
170
  // The reason why we put categories validation here because we can not share data between instance.
175
171
  if (categories == null) {
176
- categories = mailChimpClient.extractInterestCategoriesByGroupNames(task);
177
-
178
- Set<String> categoriesNames = categories.keySet();
179
- Set<String> columnNames = caseInsensitiveColumnNames();
180
- if (!columnNames.containsAll(categoriesNames)) {
181
- categoriesNames.removeAll(columnNames);
182
- LOG.warn("Data column for category '{}' could not be found", on(", ").join(categoriesNames));
183
- }
172
+ categories = mailChimpClient.interestsByCategory(task, schema);
184
173
  }
185
174
 
186
175
  // Extract merge fields detail
187
176
  if (availableMergeFields == null) {
188
- availableMergeFields = mailChimpClient.extractMergeFieldsFromList(task);
177
+ availableMergeFields = mailChimpClient.mergeFieldByTag(task);
189
178
  }
190
179
 
191
180
  // Required merge fields
@@ -288,7 +277,7 @@ public class MailChimpRecordBuffer
288
277
  }
289
278
  List<String> recordInterests = fromCommaSeparatedString(inputValue.get().asText());
290
279
  // `categories` is guaranteed to contain the `category` as it already did an early check
291
- Map<String, InterestResponse> availableInterests = categories.get(category);
280
+ Map<String, Interest> availableInterests = categories.get(category);
292
281
 
293
282
  // Only update user-predefined categories if replace interests != true
294
283
  if (!task.getReplaceInterests()) {
@@ -359,21 +348,4 @@ public class MailChimpRecordBuffer
359
348
  }
360
349
  }
361
350
  }
362
-
363
- private Set<String> caseInsensitiveColumnNames()
364
- {
365
- Set<String> columns = new TreeSet<>(CASE_INSENSITIVE_ORDER);
366
- columns.addAll(FluentIterable
367
- .from(schema.getColumns())
368
- .transform(new Function<Column, String>() {
369
- @Nullable
370
- @Override
371
- public String apply(@Nullable Column col)
372
- {
373
- return col.getName();
374
- }
375
- })
376
- .toSet());
377
- return columns;
378
- }
379
351
  }
@@ -9,17 +9,23 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
9
9
  import com.google.common.base.Function;
10
10
  import com.google.common.base.Optional;
11
11
  import com.google.common.base.Splitter;
12
+ import com.google.common.collect.FluentIterable;
12
13
  import com.google.common.collect.Lists;
13
14
  import com.google.common.collect.Multimap;
14
15
  import com.google.common.collect.Multimaps;
15
16
  import org.embulk.output.mailchimp.model.AddressMergeFieldAttribute;
17
+ import org.embulk.spi.Column;
18
+ import org.embulk.spi.Schema;
16
19
 
17
20
  import javax.annotation.Nullable;
18
21
 
19
22
  import java.io.IOException;
20
23
  import java.util.Iterator;
21
24
  import java.util.List;
25
+ import java.util.Set;
26
+ import java.util.TreeSet;
22
27
 
28
+ import static java.lang.String.CASE_INSENSITIVE_ORDER;
23
29
  import static java.util.Objects.requireNonNull;
24
30
 
25
31
  /**
@@ -142,4 +148,20 @@ public final class MailChimpHelper
142
148
  }
143
149
  return Optional.absent();
144
150
  }
151
+
152
+ public static Set<String> caseInsensitiveColumnNames(Schema schema)
153
+ {
154
+ Set<String> columns = new TreeSet<>(CASE_INSENSITIVE_ORDER);
155
+ columns.addAll(FluentIterable
156
+ .from(schema.getColumns())
157
+ .transform(new Function<Column, String>() {
158
+ @Override
159
+ public String apply(Column col)
160
+ {
161
+ return col.getName();
162
+ }
163
+ })
164
+ .toSet());
165
+ return columns;
166
+ }
145
167
  }
@@ -17,7 +17,6 @@ import org.embulk.spi.Exec;
17
17
  import org.embulk.util.retryhelper.jetty92.DefaultJetty92ClientCreator;
18
18
  import org.embulk.util.retryhelper.jetty92.Jetty92RetryHelper;
19
19
  import org.embulk.util.retryhelper.jetty92.Jetty92SingleRequester;
20
- import org.embulk.util.retryhelper.jetty92.StringJetty92ResponseEntityReader;
21
20
  import org.slf4j.Logger;
22
21
 
23
22
  import java.text.MessageFormat;
@@ -44,9 +43,9 @@ public class MailChimpRetryable implements AutoCloseable
44
43
 
45
44
  public MailChimpRetryable(final PluginTask pluginTask)
46
45
  {
47
- this.retryHelper = new Jetty92RetryHelper(pluginTask.getMaximumRetries(),
48
- pluginTask.getInitialRetryIntervalMillis(),
49
- pluginTask.getMaximumRetryIntervalMillis(),
46
+ this.retryHelper = new Jetty92RetryHelper(pluginTask.getRetryLimit(),
47
+ pluginTask.getRetryInitialWaitMSec(),
48
+ pluginTask.getMaxRetryWaitMSec(),
50
49
  new DefaultJetty92ClientCreator(pluginTask.getTimeoutMillis(),
51
50
  pluginTask.getTimeoutMillis()));
52
51
  this.pluginTask = pluginTask;
@@ -67,7 +66,7 @@ public class MailChimpRetryable implements AutoCloseable
67
66
  {
68
67
  try {
69
68
  return retryHelper.requestWithRetry(
70
- new StringJetty92ResponseEntityReader(READER_TIMEOUT_MILLIS),
69
+ new PatchedStringJetty92ResponseEntityReader(READER_TIMEOUT_MILLIS),
71
70
  new Jetty92SingleRequester()
72
71
  {
73
72
  @Override
@@ -0,0 +1,55 @@
1
+ package org.embulk.output.mailchimp.helper;
2
+
3
+ import com.google.common.io.CharStreams;
4
+ import org.eclipse.jetty.client.api.Response;
5
+ import org.eclipse.jetty.client.util.InputStreamResponseListener;
6
+ import org.embulk.util.retryhelper.jetty92.Jetty92ResponseReader;
7
+
8
+ import java.io.InputStream;
9
+ import java.io.InputStreamReader;
10
+ import java.util.concurrent.TimeUnit;
11
+
12
+ /**
13
+ * A copy of {@link org.embulk.util.retryhelper.jetty92.StringJetty92ResponseEntityReader} with the only
14
+ * modification is {@link PatchedStringJetty92ResponseEntityReader#getListener()} to return a new instance every time.
15
+ * This might eventually get fixed upstream (Jetty92RetryHelper aware of Jetty92ResponseReader is stateful),
16
+ */
17
+ public class PatchedStringJetty92ResponseEntityReader implements Jetty92ResponseReader<String>
18
+ {
19
+ private InputStreamResponseListener listener;
20
+ private final long timeoutMillis;
21
+
22
+ public PatchedStringJetty92ResponseEntityReader(long timeoutMillis)
23
+ {
24
+ this.listener = new InputStreamResponseListener();
25
+ this.timeoutMillis = timeoutMillis;
26
+ }
27
+
28
+ @Override
29
+ public final Response.Listener getListener()
30
+ {
31
+ this.listener = new InputStreamResponseListener();
32
+ return this.listener;
33
+ }
34
+
35
+ @Override
36
+ public final Response getResponse() throws Exception
37
+ {
38
+ return this.listener.get(this.timeoutMillis, TimeUnit.MILLISECONDS);
39
+ }
40
+
41
+ @Override
42
+ public final String readResponseContent() throws Exception
43
+ {
44
+ final InputStream inputStream = this.listener.getInputStream();
45
+ try (InputStreamReader inputStreamReader = new InputStreamReader(inputStream)) {
46
+ return CharStreams.toString(inputStreamReader);
47
+ }
48
+ }
49
+
50
+ @Override
51
+ public final String readResponseContentInString() throws Exception
52
+ {
53
+ return this.readResponseContent();
54
+ }
55
+ }
@@ -3,7 +3,7 @@ package org.embulk.output.mailchimp.model;
3
3
  /**
4
4
  * Created by thangnc on 5/5/17.
5
5
  */
6
- public class CategoriesResponse
6
+ public class Category
7
7
  {
8
8
  private String id;
9
9
  private String title;
@@ -3,7 +3,7 @@ package org.embulk.output.mailchimp.model;
3
3
  /**
4
4
  * Created by thangnc on 5/8/17.
5
5
  */
6
- public class InterestResponse
6
+ public class Interest
7
7
  {
8
8
  private String id;
9
9
  private String name;
@@ -4,15 +4,20 @@ import com.fasterxml.jackson.databind.JsonNode;
4
4
  import com.fasterxml.jackson.databind.node.JsonNodeFactory;
5
5
  import com.fasterxml.jackson.databind.node.NullNode;
6
6
  import com.fasterxml.jackson.databind.node.ObjectNode;
7
+ import com.google.common.collect.ImmutableList;
7
8
  import com.google.common.collect.Multimap;
8
9
  import org.embulk.output.mailchimp.helper.MailChimpHelper;
9
10
  import org.embulk.output.mailchimp.model.AddressMergeFieldAttribute;
11
+ import org.embulk.spi.Column;
12
+ import org.embulk.spi.Schema;
13
+ import org.embulk.spi.type.Types;
10
14
  import org.junit.Test;
11
15
 
12
16
  import java.util.ArrayList;
13
17
  import java.util.Arrays;
14
18
  import java.util.List;
15
19
 
20
+ import static org.embulk.output.mailchimp.helper.MailChimpHelper.caseInsensitiveColumnNames;
16
21
  import static org.embulk.output.mailchimp.helper.MailChimpHelper.containsCaseInsensitive;
17
22
  import static org.embulk.output.mailchimp.helper.MailChimpHelper.extractMemberStatus;
18
23
  import static org.embulk.output.mailchimp.helper.MailChimpHelper.maskEmail;
@@ -95,4 +100,12 @@ public class TestMailChimpHelper
95
100
  assertEquals("Should be JSON", ObjectNode.class, orderJsonNode(toJsonNode(given), attributes).getClass());
96
101
  assertEquals("Should be match", expect, orderJsonNode(toJsonNode(given), attributes).toString());
97
102
  }
103
+
104
+ @Test
105
+ public void test_caseInsensitiveColumnNames()
106
+ {
107
+ Schema schema = new Schema(ImmutableList.of(
108
+ new Column(0, "InCONSisTENT", Types.LONG)));
109
+ assertTrue(caseInsensitiveColumnNames(schema).contains("inConsIstent"));
110
+ }
98
111
  }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: embulk-output-mailchimp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.28
4
+ version: 0.3.31
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thang Nguyen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-29 00:00:00.000000000 Z
11
+ date: 2019-09-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -67,13 +67,12 @@ files:
67
67
  - src/main/java/org/embulk/output/mailchimp/MailChimpRecordBuffer.java
68
68
  - src/main/java/org/embulk/output/mailchimp/helper/MailChimpHelper.java
69
69
  - src/main/java/org/embulk/output/mailchimp/helper/MailChimpRetryable.java
70
+ - src/main/java/org/embulk/output/mailchimp/helper/PatchedStringJetty92ResponseEntityReader.java
70
71
  - src/main/java/org/embulk/output/mailchimp/model/AddressMergeFieldAttribute.java
71
72
  - src/main/java/org/embulk/output/mailchimp/model/AuthMethod.java
72
- - src/main/java/org/embulk/output/mailchimp/model/CategoriesResponse.java
73
+ - src/main/java/org/embulk/output/mailchimp/model/Category.java
73
74
  - src/main/java/org/embulk/output/mailchimp/model/ErrorResponse.java
74
- - src/main/java/org/embulk/output/mailchimp/model/InterestCategoriesResponse.java
75
- - src/main/java/org/embulk/output/mailchimp/model/InterestResponse.java
76
- - src/main/java/org/embulk/output/mailchimp/model/InterestsResponse.java
75
+ - src/main/java/org/embulk/output/mailchimp/model/Interest.java
77
76
  - src/main/java/org/embulk/output/mailchimp/model/MemberStatus.java
78
77
  - src/main/java/org/embulk/output/mailchimp/model/MergeField.java
79
78
  - src/main/java/org/embulk/output/mailchimp/model/MergeFields.java
@@ -89,12 +88,12 @@ files:
89
88
  - test/override_assert_raise.rb
90
89
  - test/run-test.rb
91
90
  - classpath/jetty-io-9.2.14.v20151106.jar
91
+ - classpath/embulk-output-mailchimp-0.3.31.jar
92
92
  - classpath/jetty-util-9.2.14.v20151106.jar
93
93
  - classpath/jetty-http-9.2.14.v20151106.jar
94
94
  - classpath/jetty-client-9.2.14.v20151106.jar
95
95
  - classpath/embulk-base-restclient-0.5.3.jar
96
96
  - classpath/embulk-util-retryhelper-jetty92-0.5.3.jar
97
- - classpath/embulk-output-mailchimp-0.3.28.jar
98
97
  homepage: https://github.com/treasure-data/embulk-output-mailchimp
99
98
  licenses:
100
99
  - MIT
@@ -1,37 +0,0 @@
1
- package org.embulk.output.mailchimp.model;
2
-
3
- import com.fasterxml.jackson.annotation.JsonProperty;
4
-
5
- import java.util.List;
6
-
7
- /**
8
- * Created by thangnc on 5/8/17.
9
- */
10
- public class InterestCategoriesResponse
11
- {
12
- @JsonProperty("categories")
13
- private List<CategoriesResponse> categories;
14
-
15
- @JsonProperty("total_items")
16
- private int totalItems;
17
-
18
- public List<CategoriesResponse> getCategories()
19
- {
20
- return categories;
21
- }
22
-
23
- public void setCategories(List<CategoriesResponse> categories)
24
- {
25
- this.categories = categories;
26
- }
27
-
28
- public int getTotalItems()
29
- {
30
- return totalItems;
31
- }
32
-
33
- public void setTotalItems(int totalItems)
34
- {
35
- this.totalItems = totalItems;
36
- }
37
- }
@@ -1,24 +0,0 @@
1
- package org.embulk.output.mailchimp.model;
2
-
3
- import com.fasterxml.jackson.annotation.JsonProperty;
4
-
5
- import java.util.List;
6
-
7
- /**
8
- * Created by thangnc on 5/8/17.
9
- */
10
- public class InterestsResponse
11
- {
12
- @JsonProperty("interests")
13
- private List<InterestResponse> interests;
14
-
15
- public List<InterestResponse> getInterests()
16
- {
17
- return interests;
18
- }
19
-
20
- public void setInterests(List<InterestResponse> interests)
21
- {
22
- this.interests = interests;
23
- }
24
- }