My understanding of s/union is that you would use it to combine two specs that are at the same hierarchical level as in (s/union ::user/private ::user/public).
What I want here is a hierachical structure as in this JSON structure:
{"TransactItems": [{"Get": {"TableName": "string", "Key": "string"}}]}
(s/def ::transact-schema (s/schema [::TableName ::Item ::Key ::ConditionExpression]))
(s/def ::Get (s/select ::transact-schema [::TableName ::Key]))
(s/def ::ConditionCheck (s/select ::transact-schema [::TableName ::Key ::ConditionExpression]))
(s/def ::Put (s/select ::transact-schema [::TableName ::Item]))
(s/def ::TransactGetItem (s/schema [::Get]))
(s/def ::TransactWriteItem (s/schema [::ConditionCheck ::Put]))
(s/def ::TransactItems
(s/or :get (s/coll-of ::TransactGetItem :kind vector?)
:write (s/coll-of ::TransactWriteItem :kind vector?)))
Here I am specifing what the value of "Get" can be at the inner level (a map that contains "TableName" and "Key" as keys) and what the value of "TransactItems" can be at the outer level (an array of maps that contain "Get" as a key or an array of maps that contain "Put" and "ConditionCheck" as keys).
Source:
https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html