Query Operations¶
JSL provides powerful declarative operations for querying and filtering data, inspired by dotsuite's pedagogical approach to JSON manipulation.
The where Special Form¶
The where is a special form (not a function) that provides SQL-like declarative filtering. As a special form, it has special evaluation semantics that automatically bind item fields to the environment before evaluating the condition.
Basic Syntax¶
The condition is evaluated with each item's fields automatically bound to the environment.
Examples¶
Simple Filtering¶
; Filter users by role
(where users (= role "admin"))
; Filter products by price
(where products (> price 100))
Complex Conditions¶
; AND conditions
(where users
(and (= role "admin")
active))
; OR conditions
(where products
(or (= category "electronics")
(< price 50)))
; Nested conditions
(where orders
(and (>= total 100)
(or (= status "pending")
(= status "processing"))))
Field Binding¶
The where special form automatically extends the environment with each item's fields. For objects, all key-value pairs become available as variables. For non-objects, the item is bound to it:
(def users [@
{"name": "Alice", "age": 30, "role": "admin"}
{"name": "Bob", "age": 25, "role": "user"}
])
; 'role' and 'age' are automatically bound from each user
(where users (and (= role "admin") (> age 25)))
; Returns: [{"name": "Alice", "age": 30, "role": "admin"}]
String Literals vs Field References¶
- Field names are symbols that get looked up:
role,age,name - String literals use the @ prefix:
"@admin","@user"
(where users (= role "@admin")) ; role field equals string "admin"
(where users (= "@role" role)) ; string "role" equals role field (unusual)
Query Composition¶
Query operations compose naturally with other JSL operations:
Filter then Transform¶
Filter then Pluck¶
Multiple Filters¶
Implementation Details¶
As a special form, where is implemented directly in the evaluator (_eval_where in core.py), not as a prelude function. This allows it to:
- Control evaluation order
- Automatically bind fields without explicit lambda expressions
- Integrate seamlessly with the JSL evaluation model
- Work identically in both recursive and stack evaluators
Performance Considerations¶
The where operator:
- Uses the standard JSL evaluator for conditions
- Extends the environment once per item
- Short-circuits on false conditions
- Maintains original collection order
Comparison with Traditional Approaches¶
Traditional Lambda Approach¶
Declarative Where Approach¶
The declarative approach is: - More concise and readable - Automatically handles field binding - Consistent with SQL-like query languages - Easier to compose with other operations
Integration with Transform¶
where and transform work together for powerful data pipelines:
; Get names of active admins
(pluck
(where users (and (= role "@admin") active))
"@name")
; Add discount to expensive products
(transform
(where products (> price 100))
(assign "@discounted" (* price 0.9)))
See Also¶
- Transform Operations - Data transformation operations
- Path Navigation - Deep JSON path access
- Prelude Functions - Built-in collection functions