embulk-parser-twitter_ads_stats 0.1.1 → 0.1.2

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.
Files changed (25) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +21 -0
  3. data/README.md +8 -3
  4. data/build.gradle +1 -1
  5. data/build.sbt +10 -6
  6. data/src/main/scala/org/embulk/parser/twitter_ads_stats/Column.scala +10 -11
  7. data/src/main/scala/org/embulk/parser/twitter_ads_stats/MetricElementNames.scala +6 -3
  8. data/src/main/scala/org/embulk/parser/twitter_ads_stats/MetricsGroupJson.scala +1 -1
  9. data/src/main/scala/org/embulk/parser/twitter_ads_stats/ParseException.scala +9 -11
  10. data/src/main/scala/org/embulk/parser/twitter_ads_stats/TwitterAdsStatsParserPlugin.scala +9 -9
  11. data/src/main/scala/org/embulk/parser/twitter_ads_stats/define/Data.scala +13 -10
  12. data/src/main/scala/org/embulk/parser/twitter_ads_stats/define/IDData.scala +27 -20
  13. data/src/main/scala/org/embulk/parser/twitter_ads_stats/define/Request.scala +11 -10
  14. data/src/main/scala/org/embulk/parser/twitter_ads_stats/define/Root.scala +14 -12
  15. data/src/main/scala/org/embulk/parser/twitter_ads_stats/define/RootJson.scala +3 -8
  16. data/src/main/scala/org/embulk/parser/twitter_ads_stats/define/StatsDateTime.scala +25 -0
  17. data/src/main/scala/org/embulk/parser/twitter_ads_stats/package.scala +1 -1
  18. data/src/test/scala/org/embulk/parser/twitter_ads_stats/MetricElementNamesSpec.scala +1 -1
  19. data/src/test/scala/org/embulk/parser/twitter_ads_stats/MetricsGroupJsonSpec.scala +3 -3
  20. data/src/test/scala/org/embulk/parser/twitter_ads_stats/define/MetricsJsonSpec.scala +2 -2
  21. data/src/test/scala/org/embulk/parser/twitter_ads_stats/define/ParamsSpec.scala +3 -3
  22. data/src/test/scala/org/embulk/parser/twitter_ads_stats/define/RootJsonSpec.scala +1 -1
  23. data/src/test/scala/org/embulk/parser/twitter_ads_stats/define/RootSpec.scala +47 -47
  24. data/src/test/scala/org/embulk/parser/twitter_ads_stats/define/StatsDateTimeSpec.scala +21 -0
  25. metadata +6 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9f1833c6a364918557a8792567828b322c53c1b0
4
- data.tar.gz: 0a8b23dadeadcbf655be8f4da408ffe66cdfd034
3
+ metadata.gz: b01ca4d919c7b6a4b43fd5becbd2b2606a522a68
4
+ data.tar.gz: 3b013591fcb20ca7a2b3a0dd1bf45ce4e6687a0d
5
5
  SHA512:
6
- metadata.gz: 49e6ccdc2b3aa45b56b9a3908549eff06d0eed15dea8d6681bbb371a4b24642ee57ace7020e7647e55bf425c871415a34838f4352c399a924b783c72a51ef022
7
- data.tar.gz: 62c0e5ef405ae59c9545715f4845e22d95eb0b524977141eff0eccc6a006a00cb36a193ddf2478d70c85bf47f206851e95c82cdc2e5eddef8f425ab08fef95ee
6
+ metadata.gz: 00d138b86ec59902fc4cf150807af1343732d04541a6fe18d1915d8453226a37e21ee6f745e5ddd4df0384b8ab7f27151e486b00c5c437b0747f1551cd30bc58
7
+ data.tar.gz: 936209667f89677725f4d7b19c7efb86b7b4cf70ba57239b0abaee4cb3b7ad762ccb3fe4e210407744ea0c720289d061bc3b44ef447b079240d4de7a505422ad
data/.travis.yml ADDED
@@ -0,0 +1,21 @@
1
+ language: scala
2
+
3
+ scala:
4
+ - 2.12.3
5
+
6
+ script:
7
+ - >-
8
+ sbt
9
+ ++$TRAVIS_SCALA_VERSION
10
+ scalafmt::test
11
+ test:scalafmt::test
12
+ sbt:scalafmt::test
13
+ test
14
+
15
+ cache:
16
+ directories:
17
+ - $HOME/.ivy2/cache
18
+ - $HOME/.sbt/launchers
19
+ before_cache:
20
+ - find $HOME/.sbt -name "*.lock" | xargs rm
21
+ - find $HOME/.ivy2 -name "ivydata-*.properties" | xargs rm
data/README.md CHANGED
@@ -1,8 +1,13 @@
1
1
  # Twitter Ads Stats parser plugin for Embulk
2
2
 
