I think that handling manually "!/not" would be worth the effort rather than having two commands, especially if the boolean expression syntax may be extended some day and the negative if would become obsolete.
If there is a negative condition syntax, I would slightly prefer \ifnot to \if_not or worse \unless. I would disaprove strongly of \unless because it looses the clear symmetry with a closing \fi.
Obviously, there's a lot more in there than we'd need, and it's back quite a few versions.
I agree that the boolean tests available should be *very* simple, and all of the weight of complex calculation should be put in SQL, like we do with \gset
I propose those be:
\if STRING : true if STRING evaluates to true via ParseVariableBool, empty means false
\ifnot STRING: true if STRING evaluates to false via ParseVariableBool, empty means false
\ifdef psql_var: true if psql_var is defined
\ifndef psql_var: true if psql_var is not defined, helpful for when --set var=val was omitted and should be defaulted
A full compliment of \elseif \elseifnot \elseifdef \elseifndef, each matching the corresponding \if* above. I'm ok with these being optional in the first revision.
\else - technically we could leave this out as well
\endif
Then seems like we need an if-state-stack to handle nesting. At any given point, the mode could be:
1. None
psql currently isn't in an if-then structure, no non-conditional statements are skipped. any conditional commands other than \if* are an error.
For that matter, the script can always add a new level to the stack with an \if* command.
2. If-Then
psql is currently executing statements in an \if* branch that evaluated to true. valid conditional commands are: \if*, \else* \endif
3. If-Skip
psql is currently in a block that evaluated to false, and will still parse commands for psql-correctness, but will skip them until it encounters an \endif or \else*
4. Else-Then
Just like If-Then, but encountering an \else* command would be an error.
5. Else-Skip
Just like If-Skip, but encountering an \else* command would be an error.
The only data structure we'd need is the stack of enums listed above. Any commands would check against the stack-state before executing, but would otherwise be parsed and checked as they are now. The new \commands would manipulate that stack.