github.com/go-kivik/kivik/v4@v4.3.2/x/fsdb/put.go (about) 1 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 2 // use this file except in compliance with the License. You may obtain a copy of 3 // the License at 4 // 5 // http://www.apache.org/licenses/LICENSE-2.0 6 // 7 // Unless required by applicable law or agreed to in writing, software 8 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 // License for the specific language governing permissions and limitations under 11 // the License. 12 13 package fs 14 15 import ( 16 "context" 17 "errors" 18 "net/http" 19 "net/url" 20 "os" 21 "strings" 22 23 "github.com/go-kivik/kivik/v4" 24 "github.com/go-kivik/kivik/v4/driver" 25 "github.com/go-kivik/kivik/v4/x/fsdb/cdb" 26 "github.com/go-kivik/kivik/v4/x/fsdb/cdb/decode" 27 ) 28 29 func filename2id(filename string) (string, error) { 30 return url.PathUnescape(filename) 31 } 32 33 type metaDoc struct { 34 Rev cdb.RevID `json:"_rev" yaml:"_rev"` 35 Deleted bool `json:"_deleted" yaml:"_deleted"` 36 } 37 38 func (d *db) metadata(docID, ext string) (rev string, deleted bool, err error) { 39 f, err := os.Open(d.path(docID)) 40 if err != nil { 41 if os.IsNotExist(err) { 42 err = nil 43 } 44 return "", false, err 45 } 46 md := new(metaDoc) 47 err = decode.Decode(f, ext, md) 48 return md.Rev.String(), md.Deleted, err 49 } 50 51 var reservedPrefixes = []string{"_local/", "_design/"} 52 53 func validateID(id string) error { 54 if id[0] != '_' { 55 return nil 56 } 57 for _, prefix := range reservedPrefixes { 58 if strings.HasPrefix(id, prefix) && len(id) > len(prefix) { 59 return nil 60 } 61 } 62 return statusError{status: http.StatusBadRequest, error: errors.New("only reserved document ids may start with underscore")} 63 } 64 65 /* 66 TODO: 67 URL query params: 68 batch 69 new_edits 70 71 output_format? 72 73 X-Couch-Full-Commit header/option 74 */ 75 76 func (d *db) Put(ctx context.Context, docID string, i interface{}, options driver.Options) (string, error) { 77 if err := validateID(docID); err != nil { 78 return "", err 79 } 80 rev, err := d.cdb.NewRevision(i) 81 if err != nil { 82 return "", err 83 } 84 doc, err := d.cdb.OpenDocID(docID, options) 85 switch { 86 case kivik.HTTPStatus(err) == http.StatusNotFound: 87 // Create new doc 88 doc = d.cdb.NewDocument(docID) 89 case err != nil: 90 return "", err 91 } 92 return doc.AddRevision(ctx, rev, options) 93 }