public StandardLro(ServiceDetails svc, MethodDescriptor desc) : base(svc, desc) { OperationInfo lroData = desc.GetExtension(OperationsExtensions.OperationInfo); if (lroData is null) { throw new InvalidOperationException("LRO method must contain a `google.api.operation` option."); } ApiCallTyp = Typ.Generic(typeof(ApiCall <,>), RequestTyp, Typ.Of <Operation>()); if (string.IsNullOrEmpty(lroData.ResponseType) || string.IsNullOrEmpty(lroData.MetadataType)) { throw new InvalidOperationException($"Both response-type and metadata-type must be present for method: '{desc.FullName}'."); } var responseTypeMsg = svc.Catalog.GetMessageByName(lroData.ResponseType); var metadataTypeMsg = svc.Catalog.GetMessageByName(lroData.MetadataType); if (responseTypeMsg is null || metadataTypeMsg is null) { throw new InvalidOperationException( $"Response-type and Metadata-type must both exist in method '{desc.FullName}': '{lroData.ResponseType}', '{lroData.MetadataType}'."); } OperationResponseTyp = ProtoTyp.Of(responseTypeMsg); OperationMetadataTyp = ProtoTyp.Of(metadataTypeMsg); SyncReturnTyp = Typ.Generic(typeof(Operation <,>), OperationResponseTyp, OperationMetadataTyp); }
public Field(ServiceDetails svc, MessageDescriptor msg, string fieldName) { Descs = fieldName.Split('.').Aggregate((msg, result: ImmutableList <FieldDescriptor> .Empty), (acc, part) => { // TODO: Check nested fields aren't repeated. var fieldDesc = acc.msg.FindFieldByName(part); if (fieldDesc == null) { throw new InvalidOperationException($"Field '{part}' does not exist in message: {acc.msg.FullName}"); } return(fieldDesc.FieldType == FieldType.Message ? fieldDesc.MessageType : null, acc.result.Add(fieldDesc)); }, acc => acc.result); var lastDesc = Descs.Last(); Typ = ProtoTyp.Of(lastDesc); IsMap = lastDesc.IsMap; IsRepeated = lastDesc.IsRepeated; IsWrapperType = ProtoTyp.IsWrapperType(lastDesc); IsRequired = lastDesc.GetExtension(FieldBehaviorExtensions.FieldBehavior).Any(x => x == FieldBehavior.Required); ParameterName = lastDesc.CSharpFieldName(); PropertyName = lastDesc.CSharpPropertyName(); IsDeprecated = Descs.Any(x => x.IsDeprecated()); DocLines = lastDesc.Declaration.DocLines(); FieldResources = svc.Catalog.GetResourceDetailsByField(lastDesc); }
private MethodDetails(ServiceDetails svc, MethodDescriptor desc) { Svc = svc; ProtoRpcName = desc.Name; SyncMethodName = desc.Name; SyncSnippetMethodName = $"{desc.Name}RequestObject"; SyncTestMethodName = $"{desc.Name}RequestObject"; AsyncMethodName = $"{desc.Name}Async"; AsyncSnippetMethodName = $"{desc.Name}RequestObjectAsync"; AsyncTestMethodName = $"{desc.Name}RequestObjectAsync"; SettingsName = $"{desc.Name}Settings"; RequestTyp = ProtoTyp.Of(desc.InputType); ResponseTyp = ProtoTyp.Of(desc.OutputType); ApiCallFieldName = $"_call{desc.Name}"; ModifyApiCallMethodName = $"Modify_{desc.Name}ApiCall"; ModifyRequestMethodName = $"Modify_{RequestTyp.Name}"; DocLines = desc.Declaration.DocLines().ToList(); Signatures = desc.GetExtension(ClientExtensions.MethodSignature).Select(sig => new Signature(svc, desc.InputType, sig)).ToList(); RequestMessageDesc = desc.InputType; ResponseMessageDesc = desc.OutputType; var http = desc.GetExtension(AnnotationsExtensions.Http); var routing = desc.GetExtension(RoutingExtensions.Routing); RoutingHeaders = ReadRoutingHeaders(routing, http, desc.InputType).ToList(); (MethodRetry, MethodRetryStatusCodes, Expiration) = LoadTiming(svc, desc); // The method is considered deprecated if the RPC, request or response messages are deprecated. // In reality, it would be very odd to deprecate the messages without deprecating the RPC, but this makes it consistent. IsDeprecated = desc.IsDeprecated() || RequestMessageDesc.IsDeprecated() || ResponseMessageDesc.IsDeprecated(); }
private MethodDeclarationSyntax AbstractRequestMethod(bool sync, bool callSettings, IEnumerable <ParameterInfo> parameters, DocumentationCommentTriviaSyntax returnsXmlDoc = null) { var returnTyp = sync ? MethodDetails.SyncReturnTyp : MethodDetails.AsyncReturnTyp; var methodName = sync ? MethodDetails.SyncMethodName : MethodDetails.AsyncMethodName; var finalParam = callSettings ? _def.CallSettingsParam : _def.CancellationTokenParam; var finalParamXmlDoc = callSettings ? _def.CallSettingsXmlDoc : _def.CancellationTokenXmlDoc; returnsXmlDoc = returnsXmlDoc ?? (sync ? MethodDetails is MethodDetails.Paginated ? _def.ReturnsSyncPaginatedXmlDoc : _def.ReturnsSyncXmlDoc : MethodDetails is MethodDetails.Paginated ? _def.ReturnsAsyncPaginatedXmlDoc : _def.ReturnsAsyncXmlDoc); if (callSettings) { return(Method(Public | Virtual, Ctx.Type(returnTyp), methodName)(parameters.Select(x => x.Parameter).Append(finalParam).ToArray()) .MaybeWithAttribute(MethodDetails.IsDeprecated || _sig.HasDeprecatedField, () => Ctx.Type <ObsoleteAttribute>())() .WithBody(This.Call(methodName)(New(Ctx.Type(MethodDetails.RequestTyp))() .WithInitializer(NestInit(parameters, 0).ToArray()), finalParam)) .WithXmlDoc(parameters.Select(x => x.XmlDoc).Prepend(_def.SummaryXmlDoc).Append(finalParamXmlDoc).Append(returnsXmlDoc).ToArray())); IEnumerable <ObjectInitExpr> NestInit(IEnumerable <ParameterInfo> ps, int ofs) { var byField = ps.GroupBy(x => (x.FieldDescs ?? Enumerable.Empty <FieldDescriptor>()).Skip(ofs).SkipLast(1).FirstOrDefault()) .OrderBy(x => x.Key?.Index); foreach (var f in byField) { if (f.Key == null) { // No more nesting, these are the actual fields that need filling. foreach (var param in f.OrderBy(x => x.FieldDescs?.Last().Index ?? int.MaxValue)) { // Note: even if the signature includes a deprecated field, we don't indicate that in the // ObjectInitExpr, as we don't want or need the pragma when the method we're generating is obsolete. yield return((param.InitExpr as ObjectInitExpr) ?? new ObjectInitExpr(param.ResourcePropertyName ?? param.FieldDescs.Last().CSharpPropertyName(), param.InitExpr)); } } else { // Nested field. var code = New(Ctx.Type(ProtoTyp.Of(f.Key)))().WithInitializer(NestInit(f, ofs + 1).ToArray()); yield return(new ObjectInitExpr(f.Key.CSharpPropertyName(), code)); } } } } else { return(Method(Public | Virtual, Ctx.Type(returnTyp), methodName)(parameters.Select(x => x.Parameter).Append(finalParam).ToArray()) .MaybeWithAttribute(MethodDetails.IsDeprecated || _sig.HasDeprecatedField, () => Ctx.Type <ObsoleteAttribute>())() .WithBody(This.Call(methodName)(parameters.Select(x => (object)x.Parameter).Append( Ctx.Type <CallSettings>().Call(nameof(CallSettings.FromCancellationToken))(finalParam)))) .WithXmlDoc(parameters.Select(x => x.XmlDoc).Prepend(_def.SummaryXmlDoc).Append(finalParamXmlDoc).Append(returnsXmlDoc).ToArray())); } }
public Paginated(ServiceDetails svc, MethodDescriptor desc, FieldDescriptor responseResourceField, int pageSizeFieldNumber, int pageTokenFieldNumber) : base(svc, desc) { ResourceTyp = ProtoTyp.Of(responseResourceField, forceRepeated: false); ApiCallTyp = Typ.Generic(typeof(ApiCall <,>), RequestTyp, ResponseTyp); SyncReturnTyp = Typ.Generic(typeof(PagedEnumerable <,>), ResponseTyp, ResourceTyp); AsyncReturnTyp = Typ.Generic(typeof(PagedAsyncEnumerable <,>), ResponseTyp, ResourceTyp); SyncGrpcType = Typ.Generic(typeof(GrpcPagedEnumerable <, ,>), RequestTyp, ResponseTyp, ResourceTyp); AsyncGrpcType = Typ.Generic(typeof(GrpcPagedAsyncEnumerable <, ,>), RequestTyp, ResponseTyp, ResourceTyp); ResourcesFieldName = responseResourceField.CSharpPropertyName(); PageSizeFieldNumber = pageSizeFieldNumber; PageTokenFieldNumber = pageTokenFieldNumber; }
public Paginated(ServiceDetails svc, MethodDescriptor desc, FieldDescriptor responseResourceField, int pageSizeFieldNumber, int pageTokenFieldNumber) : base(svc, desc) { ResourceTyp = ProtoTyp.Of(responseResourceField, forceRepeated: false); // For map fields, ResourceTyp is a constructed KeyValuePair<,> type: we need the open type in a cref. ResourceTypForCref = responseResourceField.IsMap ? Typ.Generic(typeof(KeyValuePair <,>), Typ.GenericParam("TKey"), Typ.GenericParam("TValue")) : ResourceTyp; ApiCallTyp = Typ.Generic(typeof(ApiCall <,>), RequestTyp, ResponseTyp); SyncReturnTyp = Typ.Generic(typeof(PagedEnumerable <,>), ResponseTyp, ResourceTyp); AsyncReturnTyp = Typ.Generic(typeof(PagedAsyncEnumerable <,>), ResponseTyp, ResourceTyp); SyncGrpcType = Typ.Generic(typeof(GrpcPagedEnumerable <, ,>), RequestTyp, ResponseTyp, ResourceTyp); AsyncGrpcType = Typ.Generic(typeof(GrpcPagedAsyncEnumerable <, ,>), RequestTyp, ResponseTyp, ResourceTyp); ResourcesFieldName = responseResourceField.CSharpPropertyName(); PageSizeFieldNumber = pageSizeFieldNumber; PageTokenFieldNumber = pageTokenFieldNumber; }
private static MemberDeclarationSyntax PaginatedPartialInterfaceClass(SourceFileContext ctx, Typ typ, MessageDescriptor messageDesc) { var partialInterfaceCls = Class(Public | Partial, typ, baseTypes: ctx.Type <IPageRequest>()); if (messageDesc.FindFieldByName("page_size") is null) { //DiREGapic scenario where `max_results` is an option for a page size-semantic field. var maxResMessage = messageDesc.FindFieldByName("max_results"); if (maxResMessage is null) { throw new InvalidOperationException("Paginated request should have either page_size or max_results field."); } using (ctx.InClass(partialInterfaceCls)) { var underlyingProperty = Property(DontCare, ctx.TypeDontCare, "MaxResults"); var getBody = ProtoTyp.Of(maxResMessage) == Typ.Of <int>() ? Return(underlyingProperty) : Return(CheckedCast(ctx.Type <int>(), underlyingProperty)); var assignFrom = ProtoTyp.Of(maxResMessage) == Typ.Of <int>() ? Value : CheckedCast(ctx.Type(ProtoTyp.Of(maxResMessage)), Value); var setBody = underlyingProperty.Assign(assignFrom); var property = Property(Public, ctx.Type <int>(), "PageSize") .WithGetBody(getBody) .WithSetBody(setBody) .WithXmlDoc(XmlDoc.InheritDoc); partialInterfaceCls = partialInterfaceCls.AddMembers(property); } } return(partialInterfaceCls); }
private static ClassDeclarationSyntax GenerateClass(string ns, SourceFileContext ctx, IEnumerable <FileDescriptor> packageFileDescriptors) { var typ = Typ.Manual(ns, ClassName); var cls = Class(Internal | Static, typ) .WithXmlDoc(XmlDoc.Summary("Static class to provide common access to package-wide API metadata.")); var yieldStatements = packageFileDescriptors.Select(GenerateYieldStatement).ToArray(); var fileDescriptorMethod = Method(Private | Static, ctx.Type(Typ.Of <IEnumerable <FileDescriptor> >()), "GetFileDescriptors")() .WithBlockBody(yieldStatements); var apiMetadataType = ctx.Type <ApiMetadata>(); var property = AutoProperty(Internal | Static, apiMetadataType, PropertyName) .WithInitializer(New(apiMetadataType)(ns, IdentifierName(fileDescriptorMethod.Identifier))) .WithXmlDoc(XmlDoc.Summary("The ", apiMetadataType, " for services in this package.")); return(cls.AddMembers(property, fileDescriptorMethod)); YieldStatementSyntax GenerateYieldStatement(FileDescriptor descriptor) { var type = ctx.Type(ProtoTyp.OfReflectionClass(descriptor)); return(YieldStatement(SyntaxKind.YieldReturnStatement, type.Access("Descriptor"))); } }