| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 | /* * EliasDB * * Copyright 2016 Matthias Ladkau. All rights reserved. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */package v1import (	"encoding/json"	"net/http"	"devt.de/krotik/eliasdb/api"	"devt.de/krotik/eliasdb/graph")/*EndpointIndexQuery is the index endpoint URL (rooted). Handles everything under index/...*/const EndpointIndexQuery = api.APIRoot + APIv1 + "/index/"/*IndexEndpointInst creates a new endpoint handler.*/func IndexEndpointInst() api.RestEndpointHandler {	return &indexEndpoint{}}/*Handler object for search queries.*/type indexEndpoint struct {	*api.DefaultEndpointHandler}/*HandleGET handles a search query REST call.*/func (ie *indexEndpoint) HandleGET(w http.ResponseWriter, r *http.Request, resources []string) {	var err error	// Check parameters	if !checkResources(w, resources, 3, 3, "Need a partition, entity type (n or e) and a kind") {		return	}	if resources[1] != "n" && resources[1] != "e" {		http.Error(w, "Entity type must be n (nodes) or e (edges)", http.StatusBadRequest)		return	}	// Check what is queried	attr := r.URL.Query().Get("attr")	if attr == "" {		http.Error(w, "Query string for attr (attribute) is required", http.StatusBadRequest)		return	}	phrase := r.URL.Query().Get("phrase")	word := r.URL.Query().Get("word")	value := r.URL.Query().Get("value")	// Get the index query object	var iq graph.IndexQuery	if resources[1] == "n" {		iq, err = api.GM.NodeIndexQuery(resources[0], resources[2])	} else {		iq, err = api.GM.EdgeIndexQuery(resources[0], resources[2])	}	if err != nil {		http.Error(w, err.Error(), http.StatusInternalServerError)		return	} else if iq == nil {		http.Error(w, "Unknown partition or node kind", http.StatusBadRequest)		return	}	// Do the lookup	var data interface{}	switch {	case phrase != "":		data, err = iq.LookupPhrase(attr, phrase)		if len(data.([]string)) == 0 {			data = []string{}		}	case word != "":		data, err = iq.LookupWord(attr, word)		if len(data.(map[string][]uint64)) == 0 {			data = map[string][]uint64{}		}	case value != "":		data, err = iq.LookupValue(attr, value)		if len(data.([]string)) == 0 {			data = []string{}		}	default:		http.Error(w, "Query string for either phrase, word or value is required", http.StatusBadRequest)		return	}	// Check if there was an error	if err != nil {		http.Error(w, err.Error(), http.StatusInternalServerError)		return	}	// Write data	w.Header().Set("content-type", "application/json; charset=utf-8")	ret := json.NewEncoder(w)	ret.Encode(data)}/*SwaggerDefs is used to describe the endpoint in swagger.*/func (ie *indexEndpoint) SwaggerDefs(s map[string]interface{}) {	s["paths"].(map[string]interface{})["/v1/index/{partition}/{entity_type}/{kind}"] = map[string]interface{}{		"get": map[string]interface{}{			"summary":     "Run index searches on the EliasDB datastore.",			"description": "The index endpoint should be used to run index searches for either a word, phrase or a whole value. All queries must specify a kind and an node/edge attribute.",			"produces": []string{				"text/plain",				"application/json",			},			"parameters": []map[string]interface{}{				{					"name":        "partition",					"in":          "path",					"description": "Partition to query.",					"required":    true,					"type":        "string",				},				{					"name": "entity_type",					"in":   "path",					"description": "Datastore entity type which should selected. " +						"Either n for nodes or e for edges.",					"required": true,					"type":     "string",				},				{					"name":        "kind",					"in":          "path",					"description": "Node or edge kind to be queried.",					"required":    true,					"type":        "string",				},				{					"name":        "attr",					"in":          "query",					"description": "Attribute which should contain the word, phrase or value.",					"required":    true,					"type":        "string",				},				{					"name":        "word",					"in":          "query",					"description": "Word to search for in word queries.",					"required":    false,					"type":        "string",				},				{					"name":        "phrase",					"in":          "query",					"description": "Phrase to search for in phrase queries.",					"required":    false,					"type":        "string",				},				{					"name":        "value",					"in":          "query",					"description": "Value (node/edge attribute value) to search for in value queries.",					"required":    false,					"type":        "string",				},			},			"responses": map[string]interface{}{				"200": map[string]interface{}{					"description": "A list of keys or when doing a word search a map with node/edge key to word positions.",				},				"default": map[string]interface{}{					"description": "Error response",					"schema": map[string]interface{}{						"$ref": "#/definitions/Error",					},				},			},		},	}	// Add generic error object to definition	s["definitions"].(map[string]interface{})["Error"] = map[string]interface{}{		"description": "A human readable error mesage.",		"type":        "string",	}}
 |