Skip to content

Commit 7b9203d

Browse files
committed
feat: Add Delete::FieldValueConditional transform
1 parent 0776c97 commit 7b9203d

1 file changed

Lines changed: 103 additions & 0 deletions

File tree

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# frozen_string_literal: true
2+
3+
module Kiba
4+
module Extend
5+
module Transforms
6+
module Delete
7+
# Delete a field value if the arbitrary Lambda passed in evaluates to
8+
# true
9+
#
10+
# @example Without delim
11+
# xform = Delete::FieldValueConditional.new(
12+
# fields: %i[a b],
13+
# lambda: ->(val, row) { row[:c] == val }
14+
# )
15+
#
16+
# input = [
17+
# {a: nil, b: "", c: "c"},
18+
# {a: "c", b: "b", c: "c"},
19+
# {a: "a|c", b: "c", c: "c"}
20+
# ]
21+
# result = Kiba::StreamingRunner.transform_stream(input, xform)
22+
# .map{ |row| row }
23+
# expected = [
24+
# {a: nil, b: nil, c: "c"},
25+
# {a: nil, b: "b", c: "c"},
26+
# {a: "a|c", b: nil, c: "c"}
27+
# ]
28+
# expect(result).to eq(expected)
29+
#
30+
# @example With delim
31+
# xform = Delete::FieldValueConditional.new(
32+
# fields: %i[a b],
33+
# lambda: ->(val, row) { row[:c] == val },
34+
# delim: "|"
35+
# )
36+
#
37+
# input = [
38+
# {a: nil, b: "", c: "c"},
39+
# {a: "c", b: "b", c: "c"},
40+
# {a: "a|c", b: "c", c: "c"}
41+
# ]
42+
# result = Kiba::StreamingRunner.transform_stream(input, xform)
43+
# .map{ |row| row }
44+
# expected = [
45+
# {a: nil, b: nil, c: "c"},
46+
# {a: nil, b: "b", c: "c"},
47+
# {a: "a", b: nil, c: "c"}
48+
# ]
49+
# expect(result).to eq(expected)
50+
#
51+
class FieldValueConditional
52+
include BooleanLambdaParamable
53+
54+
# @param fields [Array<Symbol>,Symbol] field(s) to delete from
55+
# @param lambda [Lambda] with one parameter for row to be passed in
56+
# through. The Lambda must take `val` and `row` positional arguments
57+
# and evaulate to/return `TrueClass` or `FalseClass`
58+
# @param delim [nil, String] if provided, turns on multivalue mode;
59+
# each whole field value is split into values, each of which is
60+
# sent as `val` to the lambda
61+
def initialize(fields:, lambda:, delim: nil)
62+
@fields = [fields].flatten
63+
@lambda = lambda
64+
@multival = delim ? true : false
65+
@delim = delim || Kiba::Extend.delim
66+
end
67+
68+
# @param row [Hash{ Symbol => String, nil }]
69+
# @raise [Kiba::Extend::BooleanReturningLambdaError] if given lambda
70+
# does not evaluate to `TrueClass` or `FalseClass` using
71+
# the first row of data passed to the `process` method
72+
def process(row)
73+
test_lambda(["foo", row]) unless lambda_tested
74+
75+
fields.each { |field| row[field] = delete_from_field(row, field) }
76+
row
77+
end
78+
79+
private
80+
81+
attr_reader :fields, :lambda, :multival, :delim
82+
83+
def delete_from_field(row, field)
84+
val = row[field]
85+
return if val.blank?
86+
return do_deletes([val], row, field) unless multival
87+
88+
do_deletes(val.split(delim), row, field)
89+
end
90+
91+
# @param vals [Array<String>]
92+
def do_deletes(vals, row, field)
93+
result = vals.map { |val| lambda.call(val, row) ? nil : val }
94+
.compact
95+
return nil if result.empty?
96+
97+
result.join(delim)
98+
end
99+
end
100+
end
101+
end
102+
end
103+
end

0 commit comments

Comments
 (0)