Transform Operations¶
JSL provides powerful declarative operations for transforming and reshaping data structures.
The transform Special Form¶
The transform is a special form (not a function) that applies transformation operations to data. As a special form, it automatically binds item fields to the environment, allowing direct field references in transformation expressions.
Basic Syntax¶
The operation can be one of several transformation functions that reshape the data.
Transformation Operations¶
The transform operations are functions in the prelude that return operation descriptors. These descriptors are then interpreted by the transform special form.
assign - Add or Update Fields¶
Returns an operation descriptor that adds new fields or updates existing ones:
; Add a single field
(transform user (assign "@verified" true))
; Add computed field
(transform product (assign "@discounted" (* price 0.9)))
; Update existing field
(transform user (assign "@age" (+ age 1)))
pick - Select Specific Fields¶
Creates new objects with only specified fields:
; Pick specific fields
(transform user (pick "@name" "@email"))
; From collection
(transform users (pick "@id" "@name" "@role"))
omit - Remove Fields¶
Creates new objects without specified fields:
; Remove sensitive fields
(transform user (omit "@password" "@ssn"))
; Remove multiple fields
(transform response (omit "@internal_id" "@debug_info"))
rename - Rename Fields¶
Renames fields in objects:
; Rename single field
(transform user (rename "@username" "@login"))
; Multiple renames
(transform data (rename {"@old_name": "@new_name", "@id": "@identifier"}))
update - Update Specific Fields¶
Updates fields with computed values:
; Update with function
(transform product (update "@price" (lambda (p) (* p 1.1))))
; Update multiple fields
(transform user
(update {"@age": (lambda (a) (+ a 1)),
"@score": (lambda (s) (* s 2))}))
Field Binding¶
Within transform operations, fields are automatically bound:
(def product {"name": "Widget", "price": 100, "tax_rate": 0.08})
; Fields 'price' and 'tax_rate' are automatically available
(transform product
(assign "@total" (* price (+ 1 tax_rate))))
; Returns: {"name": "Widget", "price": 100, "tax_rate": 0.08, "total": 108}
Working with Collections¶
Transform operations work on both single objects and collections:
(def products [@
{"name": "A", "price": 100}
{"name": "B", "price": 200}
])
; Applied to each item
(transform products (assign "@on_sale" true))
; Returns: [{"name": "A", "price": 100, "on_sale": true},
; {"name": "B", "price": 200, "on_sale": true}]
Composition Patterns¶
Sequential Transformations¶
Filter and Transform¶
Transform and Aggregate¶
Advanced Examples¶
Data Normalization¶
; Normalize user data
(transform users
(do
(pick "@id" "@username" "@email")
(rename "@username" "@name")
(assign "@created_at" (now))))
Computed Fields¶
; Add multiple computed fields
(def order {"items": 5, "price_per_item": 20, "tax_rate": 0.08})
(transform order
(do
(assign "@subtotal" (* items price_per_item))
(assign "@tax" (* subtotal tax_rate))
(assign "@total" (+ subtotal tax))))
Nested Transformations¶
; Transform nested structures
(transform user
(update "@address"
(lambda (addr)
(transform addr (pick "@city" "@country")))))
String Literals vs Field References¶
- Field references (symbols):
price,name,active - String literals (@ prefix):
"@price","@name"
; Assign literal string "pending" to status field
(transform order (assign "@status" "@pending"))
; Assign value of status variable to new_status field
(transform order (assign "@new_status" status))
Implementation Details¶
The transform special form is implemented in _eval_transform in core.py. The transformation operators (pick, omit, assign, etc.) are prelude functions that return operation descriptors like ["pick", "@field1", "@field2"]. The special form then:
1. Evaluates the data expression
2. For each operation, evaluates it with item fields in scope
3. Interprets the operation descriptor to perform the transformation
4. Returns the transformed data
This design separates the operation definition (in prelude) from the execution logic (in the evaluator).
Performance Considerations¶
Transform operations: - Create new objects (immutable) - Extend environment once per transformation - Process collections item by item - Can be optimized by the compiler
Comparison with Manual Approach¶
Manual Construction¶
Transform Approach¶
The transform approach is: - More declarative and readable - Automatically handles field access - Composable with other operations - Less error-prone
See Also¶
- Query Operations - Filtering with
where - Path Navigation - Deep JSON path access
- Group By - Grouping and aggregation