diff options
author | NeonXP <i@neonxp.dev> | 2022-11-21 03:46:30 +0300 |
---|---|---|
committer | NeonXP <i@neonxp.dev> | 2022-11-21 03:46:30 +0300 |
commit | 340a623e1a35efe0182cadd780a5a3385b526705 (patch) | |
tree | 7baad78e20b922b5487fa243c68b5b6137c7e1c4 /internal/tree |
initial
Diffstat (limited to 'internal/tree')
-rw-r--r-- | internal/tree/engine.go | 42 | ||||
-rw-r--r-- | internal/tree/mutations.go | 60 |
2 files changed, 102 insertions, 0 deletions
diff --git a/internal/tree/engine.go b/internal/tree/engine.go new file mode 100644 index 0000000..0f28eb7 --- /dev/null +++ b/internal/tree/engine.go @@ -0,0 +1,42 @@ +package tree + +import ( + "context" + "sync" + + "go.neonxp.dev/djson/internal/storage" + "go.neonxp.dev/json/model" +) + +type Engine struct { + Root model.Node + mu sync.RWMutex + storage storage.Storage +} + +func New(storage storage.Storage) *Engine { + return &Engine{ + Root: model.Node{}, + mu: sync.RWMutex{}, + storage: storage, + } +} + +func (t *Engine) Run(ctx context.Context) error { + // Load initial mutations + for m := range t.storage.Load() { + if err := t.execute(&m); err != nil { + return err + } + } + + <-ctx.Done() + return nil +} + +func (t *Engine) Get(nodes []string) (*model.Node, error) { + if len(nodes) == 0 { + return &t.Root, nil + } + return t.Root.Query(nodes) +} diff --git a/internal/tree/mutations.go b/internal/tree/mutations.go new file mode 100644 index 0000000..ec80ebd --- /dev/null +++ b/internal/tree/mutations.go @@ -0,0 +1,60 @@ +package tree + +import ( + "context" + "fmt" + + "go.neonxp.dev/djson/internal/model" +) + +func (t *Engine) Mutation(ctx context.Context, mut *model.Mutation) error { + t.mu.Lock() + defer t.mu.Unlock() + if err := t.execute(mut); err != nil { + return err + } + return t.storage.Commit(ctx, *mut) +} + +func (t *Engine) execute(mut *model.Mutation) error { + switch mut.Type { + case model.Create: + if len(mut.Path) == 0 { + // create root node + t.Root = mut.Body + return nil + } + key := mut.Path[len(mut.Path)-1] + path := mut.Path[:len(mut.Path)-1] + target, err := t.Root.Query(path) + if err != nil { + return err + } + return target.Set(key, mut.Body) + case model.Merge: + if len(mut.Path) == 0 { + // patch root node + return t.Root.Merge(&mut.Body) + } + target, err := t.Root.Query(mut.Path) + if err != nil { + return err + } + return target.Merge(&mut.Body) + case model.Remove: + if len(mut.Path) == 0 { + return fmt.Errorf("can't remove root node. Only replace or create avaliable") + } + key := mut.Path[len(mut.Path)-1] + if len(mut.Path) == 1 { + return t.Root.Remove(key) + } + path := mut.Path[:len(mut.Path)-1] + target, err := t.Root.Query(path) + if err != nil { + return err + } + return target.Remove(key) + } + return fmt.Errorf("invalid command type: %d", mut.Type) +} |