sleek 0.0.1
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.
- data/.gitignore +17 -0
- data/.rspec +1 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +256 -0
- data/Rakefile +6 -0
- data/lib/sleek/base.rb +52 -0
- data/lib/sleek/core_ext/range.rb +44 -0
- data/lib/sleek/core_ext/time.rb +2 -0
- data/lib/sleek/event.rb +37 -0
- data/lib/sleek/filter.rb +24 -0
- data/lib/sleek/interval.rb +41 -0
- data/lib/sleek/queries/average.rb +21 -0
- data/lib/sleek/queries/count.rb +17 -0
- data/lib/sleek/queries/count_unique.rb +21 -0
- data/lib/sleek/queries/maximum.rb +21 -0
- data/lib/sleek/queries/minimum.rb +21 -0
- data/lib/sleek/queries/query.rb +105 -0
- data/lib/sleek/queries/sum.rb +21 -0
- data/lib/sleek/queries/targetable.rb +13 -0
- data/lib/sleek/queries.rb +8 -0
- data/lib/sleek/query_collection.rb +25 -0
- data/lib/sleek/timeframe.rb +85 -0
- data/lib/sleek/version.rb +3 -0
- data/lib/sleek.rb +23 -0
- data/sleek.gemspec +28 -0
- data/sleek.png +0 -0
- data/spec/lib/sleek/base_spec.rb +48 -0
- data/spec/lib/sleek/event_spec.rb +21 -0
- data/spec/lib/sleek/filter_spec.rb +26 -0
- data/spec/lib/sleek/interval_spec.rb +24 -0
- data/spec/lib/sleek/queries/average_spec.rb +13 -0
- data/spec/lib/sleek/queries/count_spec.rb +13 -0
- data/spec/lib/sleek/queries/count_unique_spec.rb +15 -0
- data/spec/lib/sleek/queries/maximum_spec.rb +13 -0
- data/spec/lib/sleek/queries/minimum_spec.rb +13 -0
- data/spec/lib/sleek/queries/query_spec.rb +226 -0
- data/spec/lib/sleek/queries/sum_spec.rb +13 -0
- data/spec/lib/sleek/queries/targetable_spec.rb +29 -0
- data/spec/lib/sleek/query_collection_spec.rb +27 -0
- data/spec/lib/sleek/timeframe_spec.rb +86 -0
- data/spec/lib/sleek_spec.rb +10 -0
- data/spec/spec_helper.rb +17 -0
- metadata +203 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Gosha Arinich
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,256 @@
|
|
1
|
+

