Queries
PODs are organized into collections, but often we want to find a specific set of PODs within a collection, or across multiple collections, based on the data the PODs contain. Queries allow us to describe the characteristics of a POD, and find those PODs which match our criteria.
Here’s an example query:
Queries work by specifying constraints on some POD entries. For a POD to match the query, it must have all of the specified entries (except for those explicitly marked as optional
), and those entries must satisfy the criteria provided.
Queries can use the following criteria:
type
If an entry is specified at all, it must have a type. Types can be the following:
string
, for text entriesint
, for integers, up to a maximum of 64 bits (signed), meaning 9,223,372,036,854,775,807 to -9,223,372,036,854,775,808cryptographic
, for larger numbers, typically used for hasheseddsa_pubkey
, for string-encoded EdDSA public keys
Examples:
The type optional
is also available. optional
entries can be missing. However, they have an innerType
value, which can contain filter criteria to apply to the entry if it exists, which can include the real type:
isMemberOf/isNotMemberOf
These filters allow us to specify lists of values, and check that the entries for a POD either match (with isMemberOf
) or do not match (with isNotMemberOf
) the list that we provide.
For example:
This example would match any POD with an animal_type
entry, so long as that entry is a string
, and it has a value of "Fox"
, "Rabbit"
, or "Camel"
.
inRange
For int
values, we can check if they lie with in a minimum and maximum range.
For example:
This query would match any POD with an age
entry, so long as that entry is an int
with a value between 25 and 1500, inclusive.
Tuples
Tuples work similar to isMemberOf
and isNotMemberOf
, but allow us to compare against a set of entries at the same time.
For example, say a POD represents data about songs. The POD has entries for "artist"
, and "year_published"
. If we want to find every song by Beyoncé, we could write a query like this:
If we want to find every song by either Beyoncé or Taylor Swift, we could write a query like this:
If we wanted to find every song by either Beyoncé or Taylor Swift that was published in 2016, we could do this:
But what if we want to find either songs by Beyoncé from 2016, or songs by Taylor Swift from 2020? For this, we need tuples!
We could write a query like this:
Note that the query has to declare the types of the entries to match on, and then later refers to those entries in the tuples
object.
Non-entry values
In addition to matching on the POD’s entries, we can also match on the POD’s signerPublicKey
and signature
.
For example:
This example is a bit contrived, but shows how it is possible to query for a POD by either the public key of the signer, or by the signature of the POD. Querying by signature is not particularly useful, since signatures are hard to guess, but if you happen to know a POD’s signature then you could query to see if the user has it.
Querying by signer public key is more useful: if you know the public key of a signer, such as the organizer of an event or the operator of a game, you can query for PODs signed by them.
Virtual entries in tuples
The signer public key can also be used as a “virtual” entry in a tuple. For example, if you are playing a game in which magical items are signed by different wizards, you might want to use a tuple like this:
This query will match on either a POD with an item_type
entry of "Staff"
signed by Gandalf’s public key, or a POD with an item_type
entry of "Palantir"
, signed by Saruman’s public key. Note that unlike matching directly on the public key, here we represent the public key as though it were an entry in the POD, meaning that we use { type: "eddsa_pubkey", value: "MolS1FubqfCmFB8lHOSTo1smf8hPgTPal6FgpajFiYY" }
rather than the string "MolS1FubqfCmFB8lHOSTo1smf8hPgTPal6FgpajFiYY"
directly.