added additional http handlers to cover most functionality
This commit is contained in:
parent
34afb0929e
commit
d164b017b2
|
@ -0,0 +1,49 @@
|
|||
// Copyright (c) 2014 Couchbase, Inc.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
// except in compliance with the License. You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
package http
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
type DocCountHandler struct {
|
||||
defaultIndexName string
|
||||
}
|
||||
|
||||
func NewDocCountHandler(defaultIndexName string) *DocCountHandler {
|
||||
return &DocCountHandler{
|
||||
defaultIndexName: defaultIndexName,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *DocCountHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
// find the index to operate on
|
||||
indexName := mux.Vars(req)["indexName"]
|
||||
if indexName == "" {
|
||||
indexName = h.defaultIndexName
|
||||
}
|
||||
index := IndexByName(indexName)
|
||||
if index == nil {
|
||||
showError(w, req, fmt.Sprintf("no such index '%s'", indexName), 404)
|
||||
return
|
||||
}
|
||||
|
||||
docCount := index.DocCount()
|
||||
rv := struct {
|
||||
Status string `json:"status"`
|
||||
Count uint64
|
||||
}{
|
||||
Status: "ok",
|
||||
Count: docCount,
|
||||
}
|
||||
mustEncode(w, rv)
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright (c) 2014 Couchbase, Inc.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
// except in compliance with the License. You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
package http
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
type DocDeleteHandler struct {
|
||||
defaultIndexName string
|
||||
}
|
||||
|
||||
func NewDocDeleteHandler(defaultIndexName string) *DocDeleteHandler {
|
||||
return &DocDeleteHandler{
|
||||
defaultIndexName: defaultIndexName,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *DocDeleteHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
|
||||
// find the index to operate on
|
||||
indexName := mux.Vars(req)["indexName"]
|
||||
if indexName == "" {
|
||||
indexName = h.defaultIndexName
|
||||
}
|
||||
index := IndexByName(indexName)
|
||||
if index == nil {
|
||||
showError(w, req, fmt.Sprintf("no such index '%s'", indexName), 404)
|
||||
return
|
||||
}
|
||||
|
||||
// find the doc id
|
||||
docId := mux.Vars(req)["docId"]
|
||||
if docId == "" {
|
||||
showError(w, req, "document id cannot be empty", 400)
|
||||
return
|
||||
}
|
||||
|
||||
err := index.Delete(docId)
|
||||
if err != nil {
|
||||
showError(w, req, fmt.Sprintf("error deleting document '%s': %v", docId, err), 500)
|
||||
return
|
||||
}
|
||||
|
||||
rv := struct {
|
||||
Status string `json:"status"`
|
||||
}{
|
||||
Status: "ok",
|
||||
}
|
||||
mustEncode(w, rv)
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
// Copyright (c) 2014 Couchbase, Inc.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
// except in compliance with the License. You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
package http
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/couchbaselabs/bleve/document"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
type DocGetHandler struct {
|
||||
defaultIndexName string
|
||||
}
|
||||
|
||||
func NewDocGetHandler(defaultIndexName string) *DocGetHandler {
|
||||
return &DocGetHandler{
|
||||
defaultIndexName: defaultIndexName,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *DocGetHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
// find the index to operate on
|
||||
indexName := mux.Vars(req)["indexName"]
|
||||
if indexName == "" {
|
||||
indexName = h.defaultIndexName
|
||||
}
|
||||
index := IndexByName(indexName)
|
||||
if index == nil {
|
||||
showError(w, req, fmt.Sprintf("no such index '%s'", indexName), 404)
|
||||
return
|
||||
}
|
||||
|
||||
// find the doc id
|
||||
docId := mux.Vars(req)["docId"]
|
||||
if docId == "" {
|
||||
showError(w, req, "document id cannot be empty", 400)
|
||||
return
|
||||
}
|
||||
|
||||
doc, err := index.Document(docId)
|
||||
if err != nil {
|
||||
showError(w, req, fmt.Sprintf("error deleting document '%s': %v", docId, err), 500)
|
||||
return
|
||||
}
|
||||
if doc == nil {
|
||||
showError(w, req, fmt.Sprintf("no such document '%s'", docId), 404)
|
||||
return
|
||||
}
|
||||
|
||||
rv := struct {
|
||||
ID string `json:"id"`
|
||||
Fields map[string]interface{} `json:"fields"`
|
||||
}{
|
||||
ID: docId,
|
||||
Fields: map[string]interface{}{},
|
||||
}
|
||||
for _, field := range doc.Fields {
|
||||
var newval interface{}
|
||||
switch field := field.(type) {
|
||||
case *document.TextField:
|
||||
newval = string(field.Value())
|
||||
case *document.NumericField:
|
||||
n, err := field.Number()
|
||||
if err == nil {
|
||||
newval = n
|
||||
}
|
||||
case *document.DateTimeField:
|
||||
d, err := field.DateTime()
|
||||
if err == nil {
|
||||
newval = d.Format(time.RFC3339Nano)
|
||||
}
|
||||
}
|
||||
existing, existed := rv.Fields[field.Name()]
|
||||
if existed {
|
||||
switch existing := existing.(type) {
|
||||
case []interface{}:
|
||||
rv.Fields[field.Name()] = append(existing, newval)
|
||||
case interface{}:
|
||||
arr := make([]interface{}, 2)
|
||||
arr[0] = existing
|
||||
arr[1] = newval
|
||||
rv.Fields[field.Name()] = arr
|
||||
}
|
||||
} else {
|
||||
rv.Fields[field.Name()] = newval
|
||||
}
|
||||
}
|
||||
|
||||
mustEncode(w, rv)
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright (c) 2014 Couchbase, Inc.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
// except in compliance with the License. You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
package http
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
type DocIndexHandler struct {
|
||||
defaultIndexName string
|
||||
}
|
||||
|
||||
func NewDocIndexHandler(defaultIndexName string) *DocIndexHandler {
|
||||
return &DocIndexHandler{
|
||||
defaultIndexName: defaultIndexName,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *DocIndexHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
|
||||
// find the index to operate on
|
||||
indexName := mux.Vars(req)["indexName"]
|
||||
if indexName == "" {
|
||||
indexName = h.defaultIndexName
|
||||
}
|
||||
index := IndexByName(indexName)
|
||||
if index == nil {
|
||||
showError(w, req, fmt.Sprintf("no such index '%s'", indexName), 404)
|
||||
return
|
||||
}
|
||||
|
||||
// find the doc id
|
||||
docId := mux.Vars(req)["docId"]
|
||||
if docId == "" {
|
||||
showError(w, req, "document id cannot be empty", 400)
|
||||
return
|
||||
}
|
||||
|
||||
// read the request body
|
||||
requestBody, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
showError(w, req, fmt.Sprintf("error reading request body: %v", err), 400)
|
||||
return
|
||||
}
|
||||
|
||||
err = index.Index(docId, requestBody)
|
||||
if err != nil {
|
||||
showError(w, req, fmt.Sprintf("error indexing document '%s': %v", docId, err), 500)
|
||||
return
|
||||
}
|
||||
|
||||
rv := struct {
|
||||
Status string `json:"status"`
|
||||
}{
|
||||
Status: "ok",
|
||||
}
|
||||
mustEncode(w, rv)
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright (c) 2014 Couchbase, Inc.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
// except in compliance with the License. You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
package http
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/couchbaselabs/bleve"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
type CreateIndexHandler struct {
|
||||
basePath string
|
||||
}
|
||||
|
||||
func NewCreateIndexHander(basePath string) *CreateIndexHandler {
|
||||
return &CreateIndexHandler{
|
||||
basePath: basePath,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *CreateIndexHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
// find the name of the index to create
|
||||
indexName := mux.Vars(req)["indexName"]
|
||||
if indexName == "" {
|
||||
showError(w, req, fmt.Sprintf("index name is required", indexName), 400)
|
||||
return
|
||||
}
|
||||
|
||||
indexMapping := bleve.NewIndexMapping()
|
||||
|
||||
// read the request body
|
||||
requestBody, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
showError(w, req, fmt.Sprintf("error reading request body: %v", err), 400)
|
||||
return
|
||||
}
|
||||
|
||||
// interpret request body as index mapping
|
||||
if len(requestBody) > 0 {
|
||||
err := json.Unmarshal(requestBody, &indexMapping)
|
||||
if err != nil {
|
||||
showError(w, req, fmt.Sprintf("error parsing index mapping: %v", err), 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
newIndex, err := bleve.New(h.indexPath(indexName), indexMapping)
|
||||
if err != nil {
|
||||
showError(w, req, fmt.Sprintf("error creating index: %v", err), 500)
|
||||
return
|
||||
}
|
||||
RegisterIndexName(indexName, newIndex)
|
||||
rv := struct {
|
||||
Status string `json:"status"`
|
||||
}{
|
||||
Status: "ok",
|
||||
}
|
||||
mustEncode(w, rv)
|
||||
}
|
||||
|
||||
func (h *CreateIndexHandler) indexPath(name string) string {
|
||||
return h.basePath + string(os.PathSeparator) + name
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright (c) 2014 Couchbase, Inc.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
// except in compliance with the License. You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
package http
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
type DeleteIndexHandler struct {
|
||||
basePath string
|
||||
}
|
||||
|
||||
func NewDeleteIndexHandler(basePath string) *DeleteIndexHandler {
|
||||
return &DeleteIndexHandler{
|
||||
basePath: basePath,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *DeleteIndexHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
// find the name of the index to delete
|
||||
indexName := mux.Vars(req)["indexName"]
|
||||
if indexName == "" {
|
||||
showError(w, req, fmt.Sprintf("index name is required", indexName), 400)
|
||||
return
|
||||
}
|
||||
|
||||
indexToDelete := UnregisterIndexByName(indexName)
|
||||
if indexToDelete == nil {
|
||||
showError(w, req, fmt.Sprintf("no such index '%s'", indexName), 404)
|
||||
return
|
||||
}
|
||||
|
||||
// close the index
|
||||
indexToDelete.Close()
|
||||
|
||||
// now delete it
|
||||
err := os.RemoveAll(h.indexPath(indexName))
|
||||
if err != nil {
|
||||
showError(w, req, fmt.Sprintf("error deletoing index: %v", err), 500)
|
||||
return
|
||||
}
|
||||
|
||||
rv := struct {
|
||||
Status string `json:"status"`
|
||||
}{
|
||||
Status: "ok",
|
||||
}
|
||||
mustEncode(w, rv)
|
||||
}
|
||||
|
||||
func (h *DeleteIndexHandler) indexPath(name string) string {
|
||||
return h.basePath + string(os.PathSeparator) + name
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright (c) 2014 Couchbase, Inc.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
// except in compliance with the License. You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
package http
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/couchbaselabs/bleve"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
type GetIndexHandler struct{}
|
||||
|
||||
func NewGetIndexHandler() *GetIndexHandler {
|
||||
return &GetIndexHandler{}
|
||||
}
|
||||
|
||||
func (h *GetIndexHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
// find the name of the index to create
|
||||
indexName := mux.Vars(req)["indexName"]
|
||||
if indexName == "" {
|
||||
showError(w, req, fmt.Sprintf("index name is required", indexName), 400)
|
||||
return
|
||||
}
|
||||
|
||||
index := IndexByName(indexName)
|
||||
if index == nil {
|
||||
showError(w, req, fmt.Sprintf("no such index '%s'", indexName), 404)
|
||||
return
|
||||
}
|
||||
|
||||
rv := struct {
|
||||
Status string `json:"status"`
|
||||
Name string `json:"name"`
|
||||
Mapping *bleve.IndexMapping `json:"mapping"`
|
||||
}{
|
||||
Status: "ok",
|
||||
Name: indexName,
|
||||
Mapping: index.Mapping(),
|
||||
}
|
||||
mustEncode(w, rv)
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright (c) 2014 Couchbase, Inc.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
// except in compliance with the License. You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
package http
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type ListIndexesHandler struct{}
|
||||
|
||||
func NewListIndexesHander() *ListIndexesHandler {
|
||||
return &ListIndexesHandler{}
|
||||
}
|
||||
|
||||
func (h *ListIndexesHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
indexNames := IndexNames()
|
||||
rv := struct {
|
||||
Status string `json:"status"`
|
||||
Indexes []string `json:"indexes"`
|
||||
}{
|
||||
Status: "ok",
|
||||
Indexes: indexNames,
|
||||
}
|
||||
mustEncode(w, rv)
|
||||
}
|
|
@ -27,9 +27,36 @@ func RegisterIndexName(name string, index bleve.Index) {
|
|||
indexNameMapping[name] = index
|
||||
}
|
||||
|
||||
func UnregisterIndexByName(name string) bleve.Index {
|
||||
indexNameMappingLock.Lock()
|
||||
defer indexNameMappingLock.Unlock()
|
||||
|
||||
if indexNameMapping == nil {
|
||||
return nil
|
||||
}
|
||||
rv := indexNameMapping[name]
|
||||
if rv != nil {
|
||||
delete(indexNameMapping, name)
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
func IndexByName(name string) bleve.Index {
|
||||
indexNameMappingLock.RLock()
|
||||
defer indexNameMappingLock.RUnlock()
|
||||
|
||||
return indexNameMapping[name]
|
||||
}
|
||||
|
||||
func IndexNames() []string {
|
||||
indexNameMappingLock.RLock()
|
||||
defer indexNameMappingLock.RUnlock()
|
||||
|
||||
rv := make([]string, len(indexNameMapping))
|
||||
count := 0
|
||||
for k, _ := range indexNameMapping {
|
||||
rv[count] = k
|
||||
count++
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
|
|
@ -18,8 +18,8 @@ import (
|
|||
type DocumentMapping struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
Dynamic bool `json:"dynamic"`
|
||||
Properties map[string]*DocumentMapping `json:"properties"`
|
||||
Fields []*FieldMapping `json:"fields"`
|
||||
Properties map[string]*DocumentMapping `json:"properties,omitempty"`
|
||||
Fields []*FieldMapping `json:"fields,omitempty"`
|
||||
DefaultAnalyzer string `json:"default_analyzer"`
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ const DefaultDateTimeParser = "dateTimeOptional"
|
|||
const DefaultByteArrayConverter = "json"
|
||||
|
||||
type IndexMapping struct {
|
||||
TypeMapping map[string]*DocumentMapping `json:"types"`
|
||||
TypeMapping map[string]*DocumentMapping `json:"types,omitempty"`
|
||||
DefaultMapping *DocumentMapping `json:"default_mapping"`
|
||||
TypeField string `json:"type_field"`
|
||||
DefaultType string `json:"default_type"`
|
||||
|
|
Loading…
Reference in New Issue