redis-time-series 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 51234a8f3542da255912f95982ebab2bf66dd657da9e38e55afdedd97029685d
4
- data.tar.gz: 42a49fdafb136d8ebe4b094f935b0427430672ab810691a35ca2f78328d92135
3
+ metadata.gz: 0d699daec01bb891952501de6a51cc4b966be74a0f8585030bafb4f6a908b36e
4
+ data.tar.gz: dfa027d344c4d5485b0a22a33edd67973c2a60cb60dbbaa1a57101ccce8833fc
5
5
  SHA512:
6
- metadata.gz: acc08d1745cf24bfc87c22d3809570daa0b2feae4e5d5b97d4a43a0626217b44ea3ffdb12c3f6799c068bb6e62f0cc7a1b65274e5d8eac5cb13017bfea73dff4
7
- data.tar.gz: 1ff7aa6fb44dd2729612ac24e2be45496d45bd5a0fc86ed692bd18c38bcb160971c0efed05e598ffabb6471cf4d6903d303a1d0b74e55672c479829b98b26012
6
+ metadata.gz: acadcad9c6919e810f0e100bfe20b60055507e2efa98d0853fca6c15a252f99b65c722c71acc99d37d8d9f72964d91f862c9604fb96458ca3faaddce9f841752
7
+ data.tar.gz: 489415e8247d8cffefcf13e4e70c82cde752170c4416bc0973495c5d38b1d27d2b554cdd62db8729c9c71b125cb4848aa5a1efd81b998aa5f6e5683c13be8ccc
@@ -2,6 +2,9 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.3.0
6
+ * Added `TS.QUERYINDEX` command
7
+
5
8
  ## 0.2.0
6
9
  * Converted `#info` to a struct instead of a hash.
7
10
  * Added methods on time series for getting info attributes.
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- redis-time-series (0.1.1)
4
+ redis-time-series (0.3.0)
5
5
  redis (~> 4.0)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
