Skip to content

Selecting Object literals

(obj) selects Object literals and, optionally, their properties -- similar to what (arr) does for Array literals. It has the following signature:

clojure
(obj [props?])
(obj [props?])

In its bare form, (obj) will match any Object, like {} or {a}:

clojure
(obj)
(obj)

To select an object based on its properties, the (prop) selector can be used, which is also analogous to (el) for Array elements. It has the following signature:

clojure
(prop [key?] [val?])
(prop [key?] [val?])

The following query selects an object that has a property named by the identifier x:

clojure
(obj (prop x))
(obj (prop x))

Property names are not restricted to identifiers: they can be strings -- { "a": 1 }, or numbers -- { 3: 1 }, or computed -- { [a]: 1 }. To be specific about the type of a key, we can use one of the corresponding selectors we've encountered before:

clojure
(obj (prop (str a))) ; { "a": 1 }
(obj (prop (comp (num)))) ; { [3]: 1 }
(obj (prop (str a))) ; { "a": 1 }
(obj (prop (comp (num)))) ; { [3]: 1 }

Property values can be selected in a similar fashion by providing a selector as the second argument to (prop):

clojure
(obj (prop x (str))) ; { x: "foo" }
(obj (prop x (str))) ; { x: "foo" }

When the property name is irrelevant, disregard it using the placeholder atom:

clojure
(obj (prop _ (str))) ; {   x: "foo" }
                     ; { [x]: "foo" }
(obj (prop _ (str))) ; {   x: "foo" }
                     ; { [x]: "foo" }

Selecting objects based on multiple properties

As we've seen with Arrays in the introduction to the logical operators, we can use (:and) to combine multiple (prop) selectors and cover more than one property of an object. Say we want to select an object that has the properties named "headers" and "url":

clojure
(obj (:and (prop headers)
           (prop url)))
(obj (:and (prop headers)
           (prop url)))

Alternating with (:or) and excluding with (:not) behave similarly. Alternates are especially useful for property selection since property names (keys) may be more than identifiers; a problem we did not have with Arrays. For example, to match the "headers" and "url" properties regardless of whether they are defined as an identifier or a string:

clojure
(obj (:and (prop (:or (id headers) (str "headers")))
           (prop (:or (id url)     (str "url")))))
(obj (:and (prop (:or (id headers) (str "headers")))
           (prop (:or (id url)     (str "url")))))

Such patterns are often necessary and could get unwieldy rather quickly; consider that a name may also be a computed property of a string literal:

clojure
(obj (:and (prop (:or (id headers) (str "headers") (comp (str "headers"))))
           (prop (:or (id url)     (str "url")     (comp (str "url"))))))
(obj (:and (prop (:or (id headers) (str "headers") (comp (str "headers"))))
           (prop (:or (id url)     (str "url")     (comp (str "url"))))))

SYNG provides dedicated constructs for dealing with these patterns. We discuss this in more detail later in the chapter on supertype selection.

Copyright © 2022-present Semantic Works, Inc.