burner 1.8.0 → 1.9.0.pre.alpha

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: 9f7acc476043a573e329d1f0dc07e3b6f8a90f456517d4b98c66ac3e370f26fe
4
- data.tar.gz: 8317c42ba254babbb8b72c7468dab2ca132e809a812625241d8f393077a8ba2f
3
+ metadata.gz: eca471b05b356ad1e96f71c0173673109622e14dc7d7d46bdab0beccc1e03396
4
+ data.tar.gz: 55f81d7080c1f0eb4a4cc1d51df7534376306362a1d97a8369f3fd85c0107a3b
5
5
  SHA512:
6
- metadata.gz: 93a1a11b8b7506c2e5508e9e34c34224a1b988cf49364f29a487103e331396a0852636fc83615bf53a963df29f34393e9f69fd4a66c2062ede0ec4620680a6db
7
- data.tar.gz: c82edbbe587a36c30573720908688cebf046ef7a13c864682a16b14fd14de5e6f19bc48d676fe568ccc35cdbdae25e4c64b2f835249d819d1bc2c415c330ad45
6
+ metadata.gz: bbd76fedb82b0499f7f8913e5530a1c35e2d4fc613ef11e95fb8ad6c759a28a7f4737d5ae29a71e0409dbd8f45b03de5b96dc22b84e3b85384cb256d1742eb9c
7
+ data.tar.gz: 311f81afb55fdbf5548c9394ec1ee30e020833f205e4e1c53fef87630c2e77d0b6cbd6639689efaa8956ae7bb188555f35ffb1dca7c08c2cedb6881f959cd508
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ # 1.9.0 (TBD)
2
+
3
+ Added Jobs:
4
+
5
+ * b/collection/pivot
1
6
  # 1.8.0 (March 31st, 2021)
2
7
 
3
8
  Added Jobs:
data/README.md CHANGED
@@ -271,6 +271,8 @@ This library only ships with very basic, rudimentary jobs that are meant to just
271
271
  * **b/collection/nested_aggregate** [register, key_mappings, key, separator]: Traverse a set of objects, resolving key's value for each object, optionally copying down key_mappings to the child records, then merging all the inner records together.
272
272
  * **b/collection/number** [key, register, separator, start_at]: This job can iterate over a set of records and sequence them (set the specified key to a sequential index value.)
273
273
  * **b/collection/objects_to_arrays** [mappings, register]: Convert an array of objects to an array of arrays.
274
+ * **b/collection/pivot** [unique_keys, insensitive, other_keys, pivot_key, pivot_value_key, register, separator]:
275
+ Take an array of objects and pivot a key into multiple keys. It essentially takes all the values for a key and creates N number of keys (one per value.) Under the hood it uses HashMath's [Record](https://github.com/bluemarblepayroll/hash_math#record-the-hash-prototype) and [Table](https://github.com/bluemarblepayroll/hash_math#table-the-double-hash-hash-of-hashes) classes.
274
276
  * **b/collection/shift** [amount, register]: Remove the first N number of elements from an array.
