influx 0.1.0.alpha → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d4b53c95048c7332be3eed378213fe0952d7815ec5f3780e18ceaeac0328cc83
4
- data.tar.gz: 0ac5483c268718a4267227a6a18636e6ce68fb9c5c63076a47f174e8a0ded456
3
+ metadata.gz: 0d2c6ec69b8f21ac0b2fab377c7215598ac2cd8ecd20f443b971e5909fa014aa
4
+ data.tar.gz: 120f06af14b691787c7b25e6ed40fc287d8e0d7a7e0f03ea3d97348f4e76a8b2
5
5
  SHA512:
6
- metadata.gz: 01c4f79cf46720f791139bf14507c8ead9e4e7a8560ad8ca03886188552e219a15a968646671a6eaa8d084893a2c16d11e75b188ce9bf74292913ee7985263b7
7
- data.tar.gz: f10c0ebf7fd02de18f1e120ade62e4c0a5d7fe02607123e28aaa2379a38cdc10c79347ddda3f505f679382a925286f689db201c54aec88e2543148081efabd33
6
+ metadata.gz: 6e1df569de6d83a399004cb32597a00e51fd454d07a929f47a62b439867b63da2cf6e81c1830bd8b9d279f0ea8be439de962580533501119d2c03867a90d50ce
7
+ data.tar.gz: 002a155c47b90be78d75ecbeee8ee980559c6088992023e3ba079556a068dba18978ed838ffe0b0d53dadb34cd894e217c50704932817573381ebff89dad8a24
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/.rubocop.yml CHANGED
@@ -1,13 +1,177 @@
1
+ # require: rubocop-graphql
2
+
3
+ # Allow longer lines and methods
4
+ Layout/LineLength:
5
+ Max: 500
6
+
7
+ Metrics/MethodLength:
8
+ Max: 30
9
+
10
+ # Tests are declarative, no block length test
11
+ Metrics/BlockLength:
12
+ IgnoredMethods: ["describe", "context", "namespace"]
13
+
1
14
  AllCops:
2
- TargetRubyVersion: 2.6
15
+ TargetRubyVersion: 3.0.2
16
+ # RuboCop has a bunch of cops enabled by default. This setting tells RuboCop
17
+ # to ignore them, so only the ones explicitly set in this file are enabled.
18
+ DisabledByDefault: true
19
+
20
+ # Prefer &&/|| over and/or.
21
+ Style/AndOr:
22
+ Enabled: true
23
+
24
+ # Align `when` with `case`.
25
+ Layout/CaseIndentation:
26
+ Enabled: true
27
+
28
+ # Align comments with method definitions.
29
+ Layout/CommentIndentation:
30
+ Enabled: true
31
+
32
+ Layout/ElseAlignment:
33
+ Enabled: true
34
+
35
+ # Align `end` with the matching keyword or starting expression except for
36
+ # assignments, where it should be aligned with the LHS.
37
+ Layout/EndAlignment:
38
+ Enabled: true
39
+ EnforcedStyleAlignWith: variable
40
+ AutoCorrect: true
41
+
42
+ Layout/EmptyLineAfterMagicComment:
43
+ Enabled: true
44
+
45
+ # In a regular class definition, no empty lines around the body.
46
+ Layout/EmptyLinesAroundClassBody:
47
+ Enabled: true
48
+
49
+ # In a regular method definition, no empty lines around the body.
50
+ Layout/EmptyLinesAroundMethodBody:
51
+ Enabled: true
52
+
53
+ # In a regular module definition, no empty lines around the body.
54
+ Layout/EmptyLinesAroundModuleBody:
55
+ Enabled: true
56
+
57
+ Layout/FirstArgumentIndentation:
58
+ Enabled: true
59
+
60
+ # Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }.
61
+ Style/HashSyntax:
62
+ Enabled: true
63
+
64
+ # Method definitions after `private` or `protected` isolated calls need one
65
+ # extra level of indentation.
66
+ Layout/IndentationConsistency:
67
+ Enabled: true
68
+ EnforcedStyle: indented_internal_methods
69
+
70
+ # Two spaces, no tabs (for indentation).
71
+ Layout/IndentationWidth:
72
+ Enabled: true
73
+
74
+ Layout/LeadingCommentSpace:
75
+ Enabled: true
76
+
77
+ Layout/SpaceAfterColon:
78
+ Enabled: true
79
+
80
+ Layout/SpaceAfterComma:
81
+ Enabled: true
82
+
83
+ Layout/SpaceAroundEqualsInParameterDefault:
84
+ Enabled: true
85
+
86
+ Layout/SpaceAroundKeyword:
87
+ Enabled: true
88
+
89
+ Layout/SpaceAroundOperators:
90
+ Enabled: true
91
+
92
+ Layout/SpaceBeforeComma:
93
+ Enabled: true
94
+
95
+ Layout/SpaceBeforeFirstArg:
96
+ Enabled: true
97
+
98
+ Style/DefWithParentheses:
99
+ Enabled: true
100
+
101
+ # Defining a method with parameters needs parentheses.
102
+ Style/MethodDefParentheses:
103
+ Enabled: true
104
+
105
+ Style/FrozenStringLiteralComment:
106
+ Enabled: true
107
+ EnforcedStyle: always
108
+ Exclude:
109
+ - "actionview/test/**/*.builder"
110
+ - "actionview/test/**/*.ruby"
111
+ - "actionpack/test/**/*.builder"
112
+ - "actionpack/test/**/*.ruby"
113
+ - "activestorage/db/migrate/**/*.rb"
114
+ - "db/migrate/**/*.rb"
115
+ - "db/*.rb"
116
+
117
+ # Use `foo {}` not `foo{}`.
118
+ Layout/SpaceBeforeBlockBraces:
119
+ Enabled: true
3
120
 
