portolan 0.1.0.pre.1 → 0.1.0.pre.2
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 +4 -4
- data/README.md +7 -3
- data/lib/portolan/measure.rb +9 -0
- data/lib/portolan/query/aggregate.rb +26 -10
- data/lib/portolan/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 557009d4c18190afccf70236dd6697ce44463bf51a278e6730a493f6f4235d01
|
|
4
|
+
data.tar.gz: 3caa4daa83800e0c510f60c377bf999f36510fba94dfc928532489a97a805492
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f1edc5628a9cfcf11ff46e2e86bb7f7db491f26cb9785193ccd3025f37463421f73c434966127fa359bc8d077d2d1ec2a9e451b491acb7fa237c84583d00eb32
|
|
7
|
+
data.tar.gz: 0cc74bd0d2f599f602f1613ca8b57b5f303ca9f5af3099d46a460cf8d591e1f6b18ebe68c5feb568be0d7a1d9c8da8cd2b61726c98b460d110b4f6ab6c633d4d
|
data/README.md
CHANGED
|
@@ -184,11 +184,15 @@ in Ruby).
|
|
|
184
184
|
- Dimensions cannot join through a `has_many` or a polymorphic association; see
|
|
185
185
|
the grain rule above.
|
|
186
186
|
- The timeout applies to each SQL statement, not to the whole request. Grouping
|
|
187
|
-
by buckets runs one
|
|
187
|
+
by buckets runs one or two statements per bucket combination.
|
|
188
|
+
- Without a date dimension, the database sorts the groups by the measure and
|
|
189
|
+
returns at most the row limit, largest first; a second statement counts
|
|
190
|
+
them for the truncation note. A series loads every group, up to the group
|
|
191
|
+
limit, so it can keep whole periods.
|
|
188
192
|
- Your `relation` block runs before Portolan's guard is in place, so it should
|
|
189
193
|
build a relation, not run queries itself.
|
|
190
|
-
- The timeout (5 seconds), row limit (50), group limit (10,000), and
|
|
191
|
-
bucket combinations (50) are fixed for now.
|
|
194
|
+
- The timeout (5 seconds), row limit (50), group limit for series (10,000), and
|
|
195
|
+
number of bucket combinations (50) are fixed for now.
|
|
192
196
|
|
|
193
197
|
## Why the name?
|
|
194
198
|
|
data/lib/portolan/measure.rb
CHANGED
|
@@ -24,6 +24,15 @@ module Portolan
|
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
def node(scope)
|
|
28
|
+
case aggregate
|
|
29
|
+
when :count then Arel.star.count
|
|
30
|
+
when :count_distinct then scope.arel_table[column].count(true)
|
|
31
|
+
when :sum then scope.arel_table[column].sum
|
|
32
|
+
when :average then scope.arel_table[column].average
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
27
36
|
def describe = { name:, description: }
|
|
28
37
|
def label(value) = value.is_a?(::BigDecimal) ? value.to_f : value
|
|
29
38
|
|
|
@@ -76,26 +76,26 @@ module Portolan
|
|
|
76
76
|
def period = @params['period']
|
|
77
77
|
|
|
78
78
|
def answer(scope)
|
|
79
|
-
rows = measured_rows(scope)
|
|
79
|
+
rows, total_rows = measured_rows(scope)
|
|
80
80
|
raise Refused, TOO_MANY_GROUPS if rows.size > GROUP_LIMIT
|
|
81
81
|
|
|
82
|
-
rows
|
|
83
|
-
Result.new(request:, rows: trimmed(rows), definitions:, total_rows: rows.size)
|
|
82
|
+
Result.new(request:, rows: trimmed(sorted(rows)), definitions:, total_rows:)
|
|
84
83
|
end
|
|
85
84
|
|
|
86
85
|
def measured_rows(scope)
|
|
87
86
|
bucket_dimensions, column_dimensions = group_dimensions.partition(&:buckets?)
|
|
88
87
|
rows = []
|
|
88
|
+
total_rows = 0
|
|
89
89
|
|
|
90
90
|
bucket_combinations(bucket_dimensions).each do |combination|
|
|
91
91
|
narrowed = combination.reduce(scope) { |current, (_dimension, bucket)| bucket.apply(current) }
|
|
92
92
|
bucket_labels = combination.to_h { |dimension, bucket| [dimension.name, bucket.name] }
|
|
93
|
-
grouped_values(narrowed, column_dimensions)
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
values, group_count = grouped_values(narrowed, column_dimensions)
|
|
94
|
+
values.each { |keys, value| rows << row(bucket_labels, column_dimensions.zip(keys), value) }
|
|
95
|
+
total_rows += group_count
|
|
96
96
|
break if rows.size > GROUP_LIMIT
|
|
97
97
|
end
|
|
98
|
-
rows
|
|
98
|
+
[rows, total_rows]
|
|
99
99
|
end
|
|
100
100
|
|
|
101
101
|
def bucket_combinations(dimensions)
|
|
@@ -112,15 +112,31 @@ module Portolan
|
|
|
112
112
|
end
|
|
113
113
|
|
|
114
114
|
def grouped_values(scope, dimensions)
|
|
115
|
-
return [[[], measure.call(scope)]] if dimensions.empty?
|
|
115
|
+
return [[[[], measure.call(scope)]], 1] if dimensions.empty?
|
|
116
116
|
|
|
117
|
-
grouped =
|
|
117
|
+
grouped = grouped_scope(scope, dimensions)
|
|
118
|
+
return largest_first(grouped, dimensions) unless time_dimension
|
|
119
|
+
|
|
120
|
+
values = keyed(measure.call(grouped.limit(GROUP_LIMIT + 1)), dimensions)
|
|
121
|
+
[values, values.size]
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def grouped_scope(scope, dimensions)
|
|
125
|
+
dimensions.reduce(scope) do |current, dimension|
|
|
118
126
|
current = dimension.join(current)
|
|
119
127
|
current.group(group_expression(current, dimension))
|
|
120
128
|
end
|
|
121
|
-
measure.call(grouped.limit(GROUP_LIMIT + 1)).map { |keys, value| [dimensions.one? ? [keys] : keys, value] }
|
|
122
129
|
end
|
|
123
130
|
|
|
131
|
+
def largest_first(grouped, dimensions)
|
|
132
|
+
largest = grouped.order(measure.node(grouped).desc.nulls_last).limit(limit)
|
|
133
|
+
[keyed(measure.call(largest), dimensions), group_count(grouped)]
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def group_count(grouped) = grouped.klass.unscoped.from(grouped.select(Arel.sql('1')), :groups).count
|
|
137
|
+
|
|
138
|
+
def keyed(values, dimensions) = values.map { |keys, value| [dimensions.one? ? [keys] : keys, value] }
|
|
139
|
+
|
|
124
140
|
def group_expression(scope, dimension) = dimension.type.group(dimension.column(scope), period)
|
|
125
141
|
|
|
126
142
|
def row(bucket_labels, keyed, value)
|
data/lib/portolan/version.rb
CHANGED