275
277
  * **b/collection/transform** [attributes, exclusive, separator, register]: Iterate over all objects and transform each key per the attribute transformers specifications. If exclusive is set to false then the current object will be overridden/merged. Separator can also be set for key path support. This job uses [Realize](https://github.com/bluemarblepayroll/realize), which provides its own extendable value-transformation pipeline. If an attribute is not set with `explicit: true` then it will automatically start from the key's value from the record. If `explicit: true` is started, then it will start from the record itself.
276
278
  * **b/collection/unpivot** [pivot_set, register]: Take an array of objects and unpivot specific sets of keys into rows. Under the hood it uses [HashMath's Unpivot class](https://github.com/bluemarblepayroll/hash_math#unpivot-hash-key-coalescence-and-row-extrapolation).
data/lib/burner/jobs.rb CHANGED
@@ -30,6 +30,7 @@ module Burner
30
30
  register 'b/collection/nested_aggregate', Library::Collection::NestedAggregate
31
31
  register 'b/collection/number', Library::Collection::Number
32
32
  register 'b/collection/objects_to_arrays', Library::Collection::ObjectsToArrays
33
+ register 'b/collection/pivot', Library::Collection::Pivot
33
34
  register 'b/collection/shift', Library::Collection::Shift
34
35
  register 'b/collection/transform', Library::Collection::Transform
35
36
  register 'b/collection/unpivot', Library::Collection::Unpivot
@@ -21,6 +21,7 @@ require_relative 'library/collection/group'
21
21
  require_relative 'library/collection/nested_aggregate'
22
22
  require_relative 'library/collection/number'
23
23
  require_relative 'library/collection/objects_to_arrays'
24
+ require_relative 'library/collection/pivot'
24
25
  require_relative 'library/collection/shift'
25
26
  require_relative 'library/collection/transform'
26
27
  require_relative 'library/collection/unpivot'
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Burner
11
+ module Library
12
+ module Collection
13
+ # Take an array of objects and pivot a key into multiple keys. It essentially takes all
14
+ # the values for a key and creates N number of keys (one per value.)
15
+ # Under the hood it uses HashMath's Record and Table classes:
16
+ # https://github.com/bluemarblepayroll/hash_math
17
+ #
18
+ # An example of a normalized dataset that could be pivoted:
19
+ #
20
+ # records = [
21
+ # { patient_id: 1, key: :first_name, value: 'bozo' },
22
+ # { patient_id: 1, key: :last_name, value: 'clown' },
23
+ # { patient_id: 2, key: :first_name, value: 'frank' },
24
+ # { patient_id: 2, key: :last_name, value: 'rizzo' },
25
+ # ]
26
+ #
27
+ # Using the following job configuration:
28
+ #
29
+ # config = {
30
+ # unique_key: :patient_id
31
+ # }
32
+ #
33
+ # Once ran through this job, it would set the register to:
34
+ #
35
+ # records = [
36
+ # { patient_id: 1, first_name: 'bozo', last_name: 'clown' },
37
+ # { patient_id: 2, first_name: 'frank', last_name: 'rizzo' },
38
+ # ]
39
+ #
40
+ # Expected Payload[register] input: array of objects.
41
+ # Payload[register] output: An array of objects.
42
+ class Pivot < JobWithRegister
43
+ DEFAULT_PIVOT_KEY = :key
44
+ DEFAULT_PIVOT_VALUE_KEY = :value
45
+
46
+ attr_reader :insensitive,
47
+ :other_keys,
48
+ :non_pivoted_keys,
49
+ :pivot_key,
50
+ :pivot_value_key,
51
+ :resolver,
52
+ :unique_keys
53
+
54
+ def initialize(
55
+ unique_keys:,
56
+ insensitive: false,
57
+ name: '',
58
+ other_keys: [],
59
+ pivot_key: DEFAULT_PIVOT_KEY,
60
+ pivot_value_key: DEFAULT_PIVOT_KEY_VALUE,
61
+ register: DEFAULT_REGISTER,
62
+ separator: ''
63
+ )
64
+ super(name: name, register: register)
65
+
66
+ @insensitive = insensitive || false
67
+ @pivot_key = pivot_key.to_s
68
+ @pivot_value_key = pivot_value_key.to_s
69
+ @resolver = Objectable.resolver(separator: separator)
70
+ @unique_keys = Array(unique_keys)
71
+ @other_keys = Array(other_keys)
72
+ @non_pivoted_keys = @unique_keys + @other_keys
73
+
74
+ freeze
75
+ end
76
+
77
+ def perform(output, payload)
78
+ objects = array(payload[register])
79
+ table = make_table(objects)
80
+
81
+ output.detail("Pivoting #{objects.length} object(s)")
82
+ output.detail("By key: #{pivot_key} and value: #{pivot_value_key}")
83
+
84
+ objects.each { |object| object_to_table(object, table) }
85
+
86
+ pivoted_objects = table.to_a.map(&:fields)
87
+
88
+ output.detail("Resulting dataset has #{pivoted_objects.length} object(s)")
89
+
90
+ payload[register] = pivoted_objects
91
+ end
92
+
93
+ private
94
+
95
+ def resolve_key(object)
96
+ key_to_use = resolver.get(object, pivot_key)
97
+
98
+ make_key(key_to_use)
99
+ end
100
+
101
+ def make_key(value)
102
+ insensitive ? value.to_s.downcase : value
103
+ end
104
+
105
+ def make_row_id(object)
106
+ unique_keys.map { |k| make_key(resolver.get(object, k)) }
107
+ end
108
+
109
+ def make_key_map(objects)
110
+ objects.each_with_object({}) do |object, key_map|
111
+ key = resolver.get(object, pivot_key)
112
+ unique_key = make_key(key)
113
+
114
+ key_map[unique_key] ||= Set.new
115
+
116
+ key_map[unique_key] << key
117
+ end
118
+ end
119
+
120
+ def make_record(objects)
121
+ key_map = make_key_map(objects)
122
+ keys = non_pivoted_keys + key_map.values.map(&:first)
123
+
124
+ HashMath::Record.new(keys)
125
+ end
126
+
127
+ def make_table(objects)
128
+ HashMath::Table.new(make_record(objects))
129
+ end
130
+
131
+ def object_to_table(object, table)
132
+ row_id = make_row_id(object)
133
+
134
+ non_pivoted_keys.each do |key|
135
+ value = resolver.get(object, key)
136
+
137
+ table.add(row_id, key, value)
138
+ end
139
+
140
+ key_to_use = resolve_key(object)
141
+ value_to_use = resolver.get(object, pivot_value_key)
142
+
143
+ table.add(row_id, key_to_use, value_to_use)
144
+
145
+ self
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
@@ -8,5 +8,5 @@
8
8
  #
9
9
 
10
10
  module Burner
11
- VERSION = '1.8.0'
11
+ VERSION = '1.9.0-alpha'
12
12
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: burner
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.0
4
+ version: 1.9.0.pre.alpha
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Ruggio
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-03-31 00:00:00.000000000 Z
11
+ date: 2021-04-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: acts_as_hashable
@@ -251,6 +251,7 @@ files:
251
251
  - lib/burner/library/collection/nested_aggregate.rb
252
252
  - lib/burner/library/collection/number.rb
253
253
  - lib/burner/library/collection/objects_to_arrays.rb
254
+ - lib/burner/library/collection/pivot.rb
254
255
  - lib/burner/library/collection/shift.rb
255
256
  - lib/burner/library/collection/transform.rb
256
257
  - lib/burner/library/collection/unpivot.rb
@@ -320,9 +321,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
320
321
  version: '2.5'
321
322
  required_rubygems_version: !ruby/object:Gem::Requirement
322
323
  requirements:
323
- - - ">="
324
+ - - ">"
324
325
  - !ruby/object:Gem::Version
325
- version: '0'
326
+ version: 1.3.1
326
327
  requirements: []
327
328
  rubygems_version: 3.0.3
328
329
  signing_key: