keen-csv 1.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.
- checksums.yaml +7 -0
- data/lib/keen/query_wrapper.rb +31 -0
- data/lib/keen-csv.rb +135 -0
- metadata +59 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b9fe8e0dce221ce5b5e2f0b915e85bd2e8084b36
|
4
|
+
data.tar.gz: 1ab02862ac7b47d6fffb82c8b22633e09dc50fe5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e2df446da5ab8e23eb305d2555487a37cd131dbef5650cff34d1ad1234fa91c501ef3505ea4502f220ca5ece89dde98ccdf561f925b21b9a55c7216bac441c45
|
7
|
+
data.tar.gz: 9b009e1685d3d5f4c99daedef05991d406cbd1e32aaf4ad1c7cb8e22558bde26354c31a645481c6344b032aa963f07c53ca87f67bf944505bd5f4905759bd845
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require('keen')
|
2
|
+
|
3
|
+
# Monkeypatch the Keen gem to wrap :query and steal the :csv option
|
4
|
+
module Keen
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def query_wrapper(*args)
|
8
|
+
# let's optimize for lowest-possible overhead in case 'csv' output isn't requested
|
9
|
+
if args[-1][:csv]
|
10
|
+
# CSV ouput was requested.
|
11
|
+
# First, remove the :csv option to keep from messing up the Keen gem
|
12
|
+
options = args[-1].delete(:csv)
|
13
|
+
# and perform the query
|
14
|
+
response = naked_query(*args)
|
15
|
+
|
16
|
+
# and now for the main event . . . generating the CSV output
|
17
|
+
keenCSV = Keen::CSV.new(response, options)
|
18
|
+
return keenCSV.csvString
|
19
|
+
else
|
20
|
+
# not CSV; just pass through to the naked query
|
21
|
+
return naked_query(*args)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Wrap :query with :query_wrapper via aliases
|
26
|
+
alias :naked_query :query
|
27
|
+
alias :query :query_wrapper
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
data/lib/keen-csv.rb
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
require_relative('keen/query_wrapper')
|
2
|
+
|
3
|
+
class Keen::CSV
|
4
|
+
@@defaultOptions = {
|
5
|
+
delimiter: ',',
|
6
|
+
delimiterSub: '.',
|
7
|
+
nestedDelimiter: '.',
|
8
|
+
filteredColumns: nil,
|
9
|
+
}
|
10
|
+
|
11
|
+
def initialize(response, options = {})
|
12
|
+
@rawResponse = response
|
13
|
+
@options = options.is_a?(Hash) ? @@defaultOptions.merge(options) : @@defaultOptions
|
14
|
+
end
|
15
|
+
|
16
|
+
# ---------------------------------------------------------------------------
|
17
|
+
# generateResultColumns
|
18
|
+
# Transforms the Keen result columnar Map, keyed by header
|
19
|
+
# ---------------------------------------------------------------------------
|
20
|
+
def generateResultColumns
|
21
|
+
resultColumns = {
|
22
|
+
columns: {},
|
23
|
+
maxRowIndex: 0 # We're going to count the rows, for future use
|
24
|
+
}
|
25
|
+
|
26
|
+
# Using a lambda to add the right columns into resultColumns, and keep track
|
27
|
+
# of maxRowIndex
|
28
|
+
setColumnValue = lambda do |column, rowIndex, value|
|
29
|
+
unless self.columnIsFiltered?(column)
|
30
|
+
resultColumns[:columns][column] ||= []
|
31
|
+
resultColumns[:columns][column][rowIndex] = value
|
32
|
+
end
|
33
|
+
|
34
|
+
# Gotta keep track of how many rows we're working with.
|
35
|
+
resultColumns[:maxRowIndex] = rowIndex if rowIndex > resultColumns[:maxRowIndex]
|
36
|
+
end
|
37
|
+
|
38
|
+
# Exit early if this is a simple math operation
|
39
|
+
if @rawResponse.is_a? Numeric
|
40
|
+
resultColumns[:columns]['result'] = [@rawResponse]
|
41
|
+
resultColumns[:maxRowIndex] = 1
|
42
|
+
return resultColumns
|
43
|
+
end
|
44
|
+
|
45
|
+
rowIndex = 0
|
46
|
+
@rawResponse.each do |object|
|
47
|
+
if object["value"].is_a? Array
|
48
|
+
# This result is grouped! We're gonna have to create alot more columns and rows
|
49
|
+
object["value"].each do |group|
|
50
|
+
|
51
|
+
# iterate over each value grouping, and store the values
|
52
|
+
self.flatten(group).each do |column, value|
|
53
|
+
setColumnValue.call(column, rowIndex, value)
|
54
|
+
end
|
55
|
+
if object["timeframe"]
|
56
|
+
self.flatten({"timeframe" => object["timeframe"]}).each do |column, value|
|
57
|
+
setColumnValue.call(column, rowIndex, value)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
rowIndex += 1
|
61
|
+
|
62
|
+
end
|
63
|
+
else
|
64
|
+
# Not grouped: This either an Extraction or a math operation on an interval.
|
65
|
+
self.flatten(object).each do |column, value|
|
66
|
+
setColumnValue.call(column, rowIndex, value)
|
67
|
+
end
|
68
|
+
rowIndex += 1
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
resultColumns
|
74
|
+
end
|
75
|
+
|
76
|
+
# ---------------------------------------------------------------------------
|
77
|
+
# columnIsFiltered?
|
78
|
+
# Takes a column header, and determines whether that column should be
|
79
|
+
# filtered out
|
80
|
+
# ---------------------------------------------------------------------------
|
81
|
+
def columnIsFiltered?(header)
|
82
|
+
return @options[:filteredColumns] &&
|
83
|
+
@options[:filteredColumns].is_a?(Array) &&
|
84
|
+
@options[:filteredColumns].include?(header)
|
85
|
+
end
|
86
|
+
|
87
|
+
# ---------------------------------------------------------------------------
|
88
|
+
# csvString
|
89
|
+
# Generates and returns a CSV for this Keen response
|
90
|
+
# ---------------------------------------------------------------------------
|
91
|
+
def csvString
|
92
|
+
resultColumns = self.generateResultColumns
|
93
|
+
headers = resultColumns[:columns].keys
|
94
|
+
# Start off instantiating the csv string with the header values
|
95
|
+
csvString = headers.map{|s| self.filterValue(s)}.join(@options[:delimiter])
|
96
|
+
|
97
|
+
# Now iterate over each row, sticking its value under each header
|
98
|
+
(0..resultColumns[:maxRowIndex]).each do |rowIndex|
|
99
|
+
csvString << "\r\n"
|
100
|
+
csvString << headers.map{ |header|
|
101
|
+
self.filterValue(resultColumns[:columns][header][rowIndex])
|
102
|
+
}.join(@options[:delimiter])
|
103
|
+
end
|
104
|
+
return csvString
|
105
|
+
end
|
106
|
+
|
107
|
+
# ---------------------------------------------------------------------------
|
108
|
+
# filterValue
|
109
|
+
# Takes a scalar value, and returns a CSV-compatible one
|
110
|
+
# ---------------------------------------------------------------------------
|
111
|
+
def filterValue(value)
|
112
|
+
if value == nil
|
113
|
+
return ''
|
114
|
+
else
|
115
|
+
return value.to_s.gsub(/#{Regexp.escape(@options[:delimiter])}/, @options[:delimiterSub])
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# ---------------------------------------------------------------------------
|
120
|
+
# flatten
|
121
|
+
# Converts any nested dictionaries into a flattened/delimited one.
|
122
|
+
# ---------------------------------------------------------------------------
|
123
|
+
def flatten(object, flattened = {}, prefix = "")
|
124
|
+
object.each do |key, value|
|
125
|
+
if value.is_a?(Hash) || value.is_a?(Array)
|
126
|
+
# recurse!
|
127
|
+
flatten(value, flattened, prefix + key + @options[:nestedDelimiter])
|
128
|
+
else
|
129
|
+
flattened[prefix + key] = value
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
return flattened
|
134
|
+
end
|
135
|
+
end
|
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: keen-csv
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jevon Wild
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-10-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: keen
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: Builds a CSV string from a Keen IO response
|
28
|
+
email: jevon@keenio
|
29
|
+
executables: []
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- lib/keen-csv.rb
|
34
|
+
- lib/keen/query_wrapper.rb
|
35
|
+
homepage: https://keen.io/
|
36
|
+
licenses:
|
37
|
+
- MIT
|
38
|
+
metadata: {}
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options: []
|
41
|
+
require_paths:
|
42
|
+
- lib
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
requirements: []
|
54
|
+
rubyforge_project:
|
55
|
+
rubygems_version: 2.4.8
|
56
|
+
signing_key:
|
57
|
+
specification_version: 4
|
58
|
+
summary: CSV output for Keen IO
|
59
|
+
test_files: []
|