diff --git a/pom.xml b/pom.xml index aea79c1..eeae816 100644 --- a/pom.xml +++ b/pom.xml @@ -117,6 +117,10 @@ + + false + true + org.apache.maven.plugins diff --git a/src/main/antlr4/io/github/willena/influxql/parser/InfluxqlLexer.g4 b/src/main/antlr4/io/github/willena/influxql/parser/InfluxqlLexer.g4 new file mode 100644 index 0000000..b04771c --- /dev/null +++ b/src/main/antlr4/io/github/willena/influxql/parser/InfluxqlLexer.g4 @@ -0,0 +1,146 @@ +lexer grammar InfluxqlLexer; + +options { + caseInsensitive = true; +} + +QUOTE: '"'; +SCOL : ';'; +DOT : '.'; +OPEN_PAR : '('; +CLOSE_PAR : ')'; +COMMA : ','; +ASSIGN : '='; +STAR : '*'; +PLUS : '+'; +MINUS : '-'; +TILDE : '~'; +SLASH : '/'; +MOD : '%'; +LT2 : '<<'; +GT2 : '>>'; +AMP : '&'; +LT : '<'; +LT_EQ : '<='; +GT : '>'; +GT_EQ : '>='; +EQ : '=='; +NOT_EQ1 : '!='; +NOT_EQ2 : '<>'; +REG_MATCH: '=~'; +OR_EX: '^'; +PIPE: '|'; +PIPE2: '||'; +START_TAGS: STAR '::tag'; +START_FIELD: STAR '::field'; + +// Keywords +AND: 'AND'; +OR: 'OR'; +ALL: 'ALL'; +ALTER: 'ALTER'; +ANALYZE: 'ANALYZE'; +ANY: 'ANY'; +AS: 'AS'; +ASC: 'ASC'; +BEGIN: 'BEGIN'; +BY: 'BY'; +CREATE: 'CREATE'; +CONTINUOUS: 'CONTINUOUS'; +DATABASE: 'DATABASE'; +DATABASES: 'DATABASES'; +DEFAULT: 'DEFAULT'; +DELETE: 'DELETE'; +DESC: 'DESC'; +DESTINATIONS: 'DESTINATIONS'; +DIAGNOSTICS: 'DIAGNOSTICS'; +DISTINCT: 'DISTINCT'; +DROP: 'DROP'; +DURATION: 'DURATION'; +END: 'END'; +EVERY: 'EVERY'; +EXPLAIN: 'EXPLAIN'; +FIELD: 'FIELD'; +FOR: 'FOR'; +FROM: 'FROM'; +GRANT: 'GRANT'; +GRANTS: 'GRANTS'; +GROUP: 'GROUP'; +GROUPS: 'GROUPS'; +IN: 'IN'; +INF: 'INF'; +INSERT: 'INSERT'; +INTO: 'INTO'; +KEY: 'KEY'; +KEYS: 'KEYS'; +KILL: 'KILL'; +LIMIT: 'LIMIT'; +SHOW: 'SHOW'; +MEASUREMENT: 'MEASUREMENT'; +MEASUREMENTS: 'MEASUREMENTS'; +NAME: 'NAME'; +OFFSET: 'OFFSET'; +ON: 'ON'; +ORDER: 'ORDER'; +PASSWORD: 'PASSWORD'; +POLICY: 'POLICY'; +POLICIES: 'POLICIES'; +PRIVILEGES: 'PRIVILEGES'; +QUERIES: 'QUERIES'; +QUERY: 'QUERY'; +READ: 'READ'; +REPLICATION: 'REPLICATION'; +RESAMPLE: 'RESAMPLE'; +RETENTION: 'RETENTION'; +REVOKE: 'REVOKE'; +SELECT: 'SELECT'; +SERIES: 'SERIES'; +SET: 'SET'; +SHARD: 'SHARD'; +SHARDS: 'SHARDS'; +SLIMIT: 'SLIMIT'; +SOFFSET: 'SOFFSET'; +STATS: 'STATS'; +SUBSCRIPTION: 'SUBSCRIPTION'; +SUBSCRIPTIONS: 'SUBSCRIPTIONS'; +TAG: 'TAG'; +TO: 'TO'; +USER: 'USER'; +USERS: 'USERS'; +VALUES: 'VALUES'; +WHERE: 'WHERE'; +WITH: 'WITH'; +WRITE: 'WRITE'; +CARDINALITY: 'CARDINALITY'; +EXACT: 'EXACT'; + +FILL: 'FILL'; +NULL: 'NULL'; +NONE: 'NONE'; +PREVIOUS: 'PREVIOUS'; +LINEAR: 'LINEAR'; +TZ: 'TZ'; +TRUE: 'TRUE'; +FALSE: 'FALSE'; +MEASUREMENT_BACK_REF: '.:MEASUREMENT'; + +IDENTIFIER: + '"' (~'"' | '""')* '"' + | '`' (~'`' | '``')* '`' + | [A-Z_\u007F-\uFFFF] [A-Z_0-9\u007F-\uFFFF]* + ; + +INTEGER_LITERAL: DIGIT+; +NUMERIC_LITERAL: (DIGIT+ ('.' DIGIT*)? | '.' DIGIT+); +STRING_LITERAL: '\'' ( ~'\'' | '\'\'')* '\''; + +DURATION_LITERAL: INTEGER_LITERAL ('ns' | 'u' | 'µ' | 'ms' | 's' | 'm' | 'h' | 'd' | 'w'); + +REGULAR_EXPRESSION_LITERAL: '/' UNICODE_CHAR* '/'; + +UNICODE_CHAR: ~[ \t\r\n]; + +fragment DIGIT: [0-9]; + +SPACES: [ \u000B\t\r\n] -> channel(HIDDEN); +UNEXPECTED_CHAR: .; diff --git a/src/main/antlr4/io/github/willena/influxql/parser/InfluxqlParser.g4 b/src/main/antlr4/io/github/willena/influxql/parser/InfluxqlParser.g4 index 955e557..f4c669d 100644 --- a/src/main/antlr4/io/github/willena/influxql/parser/InfluxqlParser.g4 +++ b/src/main/antlr4/io/github/willena/influxql/parser/InfluxqlParser.g4 @@ -15,10 +15,10 @@ * limitations under the License. */ -grammar InfluxqlParser; +parser grammar InfluxqlParser; options { - caseInsensitive = true; + tokenVocab = InfluxqlLexer; } // ------------- PARSER --------------------- @@ -54,7 +54,9 @@ statement : alter_retention_policy_stmt | show_shards_stmt | show_subscriptions_stmt| show_tag_keys_stmt | + show_tag_key_cardinality_stmt show_tag_values_stmt | + show_tag_values_cardinality_stmt show_users_stmt | revoke_stmt | select_stmt ; @@ -64,32 +66,38 @@ create_continuous_query_stmt: CREATE CONTINUOUS QUERY query_name=IDENTIFIER on_c create_database_stmt: CREATE DATABASE db_name=IDENTIFIER ( WITH retention_policy_duration? retention_policy_replication? retention_policy_shard_group_duration? retention_policy_name? )?; create_retention_policy_stmt : CREATE RETENTION POLICY policy_name=IDENTIFIER on_clause retention_policy_duration retention_policy_replication ( retention_policy_shard_group_duration )? ( DEFAULT )?; create_subscription_stmt : CREATE SUBSCRIPTION subscription_name=IDENTIFIER ON db_name=IDENTIFIER DOT retention_policy=IDENTIFIER DESTINATIONS (ANY|ALL) host=STRING_LITERAL ( COMMA host=STRING_LITERAL)*; -create_user_stmt : CREATE USER user_name=IDENTIFIER WITH PASSWORD password=STRING_LITERAL ( WITH ALL PRIVILEGES )?; +create_user_stmt : CREATE USER user_name=IDENTIFIER WITH PASSWORD password=STRING_LITERAL (WITH ALL PRIVILEGES)?; delete_stmt : DELETE ( from_clause | where_clause | from_clause where_clause ); drop_continuous_query_stmt : DROP CONTINUOUS QUERY query_name=IDENTIFIER on_clause; drop_database_stmt : DROP DATABASE db_name=IDENTIFIER; -drop_measurement_stmt : DROP MEASUREMENT measurement; +// Drop measurement does not currently support the full range of rules (limitation of influxdb) and has been updated +// The described grammar on influx website should be: +// drop_measurement_stmt : DROP MEASUREMENT measurement; +drop_measurement_stmt : DROP MEASUREMENT measurement_value=IDENTIFIER; drop_retention_policy_stmt : DROP RETENTION POLICY policy_name=IDENTIFIER on_clause; drop_series_stmt : DROP SERIES ( from_clause | where_clause | from_clause where_clause ); -drop_shard_stmt : DROP SHARD ( shard_id=NUMERIC_LITERAL ); +drop_shard_stmt : DROP SHARD ( shard_id=INTEGER_LITERAL ); drop_subscription_stmt : DROP SUBSCRIPTION subscription_name=IDENTIFIER ON db_name=IDENTIFIER DOT retention_policy=IDENTIFIER; -drop_user_stmt : DROP USER user_name=IDENTIFIER ; +drop_user_stmt : DROP USER user_name=IDENTIFIER; explain_stmt : EXPLAIN ANALYZE? select_stmt; grant_stmt : GRANT privilege on_clause? to_clause; -kill_query_statement : KILL QUERY query_id=NUMERIC_LITERAL; +// On host is only available for cluster installation of influxdb +kill_query_statement : KILL QUERY query_id=INTEGER_LITERAL (ON host=STRING_LITERAL)?; show_continuous_queries_stmt : SHOW CONTINUOUS QUERIES; show_databases_stmt : SHOW DATABASES; -show_field_keys_stmt : SHOW FIELD KEYS from_clause?; -show_grants_stmt : SHOW GRANTS FOR user_name=IDENTIFIER ; +show_field_keys_stmt : SHOW FIELD KEYS on_clause? from_clause? order_by_clause? limit_clause? offset_clause?; +show_grants_stmt : SHOW GRANTS FOR user_name=IDENTIFIER; show_measurements_stmt : SHOW MEASUREMENTS on_clause? with_measurement_clause? where_clause? limit_clause? offset_clause?; show_queries_stmt : SHOW QUERIES; show_retention_policies : SHOW RETENTION POLICIES on_clause; -show_series_stmt : SHOW SERIES from_clause? where_clause? limit_clause? offset_clause?; +show_series_stmt : SHOW SERIES on_clause? from_clause? where_clause? limit_clause? offset_clause?; show_shard_groups_stmt : SHOW SHARD GROUPS; show_shards_stmt : SHOW SHARDS; show_subscriptions_stmt : SHOW SUBSCRIPTIONS; -show_tag_keys_stmt : SHOW TAG KEYS from_clause? where_clause? group_by_clause? limit_clause? offset_clause?; -show_tag_values_stmt : SHOW TAG VALUES from_clause? with_tag_clause where_clause? group_by_clause? limit_clause? offset_clause?; +show_tag_keys_stmt : SHOW TAG KEYS on_clause? from_clause? where_clause? order_by_clause? limit_clause? offset_clause?; +show_tag_key_cardinality_stmt: SHOW TAG KEY EXACT? CARDINALITY on_clause? from_clause? where_clause? group_by_clause? limit_clause? offset_clause?; +show_tag_values_stmt : SHOW TAG VALUES on_clause? from_clause? with_tag_clause where_clause? limit_clause? offset_clause?; +show_tag_values_cardinality_stmt: SHOW TAG VALUES EXACT? CARDINALITY on_clause? from_clause? where_clause? group_by_clause? limit_clause? offset_clause? with_tag_clause; show_users_stmt : SHOW USERS; revoke_stmt : REVOKE privilege on_clause? FROM user_name=IDENTIFIER ; select_stmt : SELECT fields from_clause into_clause? where_clause? group_by_clause? order_by_clause? limit_clause? offset_clause? slimit_clause? soffset_clause? timezone_clause?; @@ -100,7 +108,7 @@ every_stmt: EVERY DURATION_LITERAL; for_stmt: FOR DURATION_LITERAL; alias: AS IDENTIFIER; -back_ref: ( policy_name=IDENTIFIER '.:MEASUREMENT' ) | ( db_name=IDENTIFIER '.' ( policy_name=IDENTIFIER )? '.:MEASUREMENT' ); +back_ref: ( policy_name=IDENTIFIER MEASUREMENT_BACK_REF ) | ( db_name=IDENTIFIER DOT ( policy_name=IDENTIFIER )? MEASUREMENT_BACK_REF ); dimension : expression; dimensions : dimension ( COMMA dimension )*; field: expression ( alias )?; @@ -111,11 +119,11 @@ measurment_with_rp: policy_name=IDENTIFIER DOT simple_measurement_name; measurement_with_rp_and_database: db_name=IDENTIFIER (DOT policy_name=IDENTIFIER )? DOT simple_measurement_name; measurements: measurement ( COMMA measurement )*; simple_measurement_name : IDENTIFIER | REGULAR_EXPRESSION_LITERAL; -privilege: ALL PRIVILEGES? | READ | WRITE; +privilege: (ALL PRIVILEGES?) | READ | WRITE; retention_policy_option : retention_policy_duration | retention_policy_replication | retention_policy_shard_group_duration | DEFAULT; retention_policy_duration : DURATION DURATION_LITERAL; -retention_policy_replication : REPLICATION NUMERIC_LITERAL; +retention_policy_replication : REPLICATION INTEGER_LITERAL; retention_policy_shard_group_duration : SHARD DURATION DURATION_LITERAL; retention_policy_name : NAME IDENTIFIER; @@ -123,160 +131,65 @@ sort_field : field_key=IDENTIFIER ( ASC | DESC )?; sort_fields : sort_field ( COMMA sort_field )*; tag_keys : tag_key=IDENTIFIER ( COMMA tag_key=IDENTIFIER )*; var_ref : measurement; -binary_op : PLUS | MINUS | STAR | SLASH | MOD | AMP | PIPE | OR_EX | AND | OR | ASSIGN | NOT_EQ1 | NOT_EQ2 | LT | LT_EQ | GT | GT_EQ; +//binary_op : PLUS | MINUS | STAR | SLASH | MOD | AMP | PIPE | OR_EX| AND | OR | ASSIGN | NOT_EQ1 | NOT_EQ2 | LT | LT_EQ | GT | GT_EQ; -expression : unary_expr ( binary_op unary_expr )*; -unary_expr : group_expr | call | var_ref | literal_expr; +//expression : unary_expr ( binary_op unary_expr )*; +//unary_expr : group_expr | call | var_ref | literal_expr; group_expr: OPEN_PAR expression CLOSE_PAR; -literal_expr: STRING_LITERAL | NUMERIC_LITERAL | TRUE | FALSE | DURATION_LITERAL; +//literal_expr: STRING_LITERAL | signed_number | TRUE | FALSE | DURATION_LITERAL; +//signed_number: (PLUS|MINUS)? NUMERIC_LITERAL; call: IDENTIFIER OPEN_PAR expression CLOSE_PAR; +unary_operator + : MINUS + | PLUS + | TILDE; + +expression + : literal_value + | unary_operator expression + | expression PIPE2 expression + | expression ( STAR | SLASH | MOD) expression + | expression ( PLUS | MINUS) expression + | expression ( LT2 | GT2 | AMP | PIPE | OR_EX) expression + | expression ( LT | LT_EQ | GT | GT_EQ) expression + | expression ( + ASSIGN + | EQ + | NOT_EQ1 + | NOT_EQ2 + ) expression + | expression AND expression + | expression OR expression + | call + | group_expr + | var_ref + | STAR | START_FIELD | START_TAGS +; + +literal_value + : INTEGER_LITERAL + | NUMERIC_LITERAL + | STRING_LITERAL + | DURATION_LITERAL + | NULL + | TRUE + | FALSE +; + from_clause : FROM measurements; group_by_clause : GROUP BY dimensions fill_clause?; into_clause : INTO ( measurement | back_ref ); -limit_clause : LIMIT NUMERIC_LITERAL; -offset_clause : OFFSET NUMERIC_LITERAL; -slimit_clause : SLIMIT NUMERIC_LITERAL; -soffset_clause : SOFFSET NUMERIC_LITERAL; +limit_clause : LIMIT INTEGER_LITERAL; +offset_clause : OFFSET INTEGER_LITERAL; +slimit_clause : SLIMIT INTEGER_LITERAL; +soffset_clause : SOFFSET INTEGER_LITERAL; timezone_clause : TZ OPEN_PAR STRING_LITERAL CLOSE_PAR; on_clause : ON db_name=IDENTIFIER; fill_clause: FILL OPEN_PAR fill_option CLOSE_PAR; order_by_clause: ORDER BY sort_fields; -to_clause : TO user_name= IDENTIFIER ; +to_clause : TO user_name=IDENTIFIER ; where_clause : WHERE expression; with_measurement_clause : WITH MEASUREMENT ( EQ measurement | REG_MATCH REGULAR_EXPRESSION_LITERAL ); -with_tag_clause : WITH KEY ( ASSIGN tag_key=IDENTIFIER | NOT_EQ1 tag_key=IDENTIFIER | REG_MATCH REGULAR_EXPRESSION_LITERAL | IN OPEN_PAR tag_keys CLOSE_PAR ); - -QUOTE: '"'; -SCOL : ';'; -DOT : '.'; -OPEN_PAR : '('; -CLOSE_PAR : ')'; -COMMA : ','; -ASSIGN : '='; -STAR : '*'; -PLUS : '+'; -MINUS : '-'; -TILDE : '~'; -SLASH : '/'; -MOD : '%'; -LT2 : '<<'; -GT2 : '>>'; -AMP : '&'; -LT : '<'; -LT_EQ : '<='; -GT : '>'; -GT_EQ : '>='; -EQ : '=='; -NOT_EQ1 : '!='; -NOT_EQ2 : '<>'; -REG_MATCH: '=~'; -OR_EX: '^'; -PIPE: '|'; -PIPE2: '||'; - -// Keywords -AND: 'AND'; -OR: 'OR'; -ALL: 'ALL'; -ALTER: 'ALTER'; -ANALYZE: 'ANALYZE'; -ANY: 'ANY'; -AS: 'AS'; -ASC: 'ASC'; -BEGIN: 'BEGIN'; -BY: 'BY'; -CREATE: 'CREATE'; -CONTINUOUS: 'CONTINUOUS'; -DATABASE: 'DATABASE'; -DATABASES: 'DATABASES'; -DEFAULT: 'DEFAULT'; -DELETE: 'DELETE'; -DESC: 'DESC'; -DESTINATIONS: 'DESTINATIONS'; -DIAGNOSTICS: 'DIAGNOSTICS'; -DISTINCT: 'DISTINCT'; -DROP: 'DROP'; -DURATION: 'DURATION'; -END: 'END'; -EVERY: 'EVERY'; -EXPLAIN: 'EXPLAIN'; -FIELD: 'FIELD'; -FOR: 'FOR'; -FROM: 'FROM'; -GRANT: 'GRANT'; -GRANTS: 'GRANTS'; -GROUP: 'GROUP'; -GROUPS: 'GROUPS'; -IN: 'IN'; -INF: 'INF'; -INSERT: 'INSERT'; -INTO: 'INTO'; -KEY: 'KEY'; -KEYS: 'KEYS'; -KILL: 'KILL'; -LIMIT: 'LIMIT'; -SHOW: 'SHOW'; -MEASUREMENT: 'MEASUREMENT'; -MEASUREMENTS: 'MEASUREMENTS'; -NAME: 'NAME'; -OFFSET: 'OFFSET'; -ON: 'ON'; -ORDER: 'ORDER'; -PASSWORD: 'PASSWORD'; -POLICY: 'POLICY'; -POLICIES: 'POLICIES'; -PRIVILEGES: 'PRIVILEGES'; -QUERIES: 'QUERIES'; -QUERY: 'QUERY'; -READ: 'READ'; -REPLICATION: 'REPLICATION'; -RESAMPLE: 'RESAMPLE'; -RETENTION: 'RETENTION'; -REVOKE: 'REVOKE'; -SELECT: 'SELECT'; -SERIES: 'SERIES'; -SET: 'SET'; -SHARD: 'SHARD'; -SHARDS: 'SHARDS'; -SLIMIT: 'SLIMIT'; -SOFFSET: 'SOFFSET'; -STATS: 'STATS'; -SUBSCRIPTION: 'SUBSCRIPTION'; -SUBSCRIPTIONS: 'SUBSCRIPTIONS'; -TAG: 'TAG'; -TO: 'TO'; -USER: 'USER'; -USERS: 'USERS'; -VALUES: 'VALUES'; -WHERE: 'WHERE'; -WITH: 'WITH'; -WRITE: 'WRITE'; - -FILL: 'FILL'; -NULL: 'NULL'; -NONE: 'NONE'; -PREVIOUS: 'PREVIOUS'; -LINEAR: 'LINEAR'; -TZ: 'tz'; -TRUE: 'TRUE'; -FALSE: 'FALSE'; - -IDENTIFIER: - '"' (~'"' | '""')* '"' - | '`' (~'`' | '``')* '`' - | [A-Z_\u007F-\uFFFF] [A-Z_0-9\u007F-\uFFFF]* - ; - -NUMERIC_LITERAL: (DIGIT+ ('.' DIGIT*)?) | ('.' DIGIT+); -STRING_LITERAL: '\'' ( ~'\'' | '\'\'')* '\''; - -DURATION_LITERAL: ([1-9] DIGIT*)+ ('u' | 'µ' | 'ms' | 's' | 'm' | 'h' | 'd' | 'w'); -REGULAR_EXPRESSION_LITERAL: '/' UNICODE_CHAR* '/'; - -UNICODE_CHAR: ~[ \t\r\n]; - -fragment DIGIT: [0-9]; +with_tag_clause : WITH KEY ( op=ASSIGN tag_key=IDENTIFIER | op=NOT_EQ1 tag_key=IDENTIFIER | op=REG_MATCH tag_key=REGULAR_EXPRESSION_LITERAL | op=IN OPEN_PAR tag_keys CLOSE_PAR ); -SPACES: [ \u000B\t\r\n] -> channel(HIDDEN); -UNEXPECTED_CHAR: .; diff --git a/src/main/java/io/github/willena/influxql/ast/expr/Dimensions.java b/src/main/java/io/github/willena/influxql/ast/expr/Dimensions.java index caf1fe5..ea7ad2c 100644 --- a/src/main/java/io/github/willena/influxql/ast/expr/Dimensions.java +++ b/src/main/java/io/github/willena/influxql/ast/expr/Dimensions.java @@ -17,11 +17,12 @@ package io.github.willena.influxql.ast.expr; +import io.github.willena.influxql.ast.Node; import io.github.willena.influxql.ast.utils.StringJoiningList; import java.util.List; /** Dimensions list */ -public class Dimensions extends StringJoiningList { +public class Dimensions extends StringJoiningList implements Node { /** * Create using initialized list * diff --git a/src/main/java/io/github/willena/influxql/ast/expr/literal/IdentifierlLiteral.java b/src/main/java/io/github/willena/influxql/ast/expr/literal/IdentifierlLiteral.java new file mode 100644 index 0000000..0b249f9 --- /dev/null +++ b/src/main/java/io/github/willena/influxql/ast/expr/literal/IdentifierlLiteral.java @@ -0,0 +1,56 @@ +/* + * InfluxQL Java package + * Copyright 2024 Guillaume VILLENA also known as "Willena" on GitHub + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.github.willena.influxql.ast.expr.literal; + +import io.github.willena.influxql.ast.Literal; + +import static io.github.willena.influxql.ast.utils.Utils.*; + +public class IdentifierlLiteral implements Literal { + private final String value; + + /** + * Build string literal + * + * @param value string + */ + public IdentifierlLiteral(String value) { + this.value = value; + ensureDefined("value", value); + } + + /** + * Create string literal + * + * @param value string + * @return literal + */ + public static IdentifierlLiteral of(String value) { + return new IdentifierlLiteral(value); + } + + @Override + public String getValue() { + return value; + } + + @Override + public String toString() { + return quoteIdentifier(value); + } +} \ No newline at end of file diff --git a/src/main/java/io/github/willena/influxql/ast/expr/literal/ListLiteral.java b/src/main/java/io/github/willena/influxql/ast/expr/literal/ListLiteral.java index 7b029c4..9804906 100644 --- a/src/main/java/io/github/willena/influxql/ast/expr/literal/ListLiteral.java +++ b/src/main/java/io/github/willena/influxql/ast/expr/literal/ListLiteral.java @@ -25,16 +25,16 @@ import java.util.List; /** List of string value literal */ -public class ListLiteral implements Literal> { - private final List values; +public class ListLiteral implements Literal>> { + private final List> values; /** * New list literal given an input list of string * * @param values list */ - public ListLiteral(final List values) { - this.values = new StringJoiningList<>(values, Utils::quoteIdentifier); + public ListLiteral(final List> values) { + this.values = new StringJoiningList<>(values); ensureDefined("values", values); } @@ -44,7 +44,7 @@ public ListLiteral(final List values) { * @param values list * @return ListLiteral */ - public static ListLiteral of(final List values) { + public static ListLiteral of(final List> values) { return new ListLiteral(values); } @@ -54,12 +54,12 @@ public static ListLiteral of(final List values) { * @param values list * @return ListLiteral */ - public static ListLiteral of(String... values) { + public static ListLiteral of(Literal... values) { return of(List.of(values)); } @Override - public List getValue() { + public List> getValue() { return values; } diff --git a/src/main/java/io/github/willena/influxql/ast/field/Fields.java b/src/main/java/io/github/willena/influxql/ast/field/Fields.java index 3347f0a..d47da14 100644 --- a/src/main/java/io/github/willena/influxql/ast/field/Fields.java +++ b/src/main/java/io/github/willena/influxql/ast/field/Fields.java @@ -17,11 +17,12 @@ package io.github.willena.influxql.ast.field; +import io.github.willena.influxql.ast.Node; import io.github.willena.influxql.ast.utils.StringJoiningList; import java.util.List; /** List of fields */ -public class Fields extends StringJoiningList { +public class Fields extends StringJoiningList implements Node { /** * Create initialized list of field * diff --git a/src/main/java/io/github/willena/influxql/ast/field/SortFields.java b/src/main/java/io/github/willena/influxql/ast/field/SortFields.java index 1e77135..64d1247 100644 --- a/src/main/java/io/github/willena/influxql/ast/field/SortFields.java +++ b/src/main/java/io/github/willena/influxql/ast/field/SortFields.java @@ -17,11 +17,12 @@ package io.github.willena.influxql.ast.field; +import io.github.willena.influxql.ast.Node; import io.github.willena.influxql.ast.utils.StringJoiningList; import java.util.List; /** List of sort fields */ -public class SortFields extends StringJoiningList { +public class SortFields extends StringJoiningList implements Node { /** * Create initialized list * diff --git a/src/main/java/io/github/willena/influxql/ast/source/Sources.java b/src/main/java/io/github/willena/influxql/ast/source/Sources.java index 540a454..92b99bf 100644 --- a/src/main/java/io/github/willena/influxql/ast/source/Sources.java +++ b/src/main/java/io/github/willena/influxql/ast/source/Sources.java @@ -17,13 +17,14 @@ package io.github.willena.influxql.ast.source; +import io.github.willena.influxql.ast.Node; import io.github.willena.influxql.ast.Source; import io.github.willena.influxql.ast.utils.StringJoiningList; import java.util.Arrays; import java.util.List; /** List of {@link Source} */ -public class Sources extends StringJoiningList { +public class Sources extends StringJoiningList implements Node { /** * Source list initialized with base * diff --git a/src/main/java/io/github/willena/influxql/ast/statement/CreateSubscriptionStatement.java b/src/main/java/io/github/willena/influxql/ast/statement/CreateSubscriptionStatement.java index 2a6882f..49b57ab 100644 --- a/src/main/java/io/github/willena/influxql/ast/statement/CreateSubscriptionStatement.java +++ b/src/main/java/io/github/willena/influxql/ast/statement/CreateSubscriptionStatement.java @@ -22,7 +22,7 @@ import io.github.willena.influxql.ast.Buildable; import io.github.willena.influxql.ast.Statement; -import io.github.willena.influxql.ast.token.SubscriptionMode; +import io.github.willena.influxql.ast.token.DestinationMode; import io.github.willena.influxql.ast.utils.Utils; import java.util.LinkedList; import java.util.List; @@ -33,7 +33,7 @@ public class CreateSubscriptionStatement implements Statement { private final String database; private final String retentionPolicy; private final List destinations; - private final SubscriptionMode mode; + private final DestinationMode mode; private CreateSubscriptionStatement(Builder builder) { name = builder.name; @@ -69,7 +69,7 @@ public static final class Builder implements Buildable destinations; - private SubscriptionMode mode; + private DestinationMode mode; public Builder() {} @@ -135,7 +135,7 @@ public Builder destinations(String destination, String... destinations) { * @param mode the {@code mode} to set * @return a reference to this Builder */ - public Builder destinationMode(SubscriptionMode mode) { + public Builder destinationMode(DestinationMode mode) { this.mode = mode; return this; } diff --git a/src/main/java/io/github/willena/influxql/ast/statement/ShowTagValuesStatement.java b/src/main/java/io/github/willena/influxql/ast/statement/ShowTagValuesStatement.java index 2144754..661e228 100644 --- a/src/main/java/io/github/willena/influxql/ast/statement/ShowTagValuesStatement.java +++ b/src/main/java/io/github/willena/influxql/ast/statement/ShowTagValuesStatement.java @@ -26,6 +26,7 @@ import io.github.willena.influxql.ast.field.SortFields; import io.github.willena.influxql.ast.source.Sources; import io.github.willena.influxql.ast.token.Operator; + import java.util.List; public class ShowTagValuesStatement implements Statement { @@ -91,7 +92,9 @@ public String toString() { return buf.toString(); } - /** {@code ShowTagValuesStatement} builder static inner class. */ + /** + * {@code ShowTagValuesStatement} builder static inner class. + */ public static final class Builder implements Buildable { private String database; private Sources sources; @@ -102,7 +105,8 @@ public static final class Builder implements Buildable { private int limit; private int offset; - public Builder() {} + public Builder() { + } /** * Sets the {@code database} and returns a reference to this Builder enabling method @@ -168,13 +172,24 @@ public Builder where(Expression condition) { * * @param sortFields the {@code sortFields} to set * @return a reference to this Builder + * @deprecated Not allowed by the specification; Left for compatibility; Ignored by influxdb. */ - public Builder orderBY(SortFields sortFields) { + @Deprecated() + public Builder orderBy(SortFields sortFields) { this.sortFields = sortFields; return this; } - public Builder orderBY(SortField sortField, SortField... sortFields) { + /** + * Sets the {@code sortFields} and returns a reference to this Builder enabling method + * chaining. + * + * @param sortFields the {@code sortFields} to set + * @return a reference to this Builder + * @deprecated Not allowed by the specification; Left for compatibility; Ignored by influxdb. + */ + @Deprecated + public Builder orderBy(SortField sortField, SortField... sortFields) { if (this.sortFields == null) { this.sortFields = new SortFields(); } @@ -209,7 +224,7 @@ public Builder offset(int offset) { * Returns a {@code ShowTagValuesStatement} built from the parameters previously set. * * @return a {@code ShowTagValuesStatement} built with parameters of this {@code - * ShowTagValuesStatement.Builder} + * ShowTagValuesStatement.Builder} */ public ShowTagValuesStatement build() { return new ShowTagValuesStatement(this); diff --git a/src/main/java/io/github/willena/influxql/ast/token/SubscriptionMode.java b/src/main/java/io/github/willena/influxql/ast/token/DestinationMode.java similarity index 96% rename from src/main/java/io/github/willena/influxql/ast/token/SubscriptionMode.java rename to src/main/java/io/github/willena/influxql/ast/token/DestinationMode.java index b55cdf7..58963d6 100644 --- a/src/main/java/io/github/willena/influxql/ast/token/SubscriptionMode.java +++ b/src/main/java/io/github/willena/influxql/ast/token/DestinationMode.java @@ -18,7 +18,7 @@ package io.github.willena.influxql.ast.token; /** Subscription mode */ -public enum SubscriptionMode { +public enum DestinationMode { ANY, ALL } diff --git a/src/main/java/io/github/willena/influxql/ast/token/FillOption.java b/src/main/java/io/github/willena/influxql/ast/token/FillOption.java index 1d882fb..e6e8dff 100644 --- a/src/main/java/io/github/willena/influxql/ast/token/FillOption.java +++ b/src/main/java/io/github/willena/influxql/ast/token/FillOption.java @@ -18,10 +18,11 @@ package io.github.willena.influxql.ast.token; import io.github.willena.influxql.ast.Literal; +import io.github.willena.influxql.ast.Node; import io.github.willena.influxql.ast.expr.literal.NumericLiteral; /** Fill options */ -public enum FillOption { +public enum FillOption implements Node { /** Null fil option */ NULL { @Override diff --git a/src/main/java/io/github/willena/influxql/ast/token/Operator.java b/src/main/java/io/github/willena/influxql/ast/token/Operator.java index e253c5a..efe0ecb 100644 --- a/src/main/java/io/github/willena/influxql/ast/token/Operator.java +++ b/src/main/java/io/github/willena/influxql/ast/token/Operator.java @@ -17,7 +17,11 @@ package io.github.willena.influxql.ast.token; -/** InfluxQl well known Operators */ +import java.util.Arrays; + +/** + * InfluxQl well known Operators + */ public enum Operator { // ADD and the following are InfluxQL Operators ADD("+"), // + @@ -31,6 +35,7 @@ public enum Operator { AND("AND"), // AND OR("OR"), // OR + IN("IN"), // OR EQ("="), // = NEQ("!="), // != @@ -61,4 +66,8 @@ public enum Operator { public String toString() { return value; } + + public static Operator fromValue(String value) { + return Arrays.stream(values()).filter(v -> v.value.equals(value)).findFirst().orElseThrow(() -> new IllegalArgumentException("Invalid operator value: " + value)); + } } diff --git a/src/main/java/io/github/willena/influxql/ast/token/Privilege.java b/src/main/java/io/github/willena/influxql/ast/token/Privilege.java index dddd079..d7d1fc7 100644 --- a/src/main/java/io/github/willena/influxql/ast/token/Privilege.java +++ b/src/main/java/io/github/willena/influxql/ast/token/Privilege.java @@ -17,8 +17,10 @@ package io.github.willena.influxql.ast.token; +import io.github.willena.influxql.ast.Node; + /** Known privileges */ -public enum Privilege { +public enum Privilege implements Node { NO_PRIVILEGE("NO PRIVILEGES"), READ_PRIVILEGE("READ"), WRITE_PRIVILEGE("WRITE"), diff --git a/src/main/java/io/github/willena/influxql/ast/utils/TimezoneNode.java b/src/main/java/io/github/willena/influxql/ast/utils/TimezoneNode.java new file mode 100644 index 0000000..6a5d363 --- /dev/null +++ b/src/main/java/io/github/willena/influxql/ast/utils/TimezoneNode.java @@ -0,0 +1,38 @@ +/* + * InfluxQL Java package + * Copyright 2024 Guillaume VILLENA also known as "Willena" on GitHub + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.github.willena.influxql.ast.utils; + +import io.github.willena.influxql.ast.Node; + +import java.util.TimeZone; + +public class TimezoneNode implements Node { + private final TimeZone timeZone; + + private TimezoneNode(TimeZone z){ + this.timeZone = z; + } + + public static TimezoneNode of(TimeZone timeZone){ + return new TimezoneNode(timeZone); + } + + public TimeZone getTimeZone() { + return timeZone; + } +} diff --git a/src/main/java/io/github/willena/influxql/ast/utils/Utils.java b/src/main/java/io/github/willena/influxql/ast/utils/Utils.java index d5f702b..fcb823d 100644 --- a/src/main/java/io/github/willena/influxql/ast/utils/Utils.java +++ b/src/main/java/io/github/willena/influxql/ast/utils/Utils.java @@ -21,13 +21,35 @@ import static io.github.willena.influxql.ast.utils.ParserUtils.isIdentFirstChar; import io.github.willena.influxql.ast.token.Keywords; + import java.time.Duration; +import java.time.temporal.ChronoUnit; +import java.util.Map; +import java.util.Optional; import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; -/** Utility class for String and conversion utils */ +/** + * Utility class for String and conversion utils + */ public final class Utils { - private Utils() {} + private static final Pattern DURATION_PATTERN = Pattern.compile("([1-9][0-9]*)(ns|u|µ|ms|s|m|h|d|w)"); + private static final Map UNITS_MAP = Map.ofEntries( + Map.entry("ns", ChronoUnit.NANOS), + Map.entry("u", ChronoUnit.MICROS), + Map.entry("µ", ChronoUnit.MICROS), + Map.entry("ms", ChronoUnit.MILLIS), + Map.entry("s", ChronoUnit.SECONDS), + Map.entry("m", ChronoUnit.MINUTES), + Map.entry("h", ChronoUnit.HOURS), + Map.entry("d", ChronoUnit.DAYS), + Map.entry("w", ChronoUnit.WEEKS) + ); + + private Utils() { + } /** * Escape the given string to be influxql compatible and safe. @@ -114,6 +136,14 @@ else if (asNano % TimeUnit.MICROSECONDS.toNanos(1) == 0) { } } + public static Duration parseDuration(String duration) { + Matcher matcher = DURATION_PATTERN.matcher(duration); + long intValue = Long.parseLong(matcher.group(0)); + ChronoUnit unit = Optional.ofNullable(UNITS_MAP.get(matcher.group(1))).orElseThrow(() -> new UnsupportedOperationException("Unsupported unit")); + + return Duration.of(intValue, unit); + } + /** * Returns a quoted identifier if required, from multiple bare identifiers. * @@ -154,7 +184,7 @@ public static String quoteIdentifier(String... segments) { /** * Ensure the given value is not null and not blank * - * @param name the value name (used to fill the exception) + * @param name the value name (used to fill the exception) * @param value the current value */ public static void ensureDefined(String name, String value) { @@ -166,7 +196,7 @@ public static void ensureDefined(String name, String value) { /** * Ensure the given value is not null * - * @param name the value name (used to full the exception) + * @param name the value name (used to full the exception) * @param value the current value */ public static void ensureDefined(String name, Object value) { diff --git a/src/main/java/io/github/willena/influxql/parser/DefaultParser.java b/src/main/java/io/github/willena/influxql/parser/DefaultParser.java new file mode 100644 index 0000000..84926f7 --- /dev/null +++ b/src/main/java/io/github/willena/influxql/parser/DefaultParser.java @@ -0,0 +1,55 @@ +/* + * InfluxQL Java package + * Copyright 2024 Guillaume VILLENA also known as "Willena" on GitHub + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.github.willena.influxql.parser; + +import io.github.willena.influxql.ast.Node; +import org.antlr.v4.runtime.*; + +import java.util.function.BiFunction; +import java.util.function.Function; + +public class DefaultParser { + + private static class ErrorListener extends BaseErrorListener { + + public ErrorListener() { + + } + + @Override + public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { + throw new IllegalArgumentException("InfluxQL syntax error: " + msg, e); + } + } + + public static Node parseFrom(Function entryPoint, BiFunction adapterFunction, String influxql) { + ErrorListener errorListener = new ErrorListener(); + InfluxqlLexer lexer = new InfluxqlLexer(CharStreams.fromString(influxql)); + lexer.addErrorListener(errorListener); + + CommonTokenStream token = new CommonTokenStream(lexer); + InfluxqlParser parser = new InfluxqlParser(token); + parser.addErrorListener(errorListener); + + InfluxqlAstAdapter adapter = new InfluxqlAstAdapter(); + + TREE ctx = entryPoint.apply(parser); + + return adapterFunction.apply(ctx, adapter); + } +} diff --git a/src/main/java/io/github/willena/influxql/parser/InfluxQlParseException.java b/src/main/java/io/github/willena/influxql/parser/InfluxQlParseException.java new file mode 100644 index 0000000..0e351ff --- /dev/null +++ b/src/main/java/io/github/willena/influxql/parser/InfluxQlParseException.java @@ -0,0 +1,21 @@ +/* + * InfluxQL Java package + * Copyright 2024 Guillaume VILLENA also known as "Willena" on GitHub + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.github.willena.influxql.parser; + +public class InfluxQlParseException { +} diff --git a/src/main/java/io/github/willena/influxql/parser/InfluxqlAstAdapter.java b/src/main/java/io/github/willena/influxql/parser/InfluxqlAstAdapter.java new file mode 100644 index 0000000..2ef255c --- /dev/null +++ b/src/main/java/io/github/willena/influxql/parser/InfluxqlAstAdapter.java @@ -0,0 +1,721 @@ +/* + * InfluxQL Java package + * Copyright 2024 Guillaume VILLENA also known as "Willena" on GitHub + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.github.willena.influxql.parser; + +import io.github.willena.influxql.ast.*; +import io.github.willena.influxql.ast.expr.Dimension; +import io.github.willena.influxql.ast.expr.Dimensions; +import io.github.willena.influxql.ast.expr.literal.IdentifierlLiteral; +import io.github.willena.influxql.ast.expr.literal.ListLiteral; +import io.github.willena.influxql.ast.expr.literal.RegexLiteral; +import io.github.willena.influxql.ast.extra.RetentionPolicy; +import io.github.willena.influxql.ast.field.Field; +import io.github.willena.influxql.ast.field.Fields; +import io.github.willena.influxql.ast.field.SortFields; +import io.github.willena.influxql.ast.source.Measurement; +import io.github.willena.influxql.ast.source.Sources; +import io.github.willena.influxql.ast.source.Target; +import io.github.willena.influxql.ast.statement.*; +import io.github.willena.influxql.ast.token.DestinationMode; +import io.github.willena.influxql.ast.token.FillOption; +import io.github.willena.influxql.ast.token.Operator; +import io.github.willena.influxql.ast.token.Privilege; +import io.github.willena.influxql.ast.utils.TimezoneNode; +import io.github.willena.influxql.ast.utils.Utils; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.tree.ParseTree; + +import java.util.Optional; +import java.util.stream.Collectors; + +import static io.github.willena.influxql.ast.utils.Utils.parseDuration; + +public class InfluxqlAstAdapter extends InfluxqlParserBaseVisitor { + @Override + public Query visitQuery(InfluxqlParser.QueryContext ctx) { + return new Query( + ctx.statement() + .stream() + .map(s -> (Statement) visitStatement(s)) + .collect(Collectors.toList()) + ); + } + + @Override + public Node visitStatement(InfluxqlParser.StatementContext ctx) { + if (ctx.alter_retention_policy_stmt() != null) { + return visitAlter_retention_policy_stmt(ctx.alter_retention_policy_stmt()); + } else if (ctx.create_continuous_query_stmt() != null) { + return visitCreate_continuous_query_stmt(ctx.create_continuous_query_stmt()); + } else if (ctx.create_database_stmt() != null) { + return visitCreate_database_stmt(ctx.create_database_stmt()); + } else if (ctx.create_retention_policy_stmt() != null) { + return visitCreate_retention_policy_stmt(ctx.create_retention_policy_stmt()); + } else if (ctx.create_subscription_stmt() != null) { + return visitCreate_subscription_stmt(ctx.create_subscription_stmt()); + } else if (ctx.create_user_stmt() != null) { + return visitCreate_user_stmt(ctx.create_user_stmt()); + } else if (ctx.delete_stmt() != null) { + return visitDelete_stmt(ctx.delete_stmt()); + } else if (ctx.drop_continuous_query_stmt() != null) { + return visitDrop_continuous_query_stmt(ctx.drop_continuous_query_stmt()); + } else if (ctx.drop_database_stmt() != null) { + return visitDrop_database_stmt(ctx.drop_database_stmt()); + } else if (ctx.drop_measurement_stmt() != null) { + return visitDrop_measurement_stmt(ctx.drop_measurement_stmt()); + } else if (ctx.drop_retention_policy_stmt() != null) { + return visitDrop_retention_policy_stmt(ctx.drop_retention_policy_stmt()); + } else if (ctx.drop_series_stmt() != null) { + return visitDrop_series_stmt(ctx.drop_series_stmt()); + } else if (ctx.drop_shard_stmt() != null) { + return visitDrop_shard_stmt(ctx.drop_shard_stmt()); + } else if (ctx.drop_subscription_stmt() != null) { + return visitDrop_subscription_stmt(ctx.drop_subscription_stmt()); + } else if (ctx.drop_user_stmt() != null) { + return visitDrop_user_stmt(ctx.drop_user_stmt()); + } else if (ctx.explain_stmt() != null) { + return visitExplain_stmt(ctx.explain_stmt()); + } else if (ctx.grant_stmt() != null) { + return visitGrant_stmt(ctx.grant_stmt()); + } else if (ctx.kill_query_statement() != null) { + return visitKill_query_statement(ctx.kill_query_statement()); + } else if (ctx.show_continuous_queries_stmt() != null) { + return visitShow_continuous_queries_stmt(ctx.show_continuous_queries_stmt()); + } else if (ctx.show_databases_stmt() != null) { + return visitShow_databases_stmt(ctx.show_databases_stmt()); + } else if (ctx.show_field_keys_stmt() != null) { + return visitShow_field_keys_stmt(ctx.show_field_keys_stmt()); + } else if (ctx.show_grants_stmt() != null) { + return visitShow_grants_stmt(ctx.show_grants_stmt()); + } else if (ctx.show_measurements_stmt() != null) { + return visitShow_measurements_stmt(ctx.show_measurements_stmt()); + } else if (ctx.show_queries_stmt() != null) { + return visitShow_queries_stmt(ctx.show_queries_stmt()); + } else if (ctx.show_retention_policies() != null) { + return visitShow_retention_policies(ctx.show_retention_policies()); + } else if (ctx.show_series_stmt() != null) { + return visitShow_series_stmt(ctx.show_series_stmt()); + } else if (ctx.show_shard_groups_stmt() != null) { + return visitShow_shard_groups_stmt(ctx.show_shard_groups_stmt()); + } else if (ctx.show_shards_stmt() != null) { + return visitShow_shards_stmt(ctx.show_shards_stmt()); + } else if (ctx.show_subscriptions_stmt() != null) { + return visitShow_subscriptions_stmt(ctx.show_subscriptions_stmt()); + } else if (ctx.show_tag_keys_stmt() != null) { + return visitShow_tag_keys_stmt(ctx.show_tag_keys_stmt()); + } else if (ctx.show_tag_values_stmt() != null) { + return visitShow_tag_values_stmt(ctx.show_tag_values_stmt()); + } else if (ctx.show_users_stmt() != null) { + return visitShow_users_stmt(ctx.show_users_stmt()); + } else if (ctx.revoke_stmt() != null) { + return visitRevoke_stmt(ctx.revoke_stmt()); + } else if (ctx.select_stmt() != null) { + return visitSelect_stmt(ctx.select_stmt()); + } else { + throw new UnsupportedOperationException("Code does not reflect grammar. Please update code / grammar"); + } + } + + @Override + public AlterRetentionPolicyStatement visitAlter_retention_policy_stmt(InfluxqlParser.Alter_retention_policy_stmtContext ctx) { + AlterRetentionPolicyStatement.Builder builder = new AlterRetentionPolicyStatement.Builder(); + + for (InfluxqlParser.Retention_policy_optionContext retentionPolicyOptionContext : ctx.retention_policy_option()) { + if (retentionPolicyOptionContext.retention_policy_replication() != null) { + builder.replicationFactor(Integer.parseInt(retentionPolicyOptionContext.retention_policy_replication().INTEGER_LITERAL().getText())); + } else if (retentionPolicyOptionContext.retention_policy_duration() != null) { + builder.duration(parseDuration(retentionPolicyOptionContext.retention_policy_duration().DURATION_LITERAL().getText())); + } else if (retentionPolicyOptionContext.retention_policy_shard_group_duration() != null) { + builder.shardDuration(parseDuration(retentionPolicyOptionContext.retention_policy_shard_group_duration().DURATION_LITERAL().getText())); + } else if (retentionPolicyOptionContext.DEFAULT() != null) { + builder.default_(); + } + } + + return builder + .on(ctx.on_clause().db_name.getText()) + .policyName(ctx.policy_name.getText()) + .build(); + } + + @Override + public CreateContinuousQueryStatement visitCreate_continuous_query_stmt(InfluxqlParser.Create_continuous_query_stmtContext ctx) { + CreateContinuousQueryStatement.Builder builder = new CreateContinuousQueryStatement.Builder(); + + if (ctx.resample_opts() != null) { + if (ctx.resample_opts().for_stmt() != null) { + builder.for_(parseDuration(ctx.resample_opts().for_stmt().DURATION_LITERAL().getText())); + } + if (ctx.resample_opts().every_stmt() != null) { + builder.resampleEvery(parseDuration(ctx.resample_opts().every_stmt().DURATION_LITERAL().getText())); + } + } + + return builder + .name(ctx.query_name.getText()) + .on(ctx.on_clause().db_name.getText()) + .select(visitSelect_stmt(ctx.select_stmt())) + .build(); + } + + @Override + public CreateDatabaseStatement visitCreate_database_stmt(InfluxqlParser.Create_database_stmtContext ctx) { + + RetentionPolicy rp = new RetentionPolicy.Builder() + .withRetentionPolicyName(Optional.ofNullable(ctx.retention_policy_name()).map(e -> e.IDENTIFIER().getText()).orElse(null)) + .duration(Optional.ofNullable(ctx.retention_policy_duration()).map(e -> ctx.retention_policy_duration().DURATION_LITERAL().getText()).map(Utils::parseDuration).orElse(null)) + .shardDuration(Optional.ofNullable(ctx.retention_policy_shard_group_duration()).map(e -> ctx.retention_policy_duration().DURATION_LITERAL().getText()).map(Utils::parseDuration).orElse(null)) + .replication(Optional.ofNullable(ctx.retention_policy_replication()).map(e -> ctx.retention_policy_replication().INTEGER_LITERAL().getText()).map(Integer::parseInt).orElse(null)).build(); + + return new CreateDatabaseStatement.Builder() + .name(ctx.db_name.getText()) + .withRetentionPolicy(rp) + .build(); + } + + @Override + public CreateRetentionPolicyStatement visitCreate_retention_policy_stmt(InfluxqlParser.Create_retention_policy_stmtContext ctx) { + CreateRetentionPolicyStatement.Builder builder = new CreateRetentionPolicyStatement.Builder(); + + if (ctx.retention_policy_shard_group_duration() != null) { + builder.shardDuration(parseDuration(ctx.retention_policy_shard_group_duration().DURATION_LITERAL().getText())); + } + + return builder + .name(ctx.policy_name.getText()) + .on(ctx.on_clause().db_name.getText()) + .duration(parseDuration(ctx.retention_policy_duration().DURATION_LITERAL().getText())) + .replication(Integer.parseInt(ctx.retention_policy_replication().INTEGER_LITERAL().getText())) + .withIsDefault(ctx.DEFAULT() != null) + .build(); + } + + @Override + public CreateSubscriptionStatement visitCreate_subscription_stmt(InfluxqlParser.Create_subscription_stmtContext ctx) { + CreateSubscriptionStatement.Builder builder = new CreateSubscriptionStatement.Builder(); + boolean isAny = ctx.ANY() != null; + boolean isAll = ctx.ALL() != null; + + if (isAny) { + builder.destinationMode(DestinationMode.ANY); + } + if (isAll) { + builder.destinationMode(DestinationMode.ALL); + } + + return builder + .name(ctx.subscription_name.getText()) + .on(ctx.db_name.getText()) + .retentionPolicy(ctx.retention_policy.getText()) + .destinations(ctx.STRING_LITERAL().stream().map(ParseTree::getText).collect(Collectors.toList())) + .build(); + } + + @Override + public CreateUserStatement visitCreate_user_stmt(InfluxqlParser.Create_user_stmtContext ctx) { + return new CreateUserStatement.Builder() + .username(ctx.user_name.getText()) + .password(ctx.password.getText()) + .admin(ctx.PRIVILEGES() != null) + .build(); + } + + @Override + public DeleteStatement visitDelete_stmt(InfluxqlParser.Delete_stmtContext ctx) { + return new DeleteStatement.Builder() + .from(visitFrom_clause(ctx.from_clause()).getFirst()) + .where(visitWhere_clause(ctx.where_clause())) + .build(); + } + + @Override + public DropContinuousQueryStatement visitDrop_continuous_query_stmt(InfluxqlParser.Drop_continuous_query_stmtContext ctx) { + return new DropContinuousQueryStatement.Builder() + .query(ctx.query_name.getText()) + .on(ctx.on_clause().db_name.getText()) + .build(); + } + + @Override + public DropDatabaseStatement visitDrop_database_stmt(InfluxqlParser.Drop_database_stmtContext ctx) { + return new DropDatabaseStatement.Builder() + .database(ctx.db_name.getText()) + .build(); + } + + @Override + public DropMeasurementStatement visitDrop_measurement_stmt(InfluxqlParser.Drop_measurement_stmtContext ctx) { + + return new DropMeasurementStatement.Builder() + .measurement(ctx.measurement_value.getText()) + .build(); + } + + @Override + public DropRetentionPolicyStatement visitDrop_retention_policy_stmt(InfluxqlParser.Drop_retention_policy_stmtContext ctx) { + return new DropRetentionPolicyStatement.Builder() + .on(ctx.on_clause().db_name.getText()) + .retentionPolicy(ctx.policy_name.getText()) + .build(); + } + + @Override + public DropSeriesStatement visitDrop_series_stmt(InfluxqlParser.Drop_series_stmtContext ctx) { + return new DropSeriesStatement.Builder() + .where(visitWhere_clause(ctx.where_clause())) + .from(visitFrom_clause(ctx.from_clause())) + .build(); + } + + @Override + public DropShardStatement visitDrop_shard_stmt(InfluxqlParser.Drop_shard_stmtContext ctx) { + return new DropShardStatement.Builder() + .shardId(Long.parseLong(ctx.shard_id.getText())) + .build(); + } + + @Override + public DropSubscriptionStatement visitDrop_subscription_stmt(InfluxqlParser.Drop_subscription_stmtContext ctx) { + return new DropSubscriptionStatement.Builder() + .subscription(ctx.subscription_name.getText()) + .on(ctx.db_name.getText()) + .retentionPolicy(ctx.retention_policy.getText()) + .build(); + } + + @Override + public DropUserStatement visitDrop_user_stmt(InfluxqlParser.Drop_user_stmtContext ctx) { + return new DropUserStatement.Builder() + .username(ctx.user_name.getText()) + .build(); + } + + @Override + public ExplainStatement visitExplain_stmt(InfluxqlParser.Explain_stmtContext ctx) { + return new ExplainStatement.Builder() + .select(visitSelect_stmt(ctx.select_stmt())) + .analyse(ctx.ANALYZE() != null) + .build(); + } + + @Override + public GrantStatement visitGrant_stmt(InfluxqlParser.Grant_stmtContext ctx) { + GrantStatement.Builder builder = new GrantStatement.Builder(); + + + if (ctx.on_clause() != null) { + builder.on(ctx.on_clause().db_name.getText()); + } + + return builder + .to(ctx.to_clause().user_name.getText()) + .privilege(visitPrivilege(ctx.privilege())) + .build(); + } + + @Override + public KillQueryStatement visitKill_query_statement(InfluxqlParser.Kill_query_statementContext ctx) { + return new KillQueryStatement.Builder() + .queryId(Long.parseLong(ctx.INTEGER_LITERAL().getText())) + .on(Optional.ofNullable(ctx.host).map(Token::getText).orElse(null)) + .build(); + } + + @Override + public ShowContinuousQueriesStatement visitShow_continuous_queries_stmt(InfluxqlParser.Show_continuous_queries_stmtContext ctx) { + return new ShowContinuousQueriesStatement(); + } + + @Override + public ShowDatabasesStatement visitShow_databases_stmt(InfluxqlParser.Show_databases_stmtContext ctx) { + return new ShowDatabasesStatement(); + } + + @Override + public ShowFieldKeysStatement visitShow_field_keys_stmt(InfluxqlParser.Show_field_keys_stmtContext ctx) { + return new ShowFieldKeysStatement.Builder() + .on(Optional.ofNullable(ctx.on_clause()).map(c -> c.db_name.getText()).orElse(null)) + .from(visitFrom_clause(ctx.from_clause())) + .limit(Optional.ofNullable(ctx.limit_clause()).map(l -> Integer.parseInt(l.INTEGER_LITERAL().getText())).orElse(0)) + .offset(Optional.ofNullable(ctx.offset_clause()).map(o -> Integer.parseInt(o.INTEGER_LITERAL().getText())).orElse(0)) + .orderBy(Optional.ofNullable(ctx.order_by_clause()).map(this::visitOrder_by_clause).orElse(null)) + .build(); + } + + @Override + public ShowGrantsForUserStatement visitShow_grants_stmt(InfluxqlParser.Show_grants_stmtContext ctx) { + return new ShowGrantsForUserStatement.Builder() + .for_(ctx.user_name.getText()) + .build(); + } + + @Override + public ShowMeasurementsStatement visitShow_measurements_stmt(InfluxqlParser.Show_measurements_stmtContext ctx) { + return new ShowMeasurementsStatement.Builder() + .on(Optional.ofNullable(ctx.on_clause()).map(o -> o.db_name.getText()).orElse(null)) + .limit(Optional.ofNullable(ctx.limit_clause()).map(l -> Integer.parseInt(l.INTEGER_LITERAL().getText())).orElse(0)) + .offset(Optional.ofNullable(ctx.offset_clause()).map(o -> Integer.parseInt(o.INTEGER_LITERAL().getText())).orElse(0)) + .where(Optional.ofNullable(ctx.where_clause()).map(this::visitWhere_clause).orElse(null)) + .from(Optional.ofNullable(ctx.with_measurement_clause()).map(this::visitWith_measurement_clause).orElse(null)) + .build(); + } + + @Override + public ShowQueriesStatement visitShow_queries_stmt(InfluxqlParser.Show_queries_stmtContext ctx) { + return new ShowQueriesStatement(); + } + + @Override + public ShowRetentionPoliciesStatement visitShow_retention_policies(InfluxqlParser.Show_retention_policiesContext ctx) { + return new ShowRetentionPoliciesStatement.Builder() + .on(ctx.on_clause().db_name.getText()) + .build(); + } + + @Override + public ShowSeriesStatement visitShow_series_stmt(InfluxqlParser.Show_series_stmtContext ctx) { + return new ShowSeriesStatement.Builder() + .on(Optional.ofNullable(ctx.on_clause()).map(c -> c.db_name.getText()).orElse(null)) + .from(Optional.ofNullable(ctx.from_clause()).map(this::visitFrom_clause).orElse(null)) + .where(Optional.ofNullable(ctx.where_clause()).map(this::visitWhere_clause).orElse(null)) + .limit(Optional.ofNullable(ctx.limit_clause()).map(l -> Integer.parseInt(l.INTEGER_LITERAL().getText())).orElse(0)) + .offset(Optional.ofNullable(ctx.offset_clause()).map(o -> Integer.parseInt(o.INTEGER_LITERAL().getText())).orElse(0)) + .build(); + } + + @Override + public ShowShardGroupsStatement visitShow_shard_groups_stmt(InfluxqlParser.Show_shard_groups_stmtContext ctx) { + return new ShowShardGroupsStatement(); + } + + @Override + public ShowShardsStatement visitShow_shards_stmt(InfluxqlParser.Show_shards_stmtContext ctx) { + return new ShowShardsStatement(); + } + + @Override + public ShowSubscriptionsStatement visitShow_subscriptions_stmt(InfluxqlParser.Show_subscriptions_stmtContext ctx) { + return new ShowSubscriptionsStatement(); + } + + @Override + public ShowTagKeysStatement visitShow_tag_keys_stmt(InfluxqlParser.Show_tag_keys_stmtContext ctx) { + return new ShowTagKeysStatement.Builder() + .on(Optional.ofNullable(ctx.on_clause()).map(c -> c.db_name.getText()).orElse(null)) + .from(Optional.ofNullable(ctx.from_clause()).map(this::visitFrom_clause).orElse(null)) + .where(Optional.ofNullable(ctx.where_clause()).map(this::visitWhere_clause).orElse(null)) + .orderBy(Optional.ofNullable(ctx.order_by_clause()).map(this::visitOrder_by_clause).orElse(null)) + .limit(Optional.ofNullable(ctx.limit_clause()).map(l -> Integer.parseInt(l.INTEGER_LITERAL().getText())).orElse(0)) + .offset(Optional.ofNullable(ctx.offset_clause()).map(o -> Integer.parseInt(o.INTEGER_LITERAL().getText())).orElse(0)) + .build(); + } + + @Override + public Node visitShow_tag_key_cardinality_stmt(InfluxqlParser.Show_tag_key_cardinality_stmtContext ctx) { + return new ShowTagKeyCardinalityStatement.Builder() + .on(Optional.ofNullable(ctx.on_clause()).map(c -> c.db_name.getText()).orElse(null)) + .from(Optional.ofNullable(ctx.from_clause()).map(this::visitFrom_clause).orElse(null)) + .where(Optional.ofNullable(ctx.where_clause()).map(this::visitWhere_clause).orElse(null)) + .limit(Optional.ofNullable(ctx.limit_clause()).map(l -> Integer.parseInt(l.INTEGER_LITERAL().getText())).orElse(0)) + .offset(Optional.ofNullable(ctx.offset_clause()).map(o -> Integer.parseInt(o.INTEGER_LITERAL().getText())).orElse(0)) + .groupBy(Optional.ofNullable(ctx.group_by_clause()).map(this::visitGroup_by_clause).orElse(null)) + .exact(Optional.ofNullable(ctx.EXACT()).isPresent()) + .build(); + } + + @Override + public ShowTagValuesStatement visitShow_tag_values_stmt(InfluxqlParser.Show_tag_values_stmtContext ctx) { + Operator op = Operator.fromValue(ctx.with_tag_clause().op.getText()); + Literal literal; + if (op == Operator.IN) { + literal = ListLiteral.of(ctx.with_tag_clause().tag_keys().IDENTIFIER().stream().map(ParseTree::getText).map(IdentifierlLiteral::of).collect(Collectors.toList())); + } else if (op == Operator.EQREGEX) { + literal = RegexLiteral.of(ctx.with_tag_clause().tag_key.getText()); + } else { + literal = IdentifierlLiteral.of(ctx.with_tag_clause().tag_key.getText()); + } + + return new ShowTagValuesStatement.Builder() + .on(Optional.ofNullable(ctx.on_clause()).map(c -> c.db_name.getText()).orElse(null)) + .from(Optional.ofNullable(ctx.from_clause()).map(this::visitFrom_clause).orElse(null)) + .where(Optional.ofNullable(ctx.where_clause()).map(this::visitWhere_clause).orElse(null)) + .limit(Optional.ofNullable(ctx.limit_clause()).map(l -> Integer.parseInt(l.INTEGER_LITERAL().getText())).orElse(0)) + .offset(Optional.ofNullable(ctx.offset_clause()).map(o -> Integer.parseInt(o.INTEGER_LITERAL().getText())).orElse(0)) + .withKey(op, literal) + .build(); + } + + @Override + public ShowTagValuesCardinalityStatement visitShow_tag_values_cardinality_stmt(InfluxqlParser.Show_tag_values_cardinality_stmtContext ctx) { + Operator op = Operator.fromValue(ctx.with_tag_clause().op.getText()); + Literal literal; + if (op == Operator.IN) { + literal = ListLiteral.of(ctx.with_tag_clause().tag_keys().IDENTIFIER().stream().map(ParseTree::getText).map(IdentifierlLiteral::of).collect(Collectors.toList())); + } else if (op == Operator.EQREGEX) { + literal = RegexLiteral.of(ctx.with_tag_clause().tag_key.getText()); + } else { + literal = IdentifierlLiteral.of(ctx.with_tag_clause().tag_key.getText()); + } + return new ShowTagValuesCardinalityStatement.Builder() + .on(Optional.ofNullable(ctx.on_clause()).map(c -> c.db_name.getText()).orElse(null)) + .from(Optional.ofNullable(ctx.from_clause()).map(this::visitFrom_clause).orElse(null)) + .where(Optional.ofNullable(ctx.where_clause()).map(this::visitWhere_clause).orElse(null)) + .limit(Optional.ofNullable(ctx.limit_clause()).map(l -> Integer.parseInt(l.INTEGER_LITERAL().getText())).orElse(0)) + .offset(Optional.ofNullable(ctx.offset_clause()).map(o -> Integer.parseInt(o.INTEGER_LITERAL().getText())).orElse(0)) + .exact(Optional.ofNullable(ctx.EXACT()).isPresent()) + .groupBy(Optional.ofNullable(ctx.group_by_clause()).map(this::visitGroup_by_clause).orElse(null)) + .withKey(op, literal) + .build(); + } + + @Override + public ShowUsersStatement visitShow_users_stmt(InfluxqlParser.Show_users_stmtContext ctx) { + return new ShowUsersStatement(); + } + + @Override + public RevokeStatement visitRevoke_stmt(InfluxqlParser.Revoke_stmtContext ctx) { + return new RevokeStatement.Builder() + .privilege(visitPrivilege(ctx.privilege())) + .on(Optional.ofNullable(ctx.on_clause()).map(c -> c.db_name.getText()).orElse(null)) + .from(ctx.user_name.getText()) + .build(); + } + + @Override + public SelectStatement visitSelect_stmt(InfluxqlParser.Select_stmtContext ctx) { + return new SelectStatement.Builder() + .select(visitFields(ctx.fields())) + .from(visitFrom_clause(ctx.from_clause())) + .into(Optional.ofNullable(ctx.into_clause()).map(this::visitInto_clause).orElse(null)) + .where(Optional.ofNullable(ctx.where_clause()).map(this::visitWhere_clause).orElse(null)) + .groupBy(Optional.ofNullable(ctx.group_by_clause()).map(this::visitGroup_by_clause).orElse(null)) + .orderBy(Optional.ofNullable(ctx.order_by_clause()).map(this::visitOrder_by_clause).orElse(null)) + .limit(Optional.ofNullable(ctx.limit_clause()).map(l -> Integer.parseInt(l.INTEGER_LITERAL().getText())).orElse(0)) + .offset(Optional.ofNullable(ctx.offset_clause()).map(o -> Integer.parseInt(o.INTEGER_LITERAL().getText())).orElse(0)) + .sLimit(Optional.ofNullable(ctx.slimit_clause()).map(l -> Integer.parseInt(l.INTEGER_LITERAL().getText())).orElse(0)) + .sOffset(Optional.ofNullable(ctx.soffset_clause()).map(o -> Integer.parseInt(o.INTEGER_LITERAL().getText())).orElse(0)) + .timezone(Optional.ofNullable(ctx.timezone_clause()).map(this::visitTimezone_clause).map(TimezoneNode::getTimeZone).orElse(null)) + .build(); + } + + + @Override + public Node visitAlias(InfluxqlParser.AliasContext ctx) { + return null; + } + + @Override + public Node visitBack_ref(InfluxqlParser.Back_refContext ctx) { + return null; + } + + @Override + public Dimension visitDimension(InfluxqlParser.DimensionContext ctx) { + return null; + } + + @Override + public Dimensions visitDimensions(InfluxqlParser.DimensionsContext ctx) { + return null; + } + + @Override + public Field visitField(InfluxqlParser.FieldContext ctx) { + return null; + } + + @Override + public Fields visitFields(InfluxqlParser.FieldsContext ctx) { + return null; + } + + @Override + public FillOption visitFill_option(InfluxqlParser.Fill_optionContext ctx) { + return null; + } + + @Override + public Measurement visitMeasurement(InfluxqlParser.MeasurementContext ctx) { + return null; + } + + @Override + public Sources visitMeasurements(InfluxqlParser.MeasurementsContext ctx) { + return null; + } + + @Override + public Privilege visitPrivilege(InfluxqlParser.PrivilegeContext ctx) { + if (ctx.ALL() != null) { + return Privilege.ALL_PRIVILEGES; + } + if (ctx.READ() != null) { + return Privilege.READ_PRIVILEGE; + } + if (ctx.WRITE() != null) { + return Privilege.WRITE_PRIVILEGE; + } + throw new IllegalArgumentException("Unsupported privilege"); + } + + @Override + public Node visitRetention_policy_option(InfluxqlParser.Retention_policy_optionContext ctx) { + return null; + } + + @Override + public Node visitRetention_policy_duration(InfluxqlParser.Retention_policy_durationContext ctx) { + return null; + } + + @Override + public Node visitRetention_policy_replication(InfluxqlParser.Retention_policy_replicationContext ctx) { + return null; + } + + @Override + public Node visitRetention_policy_shard_group_duration(InfluxqlParser.Retention_policy_shard_group_durationContext ctx) { + return null; + } + + @Override + public Node visitRetention_policy_name(InfluxqlParser.Retention_policy_nameContext ctx) { + return null; + } + + @Override + public Node visitSort_field(InfluxqlParser.Sort_fieldContext ctx) { + return null; + } + + @Override + public Node visitSort_fields(InfluxqlParser.Sort_fieldsContext ctx) { + return null; + } + + @Override + public Node visitTag_keys(InfluxqlParser.Tag_keysContext ctx) { + return null; + } + + @Override + public Node visitVar_ref(InfluxqlParser.Var_refContext ctx) { + return null; + } + + @Override + public Node visitGroup_expr(InfluxqlParser.Group_exprContext ctx) { + return null; + } + + @Override + public Node visitCall(InfluxqlParser.CallContext ctx) { + return null; + } + + @Override + public Node visitUnary_operator(InfluxqlParser.Unary_operatorContext ctx) { + return null; + } + + @Override + public Node visitExpression(InfluxqlParser.ExpressionContext ctx) { + return null; + } + + @Override + public Node visitLiteral_value(InfluxqlParser.Literal_valueContext ctx) { + return null; + } + + @Override + public Sources visitFrom_clause(InfluxqlParser.From_clauseContext ctx) { + return null; + } + + @Override + public Dimensions visitGroup_by_clause(InfluxqlParser.Group_by_clauseContext ctx) { + return null; + } + + @Override + public Target visitInto_clause(InfluxqlParser.Into_clauseContext ctx) { + return null; + } + + @Override + public Node visitLimit_clause(InfluxqlParser.Limit_clauseContext ctx) { + return null; + } + + @Override + public Node visitOffset_clause(InfluxqlParser.Offset_clauseContext ctx) { + return null; + } + + @Override + public Node visitSlimit_clause(InfluxqlParser.Slimit_clauseContext ctx) { + return null; + } + + @Override + public Node visitSoffset_clause(InfluxqlParser.Soffset_clauseContext ctx) { + return null; + } + + @Override + public TimezoneNode visitTimezone_clause(InfluxqlParser.Timezone_clauseContext ctx) { + return null; + } + + @Override + public Node visitOn_clause(InfluxqlParser.On_clauseContext ctx) { + return null; + } + + @Override + public Node visitFill_clause(InfluxqlParser.Fill_clauseContext ctx) { + return null; + } + + @Override + public SortFields visitOrder_by_clause(InfluxqlParser.Order_by_clauseContext ctx) { + return null; + } + + @Override + public Node visitTo_clause(InfluxqlParser.To_clauseContext ctx) { + return null; + } + + @Override + public Expression visitWhere_clause(InfluxqlParser.Where_clauseContext ctx) { + return null; + } + + @Override + public Measurement visitWith_measurement_clause(InfluxqlParser.With_measurement_clauseContext ctx) { + return null; + } + + @Override + public Node visitWith_tag_clause(InfluxqlParser.With_tag_clauseContext ctx) { + return null; + } +} diff --git a/src/test/java/io/github/willena/influxql/ast/statement/CreateSubscriptionStatementTest.java b/src/test/java/io/github/willena/influxql/ast/statement/CreateSubscriptionStatementTest.java index 3363d2e..ecb4139 100644 --- a/src/test/java/io/github/willena/influxql/ast/statement/CreateSubscriptionStatementTest.java +++ b/src/test/java/io/github/willena/influxql/ast/statement/CreateSubscriptionStatementTest.java @@ -17,7 +17,7 @@ package io.github.willena.influxql.ast.statement; -import io.github.willena.influxql.ast.token.SubscriptionMode; +import io.github.willena.influxql.ast.token.DestinationMode; import java.util.List; class CreateSubscriptionStatementTest extends GenericStatementTest { @@ -29,7 +29,7 @@ class CreateSubscriptionStatementTest extends GenericStatementTest