121
+ # Use `foo { bar }` not `foo {bar}`.
122
+ Layout/SpaceInsideBlockBraces:
123
+ Enabled: true
124
+
125
+ # Use `{ a: 1 }` not `{a:1}`.
126
+ Layout/SpaceInsideHashLiteralBraces:
127
+ Enabled: true
128
+
129
+ Layout/SpaceInsideParens:
130
+ Enabled: true
131
+
132
+ # Check quotes usage according to lint rule below.
4
133
  Style/StringLiterals:
5
134
  Enabled: true
6
- EnforcedStyle: double_quotes
135
+ EnforcedStyle: single_quotes
7
136
 
8
- Style/StringLiteralsInInterpolation:
137
+ # Detect hard tabs, no hard tabs.
138
+ Layout/IndentationStyle:
9
139
  Enabled: true
10
- EnforcedStyle: double_quotes
11
140
 
12
- Layout/LineLength:
13
- Max: 120
141
+ # Blank lines should not have any spaces.
142
+ Layout/TrailingEmptyLines:
143
+ Enabled: true
144
+
145
+ # No trailing whitespace.
146
+ Layout/TrailingWhitespace:
147
+ Enabled: true
148
+
149
+ # Use quotes for string literals when they are enough.
150
+ Style/RedundantPercentQ:
151
+ Enabled: true
152
+
153
+ # Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
154
+ Lint/RequireParentheses:
155
+ Enabled: true
156
+
157
+ Lint/RedundantStringCoercion:
158
+ Enabled: true
159
+
160
+ # Supports --auto-correct
161
+ Style/RedundantSelf:
162
+ Description: Don't use self where it's not needed.
163
+ StyleGuide: https://github.com/rubocop-hq/ruby-style-guide#no-self-unless-required
164
+ Enabled: true
165
+
166
+ Style/RedundantReturn:
167
+ Enabled: true
168
+ AllowMultipleReturnValues: true
169
+
170
+ Style/Semicolon:
171
+ Enabled: true
172
+ AllowAsExpressionSeparator: true
173
+
174
+ # Prefer Foo.method over Foo::method
175
+ Style/ColonMethodCall:
176
+ Enabled: true
177
+
data/Gemfile CHANGED
@@ -1,10 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source "https://rubygems.org"
3
+ source 'https://rubygems.org'
4
4
 
5
5
  # Specify your gem's dependencies in influx.gemspec
6
6
  gemspec
7
7
 
8
- gem "rake", "~> 13.0"
8
+ gem 'rake', '~> 13.0'
9
9
 