|
2
|
+
|
3
|
+
[](https://travis-ci.org/goshakkk/sleek)
|
4
|
+
|
5
|
+
Sleek is a gem for doing analytics. It allows you to easily collect and
|
6
|
+
analyze events that happen in your app.
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
The easiest way to install Sleek is to add it to your Gemfile:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
gem "sleek"
|
14
|
+
```
|
15
|
+
|
16
|
+
Then, install it:
|
17
|
+
|
18
|
+
```
|
19
|
+
$ bundle install
|
20
|
+
```
|
21
|
+
|
22
|
+
Sleek requires MongoDB to work and assumes that you have Mongoid
|
23
|
+
configured already.
|
24
|
+
|
25
|
+
## Getting started
|
26
|
+
|
27
|
+
### Namespacing
|
28
|
+
|
29
|
+
Namespaces are a great way to organize entirely different buckets of
|
30
|
+
data inside a single application. In Sleek, everything is namespaced.
|
31
|
+
|
32
|
+
Creating a namespaced instance of Sleek is easy:
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
sleek = Sleek[:my_namespace]
|
36
|
+
```
|
37
|
+
|
38
|
+
You then would just call everything on this instance.
|
39
|
+
|
40
|
+
### Sending an Event
|
41
|
+
|
42
|
+
The heart of analytics is in recording events. Events are things that
|
43
|
+
happen in your app that you want to track. Events are stored in event
|
44
|
+
buckets.
|
45
|
+
|
46
|
+
In order to send an event, you would simply need to call
|
47
|
+
`sleek.record`, passing the event bucket name and the event
|
48
|
+
payload.
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
sleek.record(:purchases, {
|
52
|
+
customer: { id: 1, name: "First Last", email: "first@last.com" },
|
53
|
+
items: [{ sku: "TSTITM1", name: "Test Item 1", price: 1999 }],
|
54
|
+
total: 1999
|
55
|
+
})
|
56
|
+
```
|
57
|
+
|
58
|
+
### Analyzing Events
|
59
|
+
|
60
|
+
#### Simple count
|
61
|
+
|
62
|
+
There are a few methods of analyzing your data. The simplest one is
|
63
|
+
counting. It, you guessed it, would count how many times the event has
|
64
|
+
occurred.
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
sleek.queries.count(:purchases)
|
68
|
+
# => 42
|
69
|
+
```
|
70
|
+
|
71
|
+
#### Average
|
72
|
+
|
73
|
+
In order to calculate average value, it's needed to additionally specify
|
74
|
+
what property should the average be calculated based on:
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
sleek.queries.average(:purchases, target_property: :total)
|
78
|
+
# => 1999
|
79
|
+
```
|
80
|
+
|
81
|
+
#### Query with timeframe
|
82
|
+
|
83
|
+
You can limit the scope of events that analysis is run on by adding the
|
84
|
+
`:timeframe` option to any query call.
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
sleek.queries.count(:purchases, timeframe: :this_day)
|
88
|
+
# => 10
|
89
|
+
```
|
90
|
+
|
91
|
+
#### Query with interval
|
92
|
+
|
93
|
+
Some kinds of applications may need to analyze trends in the data. Using
|
94
|
+
intervals, you can break a timeframe into minutes, hours, days, weeks,
|
95
|
+
or months. One can do so by passing the `:interval` option to any query
|
96
|
+
call. Using `:interval` also requires that you specify `:timeframe`.
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
sleek.queries.count(:purchases, timeframe: :this_2_days, interval: :daily)
|
100
|
+
# => [
|
101
|
+
# {:timeframe=>#<Sleek::Timeframe 2013-01-01 00:00:00 UTC..2013-01-02 00:00:00 UTC>, :value=>10},
|
102
|
+
# {:timeframe=>#<Sleek::Timeframe 2013-01-02 00:00:00 UTC..2013-01-03 00:00:00 UTC>, :value=>24}
|
103
|
+
# ]
|
104
|
+
```
|
105
|
+
|
106
|
+
## Data analysis in more detail
|
107
|
+
|
108
|
+
### Metrics
|
109
|
+
|
110
|
+
The word "metrics" is used to describe analysis queries which return a
|
111
|
+
single numeric value.
|
112
|
+
|
113
|
+
### Count
|
114
|
+
|
115
|
+
Count just counts the number of events recorded.
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
sleek.queries.count(:bucket)
|
119
|
+
# => 42
|
120
|
+
```
|
121
|
+
|
122
|
+
### Count unique
|
123
|
+
|
124
|
+
It counts how many events have an unique value for a given property.
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
sleek.queries.count_unique(:bucket, params)
|
128
|
+
```
|
129
|
+
|
130
|
+
You must pass the target property name in params like this:
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
sleek.queries.count_unique(:purchases, target_property: "customer.id")
|
134
|
+
# => 30
|
135
|
+
```
|
136
|
+
|
137
|
+
### Minimum
|
138
|
+
|
139
|
+
It finds the minimum numeric value for a given property. All non-numeric
|
140
|
+
values are ignored. If none of property values are numeric, the
|
141
|
+
exception will be raised.
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
sleek.queries.minimum(:bucket, params)
|
145
|
+
```
|
146
|
+
|
147
|
+
You must pass the target property name in params like this:
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
sleek.queries.minimum(:purchases, target_property: "total")
|
151
|
+
# => 10_99
|
152
|
+
```
|
153
|
+
|
154
|
+
### Maximum
|
155
|
+
|
156
|
+
It finds the maximum numeric value for a given property. All non-numeric
|
157
|
+
values are ignored. If none of property values are numeric, the
|
158
|
+
exception will be raised.
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
sleek.queries.maximum(:bucket, params)
|
162
|
+
```
|
163
|
+
|
164
|
+
You must pass the target property name in params like this:
|
165
|
+
|
166
|
+
```ruby
|
167
|
+
sleek.queries.maximum(:purchases, target_property: "total")
|
168
|
+
# => 199_99
|
169
|
+
```
|
170
|
+
|
171
|
+
### Average
|
172
|
+
|
173
|
+
The average query finds the average value for a given property. All
|
174
|
+
non-numeric values are ignored. If none of property values are numeric,
|
175
|
+
the exception will be raised.
|
176
|
+
|
177
|
+
```ruby
|
178
|
+
sleek.queries.average(:bucket, params)
|
179
|
+
```
|
180
|
+
|
181
|
+
You must pass the target property name in params like this:
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
sleek.queries.average(:purchases, target_property: "total")
|
185
|
+
# => 49_35
|
186
|
+
```
|
187
|
+
|
188
|
+
### Sum
|
189
|
+
|
190
|
+
The sum query sums all the numeric values for a given property. All
|
191
|
+
non-numeric values are ignored. If none of property values are numeric,
|
192
|
+
the exception will be raised.
|
193
|
+
|
194
|
+
```ruby
|
195
|
+
sleek.queries.sum(:bucket, params)
|
196
|
+
```
|
197
|
+
|
198
|
+
You must pass the target property name in params like this:
|
199
|
+
|
200
|
+
```ruby
|
201
|
+
sleek.queries.sum(:purchases, target_property: "total")
|
202
|
+
# => 2_072_70
|
203
|
+
```
|
204
|
+
|
205
|
+
## Filters
|
206
|
+
|
207
|
+
To limit the scope of events used in analysis you can use a filter. To
|
208
|
+
do so, you just pass the `:filter` option to the query.
|
209
|
+
|
210
|
+
A single filter is a 3-element array, consisting of:
|
211
|
+
|
212
|
+
* `property_name` - the property name to filter.
|
213
|
+
* `operator` - the name of the operator to apply.
|
214
|
+
* `value` - the value used in operator to compare to property value.
|
215
|
+
|
216
|
+
Operators: eq, ne, lt, lte, gt, gte, in.
|
217
|
+
|
218
|
+
You can pass either a single filter or an array of filters.
|
219
|
+
|
220
|
+
```ruby
|
221
|
+
sleek.queries.count(:purchases, filters: [:total, :gt, 1599])
|
222
|
+
# => 20
|
223
|
+
```
|
224
|
+
|
225
|
+
## Series
|
226
|
+
|
227
|
+
Series allow you to analyze trends in metrics over time. They break a
|
228
|
+
timeframe into intervals and compute the metric for those intervals.
|
229
|
+
|
230
|
+
Calculating series is simply done by adding the `:timeframe` and
|
231
|
+
`:interval` options to the metric query.
|
232
|
+
|
233
|
+
Valid intervals are:
|
234
|
+
|
235
|
+
* `:hourly`
|
236
|
+
* `:daily`
|
237
|
+
* `:weekly`
|
238
|
+
* `:monthly`
|
239
|
+
|
240
|
+
## Other
|
241
|
+
|
242
|
+
### Deleting buckets
|
243
|
+
|
244
|
+
```ruby
|
245
|
+
sleek.delete_bucket(:purchases)
|
246
|
+
```
|
247
|
+
|
248
|
+
### Deleting property from all events in the bucket
|
249
|
+
|
250
|
+
```ruby
|
251
|
+
sleek.delete_property(:purchases, :some_property)
|
252
|
+
```
|
253
|
+
|
254
|
+
## License
|
255
|
+
|
256
|
+
[MIT](LICENSE).
|
data/Rakefile
ADDED
data/lib/sleek/base.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module Sleek
|
2
|
+
class Base
|
3
|
+
attr_reader :namespace
|
4
|
+
|
5
|
+
# Internal: Initialize Sleek with namespace.
|
6
|
+
#
|
7
|
+
# namespace - the Symbol namespace name.
|
8
|
+
def initialize(namespace)
|
9
|
+
@namespace = namespace
|
10
|
+
end
|
11
|
+
|
12
|
+
# Public: Record an event.
|
13
|
+
#
|
14
|
+
# bucket - the String name of bucket.
|
15
|
+
# payload - the Hash of event data.
|
16
|
+
def record(bucket, payload)
|
17
|
+
Event.create_with_namespace(namespace, bucket, payload)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Public: Get `QueriesCollection` for the namespace.
|
21
|
+
def queries
|
22
|
+
@queries ||= QueryCollection.new(namespace)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Public: Delete event bucket.
|
26
|
+
#
|
27
|
+
# bucket - the String bucket name.
|
28
|
+
def delete_bucket(bucket)
|
29
|
+
events(bucket).delete_all
|
30
|
+
end
|
31
|
+
|
32
|
+
# Public: Delete specific property from all events in the bucket.
|
33
|
+
#
|
34
|
+
# bucket - the String bucket name.
|
35
|
+
# property - the String property name.
|
36
|
+
def delete_property(bucket, property)
|
37
|
+
events(bucket).unset("d.#{property}")
|
38
|
+
end
|
39
|
+
|
40
|
+
# Internal: Get events associated with current namespace and,
|
41
|
+
# optionally, specified bucket.
|
42
|
+
def events(bucket = nil)
|
43
|
+
evts = Event.where(namespace: namespace)
|
44
|
+
evts = evts.where(bucket: bucket) if bucket.present?
|
45
|
+
evts
|
46
|
+
end
|
47
|
+
|
48
|
+
def inspect
|
49
|
+
"#<Sleek::Base ns=#{namespace}>"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
class Range
|
2
|
+
# Public: Convert both ends of range to integers.
|
3
|
+
def to_i_range
|
4
|
+
self.begin.to_i..self.end.to_i
|
5
|
+
end
|
6
|
+
|
7
|
+
# Public: Convert both ends of range to times.
|
8
|
+
def to_time_range
|
9
|
+
Time.at(self.begin)..Time.at(self.end)
|
10
|
+
end
|
11
|
+
|
12
|
+
def int_range?
|
13
|
+
self.begin.is_a?(Integer)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Public: Check if range elements are times.
|
17
|
+
def time_range?
|
18
|
+
self.begin.is_a?(Time)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Public: Calculate the differentce between ends of the range.
|
22
|
+
def difference
|
23
|
+
self.end - self.begin
|
24
|
+
end
|
25
|
+
|
26
|
+
# Public: Make up a range for previous n periods.
|
27
|
+
# Start of new range would be start of current - difference between
|
28
|
+
# start and end * number of periods, end of new range would be start of
|
29
|
+
# current.
|
30
|
+
#
|
31
|
+
# Example
|
32
|
+
#
|
33
|
+
# (1200..1300).previous
|
34
|
+
# # => 1100..1200
|
35
|
+
def previous(n = 1)
|
36
|
+
new_begin = self.begin - difference * n
|
37
|
+
new_end = self.end - difference * n
|
38
|
+
new_begin..new_end
|
39
|
+
end
|
40
|
+
|
41
|
+
def -(what)
|
42
|
+
(self.begin - what)..(self.end - what)
|
43
|
+
end
|
44
|
+
end
|
data/lib/sleek/event.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module Sleek
|
2
|
+
class EventMetadata
|
3
|
+
include Mongoid::Document
|
4
|
+
include Mongoid::Timestamps::Created::Short
|
5
|
+
|
6
|
+
field :t, type: Time, as: :timestamp
|
7
|
+
embedded_in :event
|
8
|
+
|
9
|
+
before_create :set_timestamp
|
10
|
+
|
11
|
+
def set_timestamp
|
12
|
+
self.timestamp = created_at unless timestamp
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Event
|
17
|
+
include Mongoid::Document
|
18
|
+
|
19
|
+
field :ns, type: Symbol, as: :namespace
|
20
|
+
field :b, type: String, as: :bucket
|
21
|
+
field :d, type: Hash, as: :data
|
22
|
+
embeds_one :sleek, store_as: "s", class_name: 'Sleek::EventMetadata', cascade_callbacks: true
|
23
|
+
accepts_nested_attributes_for :sleek
|
24
|
+
|
25
|
+
validates :namespace, presence: true
|
26
|
+
validates :bucket, presence: true
|
27
|
+
|
28
|
+
after_initialize { build_sleek }
|
29
|
+
|
30
|
+
def self.create_with_namespace(namespace, bucket, payload)
|
31
|
+
sleek = payload.delete(:sleek)
|
32
|
+
event = create(namespace: namespace, bucket: bucket, data: payload)
|
33
|
+
event.sleek.update_attributes sleek
|
34
|
+
event
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/sleek/filter.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
module Sleek
|
2
|
+
class Filter
|
3
|
+
attr_reader :property_name, :operator, :value
|
4
|
+
|
5
|
+
def initialize(property_name, operator, value)
|
6
|
+
@property_name = "d.#{property_name}"
|
7
|
+
@operator = operator.to_sym
|
8
|
+
@value = value
|
9
|
+
|
10
|
+
unless [:eq, :ne, :lt, :lte, :gt, :gte, :in].include? @operator
|
11
|
+
raise ArgumentError, "unsupported operator - #{operator}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def apply(criteria)
|
16
|
+
criteria.send(operator, property_name => value)
|
17
|
+
end
|
18
|
+
|
19
|
+
def ==(other)
|
20
|
+
other.is_a?(Filter) && property_name == other.property_name &&
|
21
|
+
operator == other.operator && value == other.value
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Sleek
|
2
|
+
class Interval
|
3
|
+
def self.interval_value(desc)
|
4
|
+
case desc
|
5
|
+
when :hourly
|
6
|
+
1.hour
|
7
|
+
when :daily
|
8
|
+
1.day
|
9
|
+
when :weekly
|
10
|
+
1.week
|
11
|
+
when :monthly
|
12
|
+
1.month
|
13
|
+
else
|
14
|
+
raise ArgumentError, "invalid interval description"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_reader :interval, :timeframe
|
19
|
+
|
20
|
+
# Internal: Initialize an interval.
|
21
|
+
#
|
22
|
+
# interval_desc - the Symbol description of the interval.
|
23
|
+
# Possible values: :hourly, :daily, :weekly,
|
24
|
+
# :monthly.
|
25
|
+
# timeframe - the Timeframe object.
|
26
|
+
def initialize(interval_desc, timeframe)
|
27
|
+
@interval = self.class.interval_value(interval_desc)
|
28
|
+
@timeframe = timeframe
|
29
|
+
end
|
30
|
+
|
31
|
+
# Internal: Split the timeframe into intervals.
|
32
|
+
#
|
33
|
+
# Returns an Array of Timeframe objects.
|
34
|
+
def timeframes
|
35
|
+
@timeframes ||= timeframe.to_time_range.to_i_range.each_slice(interval)
|
36
|
+
.to_a[0..-2]
|
37
|
+
.map { |tf| (tf.first..(tf.first + interval)).to_time_range }
|
38
|
+
.map { |tf| Timeframe.new(tf) }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Sleek
|
2
|
+
module Queries
|
3
|
+
# Internal: Average query.
|
4
|
+
#
|
5
|
+
# Finds the average value for a given property.
|
6
|
+
#
|
7
|
+
# target_property - the String name of target property on event.
|
8
|
+
#
|
9
|
+
# Examples
|
10
|
+
#
|
11
|
+
# sleek.queries.average(:purchases, target_property: "total")
|
12
|
+
# # => 49_35
|
13
|
+
class Average < Query
|
14
|
+
include Targetable
|
15
|
+
|
16
|
+
def perform(events)
|
17
|
+
events.avg target_property
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Sleek
|
2
|
+
module Queries
|
3
|
+
# Internal: Count unique query.
|
4
|
+
#
|
5
|
+
# Counts how many events have unique value for a given property.
|
6
|
+
#
|
7
|
+
# target_property - the String name of target property on event.
|
8
|
+
#
|
9
|
+
# Examples
|
10
|
+
#
|
11
|
+
# sleek.queries.count_unique(:purchases, target_property: "customer.email")
|
12
|
+
# # => 4
|
13
|
+
class CountUnique < Query
|
14
|
+
include Targetable
|
15
|
+
|
16
|
+
def perform(events)
|
17
|
+
events.distinct(target_property).count
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Sleek
|
2
|
+
module Queries
|
3
|
+
# Internal: Maximum query.
|
4
|
+
#
|
5
|
+
# Finds the maximum value for a given property.
|
6
|
+
#
|
7
|
+
# target_property - the String name of target property on event.
|
8
|
+
#
|
9
|
+
# Examples
|
10
|
+
#
|
11
|
+
# sleek.queries.maximum(:purchases, target_property: "total")
|
12
|
+
# # => 199_99
|
13
|
+
class Maximum < Query
|
14
|
+
include Targetable
|
15
|
+
|
16
|
+
def perform(events)
|
17
|
+
events.max target_property
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Sleek
|
2
|
+
module Queries
|
3
|
+
# Internal: Minimum query.
|
4
|
+
#
|
5
|
+
# Finds the minimum value for a given property.
|
6
|
+
#
|
7
|
+
# target_property - the String name of target property on event.
|
8
|
+
#
|
9
|
+
# Examples
|
10
|
+
#
|
11
|
+
# sleek.queries.minimum(:purchases, target_property: "total")
|
12
|
+
# # => 19_99
|
13
|
+
class Minimum < Query
|
14
|
+
include Targetable
|
15
|
+
|
16
|
+
def perform(events)
|
17
|
+
events.min target_property
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|