This modifies the read window aggregate interfaces to future-proof it
if and when we add additional capabilities to the method. Previously,
the interface was all or nothing. If we modified the RPC call itself, we
would have to make a new interface to denote the change to the Go code.
This changes the interface so now a `WindowAggregateCapability` exists.
This way, we can modify the struct to include things like:
```
type WindowAggregateCapability struct {
WindowPeriodCapability bool
MeanAggregateCapability bool
}
```
This way we can learn if the RPC call itself supports some specific
option. If the first iteration doesn't support a mean aggregate or the
mean aggregate is only supported by single server implementations, the
window aggregate can tell the caller that it won't be able to compute
the mean aggregate.
Since it fills in a struct with these capabilities, the struct can
safely introduce new values. If a downstream consumer wants to take
advantage of that functionality, then all interfaces in the chain have
to be updated to consume the upstream capabilities.
The `ReadWindowAggregateSource` will invoke the `ReadWindowAggregate`
method on the `influxdb.Reader` and return the table. It is implemented
using the same common methods that are used for the other sources.
Added an interface for an additional storage capability. This interface
will allow for checking if the reader supports the window aggregate call
and another method for invoking the call if it does.
This is implemented using a single interface. If the reader implements
the interface, it indicates that the client is capable of reading the
response. The `HasXXX` method is intended to check if the store supports
the operation. This method also takes a context because it could require
a remote call or to wait for one.
The storage engine isn't capable of sending back empty tables when a
series is empty. Because of this, we disable the push down and let flux
do the filtering in the case where there is a filter and it is specified
to keep the empty tables.
this is a step towards providing a shared http client that manages pooling connections,
timeouts, and reducing GC for by not creating/GCing a client each req. Bring on the red!
When `exists` was used in conjunction with any other pushed down
expression, the `exists` was not rewritten properly because the rewrite
did not descend into logical expressions.
This is now fixed so those expressions will be rewritten correctly. This
affected the following form:
filter(fn: (r) => r._measurement == "cpu" and exists r.host)
It did not affect the following:
filter(fn: (r) => r._measurement == "cpu")
|> filter(fn: (r) => exists r.host)
Writes directly to a PointsWriter require the tag key, value pairs
are sorted in lexicographically ascending order. This commit uses
new API from the `models` package to ensure this invariant is
maintained.
The `v1.databases()` call did not correctly filter buckets based on
auth. Fortunately, it did not cause any improper permissions such as
allowing a person to see buckets that they had no read access to.
The error instead was that if a user did not have read access to one of
the buckets that was returned, the entire command would fail rather than
filter out the bucket that didn't have permissions.
This changes it so that if the user doesn't gets an unauthorized error
when accessing a bucket, it will filter it from the list instead of
failing. It also changes it so the error message is marked as
`ENotFound` instead of as an internal error.
This change makes it so that if an org or orgID are missing on calls to the `to` function
that the orgID is retrieved from the request context.
This is consistent with how `from` works.
The `exists` operator now gets pushed down to storage correctly. If
`exists` is used on a tag, then it will be rewritten to `tag != ""`
which is how storage defines if a tag exists. If `not exists` is used,
then it will use `tag == ""` which is how you would query storage for
only if a tag doesn't exist.
The `tag == ""` and `tag != ""` are different. For `tag == ""`, the
predicate is impossible for the storage layer to return true with.
Ideally, we would just rewrite this to return nothing and we wouldn't
bother with even querying storage. Instead, we just do not rewrite this
predicate because it cannot be rewritten to make sense with storage. If
we see `tag != ""`, it is the only one that can be passed through as-is
because `tag != ""` returns the same values as `exists tag`. It will
return true for every non-null value.