1// Copyright 2012-present Oliver Eilhard. All rights reserved. 2// Use of this source code is governed by a MIT-license. 3// See http://olivere.mit-license.org/license.txt for details. 4 5package elastic 6 7import ( 8 "context" 9 "fmt" 10 "net/http" 11 "net/url" 12 13 "github.com/olivere/elastic/uritemplates" 14) 15 16// DeleteService allows to delete a typed JSON document from a specified 17// index based on its id. 18// 19// See https://www.elastic.co/guide/en/elasticsearch/reference/6.7/docs-delete.html 20// for details. 21type DeleteService struct { 22 client *Client 23 pretty bool 24 id string 25 index string 26 typ string 27 routing string 28 timeout string 29 version interface{} 30 versionType string 31 waitForActiveShards string 32 parent string 33 refresh string 34} 35 36// NewDeleteService creates a new DeleteService. 37func NewDeleteService(client *Client) *DeleteService { 38 return &DeleteService{ 39 client: client, 40 } 41} 42 43// Type is the type of the document. 44func (s *DeleteService) Type(typ string) *DeleteService { 45 s.typ = typ 46 return s 47} 48 49// Id is the document ID. 50func (s *DeleteService) Id(id string) *DeleteService { 51 s.id = id 52 return s 53} 54 55// Index is the name of the index. 56func (s *DeleteService) Index(index string) *DeleteService { 57 s.index = index 58 return s 59} 60 61// Routing is a specific routing value. 62func (s *DeleteService) Routing(routing string) *DeleteService { 63 s.routing = routing 64 return s 65} 66 67// Timeout is an explicit operation timeout. 68func (s *DeleteService) Timeout(timeout string) *DeleteService { 69 s.timeout = timeout 70 return s 71} 72 73// Version is an explicit version number for concurrency control. 74func (s *DeleteService) Version(version interface{}) *DeleteService { 75 s.version = version 76 return s 77} 78 79// VersionType is a specific version type. 80func (s *DeleteService) VersionType(versionType string) *DeleteService { 81 s.versionType = versionType 82 return s 83} 84 85// WaitForActiveShards sets the number of shard copies that must be active 86// before proceeding with the delete operation. Defaults to 1, meaning the 87// primary shard only. Set to `all` for all shard copies, otherwise set to 88// any non-negative value less than or equal to the total number of copies 89// for the shard (number of replicas + 1). 90func (s *DeleteService) WaitForActiveShards(waitForActiveShards string) *DeleteService { 91 s.waitForActiveShards = waitForActiveShards 92 return s 93} 94 95// Parent is the ID of parent document. 96func (s *DeleteService) Parent(parent string) *DeleteService { 97 s.parent = parent 98 return s 99} 100 101// Refresh the index after performing the operation. 102// 103// See https://www.elastic.co/guide/en/elasticsearch/reference/6.7/docs-refresh.html 104// for details. 105func (s *DeleteService) Refresh(refresh string) *DeleteService { 106 s.refresh = refresh 107 return s 108} 109 110// Pretty indicates that the JSON response be indented and human readable. 111func (s *DeleteService) Pretty(pretty bool) *DeleteService { 112 s.pretty = pretty 113 return s 114} 115 116// buildURL builds the URL for the operation. 117func (s *DeleteService) buildURL() (string, url.Values, error) { 118 // Build URL 119 path, err := uritemplates.Expand("/{index}/{type}/{id}", map[string]string{ 120 "index": s.index, 121 "type": s.typ, 122 "id": s.id, 123 }) 124 if err != nil { 125 return "", url.Values{}, err 126 } 127 128 // Add query string parameters 129 params := url.Values{} 130 if s.pretty { 131 params.Set("pretty", "true") 132 } 133 if s.refresh != "" { 134 params.Set("refresh", s.refresh) 135 } 136 if s.routing != "" { 137 params.Set("routing", s.routing) 138 } 139 if s.timeout != "" { 140 params.Set("timeout", s.timeout) 141 } 142 if s.version != nil { 143 params.Set("version", fmt.Sprintf("%v", s.version)) 144 } 145 if s.versionType != "" { 146 params.Set("version_type", s.versionType) 147 } 148 if s.waitForActiveShards != "" { 149 params.Set("wait_for_active_shards", s.waitForActiveShards) 150 } 151 if s.parent != "" { 152 params.Set("parent", s.parent) 153 } 154 return path, params, nil 155} 156 157// Validate checks if the operation is valid. 158func (s *DeleteService) Validate() error { 159 var invalid []string 160 if s.typ == "" { 161 invalid = append(invalid, "Type") 162 } 163 if s.id == "" { 164 invalid = append(invalid, "Id") 165 } 166 if s.index == "" { 167 invalid = append(invalid, "Index") 168 } 169 if len(invalid) > 0 { 170 return fmt.Errorf("missing required fields: %v", invalid) 171 } 172 return nil 173} 174 175// Do executes the operation. If the document is not found (404), Elasticsearch will 176// still return a response. This response is serialized and returned as well. In other 177// words, for HTTP status code 404, both an error and a response might be returned. 178func (s *DeleteService) Do(ctx context.Context) (*DeleteResponse, error) { 179 // Check pre-conditions 180 if err := s.Validate(); err != nil { 181 return nil, err 182 } 183 184 // Get URL for request 185 path, params, err := s.buildURL() 186 if err != nil { 187 return nil, err 188 } 189 190 // Get HTTP response 191 res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ 192 Method: "DELETE", 193 Path: path, 194 Params: params, 195 IgnoreErrors: []int{http.StatusNotFound}, 196 }) 197 if err != nil { 198 return nil, err 199 } 200 201 // Return operation response 202 ret := new(DeleteResponse) 203 if err := s.client.decoder.Decode(res.Body, ret); err != nil { 204 return nil, err 205 } 206 207 // If we have a 404, we return both a result and an error, just like ES does 208 if res.StatusCode == http.StatusNotFound { 209 return ret, &Error{Status: http.StatusNotFound} 210 } 211 212 return ret, nil 213} 214 215// -- Result of a delete request. 216 217// DeleteResponse is the outcome of running DeleteService.Do. 218type DeleteResponse struct { 219 Index string `json:"_index,omitempty"` 220 Type string `json:"_type,omitempty"` 221 Id string `json:"_id,omitempty"` 222 Version int64 `json:"_version,omitempty"` 223 Result string `json:"result,omitempty"` 224 Shards *ShardsInfo `json:"_shards,omitempty"` 225 SeqNo int64 `json:"_seq_no,omitempty"` 226 PrimaryTerm int64 `json:"_primary_term,omitempty"` 227 Status int `json:"status,omitempty"` 228 ForcedRefresh bool `json:"forced_refresh,omitempty"` 229} 230