- ![](https://github.com/dzunk/redis-time-series/workflows/RSpec/badge.svg)
1
+ [![RSpec](https://github.com/dzunk/redis-time-series/workflows/RSpec/badge.svg)](https://github.com/dzunk/redis-time-series/actions?query=workflow%3ARSpec+branch%3Amaster)
2
+ [![Gem Version](https://badge.fury.io/rb/redis-time-series.svg)](https://badge.fury.io/rb/redis-time-series)
2
3
 
3
4
  # RedisTimeSeries
4
5
 
@@ -159,36 +160,50 @@ ts.length
159
160
  ts.size
160
161
  => 3
161
162
  ```
163
+ Find series matching specific label(s)
164
+ ```ruby
165
+ Redis::TimeSeries.queryindex('foo=bar')
166
+ => [#<Redis::TimeSeries:0x00007fc115ba1610
167
+ @key="ts3",
168
+ @redis=#<Redis client v4.2.1 for redis://127.0.0.1:6379/0>,
169
+ @retention=nil,
170
+ @uncompressed=false>]
171
+ # Note that you need at least one "label equals value" filter
172
+ Redis::TimeSeries.queryindex('foo!=bar')
173
+ => RuntimeError: Filtering requires at least one equality comparison
174
+ ```
175
+
162
176
 
163
177
  ### TODO
164
178
  * `TS.REVRANGE`
165
179
  * `TS.MRANGE`/`TS.MREVRANGE`
166
- * `TS.QUERYINDEX`
167
180
  * Compaction rules
168
181
  * Filters
169
182
  * Probably a bunch more stuff
170
183
 
171
184
  ## Development
172
185
 
173
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
174
-
175
- In order to run the specs or use the console, you'll need a Redis server running on the default port 6379 with the RedisTimeSeries module enabled. The easiest way to do so is by running the Docker image:
176
- ```
177
- docker run -p 6379:6379 -it --rm redislabs/redistimeseries
178
- ```
186
+ After checking out the repo, run `bin/setup`. You need the `docker` daemon installed and running. This script will:
187
+ * Install gem dependencies
188
+ * Pull the latest `redislabs/redistimeseries` image
189
+ * Start a Redis server on port 6379
190
+ * Seed three time series with some sample data
191
+ * Attach to the running server and print logs to `STDOUT`
179
192
 
180
- The `bin/console` script will set up three time series, `@ts1`, `@ts2`, and `@ts3`, with three values in each. **It will also flush the local Redis server each time you run it**, so don't try it if you have data you don't want to lose!
193
+ With the above script running, or after starting a server manually, you can run `bin/console` to interact with it. The three series are named `ts1`, `ts2`, and `ts3`, and are available as instance variables in the console.
181
194
 
182
195
  If you want to see the commands being executed, run the console with `DEBUG=true bin/console` and it will output the raw command strings as they're executed.
183
196
  ```ruby
184
197
  [1] pry(main)> @ts1.increment
185
- DEBUG: TS.INCRBY foo 1
198
+ DEBUG: TS.INCRBY ts1 1
186
199
  => 1593159795467
187
200
  [2] pry(main)> @ts1.get
188
- DEBUG: TS.GET foo
201
+ DEBUG: TS.GET ts1
189
202
  => #<Redis::TimeSeries::Sample:0x00007f8e1a190cf8 @time=2020-06-26 01:23:15 -0700, @value=0.4e1>
190
203
  ```
191
204
 
205
+ Use `rake spec` to run the test suite.
206
+
192
207
  ## Contributing
193
208
 
194
209
  Bug reports and pull requests are welcome on GitHub at https://github.com/dzunk/redis-time-series.
@@ -6,15 +6,9 @@ require 'pry'
6
6
  require 'redis'
7
7
  require 'redis-time-series'
8
8
 
9
- Redis.current.flushall
10
-
11
- @ts1 = Redis::TimeSeries.create('foo')
12
- @ts2 = Redis::TimeSeries.create('bar')
13
- @ts3 = Redis::TimeSeries.create('baz')
14
-
9
+ @ts1 = Redis::TimeSeries.new('ts1')
10
+ @ts2 = Redis::TimeSeries.new('ts2')
11
+ @ts3 = Redis::TimeSeries.new('ts3')
15
12
  @series = [@ts1, @ts2, @ts3]
16
- @series.each do |ts|
17
- 3.times { ts.increment; sleep 0.01 }
18
- end
19
13
 
20
14
  Pry.start
data/bin/setup CHANGED
@@ -1,8 +1,30 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
1
+ #!/usr/bin/env ruby
5
2
 
6
- bundle install
3
+ system 'bundle install'
4
+ system 'docker pull redislabs/redistimeseries:latest'
5
+ container_id = `docker run -p 6379:6379 -dit --rm redislabs/redistimeseries`
7
6
 
8
- # Do any other automated setup that you need to do here
7
+ require 'bundler/setup'
8
+ require 'active_support/core_ext/numeric/time'
9
+ require 'redis'
10
+
11
+ Redis.current.flushall
12
+ ts1 = Redis::TimeSeries.create('ts1')
13
+ ts2 = Redis::TimeSeries.create('ts2')
14
+ ts3 = Redis::TimeSeries.create('ts3')
15
+
16
+ ts1.add 12, 6.minutes.ago
17
+ ts1.add 34, 4.minutes.ago
18
+ ts1.add 56, 2.minutes.ago
19
+
20
+ 10.times { ts2.increment; sleep 0.01 }
21
+
22
+ ts3.labels = { foo: 'bar' }
23
+ ts3.add 1
24
+ sleep 0.01
25
+ ts3.incrby 2
26
+ sleep 0.01
27
+ ts3.decrement
28
+
29
+ at_exit { system "docker stop #{container_id}" }
30
+ system "docker logs -f #{container_id}"
@@ -1,10 +1,11 @@
1
1
  require 'bigdecimal'
2
2
  require 'forwardable'
3
3
  require 'time/msec'
4
+ require 'redis/time_series/filter'
4
5
  require 'redis/time_series/info'
5
- require 'redis/time_series'
6
6
  require 'redis/time_series/sample'
7
+ require 'redis/time_series'
7
8
 
8
9
  class RedisTimeSeries
9
- VERSION = '0.2.0'
10
+ VERSION = '0.3.0'
10
11
  end
@@ -33,6 +33,12 @@ class Redis
33
33
  end
34
34
  end
35
35
 
36
+ def queryindex(filter_value)
37
+ filters = Filter.new(filter_value)
38
+ filters.validate!
39
+ redis.call('TS.QUERYINDEX', *filters.to_a).map { |key| new(key) }
40
+ end
41
+
36
42
  def redis
37
43
  @redis ||= Redis.current
38
44
  end
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+ class Redis
3
+ class TimeSeries
4
+ class Filter
5
+ Equal = Struct.new(:label, :value) do
6
+ self::REGEX = /^[^!]+=[^(]+/
7
+
8
+ def self.parse(str)
9
+ new(*str.split('='))
10
+ end
11
+
12
+ def to_s
13
+ "#{label}=#{value}"
14
+ end
15
+ end
16
+
17
+ NotEqual = Struct.new(:label, :value) do
18
+ self::REGEX = /^.+!=[^(]+/
19
+
20
+ def self.parse(str)
21
+ new(*str.split('!='))
22
+ end
23
+
24
+ def to_s
25
+ "#{label}!=#{value}"
26
+ end
27
+ end
28
+
29
+ Absent = Struct.new(:label) do
30
+ self::REGEX = /^[^!]+=$/
31
+
32
+ def self.parse(str)
33
+ new(str.delete('='))
34
+ end
35
+
36
+ def to_s
37
+ "#{label}="
38
+ end
39
+ end
40
+
41
+ Present = Struct.new(:label) do
42
+ self::REGEX = /^.+!=$/
43
+
44
+ def self.parse(str)
45
+ new(str.delete('!='))
46
+ end
47
+
48
+ def to_s
49
+ "#{label}!="
50
+ end
51
+ end
52
+
53
+ AnyValue = Struct.new(:label, :values) do
54
+ self::REGEX = /^[^!]+=\(.+\)/
55
+
56
+ def self.parse(str)
57
+ label, values = str.split('=')
58
+ values = values.tr('()', '').split(',')
59
+ new(label, values)
60
+ end
61
+
62
+ def to_s
63
+ "#{label}=(#{values.join(',')})"
64
+ end
65
+ end
66
+
67
+ NoValues = Struct.new(:label, :values) do
68
+ self::REGEX = /^.+!=\(.+\)/
69
+
70
+ def self.parse(str)
71
+ label, values = str.split('!=')
72
+ values = values.tr('()', '').split(',')
73
+ new(label, values)
74
+ end
75
+
76
+ def to_s
77
+ "#{label}!=(#{values.join(',')})"
78
+ end
79
+ end
80
+
81
+ TYPES = [Equal, NotEqual, Absent, Present, AnyValue, NoValues]
82
+ TYPES.each do |type|
83
+ define_method "#{type.to_s.split('::').last.gsub(/(.)([A-Z])/,'\1_\2').downcase}_filters" do
84
+ filters.select { |f| f.is_a? type }
85
+ end
86
+ end
87
+
88
+ attr_reader :filters
89
+
90
+ def initialize(filters = nil)
91
+ filters = parse_string(filters) if filters.is_a?(String)
92
+ @filters = filters.presence || {}
93
+ end
94
+
95
+ def validate!
96
+ valid? || raise('Filtering requires at least one equality comparison')
97
+ end
98
+
99
+ def valid?
100
+ !!filters.find { |f| f.is_a? Equal }
101
+ end
102
+
103
+ def to_a
104
+ filters.map(&:to_s)
105
+ end
106
+
107
+ private
108
+
109
+ def parse_string(filter_string)
110
+ filter_string.split(' ').map do |str|
111
+ match = TYPES.find { |f| f::REGEX.match? str }
112
+ raise "Unable to parse '#{str}'" unless match
113
+ match.parse(str)
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis-time-series
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Duszynski
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-07-06 00:00:00.000000000 Z
11
+ date: 2020-07-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -114,6 +114,7 @@ files:
114
114
  - bin/setup
115
115
  - lib/redis-time-series.rb
116
116
  - lib/redis/time_series.rb
117
+ - lib/redis/time_series/filter.rb
117
118
  - lib/redis/time_series/info.rb
118
119
  - lib/redis/time_series/sample.rb
119
120
  - lib/time/msec.rb