summaryrefslogtreecommitdiff
path: root/internal/tree/mutations.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/tree/mutations.go')
-rw-r--r--internal/tree/mutations.go60
1 files changed, 60 insertions, 0 deletions
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)
+}