From 81722dc19b4a24ef8e97dc1e12c9941f43fe0800 Mon Sep 17 00:00:00 2001 From: Stuart Carnie Date: Fri, 14 Oct 2022 09:37:49 +1100 Subject: [PATCH] feat: AST traversal using Visitor pattern (#5796) * feat: Partition implementation of Visitable for InfluxQL AST * feat: Added consistent structures for each clause to simplify visitor Continued to expand `accept` and `pre` / `post` visit implementations. * feat: Added insta and tests using snapshots (thanks @crepererum) The insta crate simplifies the process of validating the combination of visitor and accept implementations are called and in the correct order. * chore: Run cargo hakari tasks * feat: Added remaining snapshot tests Some tests are failing as some minor type changes must be added along with the addition of related visitor functions. * feat: Add types to represent each clause in numerous statements These clauses permit distinct visit functions on the `Visitor` type. * chore: Reformat `SELECT` * chore: Explicitly specify access to export selected types only This required completing all the missing documentation for the exported types. * chore: Update Cargo.lock * chore: macro to implement common traits and hide 0th tuple element Co-authored-by: CircleCI[bot] --- Cargo.lock | 80 +- Cargo.toml | 7 + influxdb_influxql_parser/Cargo.toml | 3 +- influxdb_influxql_parser/src/common.rs | 177 +- influxdb_influxql_parser/src/delete.rs | 27 +- influxdb_influxql_parser/src/drop.rs | 2 +- influxdb_influxql_parser/src/explain.rs | 11 +- influxdb_influxql_parser/src/expression.rs | 5 + .../src/expression/arithmetic.rs | 54 +- .../src/expression/conditional.rs | 42 +- .../src/expression/test_util.rs | 2 +- influxdb_influxql_parser/src/identifier.rs | 14 +- influxdb_influxql_parser/src/internal.rs | 2 +- influxdb_influxql_parser/src/keywords.rs | 2 +- influxdb_influxql_parser/src/lib.rs | 22 +- influxdb_influxql_parser/src/literal.rs | 26 +- influxdb_influxql_parser/src/parameter.rs | 12 +- influxdb_influxql_parser/src/select.rs | 210 ++- influxdb_influxql_parser/src/show.rs | 26 +- .../src/show_field_keys.rs | 29 +- .../src/show_measurements.rs | 173 +- .../src/show_retention_policies.rs | 19 +- influxdb_influxql_parser/src/show_tag_keys.rs | 34 +- .../src/show_tag_values.rs | 90 +- .../src/simple_from_clause.rs | 25 +- ...rser__visit__test__delete_statement-2.snap | 21 + ...rser__visit__test__delete_statement-3.snap | 13 + ...rser__visit__test__delete_statement-4.snap | 13 + ...parser__visit__test__delete_statement.snap | 25 + ...sit__test__drop_measurement_statement.snap | 9 + ...arser__visit__test__explain_statement.snap | 25 + ...rser__visit__test__select_statement-2.snap | 23 + ...rser__visit__test__select_statement-3.snap | 25 + ...rser__visit__test__select_statement-4.snap | 25 + ...rser__visit__test__select_statement-5.snap | 29 + ...rser__visit__test__select_statement-6.snap | 93 + ...parser__visit__test__select_statement.snap | 23 + ...visit__test__show_databases_statement.snap | 9 + ...it__test__show_field_keys_statement-2.snap | 11 + ...it__test__show_field_keys_statement-3.snap | 15 + ...it__test__show_field_keys_statement-4.snap | 17 + ...isit__test__show_field_keys_statement.snap | 9 + ...__test__show_measurements_statement-2.snap | 11 + ...__test__show_measurements_statement-3.snap | 15 + ...__test__show_measurements_statement-4.snap | 21 + ...__test__show_measurements_statement-5.snap | 11 + ...__test__show_measurements_statement-6.snap | 11 + ...__test__show_measurements_statement-7.snap | 33 + ...it__test__show_measurements_statement.snap | 9 + ...__show_retention_policies_statement-2.snap | 11 + ...st__show_retention_policies_statement.snap | 9 + ...isit__test__show_tag_keys_statement-2.snap | 33 + ..._visit__test__show_tag_keys_statement.snap | 9 + ...it__test__show_tag_values_statement-2.snap | 11 + ...it__test__show_tag_values_statement-3.snap | 11 + ...it__test__show_tag_values_statement-4.snap | 35 + ...isit__test__show_tag_values_statement.snap | 11 + influxdb_influxql_parser/src/string.rs | 17 +- influxdb_influxql_parser/src/visit.rs | 1651 +++++++++++++++++ workspace-hack/Cargo.toml | 1 + 60 files changed, 3028 insertions(+), 361 deletions(-) create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__delete_statement-2.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__delete_statement-3.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__delete_statement-4.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__delete_statement.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__drop_measurement_statement.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__explain_statement.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__select_statement-2.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__select_statement-3.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__select_statement-4.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__select_statement-5.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__select_statement-6.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__select_statement.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__show_databases_statement.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__show_field_keys_statement-2.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__show_field_keys_statement-3.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__show_field_keys_statement-4.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__show_field_keys_statement.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__show_measurements_statement-2.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__show_measurements_statement-3.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__show_measurements_statement-4.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__show_measurements_statement-5.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__show_measurements_statement-6.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__show_measurements_statement-7.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__show_measurements_statement.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__show_retention_policies_statement-2.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__show_retention_policies_statement.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__show_tag_keys_statement-2.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__show_tag_keys_statement.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__show_tag_values_statement-2.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__show_tag_values_statement-3.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__show_tag_values_statement-4.snap create mode 100644 influxdb_influxql_parser/src/snapshots/influxdb_influxql_parser__visit__test__show_tag_values_statement.snap create mode 100644 influxdb_influxql_parser/src/visit.rs diff --git a/Cargo.lock b/Cargo.lock index 5d629855fb..62fac7061b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -667,9 +667,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.0.14" +version = "4.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea54a38e4bce14ff6931c72e5b3c43da7051df056913d4e7e1fcdb1c03df69d" +checksum = "6bf8832993da70a4c6d13c581f4463c2bdda27b9bf1c5498dc4365543abe6d6f" dependencies = [ "atty", "bitflags", @@ -684,7 +684,7 @@ dependencies = [ name = "clap_blocks" version = "0.1.0" dependencies = [ - "clap 4.0.14", + "clap 4.0.15", "data_types", "futures", "humantime", @@ -834,6 +834,19 @@ dependencies = [ "workspace-hack", ] +[[package]] +name = "console" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "terminal_size", + "winapi", +] + [[package]] name = "console-api" version = "0.4.0" @@ -1432,6 +1445,12 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "encoding_rs" version = "0.8.31" @@ -1699,7 +1718,7 @@ version = "0.1.0" dependencies = [ "chrono", "chrono-english", - "clap 4.0.14", + "clap 4.0.15", "clap_blocks", "data_types", "filetime", @@ -2171,6 +2190,7 @@ name = "influxdb_influxql_parser" version = "0.1.0" dependencies = [ "assert_matches", + "insta", "nom", "test_helpers", "workspace-hack", @@ -2185,7 +2205,7 @@ dependencies = [ "assert_cmd", "backtrace", "bytes", - "clap 4.0.14", + "clap 4.0.15", "clap_blocks", "compactor", "console-subscriber", @@ -2373,6 +2393,20 @@ dependencies = [ "write_summary", ] +[[package]] +name = "insta" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581d4e3314cae4536e5d22ffd23189d4a374696c5ef733eadafae0ed273fd303" +dependencies = [ + "console", + "lazy_static", + "linked-hash-map", + "serde", + "similar", + "yaml-rust", +] + [[package]] name = "instant" version = "0.1.12" @@ -2430,7 +2464,7 @@ dependencies = [ "bytes", "chrono", "chrono-english", - "clap 4.0.14", + "clap 4.0.15", "criterion", "futures", "handlebars", @@ -2524,7 +2558,7 @@ dependencies = [ "async-trait", "bytes", "chrono", - "clap 4.0.14", + "clap 4.0.15", "clap_blocks", "data_types", "flate2", @@ -2680,7 +2714,7 @@ name = "ioxd_test" version = "0.1.0" dependencies = [ "async-trait", - "clap 4.0.14", + "clap 4.0.15", "hyper", "ioxd_common", "metric", @@ -2854,6 +2888,12 @@ dependencies = [ "cc", ] +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linux-raw-sys" version = "0.0.46" @@ -5200,6 +5240,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal_size" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "termtree" version = "0.2.4" @@ -5606,7 +5656,7 @@ version = "0.1.0" dependencies = [ "async-trait", "chrono", - "clap 4.0.14", + "clap 4.0.15", "futures", "observability_deps", "snafu", @@ -5745,7 +5795,7 @@ name = "trogging" version = "0.1.0" dependencies = [ "atty", - "clap 4.0.14", + "clap 4.0.15", "logfmt", "observability_deps", "regex", @@ -6158,6 +6208,7 @@ dependencies = [ "serde", "serde_json", "sha2", + "similar", "smallvec", "sqlx", "sqlx-core", @@ -6234,6 +6285,15 @@ dependencies = [ "workspace-hack", ] +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "yansi" version = "0.5.1" diff --git a/Cargo.toml b/Cargo.toml index 37f7b6b2c6..fe94e1e82b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -121,3 +121,10 @@ inherits = "release" codegen-units = 16 lto = false incremental = true + +# Per insta docs: https://insta.rs/docs/quickstart/#optional-faster-runs +[profile.dev.package.insta] +opt-level = 3 + +[profile.dev.package.similar] +opt-level = 3 diff --git a/influxdb_influxql_parser/Cargo.toml b/influxdb_influxql_parser/Cargo.toml index cc1b8ae84b..3b35b18281 100644 --- a/influxdb_influxql_parser/Cargo.toml +++ b/influxdb_influxql_parser/Cargo.toml @@ -9,4 +9,5 @@ workspace-hack = { path = "../workspace-hack"} [dev-dependencies] # In alphabetical order test_helpers = { path = "../test_helpers" } -assert_matches = "1" \ No newline at end of file +assert_matches = "1" +insta = { version = "1.21.0", features = ["yaml"] } \ No newline at end of file diff --git a/influxdb_influxql_parser/src/common.rs b/influxdb_influxql_parser/src/common.rs index a6b245c397..167f53edc1 100644 --- a/influxdb_influxql_parser/src/common.rs +++ b/influxdb_influxql_parser/src/common.rs @@ -11,6 +11,7 @@ use nom::combinator::{map, opt, value}; use nom::multi::separated_list1; use nom::sequence::{pair, preceded, terminated}; use std::fmt::{Display, Formatter}; +use std::ops::{Deref, DerefMut}; /// Represents a measurement name as either an identifier or a regular expression. #[derive(Clone, Debug, PartialEq, Eq)] @@ -44,8 +45,13 @@ impl Display for MeasurementName { /// Represents a fully-qualified, 3-part measurement name. #[derive(Clone, Debug, PartialEq, Eq)] pub struct QualifiedMeasurementName { + /// An optional database name. pub database: Option, + + /// An optional retention policy. pub retention_policy: Option, + + /// The measurement name. pub name: MeasurementName, } @@ -87,7 +93,7 @@ impl Display for QualifiedMeasurementName { /// policy_name ::= identifier /// measurement_name ::= identifier | regex_lit /// ``` -pub fn qualified_measurement_name(i: &str) -> ParseResult<&str, QualifiedMeasurementName> { +pub(crate) fn qualified_measurement_name(i: &str) -> ParseResult<&str, QualifiedMeasurementName> { let (remaining_input, (opt_db_rp, name)) = pair( opt(alt(( // database "." retention_policy "." @@ -122,49 +128,153 @@ pub fn qualified_measurement_name(i: &str) -> ParseResult<&str, QualifiedMeasure )) } +/// Implements common behaviour for u64 tuple-struct types +#[macro_export] +macro_rules! impl_tuple_clause { + ($NAME:ident, $FOR:ty) => { + impl $NAME { + /// Create a new instance with the specified value. + pub fn new(value: $FOR) -> Self { + Self(value) + } + } + + impl std::ops::DerefMut for $NAME { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + impl std::ops::Deref for $NAME { + type Target = $FOR; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl From<$FOR> for $NAME { + fn from(value: $FOR) -> Self { + Self(value) + } + } + }; +} + +/// Represents the value for a `LIMIT` clause. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct LimitClause(pub(crate) u64); + +impl_tuple_clause!(LimitClause, u64); + +impl Display for LimitClause { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "LIMIT {}", self.0) + } +} + /// Parse a `LIMIT ` clause. -pub fn limit_clause(i: &str) -> ParseResult<&str, u64> { +pub(crate) fn limit_clause(i: &str) -> ParseResult<&str, LimitClause> { preceded( pair(tag_no_case("LIMIT"), multispace1), expect( "invalid LIMIT clause, expected unsigned integer", - unsigned_integer, + map(unsigned_integer, LimitClause), ), )(i) } +/// Represents the value for a `OFFSET` clause. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct OffsetClause(pub(crate) u64); + +impl_tuple_clause!(OffsetClause, u64); + +impl Display for OffsetClause { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "OFFSET {}", self.0) + } +} + /// Parse an `OFFSET ` clause. -pub fn offset_clause(i: &str) -> ParseResult<&str, u64> { +pub(crate) fn offset_clause(i: &str) -> ParseResult<&str, OffsetClause> { preceded( pair(tag_no_case("OFFSET"), multispace1), expect( "invalid OFFSET clause, expected unsigned integer", - unsigned_integer, + map(unsigned_integer, OffsetClause), ), )(i) } /// Parse a terminator that ends a SQL statement. -pub fn statement_terminator(i: &str) -> ParseResult<&str, ()> { +pub(crate) fn statement_terminator(i: &str) -> ParseResult<&str, ()> { value((), char(';'))(i) } +/// Represents the `WHERE` clause of a statement. +#[derive(Debug, Clone, PartialEq)] +pub struct WhereClause(pub(crate) ConditionalExpression); + +impl WhereClause { + /// Create an instance of a `WhereClause` using `expr` + pub fn new(expr: ConditionalExpression) -> Self { + Self(expr) + } +} + +impl DerefMut for WhereClause { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl Deref for WhereClause { + type Target = ConditionalExpression; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Display for WhereClause { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "WHERE {}", self.0) + } +} + /// Parse a `WHERE` clause. -pub fn where_clause(i: &str) -> ParseResult<&str, ConditionalExpression> { +pub(crate) fn where_clause(i: &str) -> ParseResult<&str, WhereClause> { preceded( pair(tag_no_case("WHERE"), multispace1), - conditional_expression, + map(conditional_expression, WhereClause), )(i) } /// Represents an InfluxQL `ORDER BY` clause. #[derive(Default, Debug, Clone, Copy, Eq, PartialEq)] pub enum OrderByClause { + /// Signals the `ORDER BY` is in ascending order. #[default] Ascending, + + /// Signals the `ORDER BY` is in descending order. Descending, } +impl Display for OrderByClause { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "ORDER BY TIME {}", + match self { + Self::Ascending => "ASC", + Self::Descending => "DESC", + } + ) + } +} + /// Parse an InfluxQL `ORDER BY` clause. /// /// An `ORDER BY` in InfluxQL is limited when compared to the equivalent @@ -187,7 +297,7 @@ pub enum OrderByClause { /// ``` /// /// [EBNF]: https://www.w3.org/TR/2010/REC-xquery-20101214/#EBNFNotation -pub fn order_by_clause(i: &str) -> ParseResult<&str, OrderByClause> { +pub(crate) fn order_by_clause(i: &str) -> ParseResult<&str, OrderByClause> { let order = || { preceded( multispace1, @@ -221,29 +331,18 @@ pub fn order_by_clause(i: &str) -> ParseResult<&str, OrderByClause> { /// Parser is a trait that allows a type to parse itself. pub trait Parser: Sized { + /// Parse this type from the string `i`. fn parse(i: &str) -> ParseResult<&str, Self>; } /// `OneOrMore` is a container for representing a minimum of one `T`. -/// -/// `OneOrMore` provides a default implementation of [`fmt::Display`], -/// which displays the contents separated by commas. #[derive(Clone, Debug, PartialEq, Eq)] -pub struct OneOrMore { - contents: Vec, +pub struct OneOrMore { + pub(crate) contents: Vec, } -impl Display for OneOrMore { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - Display::fmt(self.first(), f)?; - for arg in self.rest() { - write!(f, ", {}", arg)?; - } - Ok(()) - } -} - -impl OneOrMore { +#[allow(clippy::len_without_is_empty)] +impl OneOrMore { /// Construct a new `OneOrMore` with `contents`. /// /// **NOTE:** that `new` panics if contents is empty. @@ -272,11 +371,11 @@ impl OneOrMore { } } -impl OneOrMore { +impl OneOrMore { /// Parse a list of one or more `T`, separated by commas. /// /// Returns an error using `msg` if `separated_list1` fails to parse any elements. - pub fn separated_list1<'a>( + pub(crate) fn separated_list1<'a>( msg: &'static str, ) -> impl FnMut(&'a str) -> ParseResult<&'a str, Self> { move |i: &str| { @@ -303,7 +402,7 @@ mod tests { impl From<&str> for MeasurementName { /// Convert a `str` to [`MeasurementName::Name`]. fn from(s: &str) -> Self { - Self::Name(Identifier(s.into())) + Self::Name(Identifier::new(s.into())) } } @@ -408,15 +507,15 @@ mod tests { #[test] fn test_limit_clause() { let (_, got) = limit_clause("LIMIT 587").unwrap(); - assert_eq!(got, 587); + assert_eq!(*got, 587); // case insensitive let (_, got) = limit_clause("limit 587").unwrap(); - assert_eq!(got, 587); + assert_eq!(*got, 587); // extra spaces between tokens let (_, got) = limit_clause("LIMIT 123").unwrap(); - assert_eq!(got, 123); + assert_eq!(*got, 123); // not digits assert_expect_error!( @@ -440,15 +539,15 @@ mod tests { #[test] fn test_offset_clause() { let (_, got) = offset_clause("OFFSET 587").unwrap(); - assert_eq!(got, 587); + assert_eq!(*got, 587); // case insensitive let (_, got) = offset_clause("offset 587").unwrap(); - assert_eq!(got, 587); + assert_eq!(*got, 587); // extra spaces between tokens let (_, got) = offset_clause("OFFSET 123").unwrap(); - assert_eq!(got, 123); + assert_eq!(*got, 123); // not digits assert_expect_error!( @@ -537,6 +636,16 @@ mod tests { type OneOrMoreString = OneOrMore; + impl Display for OneOrMoreString { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + Display::fmt(self.first(), f)?; + for arg in self.rest() { + write!(f, ", {}", arg)?; + } + Ok(()) + } + } + #[test] #[should_panic(expected = "OneOrMore requires elements")] fn test_one_or_more() { diff --git a/influxdb_influxql_parser/src/delete.rs b/influxdb_influxql_parser/src/delete.rs index 6d8a8c7cad..464f30c563 100644 --- a/influxdb_influxql_parser/src/delete.rs +++ b/influxdb_influxql_parser/src/delete.rs @@ -1,5 +1,4 @@ -use crate::common::where_clause; -use crate::expression::conditional::ConditionalExpression; +use crate::common::{where_clause, WhereClause}; use crate::internal::{expect, ParseResult}; use crate::simple_from_clause::{delete_from_clause, DeleteFromClause}; use nom::branch::alt; @@ -9,17 +8,21 @@ use nom::combinator::{map, opt}; use nom::sequence::{pair, preceded}; use std::fmt::{Display, Formatter}; +/// Represents a `DELETE` statement. #[derive(Clone, Debug, PartialEq)] pub enum DeleteStatement { - /// A DELETE with a measurement or measurements and an optional conditional expression - /// to restrict which series are deleted. + /// A DELETE with a `FROM` clause specifying one or more measurements + /// and an optional `WHERE` clause to restrict which series are deleted. FromWhere { + /// Represents the `FROM` clause. from: DeleteFromClause, - condition: Option, + + /// Represents the optional `WHERE` clause. + condition: Option, }, - /// A `DELETE` with a conditional expression to restrict which series are deleted. - Where(ConditionalExpression), + /// A `DELETE` with a `WHERE` clause to restrict which series are deleted. + Where(WhereClause), } impl Display for DeleteStatement { @@ -28,12 +31,12 @@ impl Display for DeleteStatement { match self { Self::FromWhere { from, condition } => { - write!(f, " FROM {}", from)?; - if let Some(condition) = condition { - write!(f, " WHERE {}", condition)?; + write!(f, " {}", from)?; + if let Some(where_clause) = condition { + write!(f, " {}", where_clause)?; } } - Self::Where(condition) => write!(f, " WHERE {}", condition)?, + Self::Where(where_clause) => write!(f, " {}", where_clause)?, }; Ok(()) @@ -41,7 +44,7 @@ impl Display for DeleteStatement { } /// Parse a `DELETE` statement. -pub fn delete_statement(i: &str) -> ParseResult<&str, DeleteStatement> { +pub(crate) fn delete_statement(i: &str) -> ParseResult<&str, DeleteStatement> { // delete ::= "DELETE" ( from_clause where_clause? | where_clause ) preceded( tag_no_case("DELETE"), diff --git a/influxdb_influxql_parser/src/drop.rs b/influxdb_influxql_parser/src/drop.rs index 2d83fd0763..afef146fff 100644 --- a/influxdb_influxql_parser/src/drop.rs +++ b/influxdb_influxql_parser/src/drop.rs @@ -19,7 +19,7 @@ impl Display for DropMeasurementStatement { } } -pub fn drop_statement(i: &str) -> ParseResult<&str, DropMeasurementStatement> { +pub(crate) fn drop_statement(i: &str) -> ParseResult<&str, DropMeasurementStatement> { preceded( pair(tag_no_case("DROP"), multispace1), expect( diff --git a/influxdb_influxql_parser/src/explain.rs b/influxdb_influxql_parser/src/explain.rs index c9576aa3e8..5c3923264e 100644 --- a/influxdb_influxql_parser/src/explain.rs +++ b/influxdb_influxql_parser/src/explain.rs @@ -10,7 +10,7 @@ use nom::sequence::{preceded, tuple}; use std::fmt::{Display, Formatter}; /// Represents various options for an `EXPLAIN` statement. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ExplainOption { /// `EXPLAIN VERBOSE statement` Verbose, @@ -38,8 +38,11 @@ impl Display for ExplainOption { /// ``` #[derive(Debug, Clone, PartialEq)] pub struct ExplainStatement { - options: Option, - select: Box, + /// Represents any options specified for the `EXPLAIN` statement. + pub options: Option, + + /// Represents the `SELECT` statement to be explained and / or analyzed. + pub select: Box, } impl Display for ExplainStatement { @@ -53,7 +56,7 @@ impl Display for ExplainStatement { } /// Parse an `EXPLAIN` statement. -pub fn explain_statement(i: &str) -> ParseResult<&str, ExplainStatement> { +pub(crate) fn explain_statement(i: &str) -> ParseResult<&str, ExplainStatement> { map( tuple(( tag_no_case("EXPLAIN"), diff --git a/influxdb_influxql_parser/src/expression.rs b/influxdb_influxql_parser/src/expression.rs index 250bbf2058..8292984e28 100644 --- a/influxdb_influxql_parser/src/expression.rs +++ b/influxdb_influxql_parser/src/expression.rs @@ -1,4 +1,9 @@ +pub use arithmetic::*; +pub use conditional::*; + +/// Provides arithmetic expression parsing. pub mod arithmetic; +/// Provides conditional expression parsing. pub mod conditional; #[cfg(test)] diff --git a/influxdb_influxql_parser/src/expression/arithmetic.rs b/influxdb_influxql_parser/src/expression/arithmetic.rs index a3aa7d0eed..6b2a8304f8 100644 --- a/influxdb_influxql_parser/src/expression/arithmetic.rs +++ b/influxdb_influxql_parser/src/expression/arithmetic.rs @@ -68,12 +68,21 @@ pub enum Expr { UnaryOp(UnaryOperator, Box), /// Function call - Call { name: String, args: Vec }, + Call { + /// Represents the name of the function call. + name: String, + + /// Represents the list of arguments to the function call. + args: Vec, + }, /// Binary operations, such as `1 + 2`. Binary { + /// Represents the left-hand side of the binary expression. lhs: Box, + /// Represents the operator to apply to the binary expression. op: BinaryOperator, + /// Represents the right-hand side of the binary expression. rhs: Box, }, @@ -142,7 +151,10 @@ impl Display for Expr { /// Specifies the data type of a wildcard (`*`) when using the `::` operator. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum WildcardType { + /// Indicates the wildcard refers to tags only. Tag, + + /// Indicates the wildcard refers to fields only. Field, } @@ -163,11 +175,17 @@ impl Display for WildcardType { /// [cast]: https://docs.influxdata.com/influxdb/v1.8/query_language/explore-data/#cast-operations #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum VarRefDataType { + /// Represents a 64-bit float. Float, + /// Represents a 64-bit integer. Integer, + /// Represents a UTF-8 string. String, + /// Represents a boolean. Boolean, + /// Represents a tag. Tag, + /// Represents a field. Field, } @@ -187,7 +205,9 @@ impl Display for VarRefDataType { /// An InfluxQL unary operator. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum UnaryOperator { + /// Represents the unary `+` operator. Plus, + /// Represents the unary `-` operator. Minus, } @@ -203,14 +223,22 @@ impl Display for UnaryOperator { /// An InfluxQL binary operators. #[derive(Clone, Debug, Copy, PartialEq, Eq)] pub enum BinaryOperator { - Add, // + - Sub, // - - Mul, // * - Div, // / - Mod, // % - BitwiseAnd, // & - BitwiseOr, // | - BitwiseXor, // ^ + /// Represents the `+` operator. + Add, + /// Represents the `-` operator. + Sub, + /// Represents the `*` operator. + Mul, + /// Represents the `/` operator. + Div, + /// Represents the `%` or modulus operator. + Mod, + /// Represents the `&` or bitwise-and operator. + BitwiseAnd, + /// Represents the `|` or bitwise-or operator. + BitwiseOr, + /// Represents the `^` or bitwise-xor operator. + BitwiseXor, } impl Display for BinaryOperator { @@ -259,7 +287,7 @@ where } /// Parse a function call expression -pub fn call_expression(i: &str) -> ParseResult<&str, Expr> +pub(crate) fn call_expression(i: &str) -> ParseResult<&str, Expr> where T: ArithmeticParsers, { @@ -283,7 +311,7 @@ where } /// Parse a variable reference, which is an identifier followed by an optional cast expression. -pub fn var_ref(i: &str) -> ParseResult<&str, Expr> { +pub(crate) fn var_ref(i: &str) -> ParseResult<&str, Expr> { map( pair( identifier, @@ -342,7 +370,7 @@ where /// Parse an arithmetic expression. /// /// This includes the addition, subtraction, bitwise or, and bitwise xor operators. -pub fn arithmetic(i: &str) -> ParseResult<&str, Expr> +pub(crate) fn arithmetic(i: &str) -> ParseResult<&str, Expr> where T: ArithmeticParsers, { @@ -363,7 +391,7 @@ where } /// A trait for customizing arithmetic parsers. -pub trait ArithmeticParsers { +pub(crate) trait ArithmeticParsers { /// Parse an operand of an arithmetic expression. fn operand(i: &str) -> ParseResult<&str, Expr>; } diff --git a/influxdb_influxql_parser/src/expression/conditional.rs b/influxdb_influxql_parser/src/expression/conditional.rs index 991966ce4b..15b665d5a1 100644 --- a/influxdb_influxql_parser/src/expression/conditional.rs +++ b/influxdb_influxql_parser/src/expression/conditional.rs @@ -13,19 +13,31 @@ use nom::sequence::{delimited, preceded, tuple}; use std::fmt; use std::fmt::{Display, Formatter, Write}; +/// Represents on of the conditional operators supported by [`ConditionalExpression::Binary`]. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ConditionalOperator { - Eq, // = - NotEq, // != - EqRegex, // =~ - NotEqRegex, // !~ - Lt, // < - LtEq, // <= - Gt, // > - GtEq, // >= - In, // IN - And, // AND - Or, // OR + /// Represents the `=` operator. + Eq, + /// Represents the `!=` operator. + NotEq, + /// Represents the `=~` (regular expression equals) operator. + EqRegex, + /// Represents the `!~` (regular expression not equals) operator. + NotEqRegex, + /// Represents the `<` operator. + Lt, + /// Represents the `<=` operator. + LtEq, + /// Represents the `>` operator. + Gt, + /// Represents the `>=` operator. + GtEq, + /// Represents the `IN` operator. + In, + /// Represents the `AND` operator. + And, + /// Represents the `OR` operator. + Or, } impl Display for ConditionalOperator { @@ -46,6 +58,7 @@ impl Display for ConditionalOperator { } } +/// Represents a conditional expression. #[derive(Debug, Clone, PartialEq)] pub enum ConditionalExpression { /// Represents an arithmetic expression. @@ -53,8 +66,11 @@ pub enum ConditionalExpression { /// Binary operations, such as `foo = 'bar'` or `true AND false`. Binary { + /// Represents the left-hand side of the conditional binary expression. lhs: Box, + /// Represents the operator to apply to the conditional binary expression. op: ConditionalOperator, + /// Represents the right-hand side of the conditional binary expression. rhs: Box, }, @@ -162,7 +178,7 @@ fn disjunction(i: &str) -> ParseResult<&str, ConditionalExpression> { } /// Parse an InfluxQL conditional expression. -pub fn conditional_expression(i: &str) -> ParseResult<&str, ConditionalExpression> { +pub(crate) fn conditional_expression(i: &str) -> ParseResult<&str, ConditionalExpression> { disjunction(i) } @@ -181,7 +197,7 @@ fn reduce_expr( } /// Returns true if `expr` is a valid [`Expr::Call`] expression for the `now` function. -pub fn is_valid_now_call(expr: &Expr) -> bool { +pub(crate) fn is_valid_now_call(expr: &Expr) -> bool { match expr { Expr::Call { name, args } => name.to_lowercase() == "now" && args.is_empty(), _ => false, diff --git a/influxdb_influxql_parser/src/expression/test_util.rs b/influxdb_influxql_parser/src/expression/test_util.rs index ec39ee36ae..1d1d16c77a 100644 --- a/influxdb_influxql_parser/src/expression/test_util.rs +++ b/influxdb_influxql_parser/src/expression/test_util.rs @@ -33,7 +33,7 @@ macro_rules! regex { macro_rules! param { ($EXPR: expr) => { $crate::expression::arithmetic::Expr::BindParameter( - $crate::parameter::BindParameter($EXPR.into()).into(), + $crate::parameter::BindParameter::new($EXPR.into()).into(), ) }; } diff --git a/influxdb_influxql_parser/src/identifier.rs b/influxdb_influxql_parser/src/identifier.rs index 895a5bbdad..2564978aab 100644 --- a/influxdb_influxql_parser/src/identifier.rs +++ b/influxdb_influxql_parser/src/identifier.rs @@ -14,7 +14,7 @@ use crate::internal::ParseResult; use crate::keywords::sql_keyword; use crate::string::double_quoted_string; -use crate::write_quoted_string; +use crate::{impl_tuple_clause, write_quoted_string}; use nom::branch::alt; use nom::bytes::complete::tag; use nom::character::complete::{alpha1, alphanumeric1}; @@ -25,7 +25,7 @@ use std::fmt; use std::fmt::{Display, Formatter, Write}; /// Parse an unquoted InfluxQL identifier. -pub fn unquoted_identifier(i: &str) -> ParseResult<&str, &str> { +pub(crate) fn unquoted_identifier(i: &str) -> ParseResult<&str, &str> { preceded( not(sql_keyword), recognize(pair( @@ -37,13 +37,9 @@ pub fn unquoted_identifier(i: &str) -> ParseResult<&str, &str> { /// A type that represents an InfluxQL identifier. #[derive(Clone, Debug, Eq, Hash, PartialEq)] -pub struct Identifier(pub String); +pub struct Identifier(pub(crate) String); -impl From for Identifier { - fn from(s: String) -> Self { - Self(s) - } -} +impl_tuple_clause!(Identifier, String); impl From<&str> for Identifier { fn from(s: &str) -> Self { @@ -59,7 +55,7 @@ impl Display for Identifier { } /// Parses an InfluxQL [Identifier]. -pub fn identifier(i: &str) -> ParseResult<&str, Identifier> { +pub(crate) fn identifier(i: &str) -> ParseResult<&str, Identifier> { // See: https://github.com/influxdata/influxql/blob/df51a45762be9c1b578f01718fa92d286a843fe9/scanner.go#L358-L362 alt(( map(unquoted_identifier, Into::into), diff --git a/influxdb_influxql_parser/src/internal.rs b/influxdb_influxql_parser/src/internal.rs index a18c6f5a10..a4367e0ae7 100644 --- a/influxdb_influxql_parser/src/internal.rs +++ b/influxdb_influxql_parser/src/internal.rs @@ -109,4 +109,4 @@ impl NomParseError for Error { /// ParseResult is a type alias for [`nom::IResult`] used by nom combinator /// functions for parsing InfluxQL. -pub type ParseResult> = nom::IResult; +pub(crate) type ParseResult> = nom::IResult; diff --git a/influxdb_influxql_parser/src/keywords.rs b/influxdb_influxql_parser/src/keywords.rs index 4648920c34..3af1146c9d 100644 --- a/influxdb_influxql_parser/src/keywords.rs +++ b/influxdb_influxql_parser/src/keywords.rs @@ -126,7 +126,7 @@ fn keyword_show_to_write(i: &str) -> ParseResult<&str, &str> { } /// Matches any InfluxQL reserved keyword. -pub fn sql_keyword(i: &str) -> ParseResult<&str, &str> { +pub(crate) fn sql_keyword(i: &str) -> ParseResult<&str, &str> { // NOTE that the alt function takes a tuple with a maximum arity of 21, hence // the reason these are broken into groups alt(( diff --git a/influxdb_influxql_parser/src/lib.rs b/influxdb_influxql_parser/src/lib.rs index 231e3fe0e9..9df8080544 100644 --- a/influxdb_influxql_parser/src/lib.rs +++ b/influxdb_influxql_parser/src/lib.rs @@ -14,10 +14,29 @@ clippy::dbg_macro )] +pub use crate::common::*; +pub use crate::delete::*; +pub use crate::drop::*; +pub use crate::explain::*; +pub use crate::expression::*; +pub use crate::identifier::*; +pub use crate::literal::*; +pub use crate::parameter::*; +pub use crate::select::*; +pub use crate::show::*; +pub use crate::show_field_keys::*; +pub use crate::show_measurements::*; +pub use crate::show_retention_policies::*; +pub use crate::show_tag_keys::*; +pub use crate::show_tag_values::*; +pub use crate::simple_from_clause::*; +pub use crate::statement::*; +pub use crate::string::*; +pub use crate::visit::*; + use crate::common::statement_terminator; use crate::internal::Error as InternalError; use crate::statement::statement; -pub use crate::statement::Statement; use nom::character::complete::multispace0; use nom::combinator::eof; use nom::Offset; @@ -46,6 +65,7 @@ mod show_tag_values; mod simple_from_clause; mod statement; mod string; +mod visit; /// A error returned when parsing an InfluxQL query using /// [`parse_statements`] fails. diff --git a/influxdb_influxql_parser/src/literal.rs b/influxdb_influxql_parser/src/literal.rs index 8fda175130..5497521a30 100644 --- a/influxdb_influxql_parser/src/literal.rs +++ b/influxdb_influxql_parser/src/literal.rs @@ -1,6 +1,6 @@ use crate::internal::{map_fail, ParseResult}; use crate::string::{regex, single_quoted_string, Regex}; -use crate::write_escaped; +use crate::{impl_tuple_clause, write_escaped}; use nom::branch::alt; use nom::bytes::complete::{tag, tag_no_case}; use nom::character::complete::{char, digit1, multispace0}; @@ -25,7 +25,7 @@ const NANOS_PER_DAY: i64 = 24 * NANOS_PER_HOUR; /// Number of nanoseconds in a week. const NANOS_PER_WEEK: i64 = 7 * NANOS_PER_DAY; -// Primitive InfluxQL literal values, such as strings and regular expressions. +/// Primitive InfluxQL literal values, such as strings and regular expressions. #[derive(Clone, Debug, PartialEq)] pub enum Literal { /// Unsigned integer literal. @@ -118,7 +118,7 @@ fn integer(i: &str) -> ParseResult<&str, i64> { /// ```text /// INTEGER ::= [0-9]+ /// ``` -pub fn unsigned_integer(i: &str) -> ParseResult<&str, u64> { +pub(crate) fn unsigned_integer(i: &str) -> ParseResult<&str, u64> { map_fail("unable to parse unsigned integer", digit1, &str::parse)(i) } @@ -141,7 +141,9 @@ fn float(i: &str) -> ParseResult<&str, f64> { /// Represents any signed number. #[derive(Debug, Clone, Copy, PartialEq)] pub enum Number { + /// Contains a 64-bit integer. Integer(i64), + /// Contains a 64-bit float. Float(f64), } @@ -167,7 +169,7 @@ impl From for Number { } /// Parse a signed [`Number`]. -pub fn number(i: &str) -> ParseResult<&str, Number> { +pub(crate) fn number(i: &str) -> ParseResult<&str, Number> { let (remaining, sign) = opt(alt((char('-'), char('+'))))(i)?; preceded( multispace0, @@ -204,13 +206,9 @@ enum DurationUnit { /// Represents an InfluxQL duration in nanoseconds. #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct Duration(i64); +pub struct Duration(pub(crate) i64); -impl From for Duration { - fn from(v: i64) -> Self { - Self(v) - } -} +impl_tuple_clause!(Duration, i64); static DIVISORS: [(i64, &str); 8] = [ (NANOS_PER_WEEK, "w"), @@ -276,7 +274,7 @@ fn single_duration(i: &str) -> ParseResult<&str, i64> { } /// Parse the input for an InfluxQL duration. -pub fn duration(i: &str) -> ParseResult<&str, Duration> { +pub(crate) fn duration(i: &str) -> ParseResult<&str, Duration> { map( fold_many1(single_duration, || 0, |acc, fragment| acc + fragment), Duration, @@ -286,7 +284,7 @@ pub fn duration(i: &str) -> ParseResult<&str, Duration> { /// Parse an InfluxQL literal, except a [`Regex`]. /// /// Use [`literal`] for parsing any literals, excluding regular expressions. -pub fn literal_no_regex(i: &str) -> ParseResult<&str, Literal> { +pub(crate) fn literal_no_regex(i: &str) -> ParseResult<&str, Literal> { alt(( // NOTE: order is important, as floats should be tested before durations and integers. map(float, Literal::Float), @@ -298,12 +296,12 @@ pub fn literal_no_regex(i: &str) -> ParseResult<&str, Literal> { } /// Parse any InfluxQL literal. -pub fn literal(i: &str) -> ParseResult<&str, Literal> { +pub(crate) fn literal(i: &str) -> ParseResult<&str, Literal> { alt((literal_no_regex, map(regex, Literal::Regex)))(i) } /// Parse an InfluxQL literal regular expression. -pub fn literal_regex(i: &str) -> ParseResult<&str, Literal> { +pub(crate) fn literal_regex(i: &str) -> ParseResult<&str, Literal> { map(regex, Literal::Regex)(i) } diff --git a/influxdb_influxql_parser/src/parameter.rs b/influxdb_influxql_parser/src/parameter.rs index ea62861ec8..599e38ff60 100644 --- a/influxdb_influxql_parser/src/parameter.rs +++ b/influxdb_influxql_parser/src/parameter.rs @@ -9,7 +9,7 @@ use crate::internal::ParseResult; use crate::string::double_quoted_string; -use crate::write_quoted_string; +use crate::{impl_tuple_clause, write_quoted_string}; use nom::branch::alt; use nom::bytes::complete::tag; use nom::character::complete::{alphanumeric1, char}; @@ -26,13 +26,9 @@ fn unquoted_parameter(i: &str) -> ParseResult<&str, &str> { /// A type that represents an InfluxQL bind parameter. #[derive(Clone, Debug, Eq, Hash, PartialEq)] -pub struct BindParameter(pub String); +pub struct BindParameter(pub(crate) String); -impl From for BindParameter { - fn from(s: String) -> Self { - Self(s) - } -} +impl_tuple_clause!(BindParameter, String); impl From<&str> for BindParameter { fn from(s: &str) -> Self { @@ -49,7 +45,7 @@ impl Display for BindParameter { } /// Parses an InfluxQL [BindParameter]. -pub fn parameter(i: &str) -> ParseResult<&str, BindParameter> { +pub(crate) fn parameter(i: &str) -> ParseResult<&str, BindParameter> { // See: https://github.com/influxdata/influxql/blob/df51a45762be9c1b578f01718fa92d286a843fe9/scanner.go#L358-L362 preceded( char('$'), diff --git a/influxdb_influxql_parser/src/select.rs b/influxdb_influxql_parser/src/select.rs index 7b9764c182..b23c786d23 100644 --- a/influxdb_influxql_parser/src/select.rs +++ b/influxdb_influxql_parser/src/select.rs @@ -1,19 +1,20 @@ use crate::common::{ limit_clause, offset_clause, order_by_clause, qualified_measurement_name, where_clause, - OneOrMore, OrderByClause, Parser, QualifiedMeasurementName, + LimitClause, OffsetClause, OneOrMore, OrderByClause, Parser, QualifiedMeasurementName, + WhereClause, }; use crate::expression::arithmetic::Expr::Wildcard; use crate::expression::arithmetic::{ arithmetic, call_expression, var_ref, ArithmeticParsers, Expr, WildcardType, }; -use crate::expression::conditional::{is_valid_now_call, ConditionalExpression}; +use crate::expression::conditional::is_valid_now_call; use crate::identifier::{identifier, Identifier}; use crate::internal::{expect, verify, ParseResult}; use crate::literal::{duration, literal, number, unsigned_integer, Literal, Number}; use crate::parameter::parameter; use crate::select::MeasurementSelection::Subquery; use crate::string::{regex, single_quoted_string, Regex}; -use crate::write_escaped; +use crate::{impl_tuple_clause, write_escaped}; use nom::branch::alt; use nom::bytes::complete::{tag, tag_no_case}; use nom::character::complete::{char, multispace0, multispace1}; @@ -22,6 +23,7 @@ use nom::sequence::{delimited, pair, preceded, tuple}; use std::fmt; use std::fmt::{Display, Formatter, Write}; +/// Represents a `SELECT` statement. #[derive(Clone, Debug, PartialEq)] pub struct SelectStatement { /// Expressions returned by the selection. @@ -31,85 +33,83 @@ pub struct SelectStatement { pub from: FromMeasurementClause, /// A conditional expression to filter the selection. - pub condition: Option, + pub condition: Option, /// Expressions used for grouping the selection. - pub group_by: Option, + pub group_by: Option, - /// The [fill option][fill] specified for the selection. If the value is [`None`], + /// The [fill clause] specifies the fill behaviour for the selection. If the value is [`None`], /// it is the same behavior as `fill(none)`. /// /// [fill]: https://docs.influxdata.com/influxdb/v1.8/query_language/explore-data/#group-by-time-intervals-and-fill - pub fill_option: Option, + pub fill: Option, /// Configures the ordering of the selection by time. pub order_by: Option, /// A value to restrict the number of rows returned. - pub limit: Option, + pub limit: Option, /// A value to specify an offset to start retrieving rows. - pub offset: Option, + pub offset: Option, /// A value to restrict the number of series returned. - pub series_limit: Option, + pub series_limit: Option, /// A value to specify an offset to start retrieving series. - pub series_offset: Option, + pub series_offset: Option, /// The timezone for the query, specified as [`tz('