Wrangling (it) when the (expression) returns empty

Dear Hive Mind,

This question is really about error handling, and working around null returns sets. I’m writing it to be generic, hopefully it will make sense…

Say you have an (expression) which often returns one or more results. But sometimes the resulting set is empty.

In the latter case:

Q: (expression)

Q: number of (expression)
A: 0

Q: exists (expression)
A: False

Q: exists it of (expression)

Q: exist (it) of (expression) 
A: False

Q: number of items of (expression)
A: 0

Q: (number of items of it) of (expression)

So, given this state, how to wrangle the (expression) such that you can take different actions based on the empty set?

The lack of (it) means you can’t meaningfully use if/then.

I’ve tried using the pipe error…

Q: (expression) | "oops"
E: A singular expression is required.

What say the hive mind?

How would you handle the cases where one or many results were returned?

Hm this is interesting. I’ve had to handle cases like this myself, and I don’t know whether there’s a general solution. @brolly33 I’d love to hear an opinion on it.

In the case where I expect only zero or one results, I have used the ‘unique value of’ inspector to force an error if there are zero results, as in

q: unique value of (names of files of folders "c:\does-not-exist") | "No Files Found"
A: No Files Found

That’s been handy for things like reporting Fixlet properties in an HTML table, when I retrieve things like a ‘cve id list’ that might have a value or might be empty, and I don’t want the empty CVE to remove the whole fixlet from the result table.

But ‘unique value of’ also errors if there is more than one result, so it’s not suitable in cases where the query might return multiple results.

1 Like

To avoid errors resulting from null sets, use the Plural for of the relevance.

Q: Numbers of (expression)

I’d like to do additional relevance and string handling, with properties of the one-or-many results. So something like:

(if (number of it > 0) then ("foo" & property of it as string & "bar") else "other strings") of (expression)

but currently

Q: (if (number of it > 0) then ("foo" & property of it as string & "bar") else "other strings") of (expression)

Q: (if (number of it = 0) then ("oops") else ("foo" & property of it as string & "bar")) of (expression)

Q: unique values of (expression)
E: The operator "unique values" is not defined.

This works, but (expression) runs twice and might be impactful.

Q: if (number of (expression) > 0) then (property of (expression)) else "oops"
A: oops

It’s also inelegant, and that’s no fun. :wink:

Thinking out loud: what if you use a union with a static set of values, so there would always be at least one result?

1 Like

I’ve been wondering it set logic might be a way around this. That seems to be @brolly33’s goto for magical results.

Depends what expression returns. If it is a simple result set (string/integer/etc), set can do but if it is a more complex thing like event log records; wmi objects; etc. then “set” won’t work.

For what it is worth, I prefer exists (expression), i.e. if (exists (expression)) then (… of (expression)) else error “NotExist” but as you pointed out it is being executed twice…

1 Like

Would something like this work?

if(number of (item 1 of it) > 0 then (item 0 of it as string) else "oops" ) (property of it, it) of(expression)
1 Like

Reformatting slightly, did you mean…

(if(number of (item 1 of it) > 0) then (item 0 of it as string) else "oops" ) of (property of it, it) of (expression)

…? Because when (expression ) returns a null set, and (property) is something that would make sense…

Q: (if(number of (item 1 of it) > 0) then (item 0 of it as string) else "oops" ) of (property of it, it) of (expression)
E: The tuple index 1 is out of range.

Still does not instantiate, because the mid tuple drops when expression does not have “stuff” in it.

here is testing harness I have been using to prototype.
I have not yet solved…

q: (if number of folders ("c:\does-not-exist";"c:\might-exist") > 0 then (names of files of folders ("c:\does-not-exist";"c:\might-exist")) else ("Nope!";"No folders"))  
A: Nope!
A: No folders
I: plural string

q: (if number of it > 0 then (names of files of it) else ("Nope!";"No folders")) of  folders ("c:\does-not-exist";"c:\might-exist")
I: plural string

q: (if number of item 0 of it > 0 then (names of files of item 0 of it) else (item 1 of it)) of (it, "MyError") of folders ("c:\does-not-exist";"c:\might-exist")
I: plural string

Injecting a fake value does work, but it is ugly and I hate it.

q: (if number of item 0 of it > 1 then (names of files of item 0 whose (name of it != "c:\" ) of it) else (item 1 of it)) of (it, "MyError") of folders ("c:\does-not-exist";"c:\might-exist";"c:\")
A: MyError

I love that you went to sets @atlauren My mind went there too. But:

q: size of set of (nothing;"something";nothing)
A: 1
I: singular integer

q: size of set of (nothing;nothing;nothing)
E: The operator "set" is not defined. 

With strings, it can work, because we have a String Set object…
and for things that instantiate with a string input, you can use this!

q: (if size of it > 0 then (names of files of folders (elements of it)) else ("NoFolders")) of set of (names of folders ("c:\does-not-exist";"c:\might-exist") )
A: NoFolders

But, honestly, this is cheating, because I instantiate folders twice still… Once inside the set and once again inside the it clause. If we had a Folder Set object this would work and keep your instantiation to inside of the set.

if you are OK with your outer thing being a set, then you can use string sets to trap the error like this, and only instantiate once.

q: (if size of it > 0 then elements of it else "Either No Files or Folders") of set of names of files of folders ("c:\does-not-exist";"c:\might-exist")
A: Either No Files or Folders
I: plural string