burner 1.8.0 → 1.9.0.pre.alpha

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 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: