I'm trying to use Terraform 0.13's custom variable validation to ensure that the value is either null or between a specified range. I've tried every combination I can think of (using can, try, etc) but can't get it working for every case.
Here is the full non-working example:
variable "target_group_stickiness_duration" {
default = null
type = number
validation {
condition = (
var.target_group_stickiness_duration == null ||
( var.target_group_stickiness_duration >= 1 && var.target_group_stickiness_duration <= 604800 )
)
error_message = "Target group stickiness duration must be >= 1 and <= 604800."
}
}
This will fail if the value is null with the following error:
Error during operation: argument must not be null.
I believe this is due to eager evaluation of the conditional expression. Am I missing something obvious? Or any clever workarounds for this?
It fails becasue when your target_group_stickiness_duration is null, the
(var.target_group_stickiness_duration >= 1 && var.target_group_stickiness_duration <= 604800
)
is invalid.
You can try the following which uses coalesce:
variable "target_group_stickiness_duration" {
default = null
type = number
validation {
condition = (
var.target_group_stickiness_duration == null ||
(coalesce(var.target_group_stickiness_duration, 0) >= 1 && coalesce(var.target_group_stickiness_duration, 604801) <= 604800))
error_message = "Target group stickiness duration must be >= 1 and <= 604800."
}
}
It looks like there are two different things going on here.
The first is that tour condition expression includes the following subexpression:
var.target_group_stickiness_duration == null
This seems to be allowing the value to be null.
However, if we correct that to the opposite then it will expose a second problem:
condition = (
var.target_group_stickiness_duration != null &&
( var.target_group_stickiness_duration >= 1 && var.target_group_stickiness_duration <= 604800 )
)
Terraform's logical operators don't have the "short circuit" behavior in some other languages, where the result of the first operand can prevent any attempt to evaluate the second operand. Therefore both operands of && must be valid and successfully return either true or false.
The second operand (the nested && testing the range of the number) can't succeed if the value is null, because >= isn't defined for null numbers.
To make this work requires using a different strategy that avoids applying the >= operator to a null number. There are a few different ways to do that, including one with coalesce discussed in the accepted answer to this question.
Another alternative strategy is to use the conditional operator, which does allow the unselected result operand to fail, to allow us to use it as a guard for situations like this:
condition = (
var.target_group_stickiness_duration == null ? false : (
var.target_group_stickiness_duration >= 1 &&
var.target_group_stickiness_duration <= 604800
)
)
This is essentially an explicit implementation of the automatic short-circuit behavior some other languages offer in their logical operators. Terraform, at least in its current design, requires you to explicitly write out that the >= and <= operations are desirable only for non-null numbers.
Related
def pos_neg(a, b, negative):
if negative:
return (a < 0 and b < 0)
else:
return ((a < 0 == b > 0) or (a > 0 == b < 0))
so basically I tried some basic problems.
I just started out and went to https://codingbat.com/prob/p162058 to try it and don't understand why if I were to replace the '==' with 'and' it would work? Thanks.
Oh, I got it now, thanks guys. :D
(this python community is fire!!!)
Since you're learning, you might be interested in seeing that this is an equivalent function.
basically it does a bit wise & and returns true if the result is < 0
else a bit wise exclusive or and returns true if the result is < 0
def pos_neg(a , b, negative):
if negative:
return (a & b) < 0 # both sign bits set (i.e. neg), return true
else:
return (a ^ b) < 0 # different signs, return true
In both cases, it is the sign bit of the result that is of concern. If the bit is set then the value will be negative (hence the comparison to < 0)
and is a logical operator and returns true only when both the expressions we are using it on are true.
== is used for comparisons and returns true when both expressions are equal; they don't need to be true.
To give you an example False == False will return True but False and False will return False.
This "==" means equals to, belonging to Python Comparison Operators, used to compare two values.
and language keyword "and" it is for Python Logical Operators used to combine conditional statements.
You should check out this, it may solve others doubts you have.
W3Schools
All your relational operator usages (i.e. a < 0, b < 0, etc.) result to a boolean value and thus these are known as boolean expressions.
When you put a < 0, think of it like a test of: "is a less than 0, true or false?".
So, if both a and b are negative (i.e. less than zero), their expressions will return true.
So on the line return a < 0 and b < 0, replacing and with == is like saying return true == true. Without the change it'd be return true and true.
Note: This does not mean == is the same as and. == checks for equality of the left-hand side to the right-hand side (e.g. 1 == 1) and gives a true or false value depending on the result of equality. and checks for if the left-hand side results to a true statement and if the right-hand side results to a true statement in order to result to a true expression.
I'm trying to check for two conditions- when ( a field is not null & equal to a value) then do something, but i'm getting type miss match error. can you please help?
join_df6.withColumn(
'NI',
when(
join_df6.s4chvw_zzbatposnr.isNotNull() & join_df6.s4chvw_zzbatposnr == '00000',
join_df6.s4chvw_zzbatposnr
).when(
join_df6.s4cordislips_posnr.isNotNull(),
join_df6.s4cordislips_posnr
).otherwise(join_df6.s4ibdlips_posnr)
)
Error
u"cannot resolve '((s4chvw_zzbatposnr IS NOT NULL) AND s4chvw_zzbatposnr)' due to data type mismatch: differing types in '((s4chvw_zzbatposnr IS NOT NULL) AND s4chvw_zzbatposnr)' (boolean and string).;
The conditions inside the when are evaluated according to python operator precedence, and the bitwise and (&) has higher precedence than all comparison operators including == (HT to #cronoik for pointing this out).
join_df6.s4chvw_zzbatposnr.isNotNull() & join_df6.s4chvw_zzbatposnr == '00000'
Is being evaluated as:
(join_df6.s4chvw_zzbatposnr.isNotNull() & join_df6.s4chvw_zzbatposnr) == '00000'
#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# this & is evaluated first
Which causes your data type mismatch error because .isNotNull() returns a boolean and join_df6.s4chvw_zzbatposnr seems to be a string.
The solution is to always use parentheses for multiple conditions. In your case, you should do:
join_df6.withColumn(
'NI',
when(
join_df6.s4chvw_zzbatposnr.isNotNull() & (join_df6.s4chvw_zzbatposnr == '00000'),
join_df6.s4chvw_zzbatposnr
).when(
join_df6.s4cordislips_posnr.isNotNull(),
join_df6.s4cordislips_posnr
).otherwise(join_df6.s4ibdlips_posnr)
)
How to make
sum(array[*].value) to return NULL if all values are NULL or no values?
Currently it returns 0 in both cases
The best I can think of is
first_document(array[*].value) ? sum(array[*].value) : null
which needs to iterate collection twice
Is there a better way to do it?
How about using a FOR loop instead of the shorthand notation and filter out null values? Then we can check if zero elements remain and return null:
LET tmp = (FOR elem IN array FILTER elem.value != null RETURN elem)
RETURN LENGTH(tmp) ? SUM(tmp) : null
You could also use an array inline expression, but it's about the same amount of characters:
LET tmp = arr[* FILTER CURRENT.value != null RETURN CURRENT.value]
RETURN LENGTH(tmp) ? SUM(tmp) : null
I am new to grails I found in many examples that a variable may end with question mark (?)
like this
boolean equals(other) {
if(other?.is(this))
return true
}
above code contains If condition in that other is ending with a ? so I want to know the meaning of that representation
?. is a null safe operator which is used to avoid unexpected NPE.
if ( a?.b ) { .. }
is same as
if ( a != null && a.b ) { .. }
But in this case is() is already null safe, so you would not need it
other.is( this )
should be good.
There is a subtlety of ?., the Safe navigation operator, not mentioned in #dmahapatro's answer.
Let me give an example:
def T = [test: true]
def F = [test: false]
def N = null
assert T?.test == true
assert F?.test == false
assert N?.test == null // not false!
In other words, a?.b is the same as a != null && a.b only when testing for a boolean value. The difference is that the first one can either evaluate to a.b or null, while the second one can only be a.b or false. This matters if the value of the expression is passed on to another expression.
How do I display a value whether it is true or false in groovy? I'm using Eclipse as my IDE.
assert 4 * ( 2 + 3 ) - 6 == 14 //integers only
And also I don't understand 'assert' too well in Groovy. Is it like an if() statement/boolean in Java?
What role does 'assert' play in Groovy?
An assertion is similar to an if, it verifies the expression you provide: if the expression is true it continues the execution to the next statement (and prints nothing), if the expression is false, it raises an AssertionError.
You can customize the error message providing a message separated by a colon like this:
assert 4 * ( 2 + 3 ) - 5 == 14 : "test failed"
which will print:
java.lang.AssertionError: test failed. Expression: (((4 * (2 + 3)) - 5) == 14)
but I had to change the values of your test, in order to make it fail.
The use of assertions is up to your taste: you can use them to assert something that must be true before going on in your work (see design by contract).
E.g. a function that needs a postive number to work with, could test the fact the argument is positive doing an assertion as first statement:
def someFunction(n) {
assert n > 0 : "someFunction() wants a positive number you provided $n"
...
...function logic...
}
Groovy asserts are now quite impressive! They will actually print out the value of every variable in the statement (which is fantastic for debugging)
for example, it might print something like this if b is 5, a is {it^2} and c is 15:
assert( a(b) == c)
. | | | |
. 25 | != 15
. 5
(Well--something like that--Groovy's would probably look a lot better).
If we could just get this kind of print-out on an exception line...
assert 'asserts' that the result of the expression will be a true