How to generate empty Sets?

I would like to conditionally add a Match result to a Union.
That’s what I came up with:

Query(
  Lambda(
    ["h264", "h265", "vp9"],
    Union(
      [
        If(Var("h264"), Match(Index("VideoUpload_preset_status"), ["h264", "DONE"]), []),
        If(Var("h265"), Match(Index("VideoUpload_preset_status"), ["h265", "DONE"]), []),
        If(Var("vp9"), Match(Index("VideoUpload_preset_status"), ["vp9", "DONE"]), []),
      ],
    )
  )
)

If I run this function with any falsy argument, I get:

Error: [
  {
    "position": [],
    "code": "call error",
    "description": "Calling the function resulted in an error.",
    "cause": [
      {
        "position": [
          "expr",
          "union"
        ],
        "code": "invalid argument",
        "description": "Arguments cannot be of different types, expected Set or Array."
      }
    ]
  }
]

It looks like I need to use something other than [] as my false_expr argument to the If functions. The question then is: how can I generate an empty Set?

The result of Match is a SetRef, and it cannot be included in operations like Union along with a plain Array. Think of like an overloaded function, one that only takes SetRefs and one that only takes Arrays.

Running Union on an empty Set does what you want. Also, null is a valid input for an index term, so you do not need to check for existence.

You have to Paginate the result of Union to get the results. (But maybe you want the UDF to result in the Set and Paginate later, which is totally reasonable)

Can you try the following?

Query(
  Lambda(
    ["h264", "h265", "vp9"],
    Paginate(
      Union(
        Match(Index("VideoUpload_preset_status"), Var("h264"), "DONE"),
        Match(Index("VideoUpload_preset_status"), Var("h265"), "DONE"),
        Match(Index("VideoUpload_preset_status"), Var("vp9"), "DONE"),
      )
    )
  )
)

In my code the vars h264, h265 and vp9 contain boolean values, not strings. That’s why I am using If to check if I should add their respective values to the Union or not. Using some pseudocode to explain what I need:

(h264, h265, vp9) => {
  matches = []

  if(h264) {
    matches.push(
      Match(Index("VideoUpload_preset_status"), ["h264", "DONE"])
    )
  }

  if(h265) {
    matches.push(
      Match(Index("VideoUpload_preset_status"), ["h265", "DONE"])
    )
  }

  if(vp9) {
    matches.push(
      Match(Index("VideoUpload_preset_status"), ["vp9", "DONE"])
    )
  }
    
  return Union(matches)
}

The problem is that FQL’s If requires me to have and Else clause, so it’s end up being more like this:

(h264, h265, vp9) => {
  ...
  matches.push(
    h264 ? Match(Index("VideoUpload_preset_status"), ["h264", "DONE"]) : []
  )
  ...

As we already know, the empty array above doesn’t work well there. It should be an empty set instead:

(h264, h265, vp9) => {
  ...
  matches.push(
    h264 ? Match(Index("VideoUpload_preset_status"), ["h264", "DONE"]) : new Set()
  )
  ...

So, repeating the title of this post: How to generate empty Sets in FQL?

Hi all,

I would like to re-post this issue as I see a definite value proposition in having the ability to designate an empty Set for simplification of If() statements where multiple indexes could be referenced as in zvictor’s case. Can anyone from the Fauna team assist?

Thanks

Appears you can pass an array of set references to Union which means you could filter the array to conditionally add indexes to the union. This doesn’t answer the empty set request but might allow you to work around its absence.

Union(
  Filter(
    [
      If(some_condition, Match(Index('index-1')), null),
      If(other_condition, Match(Index('index-2')), null),
      If(third_condition, Match(Index('index-3')), null),
    ],
    Lambda('set', Not(IsNull(Var('set'))))
  )
)
2 Likes

@ryanjduffy thanks for your work through. I hadn’t even thought to approach with Filter.