From a0d3f6ec2ae2ed235e42a1d1ebd0876d6a090ac1 Mon Sep 17 00:00:00 2001 From: Tobie Morgan Hitchcock Date: Tue, 6 Sep 2016 14:33:02 +0100 Subject: [PATCH] Update to work with sql parser improvements --- db/create.go | 58 +++++++++++--------- db/db.go | 68 +++++++++++++++++++----- db/define.go | 147 +++++++++++++++++++++++++++++++++++---------------- db/delete.go | 62 +++++++++++++--------- db/modify.go | 52 ++++++++++-------- db/record.go | 3 +- db/relate.go | 3 +- db/remove.go | 112 ++++++++++++++++++++++++++++++++------- db/resync.go | 29 ++++++---- db/select.go | 65 ++++++++++++++++++++--- db/update.go | 62 +++++++++++++--------- 11 files changed, 467 insertions(+), 194 deletions(-) diff --git a/db/create.go b/db/create.go index 45033228..88a08127 100644 --- a/db/create.go +++ b/db/create.go @@ -22,33 +22,41 @@ import ( "github.com/abcum/surreal/util/uuid" ) -func executeCreateStatement(ast *sql.CreateStatement) (out []interface{}, err error) { +func executeCreateStatement(txn kvs.TX, ast *sql.CreateStatement) (out []interface{}, err error) { - txn, err := db.Txn(true) - if err != nil { - return + var local bool + + if ast.EX { + return append(out, ast), nil } - defer txn.Rollback() + if txn == nil { + local = true + txn, err = db.Txn(true) + if err != nil { + return + } + defer txn.Rollback() + } for _, w := range ast.What { if what, ok := w.(*sql.Thing); ok { key := &keys.Thing{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: what.TB, ID: what.ID} kv, _ := txn.Get(key.Encode()) - doc := item.New(kv, key) - if ret, err := create(txn, doc, ast); err != nil { + doc := item.New(kv, txn, key) + if ret, err := create(doc, ast); err != nil { return nil, err } else if ret != nil { out = append(out, ret) } } - if what, ok := w.(sql.Table); ok { - key := &keys.Thing{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: what, ID: uuid.NewV5(uuid.NewV4().UUID, ast.KV).String()} + if what, ok := w.(*sql.Table); ok { + key := &keys.Thing{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: what.TB, ID: uuid.NewV5(uuid.NewV4().UUID, ast.KV).String()} kv, _ := txn.Get(key.Encode()) - doc := item.New(kv, key) - if ret, err := create(txn, doc, ast); err != nil { + doc := item.New(kv, txn, key) + if ret, err := create(doc, ast); err != nil { return nil, err } else if ret != nil { out = append(out, ret) @@ -57,32 +65,34 @@ func executeCreateStatement(ast *sql.CreateStatement) (out []interface{}, err er } - txn.Commit() + if local { + txn.Commit() + } return } -func create(txn kvs.TX, doc *item.Doc, ast *sql.CreateStatement) (out interface{}, err error) { +func create(doc *item.Doc, ast *sql.CreateStatement) (out interface{}, err error) { - if !doc.Allow(txn, "create") { + if err = doc.Merge(ast.Data); err != nil { + return + } + + if !doc.Allow("CREATE") { return nil, nil } - if err = doc.Merge(txn, ast.Data); err != nil { - return nil, err + if err = doc.StoreIndex(); err != nil { + return } - if err = doc.StoreIndex(txn); err != nil { - return nil, err + if err = doc.StartThing(); err != nil { + return } - if err = doc.StartThing(txn); err != nil { - return nil, err - } - - if err = doc.StorePatch(txn); err != nil { - return nil, err + if err = doc.StorePatch(); err != nil { + return } out = doc.Yield(ast.Echo, sql.AFTER) diff --git a/db/db.go b/db/db.go index db1bd02a..001077a3 100644 --- a/db/db.go +++ b/db/db.go @@ -63,6 +63,8 @@ func Exit() { // Prepare prepares a query for parameterization for future execution func Prepare(sql string, param ...interface{}) string { + // IMPORTANT Need to improve database paramaterization + return fmt.Sprintf(sql, param...) } @@ -120,7 +122,12 @@ func detail(e error) interface{} { func execute(ctx *fibre.Context, ast *sql.Query, chn chan<- interface{}) { + var txn kvs.TX + defer func() { + if txn != nil { + txn.Rollback() + } if r := recover(); r != nil { if err, ok := r.(error); ok { fmt.Printf("%s", debug.Stack()) @@ -143,37 +150,70 @@ func execute(ctx *fibre.Context, ast *sql.Query, chn chan<- interface{}) { continue case *sql.SelectStatement: - res, err = executeSelectStatement(stm) + res, err = executeSelectStatement(txn, stm) case *sql.CreateStatement: - res, err = executeCreateStatement(stm) + res, err = executeCreateStatement(txn, stm) case *sql.UpdateStatement: - res, err = executeUpdateStatement(stm) + res, err = executeUpdateStatement(txn, stm) case *sql.ModifyStatement: - res, err = executeModifyStatement(stm) + res, err = executeModifyStatement(txn, stm) case *sql.DeleteStatement: - res, err = executeDeleteStatement(stm) + res, err = executeDeleteStatement(txn, stm) case *sql.RelateStatement: - res, err = executeRelateStatement(stm) + res, err = executeRelateStatement(txn, stm) case *sql.RecordStatement: - res, err = executeRecordStatement(stm) + res, err = executeRecordStatement(txn, stm) + + case *sql.DefineRulesStatement: + res, err = executeDefineRulesStatement(txn, stm) + case *sql.RemoveRulesStatement: + res, err = executeRemoveRulesStatement(txn, stm) case *sql.DefineTableStatement: - res, err = executeDefineTableStatement(stm) + res, err = executeDefineTableStatement(txn, stm) case *sql.RemoveTableStatement: - res, err = executeRemoveTableStatement(stm) + res, err = executeRemoveTableStatement(txn, stm) case *sql.DefineFieldStatement: - res, err = executeDefineFieldStatement(stm) + res, err = executeDefineFieldStatement(txn, stm) case *sql.RemoveFieldStatement: - res, err = executeRemoveFieldStatement(stm) + res, err = executeRemoveFieldStatement(txn, stm) case *sql.DefineIndexStatement: - res, err = executeDefineIndexStatement(stm) + res, err = executeDefineIndexStatement(txn, stm) case *sql.ResyncIndexStatement: - res, err = executeResyncIndexStatement(stm) + res, err = executeResyncIndexStatement(txn, stm) case *sql.RemoveIndexStatement: - res, err = executeRemoveIndexStatement(stm) + res, err = executeRemoveIndexStatement(txn, stm) + case *sql.BeginStatement: + if txn != nil { + chn <- fibre.NewHTTPError(400, "Transaction already running") + return + } else if txn, err = db.Txn(true); err != nil { + chn <- err + return + } + + case *sql.CommitStatement: + if txn != nil { + txn.Commit() + txn = nil + continue + } + + case *sql.CancelStatement: + if txn != nil { + txn.Rollback() + txn = nil + continue + } + + } + + if err != nil && txn != nil { + txn.Rollback() + chn <- err } chn <- &Response{ diff --git a/db/define.go b/db/define.go index 4c874e7d..504c511d 100644 --- a/db/define.go +++ b/db/define.go @@ -15,19 +15,28 @@ package db import ( + "github.com/abcum/surreal/kvs" "github.com/abcum/surreal/sql" - "github.com/abcum/surreal/util/data" "github.com/abcum/surreal/util/keys" + "github.com/abcum/surreal/util/pack" ) -func executeDefineTableStatement(ast *sql.DefineTableStatement) (out []interface{}, err error) { +func executeDefineTableStatement(txn kvs.TX, ast *sql.DefineTableStatement) (out []interface{}, err error) { - txn, err := db.Txn(true) - if err != nil { - return + var local bool + + if ast.EX { + return append(out, ast), nil } - defer txn.Rollback() + if txn == nil { + local = true + txn, err = db.Txn(true) + if err != nil { + return + } + defer txn.Rollback() + } for _, TB := range ast.What { @@ -45,34 +54,81 @@ func executeDefineTableStatement(ast *sql.DefineTableStatement) (out []interface } - txn.Commit() + if local { + txn.Commit() + } return } -func executeDefineFieldStatement(ast *sql.DefineFieldStatement) (out []interface{}, err error) { +func executeDefineRulesStatement(txn kvs.TX, ast *sql.DefineRulesStatement) (out []interface{}, err error) { - txn, err := db.Txn(true) - if err != nil { - return + var local bool + + if ast.EX { + return append(out, ast), nil } - defer txn.Rollback() + if txn == nil { + local = true + txn, err = db.Txn(true) + if err != nil { + return + } + defer txn.Rollback() + } - doc := data.New() - doc.Set(ast.Name, "name") - doc.Set(ast.Type, "type") - doc.Set(ast.Enum, "enum") - doc.Set(ast.Code, "code") - doc.Set(ast.Min, "min") - doc.Set(ast.Max, "max") - doc.Set(ast.Match, "match") - doc.Set(ast.Default, "default") - doc.Set(ast.Notnull, "notnull") - doc.Set(ast.Readonly, "readonly") - doc.Set(ast.Mandatory, "mandatory") - doc.Set(ast.Validate, "validate") + for _, TB := range ast.What { + + for _, RU := range ast.When { + + // Set the database definition + dkey := &keys.DB{KV: ast.KV, NS: ast.NS, DB: ast.DB} + if err := txn.Put(dkey.Encode(), nil); err != nil { + return nil, err + } + + // Set the table definition + tkey := &keys.TB{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: TB} + if err := txn.Put(tkey.Encode(), nil); err != nil { + return nil, err + } + + // Set the field definition + rkey := &keys.RU{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: TB, RU: RU} + if err := txn.Put(rkey.Encode(), pack.ToPACK(ast)); err != nil { + return nil, err + } + + } + + } + + if local { + txn.Commit() + } + + return + +} + +func executeDefineFieldStatement(txn kvs.TX, ast *sql.DefineFieldStatement) (out []interface{}, err error) { + + var local bool + + if ast.EX { + return append(out, ast), nil + } + + if txn == nil { + local = true + txn, err = db.Txn(true) + if err != nil { + return + } + defer txn.Rollback() + } for _, TB := range ast.What { @@ -90,37 +146,36 @@ func executeDefineFieldStatement(ast *sql.DefineFieldStatement) (out []interface // Set the field definition fkey := &keys.FD{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: TB, FD: ast.Name} - if err := txn.Put(fkey.Encode(), doc.ToPACK()); err != nil { + if err := txn.Put(fkey.Encode(), pack.ToPACK(ast)); err != nil { return nil, err } } - txn.Commit() + if local { + txn.Commit() + } return } -func executeDefineIndexStatement(ast *sql.DefineIndexStatement) (out []interface{}, err error) { +func executeDefineIndexStatement(txn kvs.TX, ast *sql.DefineIndexStatement) (out []interface{}, err error) { - txn, err := db.Txn(true) - if err != nil { - return + var local bool + + if ast.EX { + return append(out, ast), nil } - defer txn.Rollback() - - doc := data.New() - // doc.Set(ast.Name, "name") - // doc.Set(ast.Type, "type") - // doc.Set(ast.Code, "code") - // doc.Set(ast.Min, "min") - // doc.Set(ast.Max, "max") - // doc.Set(ast.Default, "default") - // doc.Set(ast.Notnull, "notnull") - // doc.Set(ast.Readonly, "readonly") - // doc.Set(ast.Mandatory, "mandatory") + if txn == nil { + local = true + txn, err = db.Txn(true) + if err != nil { + return + } + defer txn.Rollback() + } for _, TB := range ast.What { @@ -138,13 +193,15 @@ func executeDefineIndexStatement(ast *sql.DefineIndexStatement) (out []interface // Set the index definition ikey := &keys.IX{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: TB, IX: ast.Name} - if err := txn.Put(ikey.Encode(), doc.ToPACK()); err != nil { + if err := txn.Put(ikey.Encode(), pack.ToPACK(ast)); err != nil { return nil, err } } - txn.Commit() + if local { + txn.Commit() + } return diff --git a/db/delete.go b/db/delete.go index faeddf34..5be55ff0 100644 --- a/db/delete.go +++ b/db/delete.go @@ -21,35 +21,43 @@ import ( "github.com/abcum/surreal/util/keys" ) -func executeDeleteStatement(ast *sql.DeleteStatement) (out []interface{}, err error) { +func executeDeleteStatement(txn kvs.TX, ast *sql.DeleteStatement) (out []interface{}, err error) { - txn, err := db.Txn(true) - if err != nil { - return + var local bool + + if ast.EX { + return append(out, ast), nil } - defer txn.Rollback() + if txn == nil { + local = true + txn, err = db.Txn(true) + if err != nil { + return + } + defer txn.Rollback() + } for _, w := range ast.What { if what, ok := w.(*sql.Thing); ok { key := &keys.Thing{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: what.TB, ID: what.ID} kv, _ := txn.Get(key.Encode()) - doc := item.New(kv, key) - if ret, err := delete(txn, doc, ast); err != nil { + doc := item.New(kv, txn, key) + if ret, err := delete(doc, ast); err != nil { return nil, err } else if ret != nil { out = append(out, ret) } } - if what, ok := w.(sql.Table); ok { - beg := &keys.Thing{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: what, ID: keys.Prefix} - end := &keys.Thing{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: what, ID: keys.Suffix} + if what, ok := w.(*sql.Table); ok { + beg := &keys.Thing{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: what.TB, ID: keys.Prefix} + end := &keys.Thing{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: what.TB, ID: keys.Suffix} kvs, _ := txn.RGet(beg.Encode(), end.Encode(), 0) for _, kv := range kvs { - doc := item.New(kv, nil) - if ret, err := delete(txn, doc, ast); err != nil { + doc := item.New(kv, txn, nil) + if ret, err := delete(doc, ast); err != nil { return nil, err } else if ret != nil { out = append(out, ret) @@ -59,38 +67,40 @@ func executeDeleteStatement(ast *sql.DeleteStatement) (out []interface{}, err er } - txn.Commit() + if local { + txn.Commit() + } return } -func delete(txn kvs.TX, doc *item.Doc, ast *sql.DeleteStatement) (out interface{}, err error) { +func delete(doc *item.Doc, ast *sql.DeleteStatement) (out interface{}, err error) { - if !doc.Allow(txn, "delete") { - return nil, nil + if !doc.Allow("DELETE") { + return } - if !doc.Check(txn, ast.Cond) { - return nil, nil + if !doc.Check(ast.Cond) { + return } - if err = doc.Erase(txn, nil); err != nil { - return nil, err + if err = doc.Erase(); err != nil { + return } - if err = doc.PurgeIndex(txn); err != nil { - return nil, err + if err = doc.PurgeIndex(); err != nil { + return } - if err = doc.PurgeThing(txn); err != nil { - return nil, err + if err = doc.PurgeThing(); err != nil { + return } if ast.Hard { - if err = doc.PurgePatch(txn); err != nil { - return nil, err + if err = doc.PurgePatch(); err != nil { + return } } diff --git a/db/modify.go b/db/modify.go index 4ac861f5..479c54d6 100644 --- a/db/modify.go +++ b/db/modify.go @@ -21,22 +21,30 @@ import ( "github.com/abcum/surreal/util/keys" ) -func executeModifyStatement(ast *sql.ModifyStatement) (out []interface{}, err error) { +func executeModifyStatement(txn kvs.TX, ast *sql.ModifyStatement) (out []interface{}, err error) { - txn, err := db.Txn(true) - if err != nil { - return + var local bool + + if ast.EX { + return append(out, ast), nil } - defer txn.Rollback() + if txn == nil { + local = true + txn, err = db.Txn(true) + if err != nil { + return + } + defer txn.Rollback() + } for _, w := range ast.What { if what, ok := w.(*sql.Thing); ok { key := &keys.Thing{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: what.TB, ID: what.ID} kv, _ := txn.Get(key.Encode()) - doc := item.New(kv, key) - if ret, err := modify(txn, doc, ast); err != nil { + doc := item.New(kv, txn, key) + if ret, err := modify(doc, ast); err != nil { return nil, err } else if ret != nil { out = append(out, ret) @@ -45,36 +53,38 @@ func executeModifyStatement(ast *sql.ModifyStatement) (out []interface{}, err er } - txn.Commit() + if local { + txn.Commit() + } return } -func modify(txn kvs.TX, doc *item.Doc, ast *sql.ModifyStatement) (out interface{}, err error) { +func modify(doc *item.Doc, ast *sql.ModifyStatement) (out interface{}, err error) { - if !doc.Allow(txn, "modify") { - return nil, nil + if !doc.Allow("UPDATE") { + return } - if !doc.Check(txn, ast.Cond) { - return nil, nil + if !doc.Check(ast.Cond) { + return } - if err = doc.Merge(txn, ast.Diff); err != nil { - return nil, err + if err = doc.Merge(ast.Diff); err != nil { + return } - if err = doc.StoreIndex(txn); err != nil { - return nil, err + if err = doc.StoreIndex(); err != nil { + return } - if err = doc.StoreThing(txn); err != nil { - return nil, err + if err = doc.StoreThing(); err != nil { + return } - if err = doc.StorePatch(txn); err != nil { - return nil, err + if err = doc.StorePatch(); err != nil { + return } out = doc.Yield(ast.Echo, sql.DIFF) diff --git a/db/record.go b/db/record.go index 0a0a0632..71e310c4 100644 --- a/db/record.go +++ b/db/record.go @@ -15,9 +15,10 @@ package db import ( + "github.com/abcum/surreal/kvs" "github.com/abcum/surreal/sql" ) -func executeRecordStatement(ast *sql.RecordStatement) ([]interface{}, error) { +func executeRecordStatement(txn kvs.TX, ast *sql.RecordStatement) ([]interface{}, error) { return nil, nil } diff --git a/db/relate.go b/db/relate.go index 68f9b984..eef4c265 100644 --- a/db/relate.go +++ b/db/relate.go @@ -15,9 +15,10 @@ package db import ( + "github.com/abcum/surreal/kvs" "github.com/abcum/surreal/sql" ) -func executeRelateStatement(ast *sql.RelateStatement) ([]interface{}, error) { +func executeRelateStatement(txn kvs.TX, ast *sql.RelateStatement) ([]interface{}, error) { return nil, nil } diff --git a/db/remove.go b/db/remove.go index 2ce491f2..57967660 100644 --- a/db/remove.go +++ b/db/remove.go @@ -15,18 +15,27 @@ package db import ( + "github.com/abcum/surreal/kvs" "github.com/abcum/surreal/sql" "github.com/abcum/surreal/util/keys" ) -func executeRemoveTableStatement(ast *sql.RemoveTableStatement) (out []interface{}, err error) { +func executeRemoveTableStatement(txn kvs.TX, ast *sql.RemoveTableStatement) (out []interface{}, err error) { - txn, err := db.Txn(true) - if err != nil { - return + var local bool + + if ast.EX { + return append(out, ast), nil } - defer txn.Rollback() + if txn == nil { + local = true + txn, err = db.Txn(true) + if err != nil { + return + } + defer txn.Rollback() + } for _, TB := range ast.What { @@ -36,6 +45,12 @@ func executeRemoveTableStatement(ast *sql.RemoveTableStatement) (out []interface return nil, err } + // Remove the rules config + rkey := &keys.RU{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: TB, RU: keys.Ignore} + if err := txn.PDel(rkey.Encode()); err != nil { + return nil, err + } + // Remove the field config fkey := &keys.FD{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: TB, FD: keys.Ignore} if err := txn.PDel(fkey.Encode()); err != nil { @@ -56,20 +71,69 @@ func executeRemoveTableStatement(ast *sql.RemoveTableStatement) (out []interface } - txn.Commit() + if local { + txn.Commit() + } return } -func executeRemoveFieldStatement(ast *sql.RemoveFieldStatement) (out []interface{}, err error) { +func executeRemoveRulesStatement(txn kvs.TX, ast *sql.RemoveRulesStatement) (out []interface{}, err error) { - txn, err := db.Txn(true) - if err != nil { - return + var local bool + + if ast.EX { + return append(out, ast), nil } - defer txn.Rollback() + if txn == nil { + local = true + txn, err = db.Txn(true) + if err != nil { + return + } + defer txn.Rollback() + } + + for _, TB := range ast.What { + + for _, RU := range ast.When { + + // Remove the rules config + ckey := &keys.RU{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: TB, RU: RU} + if err := txn.Del(ckey.Encode()); err != nil { + return nil, err + } + + } + + } + + if local { + txn.Commit() + } + + return + +} + +func executeRemoveFieldStatement(txn kvs.TX, ast *sql.RemoveFieldStatement) (out []interface{}, err error) { + + var local bool + + if ast.EX { + return append(out, ast), nil + } + + if txn == nil { + local = true + txn, err = db.Txn(true) + if err != nil { + return + } + defer txn.Rollback() + } for _, TB := range ast.What { @@ -81,20 +145,30 @@ func executeRemoveFieldStatement(ast *sql.RemoveFieldStatement) (out []interface } - txn.Commit() + if local { + txn.Commit() + } return } -func executeRemoveIndexStatement(ast *sql.RemoveIndexStatement) (out []interface{}, err error) { +func executeRemoveIndexStatement(txn kvs.TX, ast *sql.RemoveIndexStatement) (out []interface{}, err error) { - txn, err := db.Txn(true) - if err != nil { - return + var local bool + + if ast.EX { + return append(out, ast), nil } - defer txn.Rollback() + if txn == nil { + local = true + txn, err = db.Txn(true) + if err != nil { + return + } + defer txn.Rollback() + } for _, TB := range ast.What { @@ -112,7 +186,9 @@ func executeRemoveIndexStatement(ast *sql.RemoveIndexStatement) (out []interface } - txn.Commit() + if local { + txn.Commit() + } return diff --git a/db/resync.go b/db/resync.go index ebbfa704..ab98ec8b 100644 --- a/db/resync.go +++ b/db/resync.go @@ -21,14 +21,21 @@ import ( "github.com/abcum/surreal/util/keys" ) -func executeResyncIndexStatement(ast *sql.ResyncIndexStatement) (out []interface{}, err error) { +func executeResyncIndexStatement(txn kvs.TX, ast *sql.ResyncIndexStatement) (out []interface{}, err error) { - txn, err := db.Txn(true) - if err != nil { - return + var local bool + + if ast.EX { + return append(out, ast), nil } - defer txn.Rollback() + if txn == nil { + txn, err = db.Txn(true) + if err != nil { + return + } + defer txn.Rollback() + } for _, TB := range ast.What { @@ -44,23 +51,25 @@ func executeResyncIndexStatement(ast *sql.ResyncIndexStatement) (out []interface iend := &keys.Thing{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: TB, ID: keys.Suffix} kvs, _ := txn.RGet(ibeg.Encode(), iend.Encode(), 0) for _, kv := range kvs { - doc := item.New(kv, nil) - if err := resync(txn, doc, ast); err != nil { + doc := item.New(kv, txn, nil) + if err := resync(doc, ast); err != nil { return nil, err } } } - txn.Commit() + if local { + txn.Commit() + } return } -func resync(txn kvs.TX, doc *item.Doc, ast *sql.ResyncIndexStatement) (err error) { +func resync(doc *item.Doc, ast *sql.ResyncIndexStatement) (err error) { - if err = doc.StoreIndex(txn); err != nil { + if err = doc.StoreIndex(); err != nil { return err } diff --git a/db/select.go b/db/select.go index 88227bcb..ba435b39 100644 --- a/db/select.go +++ b/db/select.go @@ -15,22 +15,71 @@ package db import ( + "github.com/abcum/surreal/kvs" "github.com/abcum/surreal/sql" - "github.com/abcum/surreal/util/data" + "github.com/abcum/surreal/util/item" + "github.com/abcum/surreal/util/keys" ) -func executeSelectStatement(ast *sql.SelectStatement) (out []interface{}, err error) { +func executeSelectStatement(txn kvs.TX, ast *sql.SelectStatement) (out []interface{}, err error) { - kvs, err := db.All() + if ast.EX { + return append(out, ast), nil + } - for _, kv := range kvs { + if txn == nil { + txn, err = db.Txn(false) + if err != nil { + return + } + defer txn.Close() + } + + for _, w := range ast.What { + + if what, ok := w.(*sql.Thing); ok { + key := &keys.Thing{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: what.TB, ID: what.ID} + kv, _ := txn.Get(key.Encode()) + doc := item.New(kv, txn, key) + if ret, err := detect(doc, ast); err != nil { + return nil, err + } else if ret != nil { + out = append(out, ret) + } + } + + if what, ok := w.(*sql.Table); ok { + beg := &keys.Thing{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: what.TB, ID: keys.Prefix} + end := &keys.Thing{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: what.TB, ID: keys.Suffix} + kvs, _ := txn.RGet(beg.Encode(), end.Encode(), 0) + for _, kv := range kvs { + doc := item.New(kv, txn, nil) + if ret, err := detect(doc, ast); err != nil { + return nil, err + } else if ret != nil { + out = append(out, ret) + } + } + } - out = append(out, map[string]interface{}{ - "key": string(kv.Key()), - "val": data.NewFromPACK(kv.Val()).Data(), - }) } return } + +func detect(doc *item.Doc, ast *sql.SelectStatement) (out interface{}, err error) { + + if !doc.Allow("SELECT") { + return nil, nil + } + + if !doc.Check(ast.Cond) { + return + } + + out = doc.Blaze(ast) + + return + +} diff --git a/db/update.go b/db/update.go index 744d6eca..a600099c 100644 --- a/db/update.go +++ b/db/update.go @@ -21,35 +21,43 @@ import ( "github.com/abcum/surreal/util/keys" ) -func executeUpdateStatement(ast *sql.UpdateStatement) (out []interface{}, err error) { +func executeUpdateStatement(txn kvs.TX, ast *sql.UpdateStatement) (out []interface{}, err error) { - txn, err := db.Txn(true) - if err != nil { - return + var local bool + + if ast.EX { + return append(out, ast), nil } - defer txn.Rollback() + if txn == nil { + local = true + txn, err = db.Txn(true) + if err != nil { + return + } + defer txn.Rollback() + } for _, w := range ast.What { if what, ok := w.(*sql.Thing); ok { key := &keys.Thing{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: what.TB, ID: what.ID} kv, _ := txn.Get(key.Encode()) - doc := item.New(kv, key) - if ret, err := update(txn, doc, ast); err != nil { + doc := item.New(kv, txn, key) + if ret, err := update(doc, ast); err != nil { return nil, err } else if ret != nil { out = append(out, ret) } } - if what, ok := w.(sql.Table); ok { - beg := &keys.Thing{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: what, ID: keys.Prefix} - end := &keys.Thing{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: what, ID: keys.Suffix} + if what, ok := w.(*sql.Table); ok { + beg := &keys.Thing{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: what.TB, ID: keys.Prefix} + end := &keys.Thing{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: what.TB, ID: keys.Suffix} kvs, _ := txn.RGet(beg.Encode(), end.Encode(), 0) for _, kv := range kvs { - doc := item.New(kv, nil) - if ret, err := update(txn, doc, ast); err != nil { + doc := item.New(kv, txn, nil) + if ret, err := update(doc, ast); err != nil { return nil, err } else if ret != nil { out = append(out, ret) @@ -59,36 +67,38 @@ func executeUpdateStatement(ast *sql.UpdateStatement) (out []interface{}, err er } - txn.Commit() + if local { + txn.Commit() + } return } -func update(txn kvs.TX, doc *item.Doc, ast *sql.UpdateStatement) (out interface{}, err error) { +func update(doc *item.Doc, ast *sql.UpdateStatement) (out interface{}, err error) { - if !doc.Allow(txn, "update") { - return nil, nil + if !doc.Allow("UPDATE") { + return } - if !doc.Check(txn, ast.Cond) { - return nil, nil + if !doc.Check(ast.Cond) { + return } - if err = doc.Merge(txn, ast.Data); err != nil { - return nil, err + if err = doc.Merge(ast.Data); err != nil { + return } - if err = doc.StoreIndex(txn); err != nil { - return nil, err + if err = doc.StoreIndex(); err != nil { + return } - if err = doc.StoreThing(txn); err != nil { - return nil, err + if err = doc.StoreThing(); err != nil { + return } - if err = doc.StorePatch(txn); err != nil { - return nil, err + if err = doc.StorePatch(); err != nil { + return } out = doc.Yield(ast.Echo, sql.AFTER)