transform
rel.transform(attr: :upcase)rel.transform(attr: ->(v) { v * 2 })rel.transform(attr: Integer)rel.transform(:downcase)rel.transform { |v| v.to_s }rel.transform({ attr: v => v.toUpperCase() })rel.transform({ attr: v => v * 2 })Problem
Section titled “Problem”Modify existing attribute values in place using transformations.
Example: I want to normalize all string values to uppercase, or convert all numeric strings to integers.
Description
Section titled “Description”The transform operator modifies existing attribute values (unlike extend which adds new attributes).
It supports several transformation styles:
Per-attribute transformation (Hash): attr: :method (call method), attr: Class (type conversion), attr: ->(v) { ... } (lambda), attr: { old => new } (value mapping), or Class => transformer (by type).
All-attributes transformation: Pass a Symbol (:downcase) or Proc to transform every value.
Transformations are specified as an object where keys are attribute names and values are functions that transform the attribute value.
Requirements
Section titled “Requirements”No special requirements. Works on any relation.
Examples
Section titled “Examples”Transform specific attributes
Section titled “Transform specific attributes”data = Bmg::Relation.new([ { id: 1, name: "alice", email: "ALICE@EXAMPLE.COM" }, { id: 2, name: "bob", email: "BOB@EXAMPLE.COM" }])
data.transform(name: :capitalize, email: :downcase).to_a
=>[{:id=>1, :name=>"Alice", :email=>"alice@example.com"}, {:id=>2, :name=>"Bob", :email=>"bob@example.com"}]const data = Bmg([ { id: 1, name: "alice", email: "ALICE@EXAMPLE.COM" }, { id: 2, name: "bob", email: "BOB@EXAMPLE.COM" }])
data.transform({ name: v => v.charAt(0).toUpperCase() + v.slice(1), email: v => v.toLowerCase()}).toArray()
// =>// [{ id: 1, name: "Alice", email: "alice@example.com" },// { id: 2, name: "Bob", email: "bob@example.com" }]Lambda transformation
Section titled “Lambda transformation”orders = Bmg::Relation.new([ { id: 1, total: 100, discount: 0.1 }, { id: 2, total: 200, discount: 0.2 }])
orders.transform( total: ->(v) { v.round(2) }, discount: ->(v) { "#{(v * 100).to_i}%" }).to_a
=>[{:id=>1, :total=>100, :discount=>"10%"}, {:id=>2, :total=>200, :discount=>"20%"}]const orders = Bmg([ { id: 1, total: 100.456, discount: 0.1 }, { id: 2, total: 200.789, discount: 0.2 }])
orders.transform({ total: v => Math.round(v * 100) / 100, discount: v => `${Math.round(v * 100)}%`}).toArray()
// =>// [{ id: 1, total: 100.46, discount: "10%" },// { id: 2, total: 200.79, discount: "20%" }]Comparison with extend
Section titled “Comparison with extend”| Operator | Purpose | Result |
|---|---|---|
transform | Modify existing values | Same attributes, different values |
extend | Add new attributes | Additional attributes |
# transform: modifies existing attributerel.transform(name: :upcase)# { name: "alice" } => { name: "ALICE" }
# extend: adds new attributerel.extend(upper_name: ->(t) { t[:name].upcase })# { name: "alice" } => { name: "alice", upper_name: "ALICE" }// transform: modifies existing attributerel.transform({ name: v => v.toUpperCase() })// { name: "alice" } => { name: "ALICE" }
// extend: adds new attributerel.extend({ upper_name: t => t.name.toUpperCase() })// { name: "alice" } => { name: "alice", upper_name: "ALICE" }