Skip to content

Commit

Permalink
feat: defaults implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
fulldump committed Feb 10, 2024
1 parent 1a7279f commit c127197
Show file tree
Hide file tree
Showing 21 changed files with 655 additions and 43 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ test:
go test -cover ./...

run:
go run $(FLAGS) ./cmd/inceptiondb/...
STATICS=statics/www/ go run $(FLAGS) ./cmd/inceptiondb/...

build:
go build $(FLAGS) -o bin/ ./cmd/inceptiondb/...
Expand Down
1 change: 1 addition & 0 deletions api/apicollectionv1/0_build.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func BuildV1Collection(v1 *box.R, s service.Servicer) *box.R {
box.ActionPost(dropIndex),
box.ActionPost(getIndex),
box.ActionPost(size),
box.ActionPost(setDefaults),
)

return collections
Expand Down
7 changes: 4 additions & 3 deletions api/apicollectionv1/collection.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package apicollectionv1

type CollectionResponse struct {
Name string `json:"name"`
Total int `json:"total"`
Indexes int `json:"indexes"`
Name string `json:"name"`
Total int `json:"total"`
Indexes int `json:"indexes"`
Defaults map[string]any `json:"defaults"`
}
19 changes: 16 additions & 3 deletions api/apicollectionv1/createCollection.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,14 @@ import (
)

type createCollectionRequest struct {
Name string `json:"name"`
Name string `json:"name"`
Defaults map[string]any `json:"defaults"`
}

func newCollectionDefaults() map[string]any {
return map[string]any{
"id": "uuid()",
}
}

