-
Notifications
You must be signed in to change notification settings - Fork 756
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
User-defined types - Mandatory property based on value from another property #9641
Comments
This might be solved to some degree with tagged unions (tracked in #9230), but that wouldn't cover all cases in which a property is conditionally required. |
if I am not mistaken this is possible with JSON schemas so it should be possible Bicep to come up with syntax that will transform to that. |
@alex-frankel Yes, "tagged union" is a synonym for discriminated union. I think what's being asked for here is a little different (@slavizh please correct me if I'm wrong) in that any property (not just the discriminator) could trigger additional constraints. The JSON schema equivalents would be I'm not personally in favor of implementing if/then/else in the ARM type system, if only because Azure resource provider schemas use discriminated unions instead of the more open-ended JSON schema features (which are flexible enough to make client generation really challenging). |
@jeskew looking at the latest release and discriminator is there a way to define union of array of objects likes:
Or something like that. Of course the syntax above gives error but it is for illustration purpose. |
@slavizh You can define an array whose elements are a tagged union: type typeA = {
type: 'a'
value: string
}
type typeB = {
type: 'b'
value: int
}
@discriminator('type')
type unionAB = typeA | typeB
type unionAbArray = unionAB[] If the array needs to be all strings or all ints, you could define that as a slightly different tagged union: type typeA = {
type: 'a'
value: string[]
}
type typeB = {
type: 'b'
value: int[]
}
@discriminator('type')
type unionAB = typeA | typeB |
@jeskew Great! May be one last question. I would guess you will always need some property called type or some other name in order to distinguish which object you are defining, correct? |
Right, the outer wrapper needs to be an object with a discriminator property. That property doesn't need to be named |
@jeskew Thanks! we will soon start building user defined templates for our modules so if there is some feedback I will report it here on GitHub bicep repo. |
@jeskew I have managed to play more with the discriminator feature but it seems it is limited to certain scenarios. For example let's say that you have propertyB that is mandatory if propertyA is set as value A, but you also have propertyC that is mandatory if propertyB is set to value B. With that kind of logic the best you can do is to introduce propertyD that serves as type that covers all the different scenarios depending on the values from propertyA, propertyB and propertyC. Now imagine that you have a dozen of other properties that you need to define in every type and even if you have more dependencies. With the latter you really have to become very creating on the values available for propertyD as they will not have to be very long but at the same time descriptive. |
@slavizh Tagged union polymorphism looks a bit different from the kind of dependent relationships between properties that you're describing, and tagged unions are usually impossible to retrofit onto existing data structures in a backwards compatible way. In your scenario, you could introduce a new discriminator property (this is the "propertyD" you're talking about), but it has to be a required property on all variants, so that's a breaking change right off the bat. If you do have room to make breaking changes, one of the strategies we suggest in API reviews is to group properties that must be specified together as nested types. For example, if you have two properties, One option you could try is to just capture the permitted permutations in documentation. This works best if various properties are conditionally required, as you can just mark the property as optional in the type definition and then let an access fail at runtime if the submitted value violates the documented contract. For example, param foo {
@description('Always required')
propA: string
@description('Required if propA == \'bar\'')
propB: bool?
@description('Required if propB == true')
propC: string?
}
var c = foo.?propB == true ? foo.propC : null Consumers of your module still get IntelliSense, but they must rely on documentation to avoid deployment failures, so it's not ideal. I'm still really wary of implementing something like JSON schema's |
ok |
@jeskew FYI if you use sealed with discriminator it does not work correctly in VSC intellisense. You basically get empty object as suggestion and none of the two types. Code:
Not sure if this is a bug or expected behavior, but it took me some time to find the reason as code was without errors. |
@jeskew actually I think I have found a bug that is not the sealed() one described above. If in your bicepparam file you point to the above intellisense works correclty. But if you compile the bicep file to json and point the bicepparam file to the json intellisense does not work correctly. |
Is your feature request related to a problem? Please describe.
Hi, is there a way to define property to be mandatory only if another property is set to certain value?
Also let's say I have property property1 that is not mandatory and has default value of foo1. The allowed values for property1 are foo1 and foo2. If the value is foo1 than property2 is mandatory if value is foo2, property 3 is mandatory. Also is there a way that if I do not define the value of property1 because it has default value to signal in intelliisense that property2 is mandatory?
Describe the solution you'd like
A clear and concise description of what you want to happen.
The text was updated successfully, but these errors were encountered: