Skip to content

Commit 642e886

Browse files
Merge pull request #21 from gabrielreid/20_plugin_support
Add support for query plugins #20
2 parents ecfb7e9 + 290f6d6 commit 642e886

File tree

3 files changed

+84
-5
lines changed

3 files changed

+84
-5
lines changed

src/main/scala/io/waylay/kairosdb/driver/models/Models.scala

+17-2
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ object KairosQuery {
173173
* @param order Orders the returned data points. This sorting is done before any aggregators are executed.
174174
* @param excludeTags By default, the result of the query includes tags and tag values associated with the data points.
175175
* If `excludeTags` is set to true, the tags will be excluded from the response.
176+
* @param plugins optional plugin references to customize the behavior of the query on this metric
176177
*/
177178
case class Query(
178179
metricName: MetricName,
@@ -181,16 +182,30 @@ case class Query(
181182
aggregators: Seq[Aggregator] = Seq.empty,
182183
limit: Option[Int] = None,
183184
order: Order = Order.defaultOrder,
184-
excludeTags: Boolean = false)
185+
excludeTags: Boolean = false,
186+
plugins: Seq[QueryPlugin] = Seq.empty)
185187

186188
/** @param timeZone The time zone for the time range of the query. If not specified, UTC is used. tz format, e.g. "Europe/Brussels"
187189
* @param cacheTime The amount of time in seconds to re use the cache from a previous query. When a query is made,
188190
* Kairos looks for the cache file for the query. If a cache file is found and the timestamp of the
189191
* cache file is within cache_time seconds from the current query, the cache is used.
190192
* Sending a query with a cacheTime set to 0 will always refresh the cache with new data from Cassandra.
193+
* @param plugins optional plugin references to custom the behavior of this query
191194
*/
192195
case class QueryMetrics(
193196
metrics: Seq[Query],
194197
timeSpan: TimeSpan,
195198
timeZone: Option[String] = None,
196-
cacheTime: Option[Int] = None)
199+
cacheTime: Option[Int] = None,
200+
plugins: Seq[QueryPlugin] = Seq.empty)
201+
202+
203+
/**
204+
* Reference to a plugin which can customize the behavior of a query.
205+
*
206+
* @param name published name of the plugin
207+
* @param properties properties for the plugin within the query invocation
208+
*/
209+
case class QueryPlugin(
210+
name: String,
211+
properties: Map[String,Any] = Map.empty)

src/main/scala/io/waylay/kairosdb/driver/models/json/Formats.scala

