diff options
-rw-r--r-- | .gitignore | 5 | ||||
-rw-r--r-- | pom.xml | 115 | ||||
-rw-r--r-- | src/main/scala/org/xapek/influxdb/Influxdb.scala | 165 | ||||
-rw-r--r-- | src/main/scala/org/xapek/influxdb/Main.scala | 39 | ||||
-rw-r--r-- | src/main/scala/org/xapek/influxdb/Sized.scala | 53 | ||||
-rw-r--r-- | src/test/scala/org/xapek/influxdb/AppTest.scala | 43 | ||||
-rw-r--r-- | src/test/scala/org/xapek/influxdb/SizedTest.scala | 23 |
7 files changed, 443 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a9a49f0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/target/ +/.cache-* +/.classpath +/.project +/.settings/ @@ -0,0 +1,115 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.xapek</groupId> + <artifactId>influxdb-tools</artifactId> + <version>0.0.1-SNAPSHOT</version> + <inceptionYear>2008</inceptionYear> + <properties> + <scala.version>2.11.6</scala.version> + </properties> + + <repositories> + <repository> + <id>maven-central</id> + <name>Maven Central</name> + <url>https://repo1.maven.org/maven2</url> + </repository> + <repository> + <id>scala-tools.org</id> + <name>Scala-Tools Maven2 Repository</name> + <url>http://scala-tools.org/repo-releases</url> + </repository> + </repositories> + + <pluginRepositories> + <pluginRepository> + <id>maven-central</id> + <name>Maven Central</name> + <url>https://repo1.maven.org/maven2</url> + </pluginRepository> + <pluginRepository> + <id>scala-tools.org</id> + <name>Scala-Tools Maven2 Repository</name> + <url>http://scala-tools.org/repo-releases</url> + </pluginRepository> + </pluginRepositories> + + <dependencies> + <dependency> + <groupId>org.scala-lang</groupId> + <artifactId>scala-library</artifactId> + <version>${scala.version}</version> + </dependency> + <dependency> + <groupId>com.typesafe.akka</groupId> + <artifactId>akka-actor_2.11</artifactId> + <version>2.3.9</version> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.4</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.specs</groupId> + <artifactId>specs</artifactId> + <version>1.2.5</version> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <sourceDirectory>src/main/scala</sourceDirectory> + <testSourceDirectory>src/test/scala</testSourceDirectory> + <plugins> + <plugin> + <groupId>org.scala-tools</groupId> + <artifactId>maven-scala-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>compile</goal> + <goal>testCompile</goal> + </goals> + </execution> + </executions> + <configuration> + <scalaVersion>${scala.version}</scalaVersion> + <args> + <arg>-target:jvm-1.5</arg> + </args> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-eclipse-plugin</artifactId> + <configuration> + <downloadSources>true</downloadSources> + <buildcommands> + <buildcommand>ch.epfl.lamp.sdt.core.scalabuilder</buildcommand> + </buildcommands> + <additionalProjectnatures> + <projectnature>ch.epfl.lamp.sdt.core.scalanature</projectnature> + </additionalProjectnatures> + <classpathContainers> + <classpathContainer>org.eclipse.jdt.launching.JRE_CONTAINER</classpathContainer> + <classpathContainer>ch.epfl.lamp.sdt.launching.SCALA_CONTAINER</classpathContainer> + </classpathContainers> + </configuration> + </plugin> + </plugins> + </build> + <reporting> + <plugins> + <plugin> + <groupId>org.scala-tools</groupId> + <artifactId>maven-scala-plugin</artifactId> + <configuration> + <scalaVersion>${scala.version}</scalaVersion> + </configuration> + </plugin> + </plugins> + </reporting> +</project> diff --git a/src/main/scala/org/xapek/influxdb/Influxdb.scala b/src/main/scala/org/xapek/influxdb/Influxdb.scala new file mode 100644 index 0000000..15e2021 --- /dev/null +++ b/src/main/scala/org/xapek/influxdb/Influxdb.scala @@ -0,0 +1,165 @@ +package org.xapek.influxdb + +trait InfluxValue { + type JavaT + def toString(): String + def toJava: JavaT +} + +class QueryBuilder1(select: Seq[InfluxColumn]) { + def FROM(table: String): QueryBuilder2 = { + new QueryBuilder2(select, table) + } +} + +class QueryBuilder2(select: Seq[InfluxColumn], from: String) extends QueryBuilder1(select) { + def WHERE[E <: Expr](eq: E): QueryBuilder3[E] = { + new QueryBuilder3(eq, select, from) + } + + override def toString(): String = { + "SELECT " + select.mkString(", ") + " FROM " + from + } +} + +class QueryBuilder3[WhereT <: Expr](whereExpr: WhereT, select: Seq[InfluxColumn], from: String) extends QueryBuilder2(select, from) { + def &&[E2 <: Expr](other: E2): QueryBuilder3[AndExpr[WhereT, E2]] = { + new QueryBuilder3(new AndExpr(whereExpr, other), select, from) + } + + def ||[E2 <: Expr](other: E2): QueryBuilder3[OrExpr[WhereT, E2]] = { + new QueryBuilder3(new OrExpr(whereExpr, other), select, from) + } + + def GROUP_BY[ColumnT <% InfluxColumn](column: ColumnT): QueryBuilder4[WhereT] = { + new QueryBuilder4(List(column), whereExpr, select, from) + } + + override def toString(): String = { + super.toString() + " WHERE " + whereExpr.toString() + } +} + +class QueryBuilder4[WhereT <: Expr](groupBy: Seq[InfluxColumn], whereExpr: WhereT, select: Seq[InfluxColumn], from: String) extends QueryBuilder3(whereExpr, select, from) { + def <<=[ColumnT <% InfluxColumn](column: ColumnT): QueryBuilder4[WhereT] = { + val x: InfluxColumn = column + new QueryBuilder4(groupBy :+ x, whereExpr, select, from) + } + + override def toString(): String = { + super.toString() + " GROUP BY " + groupBy.mkString(", ") + } +} + +protected trait E { + def &&[E2 <: Expr](other: E2): AndExpr[this.type, E2] + def ||[E2 <: Expr](other: E2): OrExpr[this.type, E2] +} + +abstract class Expr extends E { + def toString(): String + + def &&[E2 <: Expr](other: E2) = { + new AndExpr(this, other) + } + + def ||[E2 <: Expr](other: E2) = { + new OrExpr(this, other) + } + + def test(other: Expr): Expr = { + return this + } +} + +class ValueExpr[ValueT <: InfluxValue](val value: ValueT) extends Expr { + override def toString(): String = value.toString +} + +abstract class BinaryOp[E1 <: E, E2 <: E](val op1: E1, val op2: E2) extends Expr { + def str: String + override def toString(): String = { + "(" + op1.toString() + " " + str + " " + op2.toString() + ")" + } +} + +class AndExpr[E1 <: E, E2 <: E](op1: E1, op2: E2) extends BinaryOp[E1, E2](op1, op2) { + def str = "AND" +} + +class OrExpr[E1 <: E, E2 <: E](op1: E1, op2: E2) extends BinaryOp[E1, E2](op1, op2) { + override def str = "OR" +} + +class EqExpr[T <: InfluxValue](column: InfluxColumn, op: ValueExpr[T]) extends BinaryOp[InfluxColumn, ValueExpr[T]](column, op) { + def str = "==" +} + +class NeqExpr[T <: InfluxValue](column: InfluxColumn, op: ValueExpr[T]) extends BinaryOp[InfluxColumn, ValueExpr[T]](column, op) { + def str = "==" +} + +class InfluxString(val value: String) extends Expr with InfluxValue { + type JavaT = String + override def toString(): String = { + "'" + value.replace("\\", "\\\\").replace("'", "\\'") + "'" // TODO + } + override def toJava(): String = value +} + +class InfluxNumber(val value: Number) extends Expr with InfluxValue { + type JavaT = Number + + override def toString(): String = { + value.toString + } + override def toJava(): Number = value +} + +class InfluxColumn(val name: String) extends Expr { + override def toString(): String = { + "\"" + name.replace("\\", "\\\\").replace("\"", "\\\"") + "\"" + } + + def ==[Z <: InfluxValue, ValueT <% Z](value: ValueT): EqExpr[Z] = { + new EqExpr(this, new ValueExpr(value)) + } + + def !=[Z <: InfluxValue, ValueT <% Z](value: ValueT): NeqExpr[Z] = { + new NeqExpr(this, new ValueExpr(value)) + } +} + +object Influxdb { + def SELECT(select: Seq[String]): QueryBuilder1 = { + new QueryBuilder1(select.map { x: String => influxColumn(x) }) + } + + def SELECT[ColumnT <% InfluxColumn](select: ColumnT): QueryBuilder1 = { + new QueryBuilder1(List(select)) + } + + def col(col: String): InfluxColumn = { + new InfluxColumn(col) + } + + implicit def influxString(s: String): InfluxString = { + new InfluxString(s) + } + + implicit def influxNumber(n: Int): InfluxNumber = { + new InfluxNumber(n) + } + + implicit def influxNumber(n: Double): InfluxNumber = { + new InfluxNumber(n) + } + + implicit def influxColumn(s: String): InfluxColumn = { + new InfluxColumn(s) + } + + implicit def queryToString(q: QueryBuilder2): String = q.toString + implicit def queryToString[T <: Expr](q: QueryBuilder3[T]): String = q.toString + implicit def queryToString[T <: Expr](q: QueryBuilder4[T]): String = q.toString +} diff --git a/src/main/scala/org/xapek/influxdb/Main.scala b/src/main/scala/org/xapek/influxdb/Main.scala new file mode 100644 index 0000000..c56d3bb --- /dev/null +++ b/src/main/scala/org/xapek/influxdb/Main.scala @@ -0,0 +1,39 @@ +package org.xapek.influxdb + +import akka.actor.Actor +import akka.actor.Props +import akka.event.Logging +import akka.actor.ActorDSL +import akka.actor.ActorSystem +import akka.actor.ActorLogging +import org.xapek.influxdb.Influxdb._ + +case class Row(columns: Seq[String]) + +case class Write(measurement: String, columns: Seq[String]) +class GenericReader(query: String) extends Actor with ActorLogging { + def receive = { + case row: Row => log.info("Thanks for the pint: " + row.columns.toString()) + } +} + +object MyReader extends GenericReader(Influxdb SELECT "value" FROM "test" WHERE col("time") == 30) + + + + +object Main { + + def main(args: Array[String]): Unit = { + // val system = ActorSystem("test") + // val alice = system.actorOf(Props(MyReader), "alice") + // + // alice ! new Row(List("a")) + // + // system.shutdown() + // + // val x : Tuple2[Int,Int] = (1,2) + + } +} + diff --git a/src/main/scala/org/xapek/influxdb/Sized.scala b/src/main/scala/org/xapek/influxdb/Sized.scala new file mode 100644 index 0000000..fc402cd --- /dev/null +++ b/src/main/scala/org/xapek/influxdb/Sized.scala @@ -0,0 +1,53 @@ +package org.xapek.influxdb + +/** + * Partial re-implementation of Sized and Nat type from https://github.com/milessabin/shapeless + */ + +/** Natural Number Type */ +trait Nat { + type N <: Nat +} + +/** Successor */ +case class Succ[P <: Nat]() extends Nat { + type N = Succ[P] +} + +/** Zero */ +class _0 extends Nat with Serializable { + type N = _0 +} + +/** Nat type to Int value conversion */ +trait ToInt[N <: Nat] extends Serializable { + def apply(): Int +} + +object ToInt { + def apply[N <: Nat](implicit toInt: ToInt[N]): ToInt[N] = toInt + + implicit val toInt0 = new ToInt[_0] { + def apply() = 1 + } + implicit def toIntSucc[N <: Nat](implicit toIntN: ToInt[N]) = new ToInt[Succ[N]] { + def apply() = toIntN() + 1 + } +} + +/** Seq with size coded in type */ +class Sized[Repr, L <: Nat](val unsized: Seq[Repr]) extends AnyVal { + override def toString = unsized.toString +} + +object SizedOp { + def wrap[Repr, L <: Nat](r: Repr) = new Sized[Repr, _0](List(r)) + + def add[Repr, L <: Nat](s: Sized[Repr, L], r: Repr) = new Sized[Repr, Succ[L]](s.unsized ++ List(r)) + + def toInt[N <: Nat](implicit toIntN: ToInt[N]) = toIntN() + + def toInt(n: Nat)(implicit toIntN: ToInt[n.N]) = toIntN() + + def count[Repr, M <: Nat](s: Sized[Repr, M])(implicit ev: ToInt[M]) = toInt[M] +}
\ No newline at end of file diff --git a/src/test/scala/org/xapek/influxdb/AppTest.scala b/src/test/scala/org/xapek/influxdb/AppTest.scala new file mode 100644 index 0000000..26ed08f --- /dev/null +++ b/src/test/scala/org/xapek/influxdb/AppTest.scala @@ -0,0 +1,43 @@ +package org.xapek.influxdb + +import org.junit._ +import Assert._ +import org.xapek.influxdb.Influxdb._ + +@Test +class AppTest { + + @Test + def testStatements() = { + assertTrue((Influxdb SELECT "foo" FROM "bla" WHERE col("a") == "asd") + .toString().contains("as")) + + assertTrue((Influxdb SELECT List("foo", "bla") FROM "bla" WHERE col("a") == "asd") + .toString().contains("foo")) + + assertTrue((Influxdb SELECT List("foo", "bla") FROM "bla" WHERE col("a") == 1) + .toString().contains("== 1")) + + assertTrue((Influxdb + SELECT col("foo") + FROM "bla" + WHERE col("a") == "asd" || col("b") == "C" && col("c") == "d").toString().contains("bla")) + + assertTrue((Influxdb + SELECT "foo" + FROM "bla" + WHERE (col("a") == "asd" || col("b") == "C") && col("c") == "d").toString().contains("foo")) + + assertTrue((Influxdb + SELECT "foo" + FROM "bla" + WHERE (col("a") == "asd" || col("b") == "C") && col("c") == "d" + GROUP_BY "asd").toString().contains("GROUP BY")) + + assertTrue((Influxdb + SELECT col("foo") + FROM "bla" + WHERE (col("a") == "asd" || col("b") == "C") && col("c") == "d" + GROUP_BY "asd" <<= "asd2").toString().contains("asd2")) + } +} diff --git a/src/test/scala/org/xapek/influxdb/SizedTest.scala b/src/test/scala/org/xapek/influxdb/SizedTest.scala new file mode 100644 index 0000000..5f51e91 --- /dev/null +++ b/src/test/scala/org/xapek/influxdb/SizedTest.scala @@ -0,0 +1,23 @@ +package org.xapek.influxdb + +import org.junit._ +import org.junit.Assert._ +import org.xapek.influxdb.Influxdb._ + +@Test +class SizedTest { + @Test + def testStatements() = { + val s1 = SizedOp.wrap("abc") + assertEquals(1, SizedOp.count(s1)) + assertEquals(List("abc"), s1.unsized) + + val s2 = SizedOp.add(s1, "cde") + assertEquals(2, SizedOp.count(s2)) + assertEquals(List("abc", "cde"), s2.unsized) + + val s3 = SizedOp.add(s2, "fgh") + assertEquals(SizedOp.count(s3), 3) + assertEquals(List("abc", "cde", "fgh"), s3.unsized) + } +} |