2016-02-27 01:00:19 +00:00
|
|
|
// Copyright © 2016 Abcum Ltd
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
package db
|
|
|
|
|
|
|
|
import (
|
2016-05-11 19:23:21 +00:00
|
|
|
"fmt"
|
|
|
|
"time"
|
2016-02-27 01:00:19 +00:00
|
|
|
|
2016-05-11 19:23:21 +00:00
|
|
|
"github.com/abcum/fibre"
|
|
|
|
"github.com/abcum/surreal/cnf"
|
2016-05-25 11:33:05 +00:00
|
|
|
"github.com/abcum/surreal/kvs"
|
2016-05-11 19:23:21 +00:00
|
|
|
"github.com/abcum/surreal/log"
|
2016-02-27 01:00:19 +00:00
|
|
|
"github.com/abcum/surreal/sql"
|
2016-07-16 13:43:53 +00:00
|
|
|
|
|
|
|
_ "github.com/abcum/surreal/kvs/boltdb"
|
|
|
|
_ "github.com/abcum/surreal/kvs/mysql"
|
|
|
|
_ "github.com/abcum/surreal/kvs/pgsql"
|
2016-02-27 01:00:19 +00:00
|
|
|
)
|
|
|
|
|
2016-05-11 19:23:21 +00:00
|
|
|
type Response struct {
|
2016-05-25 11:32:32 +00:00
|
|
|
Time string `json:"time,omitempty"`
|
2016-05-11 19:23:21 +00:00
|
|
|
Status interface{} `json:"status,omitempty"`
|
|
|
|
Detail interface{} `json:"detail,omitempty"`
|
|
|
|
Result interface{} `json:"result,omitempty"`
|
|
|
|
}
|
|
|
|
|
2016-05-25 11:33:05 +00:00
|
|
|
var db *kvs.DB
|
2016-05-11 19:23:21 +00:00
|
|
|
|
|
|
|
// Setup sets up the connection with the data layer
|
|
|
|
func Setup(opts *cnf.Options) (err error) {
|
|
|
|
|
2016-07-19 11:04:22 +00:00
|
|
|
log.WithPrefix("db").Infof("Starting database")
|
2016-06-15 12:38:37 +00:00
|
|
|
|
2016-07-18 12:33:26 +00:00
|
|
|
db, err = kvs.New(opts)
|
2016-06-15 12:38:37 +00:00
|
|
|
|
2016-05-11 19:23:21 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Exit shuts down the connection with the data layer
|
|
|
|
func Exit() {
|
|
|
|
|
2016-06-15 12:38:37 +00:00
|
|
|
log.WithPrefix("db").Infof("Gracefully shutting down database")
|
2016-05-11 19:23:21 +00:00
|
|
|
|
2016-05-25 11:33:05 +00:00
|
|
|
db.Close()
|
2016-05-11 19:23:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-07-17 10:39:43 +00:00
|
|
|
// Prepare prepares a query for parameterization for future execution
|
2016-05-11 19:23:21 +00:00
|
|
|
func Prepare(sql string, param ...interface{}) string {
|
|
|
|
|
|
|
|
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) {
|
|
|
|
|
|
|
|
ast, err := sql.Parse(ctx, txt)
|
2016-02-27 12:05:35 +00:00
|
|
|
if err != nil {
|
2016-05-11 19:23:21 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
chn := make(chan interface{})
|
|
|
|
|
|
|
|
go execute(ctx, ast, chn)
|
|
|
|
|
2016-07-16 13:44:28 +00:00
|
|
|
for msg := range chn {
|
|
|
|
switch res := msg.(type) {
|
|
|
|
case error:
|
|
|
|
return nil, res
|
|
|
|
default:
|
|
|
|
out = append(out, res)
|
|
|
|
}
|
2016-02-27 12:05:35 +00:00
|
|
|
}
|
|
|
|
|
2016-05-11 19:23:21 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-05-25 11:32:32 +00:00
|
|
|
func status(e error) interface{} {
|
|
|
|
switch e.(type) {
|
|
|
|
default:
|
|
|
|
return "OK"
|
|
|
|
case *kvs.DBError:
|
|
|
|
return "ERR_DB"
|
|
|
|
case *kvs.TXError:
|
2016-07-16 13:44:48 +00:00
|
|
|
return "ERR_TX"
|
2016-05-25 11:32:32 +00:00
|
|
|
case *kvs.CKError:
|
|
|
|
return "ERR_CK"
|
|
|
|
case *kvs.KVError:
|
2016-07-16 13:44:48 +00:00
|
|
|
return "ERR_KV"
|
|
|
|
case error:
|
|
|
|
return "ERR"
|
2016-05-25 11:32:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func detail(e error) interface{} {
|
2016-06-15 12:38:37 +00:00
|
|
|
switch err := e.(type) {
|
2016-05-25 11:32:32 +00:00
|
|
|
default:
|
|
|
|
return nil
|
2016-06-15 12:38:37 +00:00
|
|
|
case error:
|
|
|
|
return err.Error()
|
2016-05-25 11:32:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-16 13:44:28 +00:00
|
|
|
func execute(ctx *fibre.Context, ast *sql.Query, chn chan<- interface{}) {
|
2016-05-11 19:23:21 +00:00
|
|
|
|
2016-07-16 13:44:28 +00:00
|
|
|
defer func() {
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
if err, ok := r.(error); ok {
|
|
|
|
chn <- err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
close(chn)
|
|
|
|
}()
|
2016-07-04 10:37:29 +00:00
|
|
|
|
2016-02-27 12:05:35 +00:00
|
|
|
for _, s := range ast.Statements {
|
2016-02-27 01:00:19 +00:00
|
|
|
|
2016-05-11 19:23:21 +00:00
|
|
|
var res []interface{}
|
|
|
|
var err error
|
|
|
|
|
|
|
|
now := time.Now()
|
|
|
|
|
|
|
|
switch stm := s.(type) {
|
|
|
|
|
|
|
|
case *sql.UseStatement:
|
|
|
|
continue
|
2016-02-27 01:00:19 +00:00
|
|
|
|
|
|
|
case *sql.SelectStatement:
|
2016-05-11 19:23:21 +00:00
|
|
|
res, err = executeSelectStatement(stm)
|
2016-02-27 01:00:19 +00:00
|
|
|
case *sql.CreateStatement:
|
2016-05-11 19:23:21 +00:00
|
|
|
res, err = executeCreateStatement(stm)
|
2016-02-27 01:00:19 +00:00
|
|
|
case *sql.UpdateStatement:
|
2016-05-11 19:23:21 +00:00
|
|
|
res, err = executeUpdateStatement(stm)
|
2016-02-27 01:00:19 +00:00
|
|
|
case *sql.ModifyStatement:
|
2016-05-11 19:23:21 +00:00
|
|
|
res, err = executeModifyStatement(stm)
|
2016-02-27 01:00:19 +00:00
|
|
|
case *sql.DeleteStatement:
|
2016-05-11 19:23:21 +00:00
|
|
|
res, err = executeDeleteStatement(stm)
|
2016-02-27 01:00:19 +00:00
|
|
|
case *sql.RelateStatement:
|
2016-05-11 19:23:21 +00:00
|
|
|
res, err = executeRelateStatement(stm)
|
2016-02-27 01:00:19 +00:00
|
|
|
case *sql.RecordStatement:
|
2016-05-11 19:23:21 +00:00
|
|
|
res, err = executeRecordStatement(stm)
|
2016-02-27 01:00:19 +00:00
|
|
|
|
2016-05-25 10:47:11 +00:00
|
|
|
case *sql.DefineTableStatement:
|
|
|
|
res, err = executeDefineTableStatement(stm)
|
|
|
|
case *sql.RemoveTableStatement:
|
|
|
|
res, err = executeRemoveTableStatement(stm)
|
|
|
|
|
2016-05-11 19:23:21 +00:00
|
|
|
case *sql.DefineFieldStatement:
|
|
|
|
res, err = executeDefineFieldStatement(stm)
|
|
|
|
case *sql.RemoveFieldStatement:
|
|
|
|
res, err = executeRemoveFieldStatement(stm)
|
2016-02-27 01:00:19 +00:00
|
|
|
|
|
|
|
case *sql.DefineIndexStatement:
|
2016-05-11 19:23:21 +00:00
|
|
|
res, err = executeDefineIndexStatement(stm)
|
2016-02-27 01:00:19 +00:00
|
|
|
case *sql.ResyncIndexStatement:
|
2016-05-11 19:23:21 +00:00
|
|
|
res, err = executeResyncIndexStatement(stm)
|
2016-02-27 01:00:19 +00:00
|
|
|
case *sql.RemoveIndexStatement:
|
2016-05-11 19:23:21 +00:00
|
|
|
res, err = executeRemoveIndexStatement(stm)
|
2016-02-27 01:00:19 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-05-11 19:23:21 +00:00
|
|
|
chn <- &Response{
|
|
|
|
Time: time.Since(now).String(),
|
2016-05-25 11:32:32 +00:00
|
|
|
Status: status(err),
|
|
|
|
Detail: detail(err),
|
2016-05-11 19:23:21 +00:00
|
|
|
Result: append([]interface{}{}, res...),
|
|
|
|
}
|
2016-02-27 12:16:59 +00:00
|
|
|
|
2016-02-27 01:00:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|