diff --git a/pkg/api/doc_find.go b/pkg/api/doc_find.go index 36b21044..d52e6ffa 100644 --- a/pkg/api/doc_find.go +++ b/pkg/api/doc_find.go @@ -29,6 +29,11 @@ type DocFindResponse struct { Docs [][]byte `json:"docs"` } +// DocFind is used for listing rows from a document database +type DocFind struct { + Docs []string `json:"docs"` +} + // DocFindHandler godoc // // @Summary Get rows from a given doc datastore @@ -38,10 +43,10 @@ type DocFindResponse struct { // @Produce json // @Param podName query string true "pod name" // @Param tableName query string true "table name" -// @Param expr query string true "expression to search for" +// @Param expr query string true "expression to search for. allowed operators in expr are =, >, =>, <=, <. eg: 'first_name=>John', 'first_name=>J.', 'first_name=>.', 'age=>30', 'age<=30'. if index is string, expr supports regex. we do not have support for multiple conditions in expr yet" // @Param limit query string false "number od documents" // @Param Cookie header string true "cookie parameter" -// @Success 200 {object} DocFindResponse +// @Success 200 {object} DocFind "array of base64 encoded string" // @Failure 400 {object} response // @Failure 500 {object} response // @Router /v1/doc/find [get] diff --git a/pkg/api/doc_new.go b/pkg/api/doc_new.go index b10a8119..edae7184 100644 --- a/pkg/api/doc_new.go +++ b/pkg/api/doc_new.go @@ -45,7 +45,7 @@ type SimpleDocRequest struct { // @Tags doc // @Accept json // @Produce json -// @Param doc_request body DocRequest true "doc table info" +// @Param doc_request body DocRequest true "doc table info. si or simple index is a comma separated list of keys and their types. eg: 'first_name=string,age=number'. valid index types can be 'string', 'number', 'map', 'list'. default index is 'id' and it should be of type string" // @Param Cookie header string true "cookie parameter" // @Success 201 {object} response // @Failure 400 {object} response diff --git a/pkg/api/doc_put_get_del.go b/pkg/api/doc_put_get_del.go index e7d667dd..224de805 100644 --- a/pkg/api/doc_put_get_del.go +++ b/pkg/api/doc_put_get_del.go @@ -41,6 +41,11 @@ type DocGetResponse struct { Doc []byte `json:"doc"` } +// DocGet represents a single document row +type DocGet struct { + Doc string `json:"doc"` +} + // DocEntryPutHandler godoc // // @Summary Add a record in document datastore @@ -124,7 +129,7 @@ func (h *Handler) DocEntryPutHandler(w http.ResponseWriter, r *http.Request) { // @Param tableName query string true "table name" // @Param id query string true "id to search for" // @Param Cookie header string true "cookie parameter" -// @Success 200 {object} DocGetResponse +// @Success 200 {object} DocGet "base64 encoded string" // @Failure 400 {object} response // @Failure 500 {object} response // @Router /v1/doc/entry/get [get] @@ -207,7 +212,7 @@ func (h *Handler) DocEntryGetHandler(w http.ResponseWriter, r *http.Request) { // @Success 200 {object} response // @Failure 400 {object} response // @Failure 500 {object} response -// @Router /v1/doc/entry/delete [delete] +// @Router /v1/doc/entry/del [delete] func (h *Handler) DocEntryDelHandler(w http.ResponseWriter, r *http.Request) { contentType := r.Header.Get("Content-Type") if contentType != jsonContentType { diff --git a/pkg/collection/document.go b/pkg/collection/document.go index c3cc21a3..ed61f319 100644 --- a/pkg/collection/document.go +++ b/pkg/collection/document.go @@ -962,11 +962,15 @@ func (d *Document) Find(dbName, expr, podPassword string, limit int) ([][]byte, } } case NumberIndex: - start, err := strconv.ParseInt(fieldValue, 10, 64) - if err != nil { // skipcq: TCV-001 - d.logger.Errorf("finding from document db: ", err.Error()) - return nil, err + var start int64 = 0 + if operator != "<" && operator != "<=" { + start, err = strconv.ParseInt(fieldValue, 10, 64) + if err != nil { // skipcq: TCV-001 + d.logger.Errorf("finding from document db: ", err.Error()) + return nil, err + } } + itr, err := idx.NewIntIterator(start, -1, int64(limit)) if err != nil { // skipcq: TCV-001 d.logger.Errorf("finding from document db: ", err.Error()) @@ -984,6 +988,46 @@ func (d *Document) Find(dbName, expr, podPassword string, limit int) ([][]byte, refs := itr.ValueAll() references = append(references, refs...) } + case "<": + end, err := strconv.ParseInt(fieldValue, 10, 64) + if err != nil { // skipcq: TCV-001 + d.logger.Errorf("finding from document db: ", err.Error()) + break + } + for itr.Next() { + if limit > 0 && references != nil && len(references) > limit { // skipcq: TCV-001 + break + } + val, err := strconv.ParseInt(itr.StringKey(), 10, 64) + if err != nil { // skipcq: TCV-001 + continue + } + if val >= end { + break + } + refs := itr.ValueAll() + references = append(references, refs...) + } + case "<=": + end, err := strconv.ParseInt(fieldValue, 10, 64) + if err != nil { // skipcq: TCV-001 + d.logger.Errorf("finding from document db: ", err.Error()) + break + } + for itr.Next() { + if limit > 0 && references != nil && len(references) > limit { // skipcq: TCV-001 + break + } + val, err := strconv.ParseInt(itr.StringKey(), 10, 64) + if err != nil { // skipcq: TCV-001 + continue + } + if val > end { + break + } + refs := itr.ValueAll() + references = append(references, refs...) + } case ">": for itr.Next() { if limit > 0 && references != nil && len(references) > limit { // skipcq: TCV-001 @@ -1003,9 +1047,8 @@ func (d *Document) Find(dbName, expr, podPassword string, limit int) ([][]byte, d.logger.Errorf("finding from document db: ", ErrInvalidIndexType) return nil, ErrInvalidIndexType } - + docs := [][]byte{} if idx.mutable { - var docs [][]byte wg := new(sync.WaitGroup) mtx := &sync.Mutex{} for _, ref := range references { @@ -1024,7 +1067,6 @@ func (d *Document) Find(dbName, expr, podPassword string, limit int) ([][]byte, d.logger.Info("found document from document db: ", dbName, expr, len(docs)) return docs, nil } else { // skipcq: TCV-001 - var docs [][]byte for _, ref := range references { if limit > 0 && len(docs) >= limit { break @@ -1138,6 +1180,8 @@ func (*Document) resolveExpression(expr string) (string, string, string, error) operator = "=>" } else if strings.Contains(expr, "<=") { // skipcq: TCV-001 operator = "<=" + } else if strings.Contains(expr, "<") { // skipcq: TCV-001 + operator = "<" } else if strings.Contains(expr, ">") { operator = ">" } else if strings.Contains(expr, "=") { @@ -1145,7 +1189,6 @@ func (*Document) resolveExpression(expr string) (string, string, string, error) } else { // skipcq: TCV-001 return "", "", "", ErrInvalidOperator } - f := strings.Split(expr, operator) fieldName := f[0] fieldValue := f[1] diff --git a/pkg/collection/document_test.go b/pkg/collection/document_test.go index 42dba3ca..9294496c 100644 --- a/pkg/collection/document_test.go +++ b/pkg/collection/document_test.go @@ -572,6 +572,16 @@ func TestDocumentStore(t *testing.T) { require.NoError(t, err) assert.Equal(t, len(docs), 5) + + docs, err = docStore.Find("docdb_8", "age<=30", podPassword, -1) + require.NoError(t, err) + + assert.Equal(t, len(docs), 4) + + docs, err = docStore.Find("docdb_8", "age<30", podPassword, -1) + require.NoError(t, err) + + assert.Equal(t, len(docs), 3) }) t.Run("del", func(t *testing.T) { diff --git a/swagger/docs.go b/swagger/docs.go index 57e2adfe..953b9679 100644 --- a/swagger/docs.go +++ b/swagger/docs.go @@ -503,7 +503,7 @@ const docTemplate = `{ } } }, - "/v1/doc/entry/delete": { + "/v1/doc/entry/del": { "delete": { "description": "DocEntryDelHandler is the api handler to delete a document from a document datastore", "consumes": [ @@ -607,9 +607,9 @@ const docTemplate = `{ ], "responses": { "200": { - "description": "OK", + "description": "base64 encoded string", "schema": { - "$ref": "#/definitions/api.DocGetResponse" + "$ref": "#/definitions/api.DocGet" } }, "400": { @@ -716,7 +716,7 @@ const docTemplate = `{ }, { "type": "string", - "description": "expression to search for", + "description": "expression to search for. allowed operators in expr are =, \u003e, =\u003e, \u003c=, \u003c. eg: 'first_name=\u003eJohn', 'first_name=\u003eJ.', 'first_name=\u003e.', 'age=\u003e30', 'age\u003c=30'. if index is string, expr supports regex. we do not have support for multiple conditions in expr yet", "name": "expr", "in": "query", "required": true @@ -737,9 +737,9 @@ const docTemplate = `{ ], "responses": { "200": { - "description": "OK", + "description": "array of base64 encoded string", "schema": { - "$ref": "#/definitions/api.DocFindResponse" + "$ref": "#/definitions/api.DocFind" } }, "400": { @@ -941,7 +941,7 @@ const docTemplate = `{ "summary": "Create in doc table", "parameters": [ { - "description": "doc table info", + "description": "doc table info. si or simple index is a comma separated list of keys and their types. eg: 'first_name=string,age=number'. valid index types can be 'string', 'number', 'map', 'list'. default index is 'id' and it should be of type string", "name": "doc_request", "in": "body", "required": true, @@ -3710,28 +3710,22 @@ const docTemplate = `{ } } }, - "api.DocFindResponse": { + "api.DocFind": { "type": "object", "properties": { "docs": { "type": "array", "items": { - "type": "array", - "items": { - "type": "integer" - } + "type": "string" } } } }, - "api.DocGetResponse": { + "api.DocGet": { "type": "object", "properties": { "doc": { - "type": "array", - "items": { - "type": "integer" - } + "type": "string" } } }, diff --git a/swagger/swagger.json b/swagger/swagger.json index 62c85f2f..3a8a544d 100644 --- a/swagger/swagger.json +++ b/swagger/swagger.json @@ -494,7 +494,7 @@ } } }, - "/v1/doc/entry/delete": { + "/v1/doc/entry/del": { "delete": { "description": "DocEntryDelHandler is the api handler to delete a document from a document datastore", "consumes": [ @@ -598,9 +598,9 @@ ], "responses": { "200": { - "description": "OK", + "description": "base64 encoded string", "schema": { - "$ref": "#/definitions/api.DocGetResponse" + "$ref": "#/definitions/api.DocGet" } }, "400": { @@ -707,7 +707,7 @@ }, { "type": "string", - "description": "expression to search for", + "description": "expression to search for. allowed operators in expr are =, \u003e, =\u003e, \u003c=, \u003c. eg: 'first_name=\u003eJohn', 'first_name=\u003eJ.', 'first_name=\u003e.', 'age=\u003e30', 'age\u003c=30'. if index is string, expr supports regex. we do not have support for multiple conditions in expr yet", "name": "expr", "in": "query", "required": true @@ -728,9 +728,9 @@ ], "responses": { "200": { - "description": "OK", + "description": "array of base64 encoded string", "schema": { - "$ref": "#/definitions/api.DocFindResponse" + "$ref": "#/definitions/api.DocFind" } }, "400": { @@ -932,7 +932,7 @@ "summary": "Create in doc table", "parameters": [ { - "description": "doc table info", + "description": "doc table info. si or simple index is a comma separated list of keys and their types. eg: 'first_name=string,age=number'. valid index types can be 'string', 'number', 'map', 'list'. default index is 'id' and it should be of type string", "name": "doc_request", "in": "body", "required": true, @@ -3701,28 +3701,22 @@ } } }, - "api.DocFindResponse": { + "api.DocFind": { "type": "object", "properties": { "docs": { "type": "array", "items": { - "type": "array", - "items": { - "type": "integer" - } + "type": "string" } } } }, - "api.DocGetResponse": { + "api.DocGet": { "type": "object", "properties": { "doc": { - "type": "array", - "items": { - "type": "integer" - } + "type": "string" } } }, diff --git a/swagger/swagger.yaml b/swagger/swagger.yaml index 64871bdf..48fc0b1c 100644 --- a/swagger/swagger.yaml +++ b/swagger/swagger.yaml @@ -53,21 +53,17 @@ definitions: tableName: type: string type: object - api.DocFindResponse: + api.DocFind: properties: docs: items: - items: - type: integer - type: array + type: string type: array type: object - api.DocGetResponse: + api.DocGet: properties: doc: - items: - type: integer - type: array + type: string type: object api.DocIndexRequest: properties: @@ -821,7 +817,7 @@ paths: summary: Delete a doc table tags: - doc - /v1/doc/entry/delete: + /v1/doc/entry/del: delete: consumes: - application/json @@ -891,9 +887,9 @@ paths: - application/json responses: "200": - description: OK + description: base64 encoded string schema: - $ref: '#/definitions/api.DocGetResponse' + $ref: '#/definitions/api.DocGet' "400": description: Bad Request schema: @@ -961,7 +957,10 @@ paths: name: tableName required: true type: string - - description: expression to search for + - description: 'expression to search for. allowed operators in expr are =, >, + =>, <=, <. eg: ''first_name=>John'', ''first_name=>J.'', ''first_name=>.'', + ''age=>30'', ''age<=30''. if index is string, expr supports regex. we do + not have support for multiple conditions in expr yet' in: query name: expr required: true @@ -979,9 +978,9 @@ paths: - application/json responses: "200": - description: OK + description: array of base64 encoded string schema: - $ref: '#/definitions/api.DocFindResponse' + $ref: '#/definitions/api.DocFind' "400": description: Bad Request schema: @@ -1116,7 +1115,10 @@ paths: - application/json description: DocCreateHandler is the api handler to create a new document database parameters: - - description: doc table info + - description: 'doc table info. si or simple index is a comma separated list + of keys and their types. eg: ''first_name=string,age=number''. valid index + types can be ''string'', ''number'', ''map'', ''list''. default index is + ''id'' and it should be of type string' in: body name: doc_request required: true