influxdb-client-java icon indicating copy to clipboard operation
influxdb-client-java copied to clipboard

Should the Flux DSL support Flux as an open langauge?

Open nathanielc opened this issue 4 years ago • 1 comments

The DSL API presents a convenient way for users to build Flux queries without having worry about the mechanics of constructing the query.

I have a question about its design and intended use cases. Currently the implementation requires that a Java class be constructed to mirror every function in the Flux standard library. Should the DSL support the addition of other custom functions? Said another way Flux is an open language, meaning users can create their own functions etc and use those. As the DSL is currently written it is not convenient to work with those kinds of functions since there are no types to create them.

For example a user could create this Flux code:

mydata = (start) => 
    from(bucket: "mybucket")
        |> range(start: start)
        |> filter(fn: (r) => r._measurement == "temp")

mydata(start: -1m)
   |> sum()
   |> yield(name: "last_minute")

mydata(start: -1d)
   |> sum()
   |> yield(name: "last_day")

There is no way to express the same thing in the DSL currently (without the use of the expression() function).

I don't really have a solution to this problem rather open to ideas and wanting to start a discussion around a way we could address the openness of the Flux language from the DSL.

nathanielc avatar Dec 03 '20 23:12 nathanielc

Users are able to create custom operator for function that are missing in the DSL: https://github.com/influxdata/influxdb-client-java/tree/master/flux-dsl#custom-operator

Create an operator for their own function is also possible, but it is no so easy:

package com.example.flux;

import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nonnull;

import com.influxdb.Arguments;
import com.influxdb.query.dsl.Flux;
import com.influxdb.query.dsl.functions.AbstractParametrizedFlux;
import com.influxdb.query.dsl.functions.YieldFlux;
import com.influxdb.query.dsl.functions.restriction.Restrictions;

import org.junit.jupiter.api.Test;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;

@RunWith(JUnitPlatform.class)
class MyDataTest {

    @Test
    void query() {

        Flux myData = new MyData();

        YieldFlux last_minute = new MyData()
                    .withStart("-1m")
                .sum()
                .yield("last_minute");
        
        YieldFlux last_day = new MyData()
                    .withStart("-1d")
                .sum()
                .yield("last_day");

        String query = Stream.of(myData, last_minute, last_day)
                .map(Flux::toString)
                .collect(Collectors.joining("\n\n"));

        System.out.println(query);
    }

    public static class MyData extends AbstractParametrizedFlux {

        @Nonnull
        @Override
        protected String operatorName() {
            return "mydata";
        }

        /**
         * @param start Specifies the oldest time to be included in the results
         * @return this
         */
        @Nonnull
        public MyData withStart(@Nonnull final String start) {

            Arguments.checkDuration(start, "Start");

            this.withPropertyValue("start", start);

            return this;
        }

        @Nonnull
        @Override
        public String toString() {
            Flux filter = Flux.from("my-bucket")
                .range()
                    .withPropertyValue("start", "start")
                .filter(Restrictions.measurement().equal("temp"));

            return operatorName() + " = (start) => \n" + filter;
        }
    }
}
mydata = (start) => 
from(bucket:"my-bucket")
	|> range(start:start)
	|> filter(fn: (r) => r["_measurement"] == "temp")

mydata(start:-1m)
	|> sum()
	|> yield(name:"last_minute")

mydata(start:-1d)
	|> sum()
	|> yield(name:"last_day")

but the better support will be useful.

Regards

bednar avatar Dec 04 '20 10:12 bednar