10
- gem "rubocop", "~> 1.21"
10
+ gem 'rspec', '~> 3'
11
+
12
+ gem 'rubocop', '~> 1'
13
+
14
+ gem 'simplecov', require: false, group: :test
data/Gemfile.lock ADDED
@@ -0,0 +1,63 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ influx (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.4.2)
10
+ diff-lcs (1.5.0)
11
+ docile (1.4.0)
12
+ parallel (1.22.0)
13
+ parser (3.1.1.0)
14
+ ast (~> 2.4.1)
15
+ rainbow (3.1.1)
16
+ rake (13.0.6)
17
+ regexp_parser (2.2.1)
18
+ rexml (3.2.5)
19
+ rspec (3.10.0)
20
+ rspec-core (~> 3.10.0)
21
+ rspec-expectations (~> 3.10.0)
22
+ rspec-mocks (~> 3.10.0)
23
+ rspec-core (3.10.2)
24
+ rspec-support (~> 3.10.0)
25
+ rspec-expectations (3.10.2)
26
+ diff-lcs (>= 1.2.0, < 2.0)
27
+ rspec-support (~> 3.10.0)
28
+ rspec-mocks (3.10.2)
29
+ diff-lcs (>= 1.2.0, < 2.0)
30
+ rspec-support (~> 3.10.0)
31
+ rspec-support (3.10.3)
32
+ rubocop (1.26.1)
33
+ parallel (~> 1.10)
34
+ parser (>= 3.1.0.0)
35
+ rainbow (>= 2.2.2, < 4.0)
36
+ regexp_parser (>= 1.8, < 3.0)
37
+ rexml
38
+ rubocop-ast (>= 1.16.0, < 2.0)
39
+ ruby-progressbar (~> 1.7)
40
+ unicode-display_width (>= 1.4.0, < 3.0)
41
+ rubocop-ast (1.16.0)
42
+ parser (>= 3.1.1.0)
43
+ ruby-progressbar (1.11.0)
44
+ simplecov (0.21.2)
45
+ docile (~> 1.1)
46
+ simplecov-html (~> 0.11)
47
+ simplecov_json_formatter (~> 0.1)
48
+ simplecov-html (0.12.3)
49
+ simplecov_json_formatter (0.1.4)
50
+ unicode-display_width (2.1.0)
51
+
52
+ PLATFORMS
53
+ arm64-darwin-21
54
+
55
+ DEPENDENCIES
56
+ influx!
57
+ rake (~> 13.0)
58
+ rspec (~> 3)
59
+ rubocop (~> 1)
60
+ simplecov
61
+
62
+ BUNDLED WITH
63
+ 2.3.9
data/README.md CHANGED
@@ -1,8 +1,42 @@
1
- # Influx
1
+ ## <img src="https://user-images.githubusercontent.com/50866745/168482997-7ed6ae74-aac9-4aee-bf03-fef5e01d683a.png" width="48" align="left"> Ruby InfluxDB Flux <!-- omit in toc -->
2
+ [![CircleCI](https://circleci.com/gh/LapoElisacci/influx/tree/main.svg?style=svg)](https://circleci.com/gh/LapoElisacci/influx/tree/main)
3
+ ![](https://img.shields.io/static/v1?label=Coverage&message=99.54%&color=brightgreen)
4
+ ![](https://img.shields.io/static/v1?label=Latest&message=0.1.0.alpha&color=blue)
5
+ ![](https://ruby-gem-downloads-badge.herokuapp.com/influx?type=total&color=blue)
6
+ ![StandWithUkraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)
2
7
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/influx`. To experiment with that code, run `bin/console` for an interactive prompt.
8
+ Write InfluxDB Flux queries in an ORM fashion with Ruby.
4
9
 
5
- TODO: Delete this and the text above, and describe your gem
10
+ ## Table of contents
11
+
12
+ - [Table of contents](#table-of-contents)
13
+ - [Installation](#installation)
14
+ - [Utilities](#utilities)
15
+ - [Now](#now)
16
+ - [Flux points](#flux-points)
17
+ - [Flux queries](#flux-queries)
18
+ - [From](#from)
19
+ - [Range](#range)
20
+ - [Query data with Flux](#query-data-with-flux)
21
+ - [From](#from-1)
22
+ - [Range](#range-1)
23
+ - [Query fields and tags](#query-fields-and-tags)
24
+ - [Group](#group)
25
+ - [Sort and limit](#sort-and-limit)
26
+ - [Window & aggregate](#window--aggregate)
27
+ - [Increase](#increase)
28
+ - [Moving Average](#moving-average)
29
+ - [Rate](#rate)
30
+ - [Histograms](#histograms)
31
+ - [Fill](#fill)
32
+ - [Median](#median)
33
+ - [Percentile & quantile](#percentile--quantile)
34
+ - [Join (TBD)](#join-tbd)
35
+ - [Cumulative sum](#cumulative-sum)
36
+ - [First & last](#first--last)
37
+ - [Contributing](#contributing)
38
+ - [License](#license)
39
+ - [Code of Conduct](#code-of-conduct)
6
40
 
7
41
  ## Installation
8
42
 
@@ -14,15 +48,290 @@ If bundler is not being used to manage dependencies, install the gem by executin
14
48
 
15
49
  $ gem install influx
16
50
 
17
- ## Usage
51
+ ## Utilities
52
+
53
+ Here are some utility methods provided by the gem.
54
+
55
+ ### Now
56
+
57
+ The gem provides a method to return the Clock timestamp in nanoseconds.
58
+
59
+ ```Ruby
60
+ Influx.now # Default precision is Nanoseconds
61
+ ```
62
+
63
+ You can also pass other precisions if needed:
64
+
65
+ ```Ruby
66
+ Influx.now(:second)
67
+ Influx.now(:millisecond)
68
+ Influx.now(:microsecond)
69
+ Influx.now(:nanosecond)
70
+ ```
71
+
72
+ ---
73
+
74
+ ## Flux points
75
+
76
+ ```Ruby
77
+ Influx::Point.new(
78
+ 'h2o', # measurement
79
+ tags: { location: 'west' },
80
+ fields: { value: 33 },
81
+ time: Influx.now # The default value is Influx.now, you can also use Time or Integer
82
+ ).to_flux # h2o,location=west value=33 1652720908000000
83
+ ```
84
+
85
+ ## Flux queries
86
+
87
+ The gem acts as an ORM therefore you can chain methods to build your `Flux` query string.
88
+
89
+ You can always call the `to_flux` method to see a preview or your query:
90
+
91
+ ```Ruby
92
+ flux_query = Influx.from(bucket: 'my-bucket').range(start: '-1d')
93
+ flux_query.to_flux # from(bucket: "my-bucket") |> range(start: -1d)
94
+ ```
95
+
96
+ ### From
97
+
98
+ The `from` method is the starting point of all queries, it allows you to specify the InfluxDB bucket.
99
+
100
+ ```Ruby
101
+ Influx.from(bucket: 'my-bucket')
102
+ ```
103
+ > ⚠️ This is mandatory to perform any query.
104
+
105
+ ### Range
106
+
107
+ The `range` method allows you to specify the time-range you want to query.
108
+
109
+ ```Ruby
110
+ Influx.from(bucket: 'my-bucket').range(start: '-1d', stop: 'now()')
111
+ ```
112
+
113
+ It supports the `Flux` sytanx as well as `Time`.
114
+
115
+ ```Ruby
116
+ Influx.from(bucket: 'my-bucket').range(start: Time.new.yesterday, stop: Time.new)
117
+ ```
118
+
119
+ > ⚠️ This is mandatory to perform any query.
120
+
121
+ ---
122
+
123
+ ## Query data with Flux
124
+
125
+ The following guides are based on top of the original InfluxData Flux Documentation, available [here](https://docs.influxdata.com/influxdb/cloud/query-data/flux/).
126
+
127
+ **Example data variable**
128
+ Many of the examples provided in the following guides use a **data** variable, which represents a basic query that filters data by measurement and field. **data** is defined as:
129
+
130
+ ```Ruby
131
+ data = Influx.from(bucket: 'my-bucket').range(start: '-1d', stop: 'now()')
132
+
133
+ # from(bucket: "my-bucket")
134
+ # |> range(start: -1d, stop: now())
135
+ ```
136
+
137
+ ### From
138
+
139
+ The `from` method allows you to specify the InfluxDB bucket. Every query starts with the `from` method.
140
+
141
+ ```Ruby
142
+ Influx.from(bucket: 'my-bucket')
143
+
144
+ # from(bucket: "my-bucket")
145
+ ```
146
+
147
+ ### Range
148
+
149
+ The `range` method allows you to bind your query to a time range, it supports native Flux syntax as well as the Ruby `Time` class and `Integer`.
150
+
151
+ ```Ruby
152
+ Influx.from(bucket: 'my-bucket').range(start: '-1d', stop: 'now()')
153
+
154
+ # from(bucket: "my-bucket")
155
+ # |> range(start: -1d, stop: now())
156
+ ```
157
+ ```Ruby
158
+ Influx.from(bucket: 'my-bucket').range(start: Time.new(2018, 1, 1, 0, 0, 0, '+00:00').utc, stop: 1514768400)
159
+
160
+ # from(bucket: "my-bucket")
161
+ # |> range(start: 2018-01-01T00:00:00Z, stop: 2018-01-01T01:00:00Z)
162
+ ```
163
+
164
+ ---
165
+
166
+ ### Query fields and tags
167
+
168
+ Use `filter()` to query data based on fields, tags, or any other column value.
169
+
170
+ ```Ruby
171
+ data.filter("_measurement": "example-measurement", tag: "example-tag")
172
+
173
+ # data
174
+ # |> filter(fn: (r) => r._measurement == "example-measurement" and r.tag == "example-tag")
175
+ ```
176
+
177
+ ### Group
178
+
179
+ Use `group()` to group data with common values in specific columns.
180
+
181
+ ```Ruby
182
+ data.group(columns: ["host"], mode: "by")
183
+
184
+ # data
185
+ # |> group(columns: ["host"], mode: "by")
186
+ ```
187
+
188
+ ### Sort and limit
189
+
190
+ Use `sort()` to order records within each table by specific columns and `limit()` to limit the number of records in output tables to a fixed number, `n`.
191
+
192
+ ```Ruby
193
+ data.sort(columns: ["host", "_value"]).limit(4)
194
+
195
+ # data
196
+ # |> sort(columns: ["host","_value"])
197
+ # |> limit(n: 4)
198
+ ```
199
+
200
+ ### Window & aggregate
201
+
202
+ ```Ruby
203
+ data.aggregate_window(every: "20m", fn: "mean")
204
+
205
+ # data
206
+ # |> aggregateWindow(every: 20m, fn: mean)
207
+ ```
208
+
209
+ ### Increase
210
+
211
+ Use `increase()` to track increases across multiple columns in a table.
212
+
213
+ ```Ruby
214
+ data.increase
215
+
216
+ # data
217
+ # |> increase()
218
+ ```
219
+
220
+ ### Moving Average
221
+
222
+ Use `moving_average()` or `timed_moving_average()` to return the moving average of data.
223
+
224
+ ```Ruby
225
+ data.moving_average(5)
226
+
227
+ # data
228
+ # |> movingAverage(n: 5)
229
+ ```
230
+ ```Ruby
231
+ data.timed_moving_average(every: "2m", period: "4m")
232
+
233
+ # data
234
+ # |> timedMovingAverage(every: 2m, period: 4m)
235
+ ```
236
+
237
+ ### Rate
238
+
239
+ Use `derivative()` to calculate the rate of change between subsequent values.
240
+
241
+ ```Ruby
242
+ data.derivative(unit: "1m", non_negative: true)
243
+
244
+ # data
245
+ # |> derivative(unit: 1m, nonNegative: true)
246
+ ```
247
+
248
+ ### Histograms
249
+
250
+ Use `histogram()` to create cumulative histograms with Flux.
251
+
252
+ ```Ruby
253
+ data.histogram(column: "_value", upper_bound_column: "le", count_column: "_value", bins: [100.0, 200.0, 300.0, 400.0])
254
+
255
+ # data
256
+ # |> histogram(
257
+ # column: "_value",
258
+ # upperBoundColumn: "le",
259
+ # countColumn: "_value",
260
+ # bins: [100.0,200.0,300.0,400.0]
261
+ # )
262
+ ```
263
+ ### Fill
264
+
265
+ Use `fill()` function to replace null values.
266
+
267
+ ```Ruby
268
+ data.fill(use_previous: true)
269
+
270
+ # data
271
+ # |> fill(usePrevious: true)
272
+ ```
273
+ ```Ruby
274
+ data.fill(value: 0.0)
275
+ # data
276
+ # |> fill(value: 0.0)
277
+ ```
278
+
279
+ ### Median
280
+
281
+ Use `median()` to return a value representing the 0.5 quantile (50th percentile) or median of input data.
282
+
283
+ ```Ruby
284
+ data.median
285
+
286
+ # data
287
+ # |> median()
288
+ ```
289
+
290
+ ### Percentile & quantile
291
+
292
+ Use the `quantile()` function to return all values within the `q` quantile or percentile of input data.
293
+
294
+ ```Ruby
295
+ data.quantile(q: 0.99, method: "estimate_tdigest")
296
+
297
+ # data
298
+ # |> quantile(q: 0.99, method: "estimate_tdigest")
299
+ ```
300
+
301
+
302
+ ### Join (TBD)
303
+
304
+ TBD
305
+
306
+ ### Cumulative sum
307
+
308
+ Use the `cumulativeSum()` function to calculate a running total of values.
309
+
310
+ ```Ruby
311
+ data.cumulative_sum
312
+
313
+ # data
314
+ # |> cumulativeSum()
315
+ ```
316
+
317
+ ### First & last
318
+
319
+ Use `first()` or `last()` to return the first or last point in an input table.
18
320
 
19
- TODO: Write usage instructions here
321
+ ```Ruby
322
+ data.first
20
323
 
21
- ## Development
324
+ # data
325
+ # |> first()
326
+ ```
327
+ ```Ruby
328
+ data.last
22
329
 
23
- After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
330
+ # data
331
+ # |> last()
332
+ ```
24
333
 
25
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
334
+ ---
26
335
 
27
336
  ## Contributing
28
337
 
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bundler/gem_tasks"
4
- require "rubocop/rake_task"
3
+ require 'bundler/gem_tasks'
4
+ require 'rubocop/rake_task'
5
5
 
6
6
  RuboCop::RakeTask.new
7
7
 
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # |> aggregateWindow(every: 20m, fn: mean)
4
+
5
+ module Influx
6
+ module Flux
7
+ class AggregateWindow
8
+ def initialize(every:, fn:)
9
+ @every = every
10
+ @fn = fn
11
+ end
12
+
13
+ def to_flux
14
+ <<~FLUX.chomp
15
+ |> aggregateWindow(every: #{@every}, fn: #{@fn})
16
+ FLUX
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # |> cumulativeSum()
4
+
5
+ module Influx
6
+ module Flux
7
+ class CumulativeSum
8
+ def self.to_flux
9
+ <<~FLUX.chomp
10
+ |> cumulativeSum()
11
+ FLUX
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # |> derivative(unit: 1m, nonNegative: true)
4
+
5
+ module Influx
6
+ module Flux
7
+ class Derivative
8
+ def initialize(unit:, non_negative:)
9
+ @unit = unit
10
+ @non_negative = non_negative
11
+ end
12
+
13
+ def to_flux
14
+ <<~FLUX.chomp
15
+ |> derivative(unit: #{@unit}, nonNegative: #{@non_negative})
16
+ FLUX
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ # |> fill(usePrevious: true)
4
+ # |> fill(value: 0.0)
5
+
6
+ module Influx
7
+ module Flux
8
+ class Fill
9
+ def initialize(use_previous: false, value: nil)
10
+ @use_previous = use_previous
11
+ @value = value
12
+ end
13
+
14
+ def to_flux
15
+ if @use_previous
16
+ <<~FLUX.chomp
17
+ |> fill(usePrevious: #{@use_previous})
18
+ FLUX
19
+ else
20
+ <<~FLUX.chomp
21
+ |> fill(value: #{@value})
22
+ FLUX
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # |> filter(fn: (r) => r._measurement == "example-measurement" and r._field == "example-field")
4
+
5
+ module Influx
6
+ module Flux
7
+ class Filter
8
+ def initialize(**params)
9
+ @params = params
10
+ end
11
+
12
+ def to_flux
13
+ <<~FLUX.chomp
14
+ |> filter(fn: (r) => #{@params.map { |k, v| "r.#{k} == #{v.to_json}" }.join(' and ')})
15
+ FLUX
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # |> first()
4
+
5
+ module Influx
6
+ module Flux
7
+ class First
8
+ def self.to_flux
9
+ <<~FLUX.chomp
10
+ |> first()
11
+ FLUX
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Influx
4
+ module Flux
5
+ class From
6
+ attr_accessor :bucket
7
+
8
+ def initialize(bucket:)
9
+ @bucket = bucket
10
+ end
11
+
12
+ def to_flux
13
+ <<~FLUX.chomp
14
+ from(bucket: "#{@bucket}")
15
+ FLUX
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # |> group(columns: ["host"], mode: "by")
4
+
5
+ module Influx
6
+ module Flux
7
+ class Group
8
+ def initialize(columns: [], mode:)
9
+ raise Influx::Error.new('Columns value has to be Array of Strings!') unless columns.is_a?(Array) && columns.all? { |c| c.is_a?(String) }
10
+
11
+ @columns = columns
12
+ @mode = mode
13
+ end
14
+
15
+ def to_flux
16
+ <<~FLUX.chomp
17
+ |> group(columns: #{@columns.to_json}, mode: "#{@mode}")
18
+ FLUX
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ # |> histogram(
4
+ # column: "_value",
5
+ # upperBoundColumn: "le",
6
+ # countColumn: "_value",
7
+ # bins: [100.0, 200.0, 300.0, 400.0],
8
+ # )
9
+
10
+ module Influx
11
+ module Flux
12
+ class Histogram
13
+ def initialize(column:, upper_bound_column:, count_column:, bins: [])
14
+ @column = column
15
+ @upper_bound_column = upper_bound_column
16
+ @count_column = count_column
17
+ @bins = bins
18
+ end
19
+
20
+ def to_flux
21
+ <<~FLUX.chomp
22
+ |> histogram(column: "#{@column}", upperBoundColumn: "#{@upper_bound_column}", countColumn: "#{@count_column}", bins: #{@bins.to_json})
23
+ FLUX
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # |> increase()
4
+
5
+ module Influx
6
+ module Flux
7
+ class Increase
8
+ def self.to_flux
9
+ <<~FLUX.chomp
10
+ |> increase()
11
+ FLUX
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # |> last()
4
+
5
+ module Influx
6
+ module Flux
7
+ class Last
8
+ def self.to_flux
9
+ <<~FLUX.chomp
10
+ |> last()
11
+ FLUX
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ # |> limit(n: 4)
4
+
5
+ module Influx
6
+ module Flux
7
+ class Limit
8
+ def initialize(n:)
9
+ raise Influx::Error.new('Limit value has to be Integer!') unless n.is_a?(Integer)
10
+
11
+ @n = n
12
+ end
13
+
14
+ def to_flux
15
+ <<~FLUX.chomp
16
+ |> limit(n: #{@n})
17
+ FLUX
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # |> median()
4
+
5
+ module Influx
6
+ module Flux
7
+ class Median
8
+ def self.to_flux
9
+ <<~FLUX.chomp
10
+ |> median()
11
+ FLUX
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ # |> movingAverage(n: 5)
4
+
5
+ module Influx
6
+ module Flux
7
+ class MovingAverage
8
+ def initialize(n:)
9
+ raise Influx::Error.new('N value has to be Integer!') unless n.is_a?(Integer)
10
+
11
+ @n = n
12
+ end
13
+
14
+ def to_flux
15
+ <<~FLUX.chomp
16
+ |> movingAverage(n: #{@n})
17
+ FLUX
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # |> quantile(q: 0.99, method: "estimate_tdigest")
4
+
5
+ module Influx
6
+ module Flux
7
+ class Quantile
8
+ def initialize(q:, method:)
9
+ @q = q
10
+ @method = method
11
+ end
12
+
13
+ def to_flux
14
+ <<~FLUX.chomp
15
+ |> quantile(q: #{@q}, method: "#{@method}")
16
+ FLUX
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ # |> range(start: -1h)
4
+
5
+ module Influx
6
+ module Flux
7
+ class Range
8
+ attr_accessor :start, :stop
9
+
10
+ def initialize(start: nil, stop: nil)
11
+ @start = cast_value(start)
12
+ @stop = cast_value(stop)
13
+ end
14
+
15
+ def to_flux
16
+ params = []
17
+
18
+ params << "start: #{@start}" if @start
19
+ params << "stop: #{@stop}" if @stop
20
+
21
+ <<~FLUX.chomp
22
+ |> range(#{params.join(', ')})
23
+ FLUX
24
+ end
25
+
26
+ private
27
+
28
+ def cast_value(time)
29
+ return if time.nil?
30
+
31
+ case time.class.to_s
32
+ when 'Time'
33
+ time.iso8601
34
+ when 'String'
35
+ time
36
+ when 'Integer'
37
+ Time.at(time).iso8601
38
+ else
39
+ raise ArgumentError, 'Invalid time format, expected Time, String or Integer'
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ # |> sort(columns: ["host", "_value"])
4
+
5
+ module Influx
6
+ module Flux
7
+ class Sort
8
+ def initialize(columns:)
9
+ raise Influx::Error.new('Columns value has to be Array of Strings!') unless columns.is_a?(Array) && columns.all? { |c| c.is_a?(String) }
10
+
11
+ @columns = columns
12
+ end
13
+
14
+ def to_flux
15
+ <<~FLUX.chomp
16
+ |> sort(columns: #{@columns.to_json})
17
+ FLUX
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # |> timedMovingAverage(every: 2m, period: 4m)
4
+
5
+ module Influx
6
+ module Flux
7
+ class TimedMovingAverage
8
+ def initialize(every:, period:)
9
+ @every = every
10
+ @period = period
11
+ end
12
+
13
+ def to_flux
14
+ <<~FLUX.chomp
15
+ |> timedMovingAverage(every: #{@every}, period: #{@period})
16
+ FLUX
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Influx
4
+ class Point
5
+ def initialize(measurement, tags: {}, fields: {}, time: Influx.now)
6
+ @measurement = measurement
7
+ @tags = tags
8
+ @fields = fields
9
+ @time = time.to_i
10
+ end
11
+
12
+ def to_flux
13
+ "#{@measurement},#{hash_to_flux(@tags)} #{hash_to_flux(@fields)} #{@time}"
14
+ end
15
+
16
+ private
17
+
18
+ def hash_to_flux(hash)
19
+ hash.map { |key, value| "#{key}=#{value}" }.join(',')
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Influx
4
+ class Query
5
+ def initialize(bucket:)
6
+ @from = Influx::Flux::From.new(bucket: bucket)
7
+ @statements = []
8
+ end
9
+
10
+ def aggregate_window(every:, fn:)
11
+ @statements << Influx::Flux::AggregateWindow.new(every: every, fn: fn)
12
+ self
13
+ end
14
+
15
+ def cumulative_sum
16
+ @statements << Influx::Flux::CumulativeSum
17
+ self
18
+ end
19
+
20
+ def derivative(unit:, non_negative: true)
21
+ @statements << Influx::Flux::Derivative.new(unit: unit, non_negative: non_negative)
22
+ self
23
+ end
24
+
25
+ def fill(use_previous: false, value: nil)
26
+ @statements << Influx::Flux::Fill.new(use_previous: use_previous, value: value)
27
+ self
28
+ end
29
+
30
+ def filter(**params)
31
+ @statements << Influx::Flux::Filter.new(**params)
32
+ self
33
+ end
34
+
35
+ def first
36
+ @statements << Influx::Flux::First
37
+ self
38
+ end
39
+
40
+ def group(columns: [], mode:)
41
+ @statements << Influx::Flux::Group.new(columns: columns, mode: mode)
42
+ self
43
+ end
44
+
45
+ def histogram(column:, upper_bound_column:, count_column:, bins: [])
46
+ @statements << Influx::Flux::Histogram.new(column: column, upper_bound_column: upper_bound_column, count_column: count_column, bins: bins)
47
+ self
48
+ end
49
+
50
+ def increase
51
+ @statements << Influx::Flux::Increase
52
+ self
53
+ end
54
+
55
+ def last
56
+ @statements << Influx::Flux::Last
57
+ self
58
+ end
59
+
60
+ def limit(n)
61
+ @statements << Influx::Flux::Limit.new(n: n)
62
+ self
63
+ end
64
+
65
+ def median
66
+ @statements << Influx::Flux::Median
67
+ self
68
+ end
69
+
70
+ def moving_average(n)
71
+ @statements << Influx::Flux::MovingAverage.new(n: n)
72
+ self
73
+ end
74
+
75
+ def quantile(q:, method:)
76
+ @statements << Influx::Flux::Quantile.new(q: q, method: method)
77
+ self
78
+ end
79
+
80
+ def range(start: nil, stop: nil)
81
+ @statements << Influx::Flux::Range.new(start: start, stop: stop)
82
+ self
83
+ end
84
+
85
+ def sort(columns:)
86
+ @statements << Influx::Flux::Sort.new(columns: columns)
87
+ self
88
+ end
89
+
90
+ def timed_moving_average(every:, period:)
91
+ @statements << Influx::Flux::TimedMovingAverage.new(every: every, period: period)
92
+ self
93
+ end
94
+
95
+ def to_flux
96
+ "#{@from.to_flux} #{@statements.map(&:to_flux).join(' ')}"
97
+ end
98
+ end
99
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Influx
4
- VERSION = "0.1.0.alpha"
4
+ VERSION = '0.1.0'
5
5
  end
data/lib/influx.rb CHANGED
@@ -1,8 +1,40 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "influx/version"
3
+ require 'json'
4
+
5
+ require_relative 'influx/point'
6
+ require_relative 'influx/query'
7
+ require_relative 'influx/version'
8
+
9
+ require_relative 'influx/flux/aggregate_window'
10
+ require_relative 'influx/flux/cumulative_sum'
11
+ require_relative 'influx/flux/derivative'
12
+ require_relative 'influx/flux/fill'
13
+ require_relative 'influx/flux/filter'
14
+ require_relative 'influx/flux/first'
15
+ require_relative 'influx/flux/from'
16
+ require_relative 'influx/flux/group'
17
+ require_relative 'influx/flux/histogram'
18
+ require_relative 'influx/flux/increase'
19
+ require_relative 'influx/flux/last'
20
+ require_relative 'influx/flux/limit'
21
+ require_relative 'influx/flux/median'
22
+ require_relative 'influx/flux/moving_average'
23
+ require_relative 'influx/flux/quantile'
24
+ require_relative 'influx/flux/range'
25
+ require_relative 'influx/flux/sort'
26
+ require_relative 'influx/flux/timed_moving_average'
4
27
 
5
28
  module Influx
6
29
  class Error < StandardError; end
7
- # Your code goes here...
30
+
31
+ class << self
32
+ def from(bucket:)
33
+ Influx::Query.new(bucket: bucket)
34
+ end
35
+
36
+ def now(precision = :nanosecond)
37
+ Process.clock_gettime(Process::CLOCK_REALTIME, precision)
38
+ end
39
+ end
8
40
  end
metadata CHANGED
@@ -1,30 +1,52 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: influx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.alpha
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lapo
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-03-23 00:00:00.000000000 Z
11
+ date: 2022-05-17 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: InfluxDB Flux ORM for Ruby
13
+ description: InfluxDB Flux queries builder for Ruby
14
14
  email:
15
15
  - lapoelisacci@gmail.com
16
16
  executables: []
17
17
  extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
+ - ".rspec"
20
21
  - ".rubocop.yml"
21
22
  - CHANGELOG.md
22
23
  - CODE_OF_CONDUCT.md
23
24
  - Gemfile
25
+ - Gemfile.lock
24
26
  - LICENSE.txt
25
27
  - README.md
26
28
  - Rakefile
27
29
  - lib/influx.rb
30
+ - lib/influx/flux/aggregate_window.rb
31
+ - lib/influx/flux/cumulative_sum.rb
32
+ - lib/influx/flux/derivative.rb
33
+ - lib/influx/flux/fill.rb
34
+ - lib/influx/flux/filter.rb
35
+ - lib/influx/flux/first.rb
36
+ - lib/influx/flux/from.rb
37
+ - lib/influx/flux/group.rb
38
+ - lib/influx/flux/histogram.rb
39
+ - lib/influx/flux/increase.rb
40
+ - lib/influx/flux/last.rb
41
+ - lib/influx/flux/limit.rb
42
+ - lib/influx/flux/median.rb
43
+ - lib/influx/flux/moving_average.rb
44
+ - lib/influx/flux/quantile.rb
45
+ - lib/influx/flux/range.rb
46
+ - lib/influx/flux/sort.rb
47
+ - lib/influx/flux/timed_moving_average.rb
48
+ - lib/influx/point.rb
49
+ - lib/influx/query.rb
28
50
  - lib/influx/version.rb
29
51
  - sig/influx.rbs
30
52
  homepage: https://github.com/LapoElisacci/influx
@@ -45,12 +67,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
45
67
  version: 2.6.0
46
68
  required_rubygems_version: !ruby/object:Gem::Requirement
47
69
  requirements:
48
- - - ">"
70
+ - - ">="
49
71
  - !ruby/object:Gem::Version
50
- version: 1.3.1
72
+ version: '0'
51
73
  requirements: []
52
- rubygems_version: 3.3.9
74
+ rubygems_version: 3.2.22
53
75
  signing_key:
54
76
  specification_version: 4
55
- summary: InfluxDB Flux ORM for Ruby
77
+ summary: InfluxDB Flux queries builder for Ruby
56
78
  test_files: []