From 87c1c485116bb21b2b93e50487bf603dde72bc3a Mon Sep 17 00:00:00 2001 From: Dapeng Zhang Date: Wed, 6 Nov 2024 17:10:15 +0800 Subject: [PATCH] add docs for discriminator (#1676) Fixes #1349 --------- Co-authored-by: Weidong Xu Co-authored-by: tadelesh Co-authored-by: Mary Gao --- .../docs/howtos/Client Generation/06types.mdx | 282 ++++++++++++++++++ 1 file changed, 282 insertions(+) diff --git a/website/src/content/docs/docs/howtos/Client Generation/06types.mdx b/website/src/content/docs/docs/howtos/Client Generation/06types.mdx index e72c52b1ba..731761c4f3 100644 --- a/website/src/content/docs/docs/howtos/Client Generation/06types.mdx +++ b/website/src/content/docs/docs/howtos/Client Generation/06types.mdx @@ -794,6 +794,288 @@ public final class Animal implements JsonSerializable { +### Discriminator + +TypeSpec uses `@discriminator` decorator to add a discriminator to a model. + + + + +TypeSpec now has two ways to represent a discriminated set. + +1. Use model + +```typespec +@discriminator("kind") +model Cat { + kind: string; +} + +model Siamese extends Cat { + kind: "siamese"; +} + +model Ragdoll extends Cat { + kind: "ragdoll"; +} +``` + +The type of the discriminator property could be an enum (extensible or fixed): + +```typespec +@discriminator("kind") +model Cat { + kind: CatKind; +} + +union CatKind { + string, + Siamese: "siamese", + Ragdoll: "ragdoll", +} + +model Siamese extends Cat { + kind: CatKind.Siamese; +} + +model Ragdoll extends Cat { + kind: CatKind.Ragdoll; +} +``` + +2. Use union + +```typespec +@discriminator("kind") +union Cat { + Siamese, + Ragdoll, +} + +model Siamese {} + +model Ragdoll {} +``` + + + + +TCGC currently only supports the discriminated set based on models, discriminated union is not supported yet. + +This is a brief structure of the models in a discriminated set in the output of TCGC. + +```json +{ + "models": [ + { + "kind": "model", + "name": "Cat", + "properties": [ + { + "kind": "property", + "name": "kind", + "type": { + "kind": "string" + }, + "discriminator": true + } + ], + "discriminatorProperty": { + // the same instance of the property in the properties list here + }, + "discriminatedSubtype": { + "siamese": { + "kind": "model", + "name": "Siamese", + "properties": [], + "discriminatorValue": "siamese" + }, + "ragdoll": { + "kind": "model", + "name": "Ragdoll", + "properties": [], + "discriminatorValue": "ragdoll" + } + } + }, + { + // the same instance of the model Siamese as we have above in `discriminatedSubtype` property + }, + { + // the same instance of the model Ragdoll as we have above in `discriminatedSubtype` property + } + ] +} +``` + + + + +```python +from .. import _model_base +from .._model_base import rest_discriminator, rest_field + +class Cat(_model_base.Model): + kind: str = rest_discriminator(name="kind") + +class Siamese(Cat): + kind: Literal["siamese"] = rest_discriminator(name="kind") + +class Ragdoll(Cat): + kind: Literal["ragdoll"] = rest_discriminator(name="kind") +``` + + + + +In .Net generated code, the discriminator property will be generated as internal by default, but configurable to be public. + +```csharp +public abstract partial class Cat +{ + protected Cat() + { + } + + internal string Kind { get; set; } +} + +public partial class Siamese : Cat +{ + public Siamese() : base() + { + Kind = "siamese"; + } +} + +public partial class Ragdoll : Cat +{ + public Ragdoll() : base() + { + Kind = "ragdoll"; + } +} +``` + + + + +```ts +// RLC input models +export interface Siamese extends CatParent { + kind: "siamese"; +} + +export interface Ragdoll extends CatParent { + kind: "ragdoll"; +} + +export type Cat = CatParent | Siamese | Ragdoll; + +// RLC output models +export interface CatOutputParent { + kind: string; +} + +export interface SiameseOutput extends CatOutputParent { + kind: "siamese"; +} + +export interface RagdollOutput extends CatOutputParent { + kind: "ragdoll"; +} + +export type CatOutput = CatOutputParent | SiameseOutput | RagdollOutput; + +// Modular models +/** model interface Cat */ +export interface Cat { + kind: string; +} + +/** Alias for CatUnion */ +export type CatUnion = Siamese | Ragdoll | Cat; + +/** model interface Siamese */ +export interface Siamese extends Cat { + kind: "siamese"; +} +/** model interface Ragdoll */ +export interface Ragdoll extends Cat { + kind: "ragdoll"; +} +``` + + + + +```java +public class Cat implements JsonSerializable { + public Cat(); + public String getKind(); +} + +public final class Ragdoll extends Cat { + public Ragdoll(); + public String getKind(); +} + +public final class Siamese extends Cat { + public Siamese(); + public String getKind(); +} +``` + + + + + +```go +// CatClassification provides polymorphic access to related types. +// Call the interface's GetCat() method to access the common type. +// Use a type switch to determine the concrete type. The possible types are: +// - *Cat, *Ragdoll, *Siamese +type CatClassification interface { + // GetCat returns the Cat content of the underlying type. + GetCat() *Cat +} + +type Cat struct { + // REQUIRED + Kind *string +} + +// GetCat implements the CatClassification interface for type Cat. +func (c *Cat) GetCat() *Cat { return c } + +type Ragdoll struct { + // CONSTANT; undefinedField has constant value "ragdoll", any specified value is ignored. + Kind *string +} + +// GetCat implements the CatClassification interface for type Ragdoll. +func (e *Ragdoll) GetCat() *Cat { + return &Cat{ + Kind: e.Kind, + } +} + +type Siamese struct { + // CONSTANT; undefinedField has constant value "siamese", any specified value is ignored. + Kind *string +} + +// GetCat implements the CatClassification interface for type Siamese. +func (e *Siamese) GetCat() *Cat { + return &Cat{ + Kind: e.Kind, + } +} +``` + + + + ### Nullable TypeSpec uses `| null` to represent nullable types. Nullability is handled differently in languages, but emitter authors will find information