integrate request builder into HTTP client for googleapis support (#159)
This commit is contained in:
		
							
								
								
									
										116
									
								
								builder/body.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								builder/body.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,116 @@ | ||||
| package builder | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"google.golang.org/protobuf/proto" | ||||
| 	"google.golang.org/protobuf/reflect/protoreflect" | ||||
| ) | ||||
|  | ||||
| func buildSingleFieldBody(msg proto.Message, fieldName string) (proto.Message, error) { | ||||
| 	msgReflect := msg.ProtoReflect() | ||||
|  | ||||
| 	fd, found := findFieldByName(msgReflect, fieldName) | ||||
| 	if !found || fd == nil { | ||||
| 		return nil, fmt.Errorf("field %s not found", fieldName) | ||||
| 	} | ||||
| 	if !msgReflect.Has(fd) { | ||||
| 		return nil, fmt.Errorf("field %s is not set", fieldName) | ||||
| 	} | ||||
|  | ||||
| 	val := msgReflect.Get(fd) | ||||
|  | ||||
| 	if fd.Kind() == protoreflect.MessageKind { | ||||
| 		return val.Message().Interface(), nil | ||||
| 	} | ||||
|  | ||||
| 	newMsg := proto.Clone(msg) | ||||
| 	newMsgReflect := newMsg.ProtoReflect() | ||||
| 	newMsgReflect.Range(func(f protoreflect.FieldDescriptor, _ protoreflect.Value) bool { | ||||
| 		if f != fd { | ||||
| 			newMsgReflect.Clear(f) | ||||
| 		} | ||||
| 		return true | ||||
| 	}) | ||||
|  | ||||
| 	return newMsg, nil | ||||
| } | ||||
|  | ||||
| func buildFullBody(msg proto.Message, usedFieldsPath *usedFields) (proto.Message, error) { | ||||
| 	var ( | ||||
| 		msgReflect    = msg.ProtoReflect() | ||||
| 		newMsg        = msgReflect.New().Interface() | ||||
| 		newMsgReflect = newMsg.ProtoReflect() | ||||
| 	) | ||||
|  | ||||
| 	fields := msgReflect.Descriptor().Fields() | ||||
| 	for i := 0; i < fields.Len(); i++ { | ||||
| 		fd := fields.Get(i) | ||||
| 		fieldName := fd.JSONName() | ||||
|  | ||||
| 		if usedFieldsPath.hasTopLevelKey(fieldName) { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		val := msgReflect.Get(fd) | ||||
| 		if !val.IsValid() { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		// Note: order of the cases is important! | ||||
| 		switch { | ||||
| 		case fd.IsList(): | ||||
| 			list := val.List() | ||||
| 			newList := newMsgReflect.Mutable(fd).List() | ||||
|  | ||||
| 			if fd.Kind() == protoreflect.MessageKind { | ||||
| 				for j := 0; j < list.Len(); j++ { | ||||
| 					elem, err := buildFullBody(list.Get(j).Message().Interface(), usedFieldsPath) | ||||
| 					if err != nil { | ||||
| 						return nil, fmt.Errorf("recursive build full body: %w", err) | ||||
| 					} | ||||
| 					newList.Append(protoreflect.ValueOfMessage(elem.ProtoReflect())) | ||||
| 				} | ||||
| 			} else { | ||||
| 				for j := 0; j < list.Len(); j++ { | ||||
| 					newList.Append(list.Get(j)) | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 		case fd.IsMap(): | ||||
| 			var ( | ||||
| 				m        = val.Map() | ||||
| 				newMap   = newMsgReflect.Mutable(fd).Map() | ||||
| 				rangeErr error | ||||
| 			) | ||||
| 			m.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool { | ||||
| 				if fd.MapValue().Kind() == protoreflect.MessageKind { | ||||
| 					elem, err := buildFullBody(v.Message().Interface(), usedFieldsPath) | ||||
| 					if err != nil { | ||||
| 						rangeErr = fmt.Errorf("recursive build full body: %w", err) | ||||
| 						return false | ||||
| 					} | ||||
| 					newMap.Set(k, protoreflect.ValueOfMessage(elem.ProtoReflect())) | ||||
| 				} else { | ||||
| 					newMap.Set(k, v) | ||||
| 				} | ||||
| 				return true | ||||
| 			}) | ||||
| 			if rangeErr != nil { | ||||
| 				return nil, fmt.Errorf("map range error: %w", rangeErr) | ||||
| 			} | ||||
|  | ||||
| 		case fd.Kind() == protoreflect.MessageKind: | ||||
| 			elem, err := buildFullBody(val.Message().Interface(), usedFieldsPath) | ||||
| 			if err != nil { | ||||
| 				return nil, fmt.Errorf("recursive build full body: %w", err) | ||||
| 			} | ||||
| 			newMsgReflect.Set(fd, protoreflect.ValueOfMessage(elem.ProtoReflect())) | ||||
|  | ||||
| 		default: | ||||
| 			newMsgReflect.Set(fd, val) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return newMsg, nil | ||||
| } | ||||
		Reference in New Issue
	
	Block a user