diff --git a/db/db.go b/db/db.go index 001077a3..372b0ad2 100644 --- a/db/db.go +++ b/db/db.go @@ -60,19 +60,10 @@ 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...) - -} - // Execute parses the query and executes it against the data layer -func Execute(ctx *fibre.Context, txt interface{}) (out []interface{}, err error) { +func Execute(ctx *fibre.Context, txt interface{}, vars map[string]interface{}) (out []*Response, err error) { - ast, err := sql.Parse(ctx, txt) + ast, err := sql.Parse(ctx, txt, vars) if err != nil { return } diff --git a/web/routes.go b/web/routes.go index 39a20377..711df547 100644 --- a/web/routes.go +++ b/web/routes.go @@ -75,7 +75,7 @@ func routes(s *fibre.Fibre) { }) s.Post("/sql", func(c *fibre.Context) error { - res, err := db.Execute(c, c.Request().Body) + res, err := db.Execute(c, c.Request().Body, nil) if err != nil { return err } @@ -91,30 +91,46 @@ func routes(s *fibre.Fibre) { }) s.Get("/key/:class", func(c *fibre.Context) error { - sql := db.Prepare("SELECT * FROM ⟨%v⟩", c.Param("class")) - res, err := db.Execute(c, sql) - if err != nil { - return fibre.NewHTTPError(500) - } - return output(c, res[0]) + + txt := "SELECT * FROM $class" + + res, err := db.Execute(c, txt, map[string]interface{}{ + "class": sql.NewTable(c.Param("class")), + }) + + return output(c, err, res) + }) s.Post("/key/:class", func(c *fibre.Context) error { - sql := db.Prepare("CREATE ⟨%v⟩ CONTENT %v RETURN AFTER", c.Param("class"), string(c.Body())) - res, err := db.Execute(c, sql) - if err != nil { - return fibre.NewHTTPError(500) + + var data interface{} + + if err := c.Bind(data); err != nil { + return fibre.NewHTTPError(422) } - return output(c, res[0]) + + txt := "CREATE $class CONTENT $data RETURN AFTER" + + res, err := db.Execute(c, txt, map[string]interface{}{ + "class": sql.NewTable(c.Param("class")), + "data": data, + }) + + return output(c, err, res) + }) s.Delete("/key/:class", func(c *fibre.Context) error { - sql := db.Prepare("DELETE FROM ⟨%v⟩", c.Param("class")) - res, err := db.Execute(c, sql) - if err != nil { - return fibre.NewHTTPError(500) - } - return output(c, res[0]) + + txt := "DELETE FROM $class" + + res, err := db.Execute(c, txt, map[string]interface{}{ + "class": sql.NewTable(c.Param("class")), + }) + + return output(c, err, res) + }) // -------------------------------------------------- @@ -126,57 +142,96 @@ func routes(s *fibre.Fibre) { }) s.Get("/key/:class/:id", func(c *fibre.Context) error { - sql := db.Prepare("SELECT * FROM @⟨%v⟩:⟨%v⟩", c.Param("class"), c.Param("id")) - res, err := db.Execute(c, sql) - if err != nil { - return fibre.NewHTTPError(500) - } - return output(c, res[0]) + + txt := "SELECT * FROM $thing" + + res, err := db.Execute(c, txt, map[string]interface{}{ + "thing": sql.NewThing(c.Param("class"), c.Param("id")), + }) + + return output(c, err, res) + }) s.Put("/key/:class/:id", func(c *fibre.Context) error { - sql := db.Prepare("CREATE @⟨%v⟩:⟨%v⟩ CONTENT %v RETURN AFTER", c.Param("class"), c.Param("id"), string(c.Body())) - res, err := db.Execute(c, sql) - if err != nil { - return fibre.NewHTTPError(500) + + var data interface{} + + if err := c.Bind(data); err != nil { + return fibre.NewHTTPError(422) } - return output(c, res[0]) + + txt := "CREATE $thing CONTENT $data RETURN AFTER" + + res, err := db.Execute(c, txt, map[string]interface{}{ + "thing": sql.NewThing(c.Param("class"), c.Param("id")), + "data": data, + }) + + return output(c, err, res) + }) s.Post("/key/:class/:id", func(c *fibre.Context) error { - sql := db.Prepare("UPDATE @⟨%v⟩:⟨%v⟩ CONTENT %v RETURN AFTER", c.Param("class"), c.Param("id"), string(c.Body())) - res, err := db.Execute(c, sql) - if err != nil { - return fibre.NewHTTPError(500) + + var data interface{} + + if err := c.Bind(data); err != nil { + return fibre.NewHTTPError(422) } - return output(c, res[0]) + + txt := "UPDATE $thing CONTENT $data RETURN AFTER" + + res, err := db.Execute(c, txt, map[string]interface{}{ + "thing": sql.NewThing(c.Param("class"), c.Param("id")), + "data": data, + }) + + return output(c, err, res) + }) s.Patch("/key/:class/:id", func(c *fibre.Context) error { - sql := db.Prepare("MODIFY @⟨%v⟩:⟨%v⟩ DIFF %v RETURN AFTER", c.Param("class"), c.Param("id"), string(c.Body())) - res, err := db.Execute(c, sql) - if err != nil { - return fibre.NewHTTPError(500) + + var data interface{} + + if err := c.Bind(data); err != nil { + return fibre.NewHTTPError(422) } - return output(c, res[0]) + + txt := "MODIFY $thing DIFF $data RETURN AFTER" + + res, err := db.Execute(c, txt, map[string]interface{}{ + "thing": sql.NewThing(c.Param("class"), c.Param("id")), + "data": data, + }) + + return output(c, err, res) + }) s.Trace("/key/:class/:id", func(c *fibre.Context) error { - sql := db.Prepare("SELECT HISTORY FROM @⟨%v⟩:⟨%v⟩", c.Param("class"), c.Param("id")) - res, err := db.Execute(c, sql) - if err != nil { - return fibre.NewHTTPError(500) - } - return output(c, res[0]) + + txt := "SELECT HISTORY FROM $thing" + + res, err := db.Execute(c, txt, map[string]interface{}{ + "thing": sql.NewThing(c.Param("class"), c.Param("id")), + }) + + return output(c, err, res) + }) s.Delete("/key/:class/:id", func(c *fibre.Context) error { - sql := db.Prepare("DELETE @⟨%v⟩:⟨%v⟩", c.Param("class"), c.Param("id")) - res, err := db.Execute(c, sql) - if err != nil { - return fibre.NewHTTPError(500) - } - return output(c, res[0]) + + txt := "DELETE $thing" + + res, err := db.Execute(c, txt, map[string]interface{}{ + "thing": sql.NewThing(c.Param("class"), c.Param("id")), + }) + + return output(c, err, res) + }) } diff --git a/web/rpc.go b/web/rpc.go index 30655597..50f7f931 100644 --- a/web/rpc.go +++ b/web/rpc.go @@ -17,40 +17,57 @@ package web import ( "github.com/abcum/fibre" "github.com/abcum/surreal/db" + "github.com/abcum/surreal/sql" ) type rpc struct{} -func (r *rpc) Sql(c *fibre.Context, sql string) (interface{}, error) { - return db.Execute(c, sql) +func (r *rpc) Sql(c *fibre.Context, sql string, vars map[string]interface{}) (interface{}, error) { + return db.Execute(c, sql, vars) } func (r *rpc) List(c *fibre.Context, class string) (interface{}, error) { - sql := db.Prepare("SELECT * FROM ⟨%v⟩", class) - return db.Execute(c, sql) + return db.Execute(c, "SELECT * FROM $class", map[string]interface{}{ + "class": sql.NewTable(class), + }) } -func (r *rpc) Select(c *fibre.Context, class, thing string) (interface{}, error) { - sql := db.Prepare("SELECT * FROM @⟨%v⟩:⟨%v⟩", class, thing) - return db.Execute(c, sql) +func (r *rpc) Create(c *fibre.Context, class string, data map[string]interface{}) (interface{}, error) { + return db.Execute(c, "CREATE $class CONTENT $data RETURN AFTER", map[string]interface{}{ + "class": sql.NewTable(class), + "data": data, + }) } -func (r *rpc) Create(c *fibre.Context, class, thing, data string) (interface{}, error) { - sql := db.Prepare("CREATE @⟨%v⟩:⟨%v⟩ CONTENT %v RETURN AFTER", class, thing, data) - return db.Execute(c, sql) +func (r *rpc) Select(c *fibre.Context, class string, thing interface{}) (interface{}, error) { + return db.Execute(c, "SELECT * FROM $thing", map[string]interface{}{ + "thing": sql.NewThing(class, thing), + }) } -func (r *rpc) Update(c *fibre.Context, class, thing, data string) (interface{}, error) { - sql := db.Prepare("UPDATE @⟨%v⟩:⟨%v⟩ CONTENT %v RETURN AFTER", class, thing, data) - return db.Execute(c, sql) +func (r *rpc) Insert(c *fibre.Context, class string, thing interface{}, data map[string]interface{}) (interface{}, error) { + return db.Execute(c, "INSERT $thing CONTENT $data RETURN AFTER", map[string]interface{}{ + "thing": sql.NewThing(class, thing), + "data": data, + }) } -func (r *rpc) Modify(c *fibre.Context, class, thing, data string) (interface{}, error) { - sql := db.Prepare("MODIFY @⟨%v⟩:⟨%v⟩ DIFF %v RETURN DIFF", class, thing, data) - return db.Execute(c, sql) +func (r *rpc) Upsert(c *fibre.Context, class string, thing interface{}, data map[string]interface{}) (interface{}, error) { + return db.Execute(c, "UPSERT $thing CONTENT $data RETURN AFTER", map[string]interface{}{ + "thing": sql.NewThing(class, thing), + "data": data, + }) } -func (r *rpc) Delete(c *fibre.Context, class, thing string) (interface{}, error) { - sql := db.Prepare("DELETE @⟨%v⟩:⟨%v⟩", class, thing) - return db.Execute(c, sql) +func (r *rpc) Modify(c *fibre.Context, class string, thing interface{}, data map[string]interface{}) (interface{}, error) { + return db.Execute(c, "MODIFY $thing DIFF $data RETURN DIFF", map[string]interface{}{ + "thing": sql.NewThing(class, thing), + "data": data, + }) +} + +func (r *rpc) Delete(c *fibre.Context, class string, thing interface{}) (interface{}, error) { + return db.Execute(c, "DELETE $thing", map[string]interface{}{ + "thing": sql.NewThing(class, thing), + }) }