3
+ [![Build Status](https://travis-ci.org/septeni-original/embulk-parser-twitter_ads_stats.svg?branch=master)](https://travis-ci.org/septeni-original/embulk-parser-twitter_ads_stats)
4
+
3
5
  This plugin parse [Twitter Ads Stats](https://developer.twitter.com/en/docs/ads/analytics/overview/metrics-and-segmentation) json file.
4
6
 
5
- ##Parse Logic
7
+ ## Notice
8
+ This plugin is an EXPERIMENTAL and support only Java8.
9
+
10
+ ## Parse Logic
6
11
  1. Flatten to metrics by date.
7
12
  2. Group Metrics into Metrics Group by json type.
8
13
 
@@ -28,7 +33,7 @@ I suppose this kind of [input file](https://github.com/septeni-original/embulk-p
28
33
  in:
29
34
  type: any file input plugin type
30
35
  parser:
31
- type: sample
36
+ type: twitter_ads_stats
32
37
  stop_on_invalid_record: true
33
38
  ```
34
39
 
@@ -75,5 +80,5 @@ sbt test
75
80
 
76
81
  ## Acknowledgement
77
82
 
78
- I developed this library with reference to [embulk-parser-firebase_avro](https://github.com/smdmts/embulk-parser-firebase_avro)
83
+ I developed this library with reference to [embulk-parser-firebase_avro](https://github.com/smdmts/embulk-parser-firebase_avro).
79
84
  Thank you very much.
data/build.gradle CHANGED
@@ -13,7 +13,7 @@ configurations {
13
13
  provided
14
14
  }
15
15
 
16
- version = "0.1.1"
16
+ version = "0.1.2"
17
17
 
18
18
  sourceCompatibility = 1.7
19
19
  targetCompatibility = 1.7
data/build.sbt CHANGED
@@ -1,15 +1,19 @@
1
- lazy val core = (project in file(".")).
2
- settings(
3
- inThisBuild(List(
1
+ lazy val core = (project in file(".")).settings(
2
+ inThisBuild(
3
+ List(
4
4
  organization := "jp.co.septeni-original",
5
5
  scalaVersion := "2.12.3",
6
6
  version := "0.1.0-SNAPSHOT"
7
- )),
8
- name := "embulk-parser-twitter_ads_stats"
9
- )
7
+ )
8
+ ),
9
+ name := "embulk-parser-twitter_ads_stats"
10
+ )
10
11
 
11
12
  enablePlugins(ScalafmtPlugin)
12
13
 
13
14
  resolvers += Resolver.jcenterRepo
14
15
  libraryDependencies ++= Dependencies.value
15
16
  scalacOptions += "-Xexperimental"
17
+
18
+ scalafmtVersion in ThisBuild := "1.2.0"
19
+ scalafmtOnCompile in ThisBuild := true
@@ -9,10 +9,10 @@ object Column {
9
9
  def createEmbulkColumns(metricElementNames: MetricElementNames): Seq[EmbulkColumn] = {
10
10
  @scala.annotation.tailrec
11
11
  def loop(
12
- curIndex: Int,
13
- curNames: List[String],
14
- acc: Seq[EmbulkColumn]
15
- ): Seq[EmbulkColumn] = {
12
+ curIndex: Int,
13
+ curNames: List[String],
14
+ acc: Seq[EmbulkColumn]
15
+ ): Seq[EmbulkColumn] = {
16
16
  curNames match {
17
17
  case Nil => acc.reverse
18
18
  case x :: xs =>
@@ -24,7 +24,6 @@ object Column {
24
24
  }
25
25
  }
26
26
 
27
-
28
27
  val baseColumns = Seq(
29
28
  new EmbulkColumn(0, "id", Types.STRING),
30
29
  new EmbulkColumn(1, "date", Types.STRING),
@@ -42,9 +41,9 @@ object Column {
42
41
  }
43
42
 
44
43
  case class Column(
45
- id: String,
46
- date: LocalDate,
47
- segment: Option[String],
48
- placement: String,
49
- metricsGroup: Map[String, MetricsGroup]
50
- )
44
+ id: String,
45
+ date: LocalDate,
46
+ segment: Option[String],
47
+ placement: String,
48
+ metricsGroup: Map[String, MetricsGroup]
49
+ )
@@ -18,9 +18,12 @@ case class MetricElementNames(names: Map[String, Seq[String]]) {
18
18
 
19
19
  import MetricElementNames._
20
20
 
21
- def getSortedMetricsGroupNames:List[String] = names.keys.toList.sorted
21
+ def getSortedMetricsGroupNames: List[String] = names.keys.toList.sorted
22
22
 
23
- private[twitter_ads_stats] def resolveMetrics(resolveMetricTimeSeries: (List[String], Option[JsValue]) => MetricTimeSeries, json: JsObject): Metrics =
23
+ private[twitter_ads_stats] def resolveMetrics(
24
+ resolveMetricTimeSeries: (List[String], Option[JsValue]) => MetricTimeSeries,
25
+ json: JsObject
26
+ ): Metrics =
24
27
  Metrics(
25
28
  names.flatMap { v =>
26
29
  v._2.map { value =>
@@ -44,4 +47,4 @@ object MetricElementNames {
44
47
  def replaceSeparator(name: String): String = {
45
48
  name.replaceAll("[.]", separator)
46
49
  }
47
- }
50
+ }
@@ -8,7 +8,7 @@ object MetricsGroupJson {
8
8
 
9
9
  private def toJValue(element: Option[Long]): JsValue = element match {
10
10
  case Some(e) => e.toJson
11
- case None => JsNull
11
+ case None => JsNull
12
12
  }
13
13
 
14
14
  override def write(obj: MetricsGroup): JsValue = {
@@ -1,25 +1,23 @@
1
1
  package org.embulk.parser.twitter_ads_stats
2
2
 
3
3
  sealed abstract class ParseException(
4
- message: String,
5
- cause: Throwable
6
- ) extends Throwable
7
-
4
+ message: String,
5
+ cause: Throwable
6
+ ) extends Throwable
8
7
 
9
8
  case class InvalidMetricTimeSeriesException(
10
- message: String,
11
- cause: Throwable
12
- ) extends ParseException(message, cause) {
9
+ message: String,
10
+ cause: Throwable
11
+ ) extends ParseException(message, cause) {
13
12
  def this(cause: Throwable, index: Int) = {
14
13
  this(s"Not Found index: $index", cause)
15
14
  }
16
15
  }
17
16
 
18
17
  case class InvalidInputFileException(
19
- message: String,
20
- cause: Throwable
21
- )
22
- extends ParseException(message, cause) {
18
+ message: String,
19
+ cause: Throwable
20
+ ) extends ParseException(message, cause) {
23
21
 
24
22
  def this(cause: Throwable) = {
25
23
  this(s"Input file can't parse", cause)
@@ -26,13 +26,13 @@ class TwitterAdsStatsParserPlugin extends ParserPlugin {
26
26
 
27
27
  override def run(taskSource: TaskSource, schema: Schema, input: FileInput, output: PageOutput): Unit = {
28
28
 
29
- val task = taskSource.loadTask(classOf[PluginTask])
29
+ val task = taskSource.loadTask(classOf[PluginTask])
30
30
  val stopOnInvalidRecord = task.getStopOnInvalidRecord
31
31
 
32
32
  LoanPattern(new PageBuilder(Exec.getBufferAllocator, schema, output)) { pb =>
33
33
  while (input.nextFile()) {
34
34
  (for {
35
- root <- createRootFrom(input)
35
+ root <- createRootFrom(input)
36
36
  columns <- root.resolveColumns(metricElementNames)
37
37
  } yield addRecord(pb, columns, root)) match {
38
38
  case Right(_) =>
@@ -54,15 +54,15 @@ class TwitterAdsStatsParserPlugin extends ParserPlugin {
54
54
  (column, embulkColumn.getName) match {
55
55
  case (Column(id, _, _, _, _), "id") =>
56
56
  pb.setString(embulkColumn, id)
57
- case (Column(_, date, _, _,_), "date") =>
57
+ case (Column(_, date, _, _, _), "date") =>
58
58
  pb.setString(embulkColumn, date.toString)
59
- case (Column(_, _, Some(segment),_, _), "segment") =>
59
+ case (Column(_, _, Some(segment), _, _), "segment") =>
60
60
  pb.setString(embulkColumn, segment)
61
- case (Column(_, _, None,_, _), "segment") =>
61
+ case (Column(_, _, None, _, _), "segment") =>
62
62
  pb.setNull(embulkColumn)
63
- case (Column(_, _, _,placement, _), "placement") =>
63
+ case (Column(_, _, _, placement, _), "placement") =>
64
64
  pb.setString(embulkColumn, placement)
65
- case (Column(_, _, _, _,metricsGroup), key) =>
65
+ case (Column(_, _, _, _, metricsGroup), key) =>
66
66
  metricsGroup.get(key) match {
67
67
  case Some(m) =>
68
68
  pb.setJson(
@@ -84,7 +84,7 @@ class TwitterAdsStatsParserPlugin extends ParserPlugin {
84
84
  val stream = new FileInputInputStream(input)
85
85
  try {
86
86
  val jsValue = scala.io.Source.fromInputStream(stream).mkString.parseJson
87
- val root = new RootJson(metricElementNames).RootReader.read(jsValue)
87
+ val root = new RootJson(metricElementNames).RootReader.read(jsValue)
88
88
  Right(root)
89
89
  } catch {
90
90
  case NonFatal(e) => Left(new InvalidInputFileException(e))
@@ -94,5 +94,5 @@ class TwitterAdsStatsParserPlugin extends ParserPlugin {
94
94
 
95
95
  object TwitterAdsStatsParserPlugin {
96
96
  val logger: Logger = Exec.getLogger(classOf[TwitterAdsStatsParserPlugin])
97
- val jsonParser = new JsonParser
97
+ val jsonParser = new JsonParser
98
98
  }
@@ -3,17 +3,20 @@ package org.embulk.parser.twitter_ads_stats.define
3
3
  import org.embulk.parser.twitter_ads_stats.{Column, MetricElementNames, ParseException}
4
4
 
5
5
  case class Data(id: String, id_data: Seq[IDData]) {
6
- private[define] def resolveColumns(metricElementNames: MetricElementNames, request: Request): Either[ParseException, Seq[Column]] = {
7
- id_data.map { idData =>
8
- idData.resolveColumns(id, metricElementNames, request)
9
- }.foldRight[Either[ParseException, Seq[Column]]](Right(Nil)) {
10
- case (Left(e), _) => Left(e)
11
- case (Right(_), Left(e)) => Left(e)
12
- case (Right(seq1), Right(seq2)) => Right(seq1 ++: seq2)
13
- }
6
+ private[define] def resolveColumns(metricElementNames: MetricElementNames,
7
+ request: Request): Either[ParseException, Seq[Column]] = {
8
+ id_data
9
+ .map { idData =>
10
+ idData.resolveColumns(id, metricElementNames, request)
11
+ }
12
+ .foldRight[Either[ParseException, Seq[Column]]](Right(Nil)) {
13
+ case (Left(e), _) => Left(e)
14
+ case (Right(_), Left(e)) => Left(e)
15
+ case (Right(seq1), Right(seq2)) => Right(seq1 ++: seq2)
16
+ }
14
17
  }
15
18
  }
16
19
 
17
20
  object Data {
18
- val fieldNames:Array[String] = FieldNameUtil.fieldList[Data]
19
- }
21
+ val fieldNames: Array[String] = FieldNameUtil.fieldList[Data]
22
+ }
@@ -6,28 +6,35 @@ import org.embulk.parser.twitter_ads_stats._
6
6
 
7
7
  case class IDData(metrics: Metrics, segment: Option[String]) {
8
8
  private def resolveColumn(
9
- id: String,
10
- metricElementNames: MetricElementNames,
11
- date: (LocalDate, Int),
12
- placement: String
13
- ): Either[ParseException, Column] = {
14
- metricElementNames.names.map { name =>
15
- (name._1, metrics.findMetricsGroup(date._2, name._2))
16
- }.foldRight[Either[ParseException, Map[String, MetricsGroup]]](Right(Map.empty)) {
17
- case ((_, Left(e)), _) => Left(e)
18
- case ((_, Right(_)), Left(e)) => Left(e)
19
- case ((s, Right(r)), Right(acc)) => Right(acc + (s -> r))
20
- }.map(Column(id, date._1, segment, placement, _))
9
+ id: String,
10
+ metricElementNames: MetricElementNames,
11
+ date: (LocalDate, Int),
12
+ placement: String
13
+ ): Either[ParseException, Column] = {
14
+ metricElementNames.names
15
+ .map { name =>
16
+ (name._1, metrics.findMetricsGroup(date._2, name._2))
17
+ }
18
+ .foldRight[Either[ParseException, Map[String, MetricsGroup]]](Right(Map.empty)) {
19
+ case ((_, Left(e)), _) => Left(e)
20
+ case ((_, Right(_)), Left(e)) => Left(e)
21
+ case ((s, Right(r)), Right(acc)) => Right(acc + (s -> r))
22
+ }
23
+ .map(Column(id, date._1, segment, placement, _))
21
24
  }
22
25
 
23
- private[define] def resolveColumns(id: String, metricElementNames: MetricElementNames, request: Request): Either[ParseException, Seq[Column]] = {
24
- request.params.targetDates.zipWithIndex.map { date =>
25
- resolveColumn(id, metricElementNames, date, request.params.placement)
26
- }.foldRight[Either[ParseException, Seq[Column]]](Right(Nil)) {
27
- case (Left(e), _) => Left(e)
28
- case (Right(_), Left(e)) => Left(e)
29
- case (Right(a), Right(seq)) => Right(a +: seq)
30
- }
26
+ private[define] def resolveColumns(id: String,
27
+ metricElementNames: MetricElementNames,
28
+ request: Request): Either[ParseException, Seq[Column]] = {
29
+ request.params.targetDates.zipWithIndex
30
+ .map { date =>
31
+ resolveColumn(id, metricElementNames, date, request.params.placement)
32
+ }
33
+ .foldRight[Either[ParseException, Seq[Column]]](Right(Nil)) {
34
+ case (Left(e), _) => Left(e)
35
+ case (Right(_), Left(e)) => Left(e)
36
+ case (Right(a), Right(seq)) => Right(a +: seq)
37
+ }
31
38
  }
32
39
  }
33
40
 
@@ -1,24 +1,25 @@
1
1
  package org.embulk.parser.twitter_ads_stats.define
2
2
 
3
- import java.time.{LocalDate, LocalDateTime}
3
+ import java.time.LocalDate
4
4
 
5
5
  case class Request(
6
- params: Params
7
- )
6
+ params: Params
7
+ )
8
8
 
9
9
  object Request {
10
10
  val fieldNames: Array[String] = FieldNameUtil.fieldList[Request]
11
11
  }
12
12
 
13
13
  case class Params(
14
- start_time: LocalDateTime,
15
- end_time: LocalDateTime,
16
- placement: String
17
- ) {
14
+ start_time: StatsDateTime,
15
+ end_time: StatsDateTime,
16
+ placement: String
17
+ ) {
18
18
  require(!start_time.isAfter(end_time))
19
+ require(start_time.isSameOffsetTime(end_time))
19
20
 
20
- val startDate = start_time.toLocalDate
21
- val endDate = end_time.toLocalDate
21
+ val startDate = start_time.adAccountLocalDate
22
+ val endDate = end_time.adAccountLocalDate
22
23
 
23
24
  /**
24
25
  * MetricTimeSeries の期間
@@ -29,7 +30,7 @@ case class Params(
29
30
  def loop(curDate: LocalDate, acc: List[LocalDate]): List[LocalDate] = {
30
31
  acc match {
31
32
  case x :: _ if !x.isBefore(endDate.minusDays(1)) => acc.reverse
32
- case _ => loop(curDate.plusDays(1), curDate :: acc)
33
+ case _ => loop(curDate.plusDays(1), curDate :: acc)
33
34
  }
34
35
  }
35
36
 
@@ -3,19 +3,21 @@ package org.embulk.parser.twitter_ads_stats.define
3
3
  import org.embulk.parser.twitter_ads_stats.{Column, MetricElementNames, ParseException}
4
4
 
5
5
  case class Root(
6
- data: Seq[Data],
7
- request: Request
8
- ) {
6
+ data: Seq[Data],
7
+ request: Request
8
+ ) {
9
9
  def resolveColumns(metricElementNames: MetricElementNames): Either[ParseException, Seq[Column]] = {
10
- data.map { d =>
11
- d.resolveColumns(metricElementNames, request)
12
- }.foldRight[Either[ParseException, Seq[Column]]](Right(Nil)) {
13
- case (Left(e), _) => Left(e)
14
- case (Right(_), Left(e)) => Left(e)
15
- case (Right(seq1), Right(seq2)) => Right(seq1 ++: seq2)
16
- }
10
+ data
11
+ .map { d =>
12
+ d.resolveColumns(metricElementNames, request)
13
+ }
14
+ .foldRight[Either[ParseException, Seq[Column]]](Right(Nil)) {
15
+ case (Left(e), _) => Left(e)
16
+ case (Right(_), Left(e)) => Left(e)
17
+ case (Right(seq1), Right(seq2)) => Right(seq1 ++: seq2)
18
+ }
17
19
  }
18
20
  }
19
21
  object Root {
20
- val fieldNames:Array[String] = FieldNameUtil.fieldList[Root]
21
- }
22
+ val fieldNames: Array[String] = FieldNameUtil.fieldList[Root]
23
+ }
@@ -1,8 +1,5 @@
1
1
  package org.embulk.parser.twitter_ads_stats.define
2
2
 
3
- import java.time.LocalDateTime
4
- import java.time.format.DateTimeFormatter
5
-
6
3
  import org.embulk.parser.twitter_ads_stats.{MetricElementNames, MetricTimeSeries}
7
4
  import spray.json.{DefaultJsonProtocol, DeserializationException, JsArray, JsString, JsValue, RootJsonReader}
8
5
 
@@ -13,7 +10,7 @@ class RootJson(metricElementNames: MetricElementNames) extends DefaultJsonProtoc
13
10
  private def readMetricTimeSeries(jsValue: JsValue): MetricTimeSeries = {
14
11
  jsValue match {
15
12
  case JsArray(arr) => Some(arr.map(_.convertTo[Long]))
16
- case _ => None
13
+ case _ => None
17
14
  }
18
15
  }
19
16
 
@@ -68,11 +65,9 @@ class RootJson(metricElementNames: MetricElementNames) extends DefaultJsonProtoc
68
65
  val fieldNames = Params.fieldNames.toList
69
66
  json.asJsObject.getFields(fieldNames: _*) match {
70
67
  case Seq(JsString(a), JsString(b), c) =>
71
- val formatter = DateTimeFormatter.ISO_DATE_TIME
72
- //todo DateTimeFormatterでフォーマットが出来ない場合の例外処理
73
68
  Params(
74
- LocalDateTime.parse(a, formatter),
75
- LocalDateTime.parse(b, formatter),
69
+ StatsDateTime(a),
70
+ StatsDateTime(b),
76
71
  c.convertTo[String]
77
72
  )
78
73
  case x => throw DeserializationException(msg = s"params can't deserialize json: $x", fieldNames = fieldNames)
@@ -0,0 +1,25 @@
1
+ package org.embulk.parser.twitter_ads_stats.define
2
+
3
+ import java.time.{LocalDate, LocalDateTime}
4
+ import java.time.format.DateTimeFormatter
5
+
6
+ /**
7
+ * @param iso8601DateTime This datetime represents midnight in the timezone of the advertiser's account.
8
+ */
9
+ case class StatsDateTime(iso8601DateTime: String) {
10
+
11
+ private val utcDateTime: LocalDateTime = LocalDateTime.parse(iso8601DateTime, DateTimeFormatter.ISO_DATE_TIME)
12
+
13
+ def adAccountLocalDate: LocalDate = utcDateTime.plusHours(StatsDateTime.DateLineOffsetHours).toLocalDate
14
+
15
+ def isAfter(that: StatsDateTime): Boolean = this.utcDateTime.isAfter(that.utcDateTime)
16
+
17
+ def isSameOffsetTime(that: StatsDateTime): Boolean = this.utcDateTime.toLocalTime == that.utcDateTime.toLocalTime
18
+
19
+ }
20
+
21
+ object StatsDateTime {
22
+
23
+ val DateLineOffsetHours = 12
24
+
25
+ }
@@ -2,7 +2,7 @@ package org.embulk.parser
2
2
 
3
3
  package object twitter_ads_stats {
4
4
  type MetricTimeSeries = Option[Vector[Long]]
5
- type MetricsGroup = Map[String, Option[Long]]
5
+ type MetricsGroup = Map[String, Option[Long]]
6
6
 
7
7
  val metricElementNames = MetricElementNames(
8
8
  Map(
@@ -6,7 +6,7 @@ class MetricElementNamesSpec extends UnitSpec {
6
6
  val names = MetricElementNames(
7
7
  Map("b" -> emptySeq, "a" -> emptySeq, "c" -> emptySeq)
8
8
  )
9
- val actual = names.getSortedMetricsGroupNames
9
+ val actual = names.getSortedMetricsGroupNames
10
10
  val expected = List("a", "b", "c")
11
11
 
12
12
  assert(actual == expected)
@@ -1,6 +1,6 @@
1
1
  package org.embulk.parser.twitter_ads_stats
2
2
 
3
- import spray.json.{JsNull, JsNumber, JsObject, pimpAny}
3
+ import spray.json.{pimpAny, JsNull, JsNumber, JsObject}
4
4
 
5
5
  class MetricsGroupJsonSpec extends UnitSpec {
6
6
  "json write" in {
@@ -11,8 +11,8 @@ class MetricsGroupJsonSpec extends UnitSpec {
11
11
  val actual = v.toJson
12
12
 
13
13
  val expected = JsObject(
14
- "a" -> JsNumber(3),
15
- "b" -> JsNumber(6),
14
+ "a" -> JsNumber(3),
15
+ "b" -> JsNumber(6),
16
16
  "c_e" -> JsNull
17
17
  )
18
18
  assert(actual == expected)
@@ -44,8 +44,8 @@ class MetricsJsonSpec extends UnitSpec {
44
44
  val actual = new RootJson(metricElementNames).MetricsReader.read(jsValue)
45
45
  val expected = Metrics(
46
46
  Map(
47
- "a" -> Some(Vector(510, 494, 364)),
48
- "b" -> Some(Vector(1, 2, 3)),
47
+ "a" -> Some(Vector(510, 494, 364)),
48
+ "b" -> Some(Vector(1, 2, 3)),
49
49
  "c_e" -> Some(Vector(1, 2, 3)),
50
50
  "c_f" -> None,
51
51
  "d_e" -> Some(Vector(2, 3, 4)),
@@ -1,12 +1,12 @@
1
1
  package org.embulk.parser.twitter_ads_stats.define
2
2
 
3
- import java.time.{LocalDate, LocalDateTime}
3
+ import java.time.LocalDate
4
4
 
5
5
  import org.embulk.parser.twitter_ads_stats.UnitSpec
6
6
 
7
7
  class ParamsSpec extends UnitSpec {
8
8
  "開始日~(終了日-1)の日程を取得する" in {
9
- val period = Params(LocalDateTime.of(2017, 1, 1, 0, 0, 0), LocalDateTime.of(2017, 1, 4, 23, 23, 23), "")
9
+ val period = Params(StatsDateTime("2016-12-31T15:00:00Z"), StatsDateTime("2017-01-03T15:00:00Z"), "")
10
10
  val actual = period.targetDates
11
11
  val expected = List(
12
12
  LocalDate.of(2017, 1, 1),
@@ -16,7 +16,7 @@ class ParamsSpec extends UnitSpec {
16
16
  assert(actual == expected)
17
17
  }
18
18
  "開始日から終了日までの全日程は、開始日から終了日が同一な場合は同一な日程となる" in {
19
- val period = Params(LocalDateTime.of(2017, 1, 1, 0, 0, 0), LocalDateTime.of(2017, 1, 1, 23, 23, 23), "")
19
+ val period = Params(StatsDateTime("2016-12-31T15:00:00Z"), StatsDateTime("2017-01-01T15:00:00Z"), "")
20
20
  val actual = period.targetDates
21
21
  val expected = List(
22
22
  LocalDate.of(2017, 1, 1)
@@ -17,4 +17,4 @@ class RootJsonSpec extends UnitSpec {
17
17
  val root = new RootJson(twitter_ads_stats.metricElementNames).RootReader.read(largeJsonSource)
18
18
  // println(root)
19
19
  }
20
- }
20
+ }
@@ -20,11 +20,11 @@ class RootSpec extends UnitSpec {
20
20
  "",
21
21
  Map(
22
22
  "media" -> Map(
23
- "media_views" -> Some(1),
23
+ "media_views" -> Some(1),
24
24
  "media_engagements" -> None
25
25
  ),
26
26
  "billing" -> Map(
27
- "billed_engagements" -> Some(1),
27
+ "billed_engagements" -> Some(1),
28
28
  "billed_charge_local_micro" -> Some(1)
29
29
  ),
30
30
  "web_conversion" -> Map(
@@ -39,11 +39,11 @@ class RootSpec extends UnitSpec {
39
39
  "",
40
40
  Map(
41
41
  "media" -> Map(
42
- "media_views" -> Some(2),
42
+ "media_views" -> Some(2),
43
43
  "media_engagements" -> None
44
44
  ),
45
45
  "billing" -> Map(
46
- "billed_engagements" -> Some(2),
46
+ "billed_engagements" -> Some(2),
47
47
  "billed_charge_local_micro" -> Some(2)
48
48
  ),
49
49
  "web_conversion" -> Map(
@@ -58,13 +58,13 @@ class RootSpec extends UnitSpec {
58
58
  "",
59
59
  Map(
60
60
  "media" -> Map(
61
- "media_views" -> Some(10),
61
+ "media_views" -> Some(10),
62
62
  "media_engagements" -> None
63
63
  ),
64
64
  "billing" -> Map(
65
- "billed_engagements" -> Some(10),
66
- "billed_charge_local_micro" -> Some(10)
67
- ),
65
+ "billed_engagements" -> Some(10),
66
+ "billed_charge_local_micro" -> Some(10)
67
+ ),
68
68
  "web_conversion" -> Map(
69
69
  "conversion_purchases_assisted" -> Some(10)
70
70
  )
@@ -77,11 +77,11 @@ class RootSpec extends UnitSpec {
77
77
  "",
78
78
  Map(
79
79
  "media" -> Map(
80
- "media_views" -> Some(20),
80
+ "media_views" -> Some(20),
81
81
  "media_engagements" -> None
82
82
  ),
83
83
  "billing" -> Map(
84
- "billed_engagements" -> Some(20),
84
+ "billed_engagements" -> Some(20),
85
85
  "billed_charge_local_micro" -> Some(20)
86
86
  ),
87
87
  "web_conversion" -> Map(
@@ -96,13 +96,13 @@ class RootSpec extends UnitSpec {
96
96
  "",
97
97
  Map(
98
98
  "media" -> Map(
99
- "media_views" -> Some(1),
99
+ "media_views" -> Some(1),
100
100
  "media_engagements" -> None
101
101
  ),
102
102
  "billing" -> Map(
103
- "billed_engagements" -> Some(1),
104
- "billed_charge_local_micro" -> Some(1)
105
- ),
103
+ "billed_engagements" -> Some(1),
104
+ "billed_charge_local_micro" -> Some(1)
105
+ ),
106
106
  "web_conversion" -> Map(
107
107
  "conversion_purchases_assisted" -> Some(1)
108
108
  )
@@ -115,11 +115,11 @@ class RootSpec extends UnitSpec {
115
115
  "",
116
116
  Map(
117
117
  "media" -> Map(
118
- "media_views" -> Some(2),
118
+ "media_views" -> Some(2),
119
119
  "media_engagements" -> None
120
120
  ),
121
121
  "billing" -> Map(
122
- "billed_engagements" -> Some(2),
122
+ "billed_engagements" -> Some(2),
123
123
  "billed_charge_local_micro" -> Some(2)
124
124
  ),
125
125
  "web_conversion" -> Map(
@@ -134,13 +134,13 @@ class RootSpec extends UnitSpec {
134
134
  "",
135
135
  Map(
136
136
  "media" -> Map(
137
- "media_views" -> Some(10),
137
+ "media_views" -> Some(10),
138
138
  "media_engagements" -> None
139
139
  ),
140
140
  "billing" -> Map(
141
- "billed_engagements" -> Some(10),
142
- "billed_charge_local_micro" -> Some(10)
143
- ),
141
+ "billed_engagements" -> Some(10),
142
+ "billed_charge_local_micro" -> Some(10)
143
+ ),
144
144
  "web_conversion" -> Map(
145
145
  "conversion_purchases_assisted" -> Some(10)
146
146
  )
@@ -153,11 +153,11 @@ class RootSpec extends UnitSpec {
153
153
  "",
154
154
  Map(
155
155
  "media" -> Map(
156
- "media_views" -> Some(20),
156
+ "media_views" -> Some(20),
157
157
  "media_engagements" -> None
158
158
  ),
159
159
  "billing" -> Map(
160
- "billed_engagements" -> Some(20),
160
+ "billed_engagements" -> Some(20),
161
161
  "billed_charge_local_micro" -> Some(20)
162
162
  ),
163
163
  "web_conversion" -> Map(
@@ -175,8 +175,8 @@ class RootSpec extends UnitSpec {
175
175
  val actual = createRoot(
176
176
  Request(
177
177
  params = Params(
178
- start_time = LocalDateTime.of(2017, 1, 1, 1, 1, 1),
179
- end_time = LocalDateTime.of(2017, 1, 4, 1, 1, 1),
178
+ start_time = StatsDateTime("2017-01-01T01:01:01Z"),
179
+ end_time = StatsDateTime("2017-01-04T01:01:01Z"),
180
180
  placement = ""
181
181
  )
182
182
  )
@@ -192,17 +192,17 @@ class RootSpec extends UnitSpec {
192
192
  val names = MetricElementNames(
193
193
  Map(
194
194
  "media" ->
195
- Seq(
196
- "media_views"
197
- )
195
+ Seq(
196
+ "media_views"
197
+ )
198
198
  )
199
199
  )
200
200
 
201
201
  val actual = createRoot(
202
202
  Request(
203
203
  params = Params(
204
- start_time = LocalDateTime.of(2017, 1, 1, 1, 1, 1),
205
- end_time = LocalDateTime.of(2017, 1, 1, 1, 1, 1),
204
+ start_time = StatsDateTime("2017-01-01T01:01:01Z"),
205
+ end_time = StatsDateTime("2017-01-01T01:01:01Z"),
206
206
  placement = ""
207
207
  )
208
208
  )
@@ -265,8 +265,8 @@ object RootSpec {
265
265
  val defaultRoot: Root = createRoot(
266
266
  Request(
267
267
  params = Params(
268
- start_time = LocalDateTime.of(2017, 1, 1, 1, 1, 1),
269
- end_time = LocalDateTime.of(2017, 1, 3, 1, 1, 1),
268
+ start_time = StatsDateTime("2017-01-01T01:01:01Z"),
269
+ end_time = StatsDateTime("2017-01-03T01:01:01Z"),
270
270
  placement = ""
271
271
  )
272
272
  )
@@ -281,10 +281,10 @@ object RootSpec {
281
281
  IDData(
282
282
  metrics = Metrics(
283
283
  Map(
284
- "billed_engagements" -> Some(Vector(1, 2)),
285
- "billed_charge_local_micro" -> Some(Vector(1, 2)),
286
- "media_views" -> Some(Vector(1, 2)),
287
- "media_engagements" -> None,
284
+ "billed_engagements" -> Some(Vector(1, 2)),
285
+ "billed_charge_local_micro" -> Some(Vector(1, 2)),
286
+ "media_views" -> Some(Vector(1, 2)),
287
+ "media_engagements" -> None,
288
288
  "conversion_purchases_assisted" -> Some(Vector(1, 2))
289
289
  )
290
290
  ),
@@ -293,10 +293,10 @@ object RootSpec {
293
293
  IDData(
294
294
  metrics = Metrics(
295
295
  Map(
296
- "billed_engagements" -> Some(Vector(10, 20)),
297
- "billed_charge_local_micro" -> Some(Vector(10, 20)),
298
- "media_views" -> Some(Vector(10, 20)),
299
- "media_engagements" -> None,
296
+ "billed_engagements" -> Some(Vector(10, 20)),
297
+ "billed_charge_local_micro" -> Some(Vector(10, 20)),
298
+ "media_views" -> Some(Vector(10, 20)),
299
+ "media_engagements" -> None,
300
300
  "conversion_purchases_assisted" -> Some(Vector(10, 20))
301
301
  )
302
302
  ),
@@ -310,10 +310,10 @@ object RootSpec {
310
310
  IDData(
311
311
  metrics = Metrics(
312
312
  Map(
313
- "billed_engagements" -> Some(Vector(1, 2)),
314
- "billed_charge_local_micro" -> Some(Vector(1, 2)),
315
- "media_views" -> Some(Vector(1, 2)),
316
- "media_engagements" -> None,
313
+ "billed_engagements" -> Some(Vector(1, 2)),
314
+ "billed_charge_local_micro" -> Some(Vector(1, 2)),
315
+ "media_views" -> Some(Vector(1, 2)),
316
+ "media_engagements" -> None,
317
317
  "conversion_purchases_assisted" -> Some(Vector(1, 2))
318
318
  )
319
319
  ),
@@ -322,10 +322,10 @@ object RootSpec {
322
322
  IDData(
323
323
  metrics = Metrics(
324
324
  Map(
325
- "billed_engagements" -> Some(Vector(10, 20)),
326
- "billed_charge_local_micro" -> Some(Vector(10, 20)),
327
- "media_views" -> Some(Vector(10, 20)),
328
- "media_engagements" -> None,
325
+ "billed_engagements" -> Some(Vector(10, 20)),
326
+ "billed_charge_local_micro" -> Some(Vector(10, 20)),
327
+ "media_views" -> Some(Vector(10, 20)),
328
+ "media_engagements" -> None,
329
329
  "conversion_purchases_assisted" -> Some(Vector(10, 20))
330
330
  )
331
331
  ),
@@ -0,0 +1,21 @@
1
+ package org.embulk.parser.twitter_ads_stats.define
2
+
3
+ import java.time.LocalDate
4
+
5
+ import org.embulk.parser.twitter_ads_stats.UnitSpec
6
+
7
+ class StatsDateTimeSpec extends UnitSpec {
8
+
9
+ "Twitter APIの日時パラメータをアドアカウントでのローカル日付に変換できる" should {
10
+ "2017-08-20T15:00:00Z は 2017/08/21になる(JST)" in {
11
+ assert(StatsDateTime("2017-08-20T15:00:00Z").adAccountLocalDate == LocalDate.of(2017, 8, 21))
12
+ }
13
+ "2017-08-20T08:00:00Z は 2017/08/20になる(PST)" in {
14
+ assert(StatsDateTime("2017-08-20T08:00:00Z").adAccountLocalDate == LocalDate.of(2017, 8, 20))
15
+ }
16
+ "2017-08-20T10:00:00Z は 2017/08/20になる(Pacific/Honolulu)" in {
17
+ assert(StatsDateTime("2017-08-20T10:00:00Z").adAccountLocalDate == LocalDate.of(2017, 8, 20))
18
+ }
19
+ }
20
+
21
+ }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: embulk-parser-twitter_ads_stats
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - kimutyam
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-25 00:00:00.000000000 Z
11
+ date: 2017-11-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -47,6 +47,7 @@ extra_rdoc_files: []
47
47
  files:
48
48
  - .gitignore
49
49
  - .scalafmt.conf
50
+ - .travis.yml
50
51
  - LICENSE.txt
51
52
  - README.md
52
53
  - build.gradle
@@ -74,6 +75,7 @@ files:
74
75
  - src/main/scala/org/embulk/parser/twitter_ads_stats/define/Request.scala
75
76
  - src/main/scala/org/embulk/parser/twitter_ads_stats/define/Root.scala
76
77
  - src/main/scala/org/embulk/parser/twitter_ads_stats/define/RootJson.scala
78
+ - src/main/scala/org/embulk/parser/twitter_ads_stats/define/StatsDateTime.scala
77
79
  - src/main/scala/org/embulk/parser/twitter_ads_stats/package.scala
78
80
  - src/test/resources/test.json
79
81
  - src/test/scala/org/embulk/parser/twitter_ads_stats/ColumnSpec.scala
@@ -84,7 +86,8 @@ files:
84
86
  - src/test/scala/org/embulk/parser/twitter_ads_stats/define/ParamsSpec.scala
85
87
  - src/test/scala/org/embulk/parser/twitter_ads_stats/define/RootJsonSpec.scala
86
88
  - src/test/scala/org/embulk/parser/twitter_ads_stats/define/RootSpec.scala
87
- - classpath/embulk-parser-twitter_ads_stats-0.1.1.jar
89
+ - src/test/scala/org/embulk/parser/twitter_ads_stats/define/StatsDateTimeSpec.scala
90
+ - classpath/embulk-parser-twitter_ads_stats-0.1.2.jar
88
91
  - classpath/scala-library-2.12.3.jar
89
92
  - classpath/spray-json_2.12-1.3.3.jar
90
93
  homepage: https://github.com/septeni-original/embulk-parser-twitter_ads_stats