mirror of
https://github.com/openai/openai-go.git
synced 2026-04-01 17:17:14 +09:00
187 lines
5.0 KiB
Go
187 lines
5.0 KiB
Go
package param
|
|
|
|
import (
|
|
"encoding/json"
|
|
"github.com/openai/openai-go/v3/internal/encoding/json/sentinel"
|
|
"reflect"
|
|
)
|
|
|
|
// NullStruct is used to set a struct to the JSON value null.
|
|
// Check for null structs with [IsNull].
|
|
//
|
|
// Only the first type parameter should be provided,
|
|
// the type PtrT will be inferred.
|
|
//
|
|
// json.Marshal(param.NullStruct[MyStruct]()) -> 'null'
|
|
//
|
|
// To send null to an [Opt] field use [Null].
|
|
func NullStruct[T ParamStruct, PtrT InferPtr[T]]() T {
|
|
var t T
|
|
pt := PtrT(&t)
|
|
pt.setMetadata(nil)
|
|
return *pt
|
|
}
|
|
|
|
// Override replaces the value of a struct with any type.
|
|
//
|
|
// Only the first type parameter should be provided,
|
|
// the type PtrT will be inferred.
|
|
//
|
|
// It's often useful for providing raw JSON
|
|
//
|
|
// param.Override[MyStruct](json.RawMessage(`{"foo": "bar"}`))
|
|
//
|
|
// The public fields of the returned struct T will be unset.
|
|
//
|
|
// To override a specific field in a struct, use its [SetExtraFields] method.
|
|
func Override[T ParamStruct, PtrT InferPtr[T]](v any) T {
|
|
var t T
|
|
pt := PtrT(&t)
|
|
pt.setMetadata(v)
|
|
return *pt
|
|
}
|
|
|
|
// SetJSON configures a param struct to serialize with the provided raw JSON data.
|
|
// Use this when you have existing JSON that you want to send as request parameters.
|
|
//
|
|
// var req example.NewUserParams
|
|
// var rawJSON = []byte(`{"name": "...", "age": 40}`)
|
|
// param.SetJSON(rawJSON, &req)
|
|
// res, err := client.Users.New(ctx, req)
|
|
//
|
|
// Note: The struct's existing fields will be ignored; only the provided JSON is serialized.
|
|
func SetJSON(rawJSON []byte, ptr anyParamStruct) {
|
|
ptr.setMetadata(json.RawMessage(rawJSON))
|
|
}
|
|
|
|
// IsOmitted returns true if v is the zero value of its type.
|
|
//
|
|
// If IsOmitted is true, and the field uses a `json:"...,omitzero"` tag,
|
|
// the field will be omitted from the request.
|
|
//
|
|
// If v is set explicitly to the JSON value "null", IsOmitted returns false.
|
|
func IsOmitted(v any) bool {
|
|
if v == nil {
|
|
return false
|
|
}
|
|
if o, ok := v.(Optional); ok {
|
|
return o.isZero()
|
|
}
|
|
return reflect.ValueOf(v).IsZero()
|
|
}
|
|
|
|
// IsNull returns true if v was set to the JSON value null.
|
|
//
|
|
// To set a param to null use [NullStruct], [Null], [NullMap], or [NullSlice]
|
|
// depending on the type of v.
|
|
//
|
|
// IsNull returns false if the value is omitted.
|
|
func IsNull[T any](v T) bool {
|
|
if nullable, ok := any(v).(ParamNullable); ok {
|
|
return nullable.null()
|
|
}
|
|
|
|
switch reflect.TypeOf(v).Kind() {
|
|
case reflect.Slice, reflect.Map:
|
|
return sentinel.IsNull(v)
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// ParamNullable encapsulates all structs in parameters,
|
|
// and all [Opt] types in parameters.
|
|
type ParamNullable interface {
|
|
null() bool
|
|
}
|
|
|
|
// ParamStruct represents the set of all structs that are
|
|
// used in API parameters, by convention these usually end in
|
|
// "Params" or "Param".
|
|
type ParamStruct interface {
|
|
Overrides() (any, bool)
|
|
null() bool
|
|
extraFields() map[string]any
|
|
}
|
|
|
|
// A pointer to ParamStruct
|
|
type anyParamStruct interface {
|
|
setMetadata(any)
|
|
}
|
|
|
|
// This is an implementation detail and should never be explicitly set.
|
|
type InferPtr[T ParamStruct] interface {
|
|
setMetadata(any)
|
|
*T
|
|
}
|
|
|
|
// APIObject should be embedded in api object fields, preferably using an alias to make private
|
|
type APIObject struct{ metadata }
|
|
|
|
// APIUnion should be embedded in all api unions fields, preferably using an alias to make private
|
|
type APIUnion struct{ metadata }
|
|
|
|
// Overrides returns the value of the struct when it is created with
|
|
// [Override], the second argument helps differentiate an explicit null.
|
|
func (m metadata) Overrides() (any, bool) {
|
|
if _, ok := m.any.(metadataExtraFields); ok {
|
|
return nil, false
|
|
}
|
|
return m.any, m.any != nil
|
|
}
|
|
|
|
// ExtraFields returns the extra fields added to the JSON object.
|
|
func (m metadata) ExtraFields() map[string]any {
|
|
if extras, ok := m.any.(metadataExtraFields); ok {
|
|
return extras
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Omit can be used with [metadata.SetExtraFields] to ensure that a
|
|
// required field is omitted. This is useful as an escape hatch for
|
|
// when a required is unwanted for some unexpected reason.
|
|
const Omit forceOmit = -1
|
|
|
|
// SetExtraFields adds extra fields to the JSON object.
|
|
//
|
|
// SetExtraFields will override any existing fields with the same key.
|
|
// For security reasons, ensure this is only used with trusted input data.
|
|
//
|
|
// To intentionally omit a required field, use [Omit].
|
|
//
|
|
// foo.SetExtraFields(map[string]any{"bar": Omit})
|
|
//
|
|
// If the struct already contains the field ExtraFields, then this
|
|
// method will have no effect.
|
|
func (m *metadata) SetExtraFields(extraFields map[string]any) {
|
|
m.any = metadataExtraFields(extraFields)
|
|
}
|
|
|
|
// extraFields aliases [metadata.ExtraFields] to avoid name collisions.
|
|
func (m metadata) extraFields() map[string]any { return m.ExtraFields() }
|
|
|
|
func (m metadata) null() bool {
|
|
if _, ok := m.any.(metadataNull); ok {
|
|
return true
|
|
}
|
|
|
|
if msg, ok := m.any.(json.RawMessage); ok {
|
|
return string(msg) == "null"
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
type metadata struct{ any }
|
|
type metadataNull struct{}
|
|
type metadataExtraFields map[string]any
|
|
|
|
func (m *metadata) setMetadata(override any) {
|
|
if override == nil {
|
|
m.any = metadataNull{}
|
|
return
|
|
}
|
|
m.any = override
|
|
}
|