+28-3
Original file line numberDiff line numberDiff line change
@@ -305,14 +305,20 @@ object Formats {
305305

306306
implicit val queryMetricsWrites: Writes[QueryMetrics] = new Writes[QueryMetrics] {
307307
override def writes(queryMetrics: QueryMetrics): JsValue = {
308+
val plugins: Seq[(String, JsValue)] = if (queryMetrics.plugins.nonEmpty) {
309+
Seq("plugins" -> Json.toJson(queryMetrics.plugins))
310+
} else {
311+
Seq.empty
312+
}
313+
308314
val fields: Seq[(String, JsValue)] = Seq(
309315
queryMetrics.timeSpan.startTime.fieldName -> Json.toJson(queryMetrics.timeSpan.startTime),
310316
"metrics" -> JsArray(queryMetrics.metrics.map(x => Json.toJson(x)))
311317
) ++ Seq(
312318
queryMetrics.timeSpan.endTime.map(x => x.fieldName -> Json.toJson(x)),
313319
queryMetrics.timeZone.map("time_zone" -> JsString(_)),
314320
queryMetrics.cacheTime.map("cache_time" -> JsNumber(_))
315-
).flatten
321+
).flatten ++ plugins
316322

317323
JsObject(fields)
318324
}
@@ -324,6 +330,20 @@ object Formats {
324330

325331
implicit val queryTagFormat = Json.format[QueryTag]
326332

333+
implicit val queryPluginWrites: Writes[QueryPlugin] = (plugin: QueryPlugin) => {
334+
JsObject(Seq("name" -> JsString(plugin.name)) ++ plugin.properties.map(
335+
prop => {
336+
val propValue: JsValue = prop._2 match {
337+
case s: String => Json.toJson(s)
338+
case l: Long => Json.toJson(l)
339+
case i: Integer => Json.toJson(i.longValue())
340+
case d: Double => Json.toJson(d)
341+
case stringSeq: Seq[String] => Json.toJson(stringSeq)
342+
}
343+
prop._1 -> propValue
344+
}))
345+
}
346+
327347
implicit val queryWrites: Writes[Query] = new Writes[Query] {
328348
override def writes(query: Query): JsValue = {
329349
val tags = if (query.tags.isEmpty) {
@@ -380,7 +400,13 @@ object Formats {
380400
"name" -> query.metricName.name
381401
)
382402

383-
name ++ limit ++ tags ++ aggregators ++ groupBys ++ excludeTags ++ order
403+
val plugins = if (query.plugins.isEmpty) {
404+
Json.obj()
405+
} else {
406+
Json.obj("plugins" -> query.plugins)
407+
}
408+
409+
name ++ limit ++ tags ++ aggregators ++ groupBys ++ excludeTags ++ order ++ plugins
384410
}
385411
}
386412

@@ -445,7 +471,6 @@ object Formats {
445471
implicit val responseTagsReads = Json.reads[TagsResponse]
446472
implicit val tagResponseReads = Json.reads[TagQueryResponse]
447473

448-
449474
private def instant2kairosLong(instant: Instant): Long = instant.toEpochMilli
450475

451476
private def unitName(unit: TimeUnit): String = {

src/test/scala/unit/QueryWritesSpec.scala

+39
Original file line numberDiff line numberDiff line change
@@ -341,5 +341,44 @@ class QueryWritesSpec extends Specification {
341341
|}
342342
""".stripMargin)
343343
}
344+
345+
"Correctly serialize a minimal QueryPlugin" in {
346+
val queryPlugin = QueryPlugin("testPlugin")
347+
Json.toJson(queryPlugin) must be equalTo Json.obj("name" -> "testPlugin")
348+
}
349+
350+
"Correctly serialize a QueryPlugin with properties" in {
351+
val queryPlugin = QueryPlugin("testPlugin",
352+
Map(
353+
"stringProp" -> "stringVal",
354+
"intProp" -> 123,
355+
"doubleProp" -> 1.23d,
356+
"stringListProp" -> List("one", "two", "three")))
357+
Json.toJson(queryPlugin) must be equalTo Json.obj(
358+
"name" -> "testPlugin",
359+
"stringProp" -> "stringVal",
360+
"intProp" -> 123,
361+
"doubleProp" -> 1.23,
362+
"stringListProp" -> Json.arr("one", "two", "three"))
363+
}
364+
365+
"Correctly serialize a query with plugins configured at the Query level" in {
366+
val query = Query(MetricName("mymetric"), plugins = Seq(QueryPlugin("testPlugin", Map("propA" -> "valA"))))
367+
Json.toJson(query) must be equalTo Json.obj("name" -> "mymetric", "plugins" -> Json.arr(Json.obj("name" -> "testPlugin", "propA" -> "valA")))
368+
}
369+
370+
"Correctly serialize a query with plugins configured at the QueryMetric level" in {
371+
val qm = QueryMetrics(Seq(Query(MetricName("mymetric"))),
372+
TimeSpan(AbsoluteStartTime(Instant.ofEpochSecond(1470052425L))),
373+
plugins = Seq(QueryPlugin("testPlugin", Map("propA" -> "valA"))))
374+
375+
Json.toJson(qm) should be equalTo Json.obj(
376+
"start_absolute" -> 1470052425000L,
377+
"metrics" -> Seq(Json.obj("name" -> "mymetric")),
378+
"plugins" -> Json.arr(Json.obj("name" -> "testPlugin", "propA" -> "valA"))
379+
)
380+
381+
}
382+
344383
}
345384
}

0 commit comments

Comments
 (0)