sobject/tree/tree.go (105 lines of code) (raw):

package tree import ( "bytes" "encoding/json" "errors" "fmt" "net/http" "regexp" "github.com/elastic/go-sfdc" "github.com/elastic/go-sfdc/session" ) // Inserter is used to define the SObject and it's records for the // composite tree API. type Inserter interface { SObject() string Records() []*Record } // InsertValue is the return value for each record. type InsertValue struct { ReferenceID string `json:"referenceId"` ID string `json:"id"` Errors []sfdc.Error `json:"errors"` } // Value is the return value from the API call. type Value struct { HasErrors bool `json:"hasErrors"` Results []InsertValue `json:"results"` } // Resource is the composite tree API resource. type Resource struct { session session.ServiceFormatter } const objectEndpoint = "/composite/tree/" // NewResource creates a new composite tree resource from the session. func NewResource(session session.ServiceFormatter) (*Resource, error) { if session == nil { return nil, errors.New("sobject tree: session can not be nil") } return &Resource{ session: session, }, nil } // Insert will call the composite tree API. func (r *Resource) Insert(inserter Inserter) (*Value, error) { if inserter == nil { return nil, errors.New("tree resourse: inserter can not be nil") } sobject := inserter.SObject() matching, err := regexp.MatchString(`\w`, sobject) if err != nil { return nil, err } if matching == false { return nil, fmt.Errorf("tree resourse: %s is not a valid sobject", sobject) } return r.callout(inserter) } func (r *Resource) callout(inserter Inserter) (*Value, error) { request, err := r.request(inserter) if err != nil { return nil, err } value, err := r.response(request) if err != nil { return nil, err } return &value, nil } func (r *Resource) request(inserter Inserter) (*http.Request, error) { url := r.session.ServiceURL() + objectEndpoint + inserter.SObject() body, err := r.payload(inserter) if err != nil { return nil, err } request, err := http.NewRequest(http.MethodPost, url, body) if err != nil { return nil, err } request.Header.Add("Accept", "application/json") request.Header.Add("Content-Type", "application/json") r.session.AuthorizationHeader(request) return request, nil } func (r *Resource) payload(inserter Inserter) (*bytes.Reader, error) { records := struct { Records []*Record `json:"records"` }{ Records: inserter.Records(), } payload, err := json.Marshal(records) if err != nil { return nil, err } return bytes.NewReader(payload), nil } func (r *Resource) response(request *http.Request) (Value, error) { response, err := r.session.Client().Do(request) if err != nil { return Value{}, err } decoder := json.NewDecoder(response.Body) defer response.Body.Close() var value Value err = decoder.Decode(&value) if err != nil { return Value{}, err } if response.StatusCode != http.StatusCreated { return value, fmt.Errorf("insert response err: %d %s", response.StatusCode, response.Status) } return value, nil }