func createCollection(ctx context.Context, w http.ResponseWriter, input *createCollectionRequest) (*CollectionResponse, error) {
Expand All @@ -25,9 +32,15 @@ func createCollection(ctx context.Context, w http.ResponseWriter, input *createC
return nil, err // todo: wrap error?
}

if input.Defaults == nil {
input.Defaults = newCollectionDefaults()
}
collection.SetDefaults(input.Defaults)

w.WriteHeader(http.StatusCreated)
return &CollectionResponse{
Name: input.Name,
Total: len(collection.Rows),
Name: input.Name,
Total: len(collection.Rows),
Defaults: collection.Defaults,
}, nil
}
7 changes: 7 additions & 0 deletions api/apicollectionv1/createIndex.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ func createIndex(ctx context.Context, r *http.Request) (*listIndexesItem, error)
col, err := s.GetCollection(collectionName)
if err == service.ErrorCollectionNotFound {
col, err = s.CreateCollection(collectionName)
if err != nil {
return nil, err // todo: handle/wrap this properly
}
err = col.SetDefaults(newCollectionDefaults())
if err != nil {
return nil, err // todo: handle/wrap this properly
}
}
if err != nil {
return nil, err // todo: handle/wrap this properly
Expand Down
7 changes: 7 additions & 0 deletions api/apicollectionv1/dropIndex.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ func dropIndex(ctx context.Context, w http.ResponseWriter, input *dropIndexReque
col, err := s.GetCollection(collectionName)
if err == service.ErrorCollectionNotFound {
col, err = s.CreateCollection(collectionName)
if err != nil {
return err // todo: handle/wrap this properly
}
err = col.SetDefaults(newCollectionDefaults())
if err != nil {
return err // todo: handle/wrap this properly
}
}
if err != nil {
return err // todo: handle/wrap this properly
Expand Down
7 changes: 4 additions & 3 deletions api/apicollectionv1/getCollection.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ func getCollection(ctx context.Context) (*CollectionResponse, error) {
}

return &CollectionResponse{
Name: collectionName,
Total: len(collection.Rows),
Indexes: len(collection.Indexes),
Name: collectionName,
Total: len(collection.Rows),
Indexes: len(collection.Indexes),
Defaults: collection.Defaults,
}, nil
}
32 changes: 25 additions & 7 deletions api/apicollectionv1/insert.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,34 +19,52 @@ func insert(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
collection, err := s.GetCollection(collectionName)
if err == service.ErrorCollectionNotFound {
collection, err = s.CreateCollection(collectionName)
if err != nil {
return err // todo: handle/wrap this properly
}
err = collection.SetDefaults(newCollectionDefaults())
if err != nil {
return err // todo: handle/wrap this properly
}
}
if err != nil {
return err // todo: handle/wrap this properly
}

jsonReader := json.NewDecoder(r.Body)
jsonWriter := json.NewEncoder(w)

for {
item := map[string]interface{}{}
for i := 0; true; i++ {
item := map[string]any{}
err := jsonReader.Decode(&item)
if err == io.EOF {
w.WriteHeader(http.StatusCreated)
if i == 0 {
w.WriteHeader(http.StatusNoContent)
}
return nil
}
if err != nil {
// TODO: handle error properly
fmt.Println("ERROR:", err.Error())
w.WriteHeader(http.StatusBadRequest)
if i == 0 {
w.WriteHeader(http.StatusBadRequest)
}
return err
}
_, err = collection.Insert(item)
row, err := collection.Insert(item)
if err != nil {
// TODO: handle error properly
w.WriteHeader(http.StatusConflict)
if i == 0 {
w.WriteHeader(http.StatusConflict)
}
return err
}

// jsonWriter.Encode(item)
if i == 0 {
w.WriteHeader(http.StatusCreated)
}
jsonWriter.Encode(row.Payload)
}

return nil
}
7 changes: 4 additions & 3 deletions api/apicollectionv1/listCollections.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ func listCollections(ctx context.Context, w http.ResponseWriter) ([]*CollectionR
response := []*CollectionResponse{}
for name, collection := range s.ListCollections() {
response = append(response, &CollectionResponse{
Name: name,
Total: len(collection.Rows),
Indexes: len(collection.Indexes),
Name: name,
Total: len(collection.Rows),
Indexes: len(collection.Indexes),
Defaults: collection.Defaults,
})
}
return response, nil
Expand Down
62 changes: 62 additions & 0 deletions api/apicollectionv1/setDefaults.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package apicollectionv1

import (
"context"
"encoding/json"
"net/http"

"github.com/fulldump/box"

"github.com/fulldump/inceptiondb/service"
)

type setDefaultsInput map[string]any

func setDefaults(ctx context.Context, w http.ResponseWriter, r *http.Request) error {

s := GetServicer(ctx)
collectionName := box.GetUrlParameter(ctx, "collectionName")
col, err := s.GetCollection(collectionName)
if err == service.ErrorCollectionNotFound {
col, err = s.CreateCollection(collectionName)
if err != nil {
return err // todo: handle/wrap this properly
}
err = col.SetDefaults(newCollectionDefaults())
if err != nil {
return err // todo: handle/wrap this properly
}
}
if err != nil {
return err // todo: handle/wrap this properly
}

defaults := col.Defaults

err = json.NewDecoder(r.Body).Decode(&defaults)
if err != nil {
return err // todo: handle/wrap this properly
}

for k, v := range defaults {
if v == nil {
delete(defaults, k)
}
}

if len(defaults) == 0 {
defaults = nil
}

err = col.SetDefaults(defaults)
if err != nil {
return err
}

err = json.NewEncoder(w).Encode(col.Defaults)
if err != nil {
return err // todo: handle/wrap this properly
}

return nil
}
67 changes: 67 additions & 0 deletions collection/collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"io"
"os"
"sync"
"sync/atomic"
"time"

jsonpatch "github.com/evanphx/json-patch"
Expand All @@ -21,6 +22,8 @@ type Collection struct {
rowsMutex *sync.Mutex
Indexes map[string]*collectionIndex // todo: protect access with mutex or use sync.Map
// buffer *bufio.Writer // TODO: use write buffer to improve performance (x3 in tests)
Defaults map[string]any
count int64
}

type collectionIndex struct {
Expand Down Expand Up @@ -118,6 +121,10 @@ func OpenCollection(filename string) (*Collection, error) {
if err != nil {
fmt.Printf("WARNING: patch item %d: %s\n", params.I, err.Error())
}
case "set_defaults":
defaults := map[string]any{}
json.Unmarshal(command.Payload, &defaults)
collection.setDefaults(defaults, false)
}
}

Expand Down Expand Up @@ -161,6 +168,33 @@ func (c *Collection) Insert(item interface{}) (*Row, error) {
return nil, fmt.Errorf("json encode payload: %w", err)
}

auto := atomic.AddInt64(&c.count, 1)

if c.Defaults != nil {
item := map[string]any{} // todo: item is shadowed, choose a better name
for k, v := range c.Defaults {
switch v {
case "uuid()":
item[k] = uuid.NewString()
case "unixnano()":
item[k] = time.Now().UnixNano()
case "auto()":
item[k] = auto
default:
item[k] = v
}
}
err := json.Unmarshal(payload, &item)
if err != nil {
return nil, fmt.Errorf("json encode defaults: %w", err)
}

payload, err = json.Marshal(item)
if err != nil {
return nil, fmt.Errorf("json encode payload: %w", err)
}
}

// Add row
row, err := c.addRow(payload)
if err != nil {
Expand Down Expand Up @@ -222,6 +256,39 @@ type CreateIndexCommand struct {
Options interface{} `json:"options"`
}

func (c *Collection) SetDefaults(defaults map[string]any) error {
return c.setDefaults(defaults, true)
}

func (c *Collection) setDefaults(defaults map[string]any, persist bool) error {

c.Defaults = defaults

if !persist {
return nil
}

payload, err := json.Marshal(defaults)
if err != nil {
return fmt.Errorf("json encode payload: %w", err)
}

command := &Command{
Name: "set_defaults", // todo: rename to create_index
Uuid: uuid.New().String(),
Timestamp: time.Now().UnixNano(),
StartByte: 0,
Payload: payload,
}

err = json.NewEncoder(c.file).Encode(command)
if err != nil {
return fmt.Errorf("json encode command: %w", err)
}

return nil
}

// IndexMap create a unique index with a name
// Constraints: values can be only scalar strings or array of strings
func (c *Collection) Index(name string, options interface{}) error { // todo: rename to CreateIndex
Expand Down
5 changes: 4 additions & 1 deletion doc/examples/create_collection.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ Host: example.com
}
HTTP/1.1 201 Created
Content-Length: 47
Content-Length: 74
Content-Type: text/plain; charset=utf-8
Date: Mon, 15 Aug 2022 02:08:13 GMT
{
"defaults": {
"id": "uuid()"
},
"indexes": 0,
"name": "my-collection",
"total": 0
Expand Down
6 changes: 5 additions & 1 deletion doc/examples/insert_many.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,13 @@ Host: example.com
HTTP/1.1 201 Created
Content-Length: 0
Content-Length: 84
Content-Type: text/plain; charset=utf-8
Date: Mon, 15 Aug 2022 02:08:13 GMT
{"id":"1","name":"Alfonso"}
{"id":"2","name":"Gerardo"}
{"id":"3","name":"Alfonso"}
```

Expand Down
9 changes: 7 additions & 2 deletions doc/examples/insert_one.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,15 @@ Host: example.com
}
HTTP/1.1 201 Created
Content-Length: 0
Content-Length: 58
Content-Type: text/plain; charset=utf-8
Date: Mon, 15 Aug 2022 02:08:13 GMT
{
"address": "Elm Street 11",
"id": "my-id",
"name": "Fulanez"
}
```


Loading

0 comments on commit c127197

Please sign in to comment.