mirror of
https://codeberg.org/scip/anydb.git
synced 2025-12-16 20:10:59 +01:00
fixed crash in api list, added filter support to api list
This commit is contained in:
@@ -154,6 +154,11 @@ curl localhost:8787/anydb/v1/foo
|
|||||||
# list keys
|
# list keys
|
||||||
curl localhost:8787/anydb/v1/
|
curl localhost:8787/anydb/v1/
|
||||||
|
|
||||||
|
# same, but do a full text search by content, searching for "foo"
|
||||||
|
curl -X POST http://127.0.0.1:8787/anydb/v1/ \
|
||||||
|
-H 'Content-Type: application/json'
|
||||||
|
-d '{"key":"foo", "fulltext": true}'
|
||||||
|
|
||||||
# as you might correctly suspect you can store multi-line values or
|
# as you might correctly suspect you can store multi-line values or
|
||||||
# the content of text files. but what to do if you want to change it?
|
# the content of text files. but what to do if you want to change it?
|
||||||
# here's one way:
|
# here's one way:
|
||||||
|
|||||||
20
TODO.md
20
TODO.md
@@ -4,36 +4,16 @@
|
|||||||
- mime-type => exec app + value
|
- mime-type => exec app + value
|
||||||
- add waitgroup to db.go funcs
|
- add waitgroup to db.go funcs
|
||||||
- RestList does not support any params?
|
- RestList does not support any params?
|
||||||
- lc() incoming tags+keys
|
|
||||||
|
|
||||||
## DB Structure
|
## DB Structure
|
||||||
|
|
||||||
- put tags into sub bucket see #1
|
- put tags into sub bucket see #1
|
||||||
- change structure to:
|
|
||||||
|
|
||||||
data bucket
|
|
||||||
key => {key,value[0:60],isbin:bool}
|
|
||||||
|
|
||||||
value bucket
|
|
||||||
key => value (maybe always use []byte here)
|
|
||||||
|
|
||||||
tags bucket
|
tags bucket
|
||||||
key/tag => tag/key
|
key/tag => tag/key
|
||||||
tag/key => tag
|
tag/key => tag
|
||||||
|
|
||||||
So, list just uses the data bucket, no large contents.
|
|
||||||
A tag search only looksup matching tags, see #1.
|
|
||||||
Only a full text search and get would need to dig into the value bucket.
|
|
||||||
|
|
||||||
A delete would just delete all keys from all values and then:
|
A delete would just delete all keys from all values and then:
|
||||||
lookup in tags bucket for all key/*, then iterate over the values and
|
lookup in tags bucket for all key/*, then iterate over the values and
|
||||||
remove all tag/key's. Then deleting a key would not leave any residue
|
remove all tag/key's. Then deleting a key would not leave any residue
|
||||||
behind.
|
behind.
|
||||||
|
|
||||||
However, maybe change the list command to just list everything and add
|
|
||||||
an extra find command for fulltext or tag search. Maybe still provide
|
|
||||||
filter options in list command but only filter for keys.
|
|
||||||
|
|
||||||
DONE: most of the above, except the tag stuff. manpage needs update and tests.
|
|
||||||
|
|
||||||
maybe stitch the find command and just add -f (full text search) to list.
|
|
||||||
|
|||||||
2
anydb.1
2
anydb.1
@@ -133,7 +133,7 @@
|
|||||||
.\" ========================================================================
|
.\" ========================================================================
|
||||||
.\"
|
.\"
|
||||||
.IX Title "ANYDB 1"
|
.IX Title "ANYDB 1"
|
||||||
.TH ANYDB 1 "2024-12-30" "1" "User Commands"
|
.TH ANYDB 1 "2025-01-01" "1" "User Commands"
|
||||||
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
|
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
|
||||||
.\" way too many mistakes in technical documents.
|
.\" way too many mistakes in technical documents.
|
||||||
.if n .ad l
|
.if n .ad l
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ type DbAttr struct {
|
|||||||
File string
|
File string
|
||||||
Encrypted bool
|
Encrypted bool
|
||||||
Binary bool
|
Binary bool
|
||||||
|
|
||||||
|
// conf flags, needed for incoming rest requests
|
||||||
|
Fulltext bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if value is to be read from a file or stdin, setup preview
|
// check if value is to be read from a file or stdin, setup preview
|
||||||
|
|||||||
15
app/db.go
15
app/db.go
@@ -95,9 +95,15 @@ func (db *DB) List(attr *DbAttr, fulltext bool) (DbEntries, error) {
|
|||||||
var filter *regexp.Regexp
|
var filter *regexp.Regexp
|
||||||
|
|
||||||
if len(attr.Args) > 0 {
|
if len(attr.Args) > 0 {
|
||||||
|
// via cli
|
||||||
filter = regexp.MustCompile(attr.Args[0])
|
filter = regexp.MustCompile(attr.Args[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(attr.Key) > 0 {
|
||||||
|
// via api
|
||||||
|
filter = regexp.MustCompile(attr.Key)
|
||||||
|
}
|
||||||
|
|
||||||
err := db.DB.View(func(tx *bolt.Tx) error {
|
err := db.DB.View(func(tx *bolt.Tx) error {
|
||||||
root := tx.Bucket([]byte(db.Bucket))
|
root := tx.Bucket([]byte(db.Bucket))
|
||||||
if root == nil {
|
if root == nil {
|
||||||
@@ -120,7 +126,13 @@ func (db *DB) List(attr *DbAttr, fulltext bool) (DbEntries, error) {
|
|||||||
return fmt.Errorf("failed to unmarshal from protobuf: %w", err)
|
return fmt.Errorf("failed to unmarshal from protobuf: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
entry.Value = databucket.Get([]byte(entry.Key)) // empty is ok
|
if fulltext {
|
||||||
|
// avoid crash due to access fault
|
||||||
|
value := databucket.Get([]byte(entry.Key)) // empty is ok
|
||||||
|
vc := make([]byte, len(value))
|
||||||
|
copy(vc, value)
|
||||||
|
entry.Value = vc
|
||||||
|
}
|
||||||
|
|
||||||
var include bool
|
var include bool
|
||||||
|
|
||||||
@@ -327,7 +339,6 @@ func (db *DB) Get(attr *DbAttr) (*DbEntry, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) Del(attr *DbAttr) error {
|
func (db *DB) Del(attr *DbAttr) error {
|
||||||
// FIXME: check if it exists prior to just call bucket.Delete()?
|
|
||||||
if err := db.Open(); err != nil {
|
if err := db.Open(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import (
|
|||||||
"github.com/tlinden/anydb/common"
|
"github.com/tlinden/anydb/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Version string = "v0.1.0"
|
var Version string = "v0.1.1"
|
||||||
|
|
||||||
type BucketConfig struct {
|
type BucketConfig struct {
|
||||||
Encrypt bool
|
Encrypt bool
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ func List(conf *cfg.Config) *cobra.Command {
|
|||||||
)
|
)
|
||||||
|
|
||||||
var cmd = &cobra.Command{
|
var cmd = &cobra.Command{
|
||||||
Use: "list [<filter-regex> | -t <tag> ] [-m <mode>] [-nNif] [-T <tpl>]",
|
Use: "list [<filter-regex> | -t <tag> ] [-m <mode>] [-nNis] [-T <tpl>]",
|
||||||
Short: "List database contents",
|
Short: "List database contents",
|
||||||
Long: `List database contents`,
|
Long: `List database contents`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func List(writer io.Writer, conf *cfg.Config, entries app.DbEntries) error {
|
func List(writer io.Writer, conf *cfg.Config, entries app.DbEntries) error {
|
||||||
// FIXME: call sort here
|
|
||||||
switch conf.Mode {
|
switch conf.Mode {
|
||||||
case "wide", "", "table":
|
case "wide", "", "table":
|
||||||
return ListTable(writer, conf, entries)
|
return ListTable(writer, conf, entries)
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ func RestList(c *fiber.Ctx, conf *cfg.Config) error {
|
|||||||
attr := new(app.DbAttr)
|
attr := new(app.DbAttr)
|
||||||
|
|
||||||
if len(c.Body()) > 0 {
|
if len(c.Body()) > 0 {
|
||||||
|
|
||||||
if err := c.BodyParser(attr); err != nil {
|
if err := c.BodyParser(attr); err != nil {
|
||||||
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{
|
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{
|
||||||
"errors": err.Error(),
|
"errors": err.Error(),
|
||||||
@@ -54,7 +53,7 @@ func RestList(c *fiber.Ctx, conf *cfg.Config) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get list
|
// get list
|
||||||
entries, err := conf.DB.List(attr, false)
|
entries, err := conf.DB.List(attr, attr.Fulltext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return JsonStatus(c, fiber.StatusForbidden,
|
return JsonStatus(c, fiber.StatusForbidden,
|
||||||
"Unable to list keys: "+err.Error())
|
"Unable to list keys: "+err.Error())
|
||||||
|
|||||||
@@ -42,6 +42,11 @@ func Runserver(conf *cfg.Config, args []string) error {
|
|||||||
return RestList(c, conf)
|
return RestList(c, conf)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
api.Post("/", func(c *fiber.Ctx) error {
|
||||||
|
// same thing as above but allows to supply parameters, see app.Dbattr{}
|
||||||
|
return RestList(c, conf)
|
||||||
|
})
|
||||||
|
|
||||||
api.Get("/:key", func(c *fiber.Ctx) error {
|
api.Get("/:key", func(c *fiber.Ctx) error {
|
||||||
return RestGet(c, conf)
|
return RestGet(c, conf)
|
||||||
})
|
})
|
||||||
@@ -78,7 +83,7 @@ func SetupServer(conf *cfg.Config) *fiber.App {
|
|||||||
})
|
})
|
||||||
|
|
||||||
router.Use(logger.New(logger.Config{
|
router.Use(logger.New(logger.Config{
|
||||||
Format: "${pid} ${ip}:${port} ${status} - ${method} ${path}\n",
|
Format: "${pid} ${ip}:${port} ${status} - ${method} ${path}\n",
|
||||||
DisableColors: true,
|
DisableColors: true,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user