Full update of the SQL package
This commit is contained in:
parent
2609d761be
commit
1d08949fff
55 changed files with 25318 additions and 3171 deletions
20013
sql/ast.gen.go
Normal file
20013
sql/ast.gen.go
Normal file
File diff suppressed because it is too large
Load diff
440
sql/ast.go
440
sql/ast.go
|
@ -16,7 +16,10 @@ package sql
|
|||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
// --------------------------------------------------
|
||||
|
@ -43,15 +46,11 @@ type AuthableStatement interface {
|
|||
}
|
||||
|
||||
type KillableStatement interface {
|
||||
Begin()
|
||||
Cease()
|
||||
Duration() time.Duration
|
||||
Timedout() <-chan struct{}
|
||||
}
|
||||
|
||||
type killable struct {
|
||||
ticker *time.Timer
|
||||
closer chan struct{}
|
||||
type WriteableStatement interface {
|
||||
Writeable() bool
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
|
@ -83,6 +82,7 @@ type UseStatement struct {
|
|||
|
||||
// InfoStatement represents an SQL INFO statement.
|
||||
type InfoStatement struct {
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
|
@ -90,12 +90,25 @@ type InfoStatement struct {
|
|||
What *Table `cork:"-" codec:"-"`
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// If
|
||||
// --------------------------------------------------
|
||||
|
||||
// IfStatement represents an if else clause.
|
||||
type IfStatement struct {
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
Cond Exprs `cork:"cond" codec:"cond"`
|
||||
Then Exprs `cork:"then" codec:"then"`
|
||||
Else Expr `cork:"else" codec:"else"`
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// LET
|
||||
// --------------------------------------------------
|
||||
|
||||
// LetStatement represents a SQL LET statement.
|
||||
type LetStatement struct {
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
|
@ -105,10 +118,11 @@ type LetStatement struct {
|
|||
|
||||
// ReturnStatement represents a SQL RETURN statement.
|
||||
type ReturnStatement struct {
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
What Expr `cork:"-" codec:"-"`
|
||||
What Exprs `cork:"-" codec:"-"`
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
|
@ -117,84 +131,127 @@ type ReturnStatement struct {
|
|||
|
||||
// LiveStatement represents a SQL LIVE statement.
|
||||
type LiveStatement struct {
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
ID string `cork:"ID" codec:"ID"`
|
||||
FB string `cork:"FB" codec:"FB"`
|
||||
KV string `cork:"KV" codec:"KV"`
|
||||
NS string `cork:"NS" codec:"NS"`
|
||||
DB string `cork:"DB" codec:"DB"`
|
||||
Diff bool `cork:"diff" codec:"diff"`
|
||||
Expr Fields `cork:"expr" codec:"expr"`
|
||||
What Exprs `cork:"what" codec:"what"`
|
||||
What *Table `cork:"what" codec:"what"`
|
||||
Cond Expr `cork:"cond" codec:"cond"`
|
||||
Echo Token `cork:"echo" codec:"echo"`
|
||||
}
|
||||
|
||||
// KillStatement represents a SQL KILL statement.
|
||||
type KillStatement struct {
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
FB string `cork:"FB" codec:"FB"`
|
||||
KV string `cork:"KV" codec:"KV"`
|
||||
NS string `cork:"NS" codec:"NS"`
|
||||
DB string `cork:"DB" codec:"DB"`
|
||||
Name *Value `cork:"name" codec:"name"`
|
||||
}
|
||||
|
||||
// SelectStatement represents a SQL SELECT statement.
|
||||
type SelectStatement struct {
|
||||
killable
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
Expr Fields `cork:"expr" codec:"expr"`
|
||||
What Exprs `cork:"what" codec:"what"`
|
||||
Cond Expr `cork:"cond" codec:"cond"`
|
||||
Group Groups `cork:"group" codec:"group"`
|
||||
Order Orders `cork:"order" codec:"order"`
|
||||
Limit Expr `cork:"limit" codec:"limit"`
|
||||
Start Expr `cork:"start" codec:"start"`
|
||||
Version Expr `cork:"version" codec:"version"`
|
||||
Timeout time.Duration `cork:"timeout" codec:"timeout"`
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"KV" codec:"KV"`
|
||||
NS string `cork:"NS" codec:"NS"`
|
||||
DB string `cork:"DB" codec:"DB"`
|
||||
Expr Fields `cork:"expr" codec:"expr"`
|
||||
What Exprs `cork:"what" codec:"what"`
|
||||
Cond Expr `cork:"cond" codec:"cond"`
|
||||
Group Groups `cork:"group" codec:"group"`
|
||||
Order Orders `cork:"order" codec:"order"`
|
||||
Limit Expr `cork:"limit" codec:"limit"`
|
||||
Start Expr `cork:"start" codec:"start"`
|
||||
Version Expr `cork:"version" codec:"version"`
|
||||
Timeout time.Duration `cork:"timeout" codec:"timeout"`
|
||||
Parallel int `cork:"parallel" codec:"parallel"`
|
||||
}
|
||||
|
||||
// CreateStatement represents a SQL CREATE statement.
|
||||
type CreateStatement struct {
|
||||
killable
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
What Exprs `cork:"what" codec:"what"`
|
||||
Data Expr `cork:"data" codec:"data"`
|
||||
Echo Token `cork:"echo" codec:"echo"`
|
||||
Timeout time.Duration `cork:"timeout" codec:"timeout"`
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"KV" codec:"KV"`
|
||||
NS string `cork:"NS" codec:"NS"`
|
||||
DB string `cork:"DB" codec:"DB"`
|
||||
What Exprs `cork:"what" codec:"what"`
|
||||
Data Expr `cork:"data" codec:"data"`
|
||||
Echo Token `cork:"echo" codec:"echo"`
|
||||
Timeout time.Duration `cork:"timeout" codec:"timeout"`
|
||||
Parallel int `cork:"parallel" codec:"parallel"`
|
||||
}
|
||||
|
||||
// UpdateStatement represents a SQL UPDATE statement.
|
||||
type UpdateStatement struct {
|
||||
killable
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
Hard bool `cork:"hard" codec:"hard"`
|
||||
What Exprs `cork:"what" codec:"what"`
|
||||
Data Expr `cork:"data" codec:"data"`
|
||||
Cond Expr `cork:"cond" codec:"cond"`
|
||||
Echo Token `cork:"echo" codec:"echo"`
|
||||
Timeout time.Duration `cork:"timeout" codec:"timeout"`
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"KV" codec:"KV"`
|
||||
NS string `cork:"NS" codec:"NS"`
|
||||
DB string `cork:"DB" codec:"DB"`
|
||||
What Exprs `cork:"what" codec:"what"`
|
||||
Data Expr `cork:"data" codec:"data"`
|
||||
Cond Expr `cork:"cond" codec:"cond"`
|
||||
Echo Token `cork:"echo" codec:"echo"`
|
||||
Timeout time.Duration `cork:"timeout" codec:"timeout"`
|
||||
Parallel int `cork:"parallel" codec:"parallel"`
|
||||
}
|
||||
|
||||
// DeleteStatement represents a SQL DELETE statement.
|
||||
type DeleteStatement struct {
|
||||
killable
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
Hard bool `cork:"hard" codec:"hard"`
|
||||
What Exprs `cork:"what" codec:"what"`
|
||||
Cond Expr `cork:"cond" codec:"cond"`
|
||||
Echo Token `cork:"echo" codec:"echo"`
|
||||
Timeout time.Duration `cork:"timeout" codec:"timeout"`
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"KV" codec:"KV"`
|
||||
NS string `cork:"NS" codec:"NS"`
|
||||
DB string `cork:"DB" codec:"DB"`
|
||||
Hard bool `cork:"hard" codec:"hard"`
|
||||
What Exprs `cork:"what" codec:"what"`
|
||||
Cond Expr `cork:"cond" codec:"cond"`
|
||||
Echo Token `cork:"echo" codec:"echo"`
|
||||
Timeout time.Duration `cork:"timeout" codec:"timeout"`
|
||||
Parallel int `cork:"parallel" codec:"parallel"`
|
||||
}
|
||||
|
||||
// RelateStatement represents a SQL RELATE statement.
|
||||
type RelateStatement struct {
|
||||
killable
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
Type Expr `cork:"type" codec:"type"`
|
||||
From Exprs `cork:"from" codec:"from"`
|
||||
With Exprs `cork:"with" codec:"with"`
|
||||
Data Expr `cork:"data" codec:"data"`
|
||||
Uniq bool `cork:"uniq" codec:"uniq"`
|
||||
Echo Token `cork:"echo" codec:"echo"`
|
||||
Timeout time.Duration `cork:"timeout" codec:"timeout"`
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"KV" codec:"KV"`
|
||||
NS string `cork:"NS" codec:"NS"`
|
||||
DB string `cork:"DB" codec:"DB"`
|
||||
Type Expr `cork:"type" codec:"type"`
|
||||
From Exprs `cork:"from" codec:"from"`
|
||||
With Exprs `cork:"with" codec:"with"`
|
||||
Data Expr `cork:"data" codec:"data"`
|
||||
Uniq bool `cork:"uniq" codec:"uniq"`
|
||||
Echo Token `cork:"echo" codec:"echo"`
|
||||
Timeout time.Duration `cork:"timeout" codec:"timeout"`
|
||||
Parallel int `cork:"parallel" codec:"parallel"`
|
||||
}
|
||||
|
||||
// InsertStatement represents a SQL INSERT statement.
|
||||
type InsertStatement struct {
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"KV" codec:"KV"`
|
||||
NS string `cork:"NS" codec:"NS"`
|
||||
DB string `cork:"DB" codec:"DB"`
|
||||
Data Expr `cork:"data" codec:"data"`
|
||||
Into *Table `cork:"into" codec:"into"`
|
||||
Echo Token `cork:"echo" codec:"echo"`
|
||||
Timeout time.Duration `cork:"timeout" codec:"timeout"`
|
||||
Parallel int `cork:"parallel" codec:"parallel"`
|
||||
}
|
||||
|
||||
// UpsertStatement represents a SQL UPSERT statement.
|
||||
type UpsertStatement struct {
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"KV" codec:"KV"`
|
||||
NS string `cork:"NS" codec:"NS"`
|
||||
DB string `cork:"DB" codec:"DB"`
|
||||
Data Expr `cork:"data" codec:"data"`
|
||||
Into *Table `cork:"into" codec:"into"`
|
||||
Echo Token `cork:"echo" codec:"echo"`
|
||||
Timeout time.Duration `cork:"timeout" codec:"timeout"`
|
||||
Parallel int `cork:"parallel" codec:"parallel"`
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
|
@ -202,6 +259,7 @@ type RelateStatement struct {
|
|||
// --------------------------------------------------
|
||||
|
||||
type DefineNamespaceStatement struct {
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
|
@ -209,6 +267,7 @@ type DefineNamespaceStatement struct {
|
|||
}
|
||||
|
||||
type RemoveNamespaceStatement struct {
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
|
@ -220,6 +279,7 @@ type RemoveNamespaceStatement struct {
|
|||
// --------------------------------------------------
|
||||
|
||||
type DefineDatabaseStatement struct {
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
|
@ -227,6 +287,7 @@ type DefineDatabaseStatement struct {
|
|||
}
|
||||
|
||||
type RemoveDatabaseStatement struct {
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
|
@ -239,6 +300,7 @@ type RemoveDatabaseStatement struct {
|
|||
|
||||
// DefineLoginStatement represents an SQL DEFINE LOGIN statement.
|
||||
type DefineLoginStatement struct {
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
|
@ -250,6 +312,7 @@ type DefineLoginStatement struct {
|
|||
|
||||
// RemoveLoginStatement represents an SQL REMOVE LOGIN statement.
|
||||
type RemoveLoginStatement struct {
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
|
@ -263,6 +326,7 @@ type RemoveLoginStatement struct {
|
|||
|
||||
// DefineTokenStatement represents an SQL DEFINE TOKEN statement.
|
||||
type DefineTokenStatement struct {
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
|
@ -274,6 +338,7 @@ type DefineTokenStatement struct {
|
|||
|
||||
// RemoveTokenStatement represents an SQL REMOVE TOKEN statement.
|
||||
type RemoveTokenStatement struct {
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
|
@ -287,18 +352,21 @@ type RemoveTokenStatement struct {
|
|||
|
||||
// DefineScopeStatement represents an SQL DEFINE SCOPE statement.
|
||||
type DefineScopeStatement struct {
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
Name *Ident `cork:"name" codec:"name"`
|
||||
Time time.Duration `cork:"time" codec:"time"`
|
||||
Code []byte `cork:"code" codec:"code"`
|
||||
Signup Expr `cork:"signup" codec:"signup"`
|
||||
Signin Expr `cork:"signin" codec:"signin"`
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
Name *Ident `cork:"name" codec:"name"`
|
||||
Time time.Duration `cork:"time" codec:"time"`
|
||||
Code []byte `cork:"code" codec:"code"`
|
||||
Signup Expr `cork:"signup" codec:"signup"`
|
||||
Signin Expr `cork:"signin" codec:"signin"`
|
||||
Connect Expr `cork:"connect" codec:"connect"`
|
||||
}
|
||||
|
||||
// RemoveScopeStatement represents an SQL REMOVE SCOPE statement.
|
||||
type RemoveScopeStatement struct {
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
|
@ -311,49 +379,79 @@ type RemoveScopeStatement struct {
|
|||
|
||||
// DefineTableStatement represents an SQL DEFINE TABLE statement.
|
||||
type DefineTableStatement struct {
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
What Tables `cork:"-" codec:"-"`
|
||||
Full bool `cork:"full" codec:"full"`
|
||||
Perm *PermExpression `cork:"perm" codec:"perm"`
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
Name *Ident `cork:"name" codec:"name"`
|
||||
What Tables `cork:"-" codec:"-"`
|
||||
Full bool `cork:"full" codec:"full"`
|
||||
Drop bool `cork:"drop" codec:"drop"`
|
||||
Lock bool `cork:"lock" codec:"lock"`
|
||||
Expr Fields `cork:"expr" codec:"expr"`
|
||||
From Tables `cork:"from" codec:"from"`
|
||||
Cond Expr `cork:"cond" codec:"cond"`
|
||||
Group Groups `cork:"group" codec:"group"`
|
||||
Perms Expr `cork:"perms" codec:"perms"`
|
||||
}
|
||||
|
||||
// RemoveTableStatement represents an SQL REMOVE TABLE statement.
|
||||
type RemoveTableStatement struct {
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
What Tables `cork:"-" codec:"-"`
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// Event
|
||||
// --------------------------------------------------
|
||||
|
||||
// DefineEventStatement represents an SQL DEFINE EVENT statement.
|
||||
type DefineEventStatement struct {
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
Name *Ident `cork:"name" codec:"name"`
|
||||
What Tables `cork:"-" codec:"-"`
|
||||
When Expr `cork:"when" codec:"when"`
|
||||
Then Expr `cork:"then" codec:"then"`
|
||||
}
|
||||
|
||||
// RemoveEventStatement represents an SQL REMOVE EVENT statement.
|
||||
type RemoveEventStatement struct {
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
Name *Ident `cork:"-" codec:"-"`
|
||||
What Tables `cork:"-" codec:"-"`
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// Field
|
||||
// --------------------------------------------------
|
||||
|
||||
// DefineFieldStatement represents an SQL DEFINE FIELD statement.
|
||||
type DefineFieldStatement struct {
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
Name *Ident `cork:"name" codec:"name"`
|
||||
What Tables `cork:"-" codec:"-"`
|
||||
Type string `cork:"type" codec:"type"`
|
||||
Perm *PermExpression `cork:"perm" codec:"perm"`
|
||||
Enum Array `cork:"enum" codec:"enum"`
|
||||
Code string `cork:"code" codec:"code"`
|
||||
Min float64 `cork:"min" codec:"min"`
|
||||
Max float64 `cork:"max" codec:"max"`
|
||||
Match string `cork:"match" codec:"match"`
|
||||
Default interface{} `cork:"default" codec:"default"`
|
||||
Notnull bool `cork:"notnull" codec:"notnull"`
|
||||
Readonly bool `cork:"readonly" codec:"readonly"`
|
||||
Mandatory bool `cork:"mandatory" codec:"mandatory"`
|
||||
Validate bool `cork:"validate" codec:"validate"`
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
Name *Ident `cork:"name" codec:"name"`
|
||||
What Tables `cork:"-" codec:"-"`
|
||||
Perms Expr `cork:"perms" codec:"perms"`
|
||||
Type string `cork:"type" codec:"type"`
|
||||
Kind string `cork:"kind" codec:"kind"`
|
||||
Value Expr `cork:"value" codec:"value"`
|
||||
Assert Expr `cork:"assert" codec:"assert"`
|
||||
}
|
||||
|
||||
// RemoveFieldStatement represents an SQL REMOVE FIELD statement.
|
||||
type RemoveFieldStatement struct {
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
|
@ -367,6 +465,7 @@ type RemoveFieldStatement struct {
|
|||
|
||||
// DefineIndexStatement represents an SQL DEFINE INDEX statement.
|
||||
type DefineIndexStatement struct {
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
|
@ -378,6 +477,7 @@ type DefineIndexStatement struct {
|
|||
|
||||
// RemoveIndexStatement represents an SQL REMOVE INDEX statement.
|
||||
type RemoveIndexStatement struct {
|
||||
RW bool `cork:"-" codec:"-"`
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
|
@ -385,30 +485,6 @@ type RemoveIndexStatement struct {
|
|||
What Tables `cork:"-" codec:"-"`
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// View
|
||||
// --------------------------------------------------
|
||||
|
||||
// DefineViewStatement represents an SQL DEFINE VIEW statement.
|
||||
type DefineViewStatement struct {
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
Name *Ident `cork:"name" codec:"name"`
|
||||
Expr Fields `cork:"expr" codec:"expr"`
|
||||
What Tables `cork:"what" codec:"what"`
|
||||
Cond Expr `cork:"cond" codec:"cond"`
|
||||
Group Groups `cork:"group" codec:"group"`
|
||||
}
|
||||
|
||||
// RemoveViewStatement represents an SQL REMOVE VIEW statement.
|
||||
type RemoveViewStatement struct {
|
||||
KV string `cork:"-" codec:"-"`
|
||||
NS string `cork:"-" codec:"-"`
|
||||
DB string `cork:"-" codec:"-"`
|
||||
Name *Ident `cork:"-" codec:"-"`
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// Literals
|
||||
// --------------------------------------------------
|
||||
|
@ -425,31 +501,17 @@ type All struct{}
|
|||
// Any represents a ? expression.
|
||||
type Any struct{}
|
||||
|
||||
// Asc represents the ASC expression.
|
||||
type Asc struct{}
|
||||
|
||||
// Desc represents the DESC expression.
|
||||
type Desc struct{}
|
||||
|
||||
// Null represents a null expression.
|
||||
type Null struct{}
|
||||
|
||||
// Void represents an expression which is not set.
|
||||
type Void struct{}
|
||||
|
||||
// Empty represents an expression which is null or "".
|
||||
type Empty struct{}
|
||||
|
||||
// Array represents a parsed json array.
|
||||
type Array []interface{}
|
||||
|
||||
// Object represents a parsed json object.
|
||||
type Object map[string]interface{}
|
||||
|
||||
// Field represents a SELECT AS clause.
|
||||
type Field struct {
|
||||
Expr Expr
|
||||
Alias *Ident
|
||||
Field string
|
||||
Alias string
|
||||
}
|
||||
|
||||
// Fields represents multiple SELECT AS clauses.
|
||||
|
@ -466,7 +528,8 @@ type Groups []*Group
|
|||
// Order represents a ORDER BY clause.
|
||||
type Order struct {
|
||||
Expr Expr
|
||||
Dir Expr
|
||||
Dir bool
|
||||
Tag language.Tag
|
||||
}
|
||||
|
||||
// Orders represents multiple ORDER BY clauses.
|
||||
|
@ -481,10 +544,18 @@ type SubExpression struct {
|
|||
Expr Expr
|
||||
}
|
||||
|
||||
// IfelExpression represents an if else clause.
|
||||
type IfelExpression struct {
|
||||
Cond Exprs
|
||||
Then Exprs
|
||||
Else Expr
|
||||
}
|
||||
|
||||
// FuncExpression represents a function call.
|
||||
type FuncExpression struct {
|
||||
Name string
|
||||
Args Exprs
|
||||
Aggr bool
|
||||
}
|
||||
|
||||
// ItemExpression represents a part of a SET expression.
|
||||
|
@ -529,7 +600,6 @@ type PermExpression struct {
|
|||
Create Expr
|
||||
Update Expr
|
||||
Delete Expr
|
||||
Relate Expr
|
||||
}
|
||||
|
||||
// DataExpression represents a SET expression.
|
||||
|
@ -632,6 +702,27 @@ func NewTable(TB string) *Table {
|
|||
return &Table{TB}
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// Batch
|
||||
// --------------------------------------------------
|
||||
|
||||
// Batchs represents multiple Batch clauses.
|
||||
type Batchs []*Batch
|
||||
|
||||
// Batch comment
|
||||
type Batch struct {
|
||||
TB string
|
||||
BA []*Thing
|
||||
}
|
||||
|
||||
func NewBatch(TB string, BA []interface{}) *Batch {
|
||||
var b = &Batch{TB: TB}
|
||||
for _, ID := range BA {
|
||||
b.BA = append(b.BA, NewThing(TB, ID))
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// Thing
|
||||
// --------------------------------------------------
|
||||
|
@ -646,23 +737,74 @@ type Thing struct {
|
|||
}
|
||||
|
||||
func NewThing(TB string, ID interface{}) *Thing {
|
||||
if str, ok := ID.(string); ok {
|
||||
if cnv, err := strconv.ParseFloat(str, 64); err == nil {
|
||||
if cnv == float64(int64(cnv)) {
|
||||
return &Thing{TB: TB, ID: int64(cnv)}
|
||||
}
|
||||
switch val := ID.(type) {
|
||||
default:
|
||||
return &Thing{TB: TB, ID: ID}
|
||||
case int:
|
||||
return &Thing{TB: TB, ID: float64(val)}
|
||||
case int64:
|
||||
return &Thing{TB: TB, ID: float64(val)}
|
||||
case string:
|
||||
val = strings.Replace(val, TB+":", "", -1)
|
||||
if cnv, err := strconv.ParseFloat(val, 64); err == nil {
|
||||
return &Thing{TB: TB, ID: cnv}
|
||||
} else if cnv, err := strconv.ParseBool(str); err == nil {
|
||||
} else if cnv, err := strconv.ParseBool(val); err == nil {
|
||||
return &Thing{TB: TB, ID: cnv}
|
||||
} else if cnv, err := time.Parse(RFCDate, str); err == nil {
|
||||
} else if cnv, err := time.Parse(RFCDate, val); err == nil {
|
||||
return &Thing{TB: TB, ID: cnv.UTC()}
|
||||
} else if cnv, err := time.Parse(RFCTime, str); err == nil {
|
||||
return &Thing{TB: TB, ID: cnv.UTC()}
|
||||
} else if cnv, err := time.Parse(RFCNorm, str); err == nil {
|
||||
return &Thing{TB: TB, ID: cnv.UTC()}
|
||||
} else if cnv, err := time.Parse(RFCText, str); err == nil {
|
||||
} else if cnv, err := time.Parse(RFCTime, val); err == nil {
|
||||
return &Thing{TB: TB, ID: cnv.UTC()}
|
||||
}
|
||||
return &Thing{TB: TB, ID: val}
|
||||
}
|
||||
return &Thing{TB: TB, ID: ID}
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// Point
|
||||
// --------------------------------------------------
|
||||
|
||||
// Points represents multiple Point clauses.
|
||||
type Points []*Point
|
||||
|
||||
// Point comment
|
||||
type Point struct {
|
||||
LA float64
|
||||
LO float64
|
||||
}
|
||||
|
||||
func NewPoint(LA, LO float64) *Point {
|
||||
return &Point{LA: LA, LO: LO}
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// Circle
|
||||
// --------------------------------------------------
|
||||
|
||||
// Circles represents multiple Circle clauses.
|
||||
type Circles []*Circle
|
||||
|
||||
// Circle comment
|
||||
type Circle struct {
|
||||
CE *Point
|
||||
RA float64
|
||||
}
|
||||
|
||||
func NewCircle(CE *Point, RA float64) *Circle {
|
||||
return &Circle{CE: CE, RA: RA}
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// Polygon
|
||||
// --------------------------------------------------
|
||||
|
||||
// Polygons represents multiple Polygon clauses.
|
||||
type Polygons []*Polygon
|
||||
|
||||
// Polygon comment
|
||||
type Polygon struct {
|
||||
PS Points
|
||||
}
|
||||
|
||||
func NewPolygon(PS ...*Point) *Polygon {
|
||||
return &Polygon{PS: PS}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,10 @@ func (s *LiveStatement) Auth() (string, string) {
|
|||
return s.NS, s.DB
|
||||
}
|
||||
|
||||
func (s *KillStatement) Auth() (string, string) {
|
||||
return s.NS, s.DB
|
||||
}
|
||||
|
||||
func (s *SelectStatement) Auth() (string, string) {
|
||||
return s.NS, s.DB
|
||||
}
|
||||
|
@ -58,6 +62,14 @@ func (s *RelateStatement) Auth() (string, string) {
|
|||
return s.NS, s.DB
|
||||
}
|
||||
|
||||
func (s *InsertStatement) Auth() (string, string) {
|
||||
return s.NS, s.DB
|
||||
}
|
||||
|
||||
func (s *UpsertStatement) Auth() (string, string) {
|
||||
return s.NS, s.DB
|
||||
}
|
||||
|
||||
func (s *DefineNamespaceStatement) Auth() (string, string) {
|
||||
return s.NS, s.DB
|
||||
}
|
||||
|
@ -106,6 +118,14 @@ func (s *RemoveTableStatement) Auth() (string, string) {
|
|||
return s.NS, s.DB
|
||||
}
|
||||
|
||||
func (s *DefineEventStatement) Auth() (string, string) {
|
||||
return s.NS, s.DB
|
||||
}
|
||||
|
||||
func (s *RemoveEventStatement) Auth() (string, string) {
|
||||
return s.NS, s.DB
|
||||
}
|
||||
|
||||
func (s *DefineFieldStatement) Auth() (string, string) {
|
||||
return s.NS, s.DB
|
||||
}
|
||||
|
@ -121,11 +141,3 @@ func (s *DefineIndexStatement) Auth() (string, string) {
|
|||
func (s *RemoveIndexStatement) Auth() (string, string) {
|
||||
return s.NS, s.DB
|
||||
}
|
||||
|
||||
func (s *DefineViewStatement) Auth() (string, string) {
|
||||
return s.NS, s.DB
|
||||
}
|
||||
|
||||
func (s *RemoveViewStatement) Auth() (string, string) {
|
||||
return s.NS, s.DB
|
||||
}
|
||||
|
|
|
@ -6,11 +6,14 @@
|
|||
{ "name": "Return" },
|
||||
|
||||
{ "name": "Live" },
|
||||
{ "name": "Kill" },
|
||||
{ "name": "Select" },
|
||||
{ "name": "Create" },
|
||||
{ "name": "Update" },
|
||||
{ "name": "Delete" },
|
||||
{ "name": "Relate" },
|
||||
{ "name": "Insert" },
|
||||
{ "name": "Upsert" },
|
||||
|
||||
{ "name": "DefineNamespace" },
|
||||
{ "name": "RemoveNamespace" },
|
||||
|
@ -24,10 +27,10 @@
|
|||
{ "name": "RemoveScope" },
|
||||
{ "name": "DefineTable" },
|
||||
{ "name": "RemoveTable" },
|
||||
{ "name": "DefineEvent" },
|
||||
{ "name": "RemoveEvent" },
|
||||
{ "name": "DefineField" },
|
||||
{ "name": "RemoveField" },
|
||||
{ "name": "DefineIndex" },
|
||||
{ "name": "RemoveIndex" },
|
||||
{ "name": "DefineView" },
|
||||
{ "name": "RemoveView" }
|
||||
{ "name": "RemoveIndex" }
|
||||
]
|
||||
|
|
246
sql/auth_test.go
Normal file
246
sql/auth_test.go
Normal file
|
@ -0,0 +1,246 @@
|
|||
// Code generated by https://github.com/abcum/tmpl
|
||||
// Source file: auth.gen.go.tmpl
|
||||
// DO NOT EDIT!
|
||||
|
||||
// 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 sql
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestAuth(t *testing.T) {
|
||||
|
||||
Convey("UseStatement should auth correctly", t, func() {
|
||||
s := &UseStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("InfoStatement should auth correctly", t, func() {
|
||||
s := &InfoStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("LetStatement should auth correctly", t, func() {
|
||||
s := &LetStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("ReturnStatement should auth correctly", t, func() {
|
||||
s := &ReturnStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("LiveStatement should auth correctly", t, func() {
|
||||
s := &LiveStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("KillStatement should auth correctly", t, func() {
|
||||
s := &KillStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("SelectStatement should auth correctly", t, func() {
|
||||
s := &SelectStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("CreateStatement should auth correctly", t, func() {
|
||||
s := &CreateStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("UpdateStatement should auth correctly", t, func() {
|
||||
s := &UpdateStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("DeleteStatement should auth correctly", t, func() {
|
||||
s := &DeleteStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("RelateStatement should auth correctly", t, func() {
|
||||
s := &RelateStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("InsertStatement should auth correctly", t, func() {
|
||||
s := &InsertStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("UpsertStatement should auth correctly", t, func() {
|
||||
s := &UpsertStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("DefineNamespaceStatement should auth correctly", t, func() {
|
||||
s := &DefineNamespaceStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("RemoveNamespaceStatement should auth correctly", t, func() {
|
||||
s := &RemoveNamespaceStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("DefineDatabaseStatement should auth correctly", t, func() {
|
||||
s := &DefineDatabaseStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("RemoveDatabaseStatement should auth correctly", t, func() {
|
||||
s := &RemoveDatabaseStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("DefineLoginStatement should auth correctly", t, func() {
|
||||
s := &DefineLoginStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("RemoveLoginStatement should auth correctly", t, func() {
|
||||
s := &RemoveLoginStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("DefineTokenStatement should auth correctly", t, func() {
|
||||
s := &DefineTokenStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("RemoveTokenStatement should auth correctly", t, func() {
|
||||
s := &RemoveTokenStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("DefineScopeStatement should auth correctly", t, func() {
|
||||
s := &DefineScopeStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("RemoveScopeStatement should auth correctly", t, func() {
|
||||
s := &RemoveScopeStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("DefineTableStatement should auth correctly", t, func() {
|
||||
s := &DefineTableStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("RemoveTableStatement should auth correctly", t, func() {
|
||||
s := &RemoveTableStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("DefineEventStatement should auth correctly", t, func() {
|
||||
s := &DefineEventStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("RemoveEventStatement should auth correctly", t, func() {
|
||||
s := &RemoveEventStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("DefineFieldStatement should auth correctly", t, func() {
|
||||
s := &DefineFieldStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("RemoveFieldStatement should auth correctly", t, func() {
|
||||
s := &RemoveFieldStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("DefineIndexStatement should auth correctly", t, func() {
|
||||
s := &DefineIndexStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
Convey("RemoveIndexStatement should auth correctly", t, func() {
|
||||
s := &RemoveIndexStatement{NS: "namespace", DB: "database"}
|
||||
n, d := s.Auth()
|
||||
So(n, ShouldEqual, "namespace")
|
||||
So(d, ShouldEqual, "database")
|
||||
})
|
||||
|
||||
}
|
62
sql/check.go
Normal file
62
sql/check.go
Normal file
|
@ -0,0 +1,62 @@
|
|||
// 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 sql
|
||||
|
||||
func checkExpression(allowed map[string]bool, expr Fields, grps Groups) error {
|
||||
|
||||
if len(grps) > 0 {
|
||||
|
||||
skip:
|
||||
for _, e := range expr {
|
||||
|
||||
for _, g := range grps {
|
||||
|
||||
// If the expression in the SELECT
|
||||
// clause is a field, then check to
|
||||
// see if it exists in the GROUP BY.
|
||||
|
||||
if i, ok := g.Expr.(*Ident); ok {
|
||||
if e.Field == i.ID {
|
||||
continue skip
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise if the expression in
|
||||
// the SELECT clause is a function
|
||||
// then check to see if it is an
|
||||
// aggregate function.
|
||||
|
||||
if f, ok := e.Expr.(*FuncExpression); ok {
|
||||
if ok = allowed[f.Name]; ok {
|
||||
continue skip
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// If the expression in the SELECT
|
||||
// clause isn't an aggregate function
|
||||
// and isn't specified in the GROUP BY
|
||||
// clause, then raise an error.
|
||||
|
||||
return &GroupError{found: e.Field}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
1436
sql/cork.go
1436
sql/cork.go
File diff suppressed because it is too large
Load diff
|
@ -16,9 +16,9 @@ package sql
|
|||
|
||||
func (p *parser) parseCreateStatement() (stmt *CreateStatement, err error) {
|
||||
|
||||
stmt = &CreateStatement{}
|
||||
stmt = &CreateStatement{RW: true}
|
||||
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthSC); err != nil {
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthNO); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -38,10 +38,6 @@ func (p *parser) parseCreateStatement() (stmt *CreateStatement, err error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, RPAREN, SEMICOLON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ func (p *parser) parseSet() (mul Expr, err error) {
|
|||
// always be an identifier, specifying a
|
||||
// record field to set.
|
||||
|
||||
tok, lit, err = p.shouldBe(IDENT)
|
||||
tok, lit, err = p.shouldBe(IDENT, EXPR)
|
||||
if err != nil {
|
||||
return nil, &ParseError{Found: lit, Expected: []string{"field name"}}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ package sql
|
|||
|
||||
func (p *parser) parseDefineDatabaseStatement() (stmt *DefineDatabaseStatement, err error) {
|
||||
|
||||
stmt = &DefineDatabaseStatement{}
|
||||
stmt = &DefineDatabaseStatement{RW: true}
|
||||
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthNS); err != nil {
|
||||
return nil, err
|
||||
|
@ -32,7 +32,7 @@ func (p *parser) parseDefineDatabaseStatement() (stmt *DefineDatabaseStatement,
|
|||
|
||||
func (p *parser) parseRemoveDatabaseStatement() (stmt *RemoveDatabaseStatement, err error) {
|
||||
|
||||
stmt = &RemoveDatabaseStatement{}
|
||||
stmt = &RemoveDatabaseStatement{RW: true}
|
||||
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthNS); err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -17,7 +17,7 @@ package sql
|
|||
func (p *parser) parseDefineStatement() (Statement, error) {
|
||||
|
||||
// Inspect the next token.
|
||||
tok, _, err := p.shouldBe(NAMESPACE, DATABASE, LOGIN, TOKEN, SCOPE, TABLE, FIELD, INDEX, VIEW)
|
||||
tok, _, err := p.shouldBe(NAMESPACE, DATABASE, LOGIN, TOKEN, SCOPE, TABLE, EVENT, FIELD, INDEX)
|
||||
|
||||
switch tok {
|
||||
case NAMESPACE:
|
||||
|
@ -32,12 +32,12 @@ func (p *parser) parseDefineStatement() (Statement, error) {
|
|||
return p.parseDefineScopeStatement()
|
||||
case TABLE:
|
||||
return p.parseDefineTableStatement()
|
||||
case EVENT:
|
||||
return p.parseDefineEventStatement()
|
||||
case FIELD:
|
||||
return p.parseDefineFieldStatement()
|
||||
case INDEX:
|
||||
return p.parseDefineIndexStatement()
|
||||
case VIEW:
|
||||
return p.parseDefineViewStatement()
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -16,9 +16,9 @@ package sql
|
|||
|
||||
func (p *parser) parseDeleteStatement() (stmt *DeleteStatement, err error) {
|
||||
|
||||
stmt = &DeleteStatement{}
|
||||
stmt = &DeleteStatement{RW: true}
|
||||
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthSC); err != nil {
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthNO); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -47,10 +47,6 @@ func (p *parser) parseDeleteStatement() (stmt *DeleteStatement, err error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, RPAREN, SEMICOLON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
|
||||
package sql
|
||||
|
||||
func (p *parser) parseEcho(empty Token) (exp Token, err error) {
|
||||
func (p *parser) parseEcho(fallback Token) (exp Token, err error) {
|
||||
|
||||
exp = empty
|
||||
exp = fallback
|
||||
|
||||
// The next token that we expect to see is a
|
||||
// RETURN token, and if we don't find one then
|
||||
|
@ -24,7 +24,7 @@ func (p *parser) parseEcho(empty Token) (exp Token, err error) {
|
|||
|
||||
if _, _, exi := p.mightBe(RETURN); exi {
|
||||
|
||||
exp, _, err = p.shouldBe(ID, NONE, INFO, BOTH, DIFF, BEFORE, AFTER)
|
||||
exp, _, err = p.shouldBe(NONE, INFO, BOTH, DIFF, BEFORE, AFTER)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
18
sql/error.go
18
sql/error.go
|
@ -43,6 +43,14 @@ func (e *BlankError) Error() string {
|
|||
return fmt.Sprint("You need to specify a namespace and a database to use")
|
||||
}
|
||||
|
||||
// TransError represents an error that occured when switching access.
|
||||
type TransError struct{}
|
||||
|
||||
// Error returns the string representation of the error.
|
||||
func (e *TransError) Error() string {
|
||||
return fmt.Sprintf("You can't change NAMESPACE or DATABASE inside of a transaction")
|
||||
}
|
||||
|
||||
// PermsError represents an error that occured when switching access.
|
||||
type PermsError struct {
|
||||
Resource string
|
||||
|
@ -53,6 +61,16 @@ func (e *PermsError) Error() string {
|
|||
return fmt.Sprintf("You don't have permission to access the '%s' resource", e.Resource)
|
||||
}
|
||||
|
||||
// GroupError occurs when a 'group' expression is invalid.
|
||||
type GroupError struct {
|
||||
found interface{}
|
||||
}
|
||||
|
||||
// Error returns the string representation of the error.
|
||||
func (e *GroupError) Error() string {
|
||||
return fmt.Sprintf("Found '%v' but field is not an aggregate function, and is not present in GROUP expression", e.found)
|
||||
}
|
||||
|
||||
// ParseError represents an error that occurred during parsing.
|
||||
type ParseError struct {
|
||||
Found string
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
|
||||
package sql
|
||||
|
||||
func (p *parser) parseDefineViewStatement() (stmt *DefineViewStatement, err error) {
|
||||
func (p *parser) parseDefineEventStatement() (stmt *DefineEventStatement, err error) {
|
||||
|
||||
stmt = &DefineViewStatement{}
|
||||
stmt = &DefineEventStatement{RW: true}
|
||||
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthDB); err != nil {
|
||||
return nil, err
|
||||
|
@ -26,38 +26,27 @@ func (p *parser) parseDefineViewStatement() (stmt *DefineViewStatement, err erro
|
|||
return nil, err
|
||||
}
|
||||
|
||||
_, _, err = p.shouldBe(AS)
|
||||
if err != nil {
|
||||
if _, _, err = p.shouldBe(ON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, _, err = p.shouldBe(SELECT)
|
||||
if err != nil {
|
||||
if stmt.What, err = p.parseTables(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stmt.Expr, err = p.parseFields(); err != nil {
|
||||
if _, _, err = p.shouldBe(WHEN); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, _, err = p.shouldBe(FROM)
|
||||
if err != nil {
|
||||
if stmt.When, err = p.parseExpr(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stmt.What, err = p.parseWhat(); err != nil {
|
||||
if _, _, err = p.shouldBe(THEN); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stmt.Cond, err = p.parseCond(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stmt.Group, err = p.parseGroup(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, SEMICOLON); err != nil {
|
||||
if stmt.Then, err = p.parseExpr(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -65,9 +54,9 @@ func (p *parser) parseDefineViewStatement() (stmt *DefineViewStatement, err erro
|
|||
|
||||
}
|
||||
|
||||
func (p *parser) parseRemoveViewStatement() (stmt *RemoveViewStatement, err error) {
|
||||
func (p *parser) parseRemoveEventStatement() (stmt *RemoveEventStatement, err error) {
|
||||
|
||||
stmt = &RemoveViewStatement{}
|
||||
stmt = &RemoveEventStatement{RW: true}
|
||||
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthDB); err != nil {
|
||||
return nil, err
|
||||
|
@ -77,7 +66,11 @@ func (p *parser) parseRemoveViewStatement() (stmt *RemoveViewStatement, err erro
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, SEMICOLON); err != nil {
|
||||
if _, _, err = p.shouldBe(ON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stmt.What, err = p.parseTables(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
464
sql/exprs.go
464
sql/exprs.go
|
@ -16,42 +16,22 @@ package sql
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"github.com/abcum/surreal/util/rand"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func (p *parser) parseWhat() (mul []Expr, err error) {
|
||||
|
||||
for {
|
||||
|
||||
tok, lit, err := p.shouldBe(IDENT, THING, PARAM, MODEL)
|
||||
exp, err := p.parsePart()
|
||||
if err != nil {
|
||||
return nil, &ParseError{Found: lit, Expected: []string{"table, or thing"}}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if p.is(tok, IDENT) {
|
||||
one, _ := p.declare(TABLE, lit)
|
||||
mul = append(mul, one)
|
||||
}
|
||||
|
||||
if p.is(tok, THING) {
|
||||
one, _ := p.declare(THING, lit)
|
||||
mul = append(mul, one)
|
||||
}
|
||||
|
||||
if p.is(tok, PARAM) {
|
||||
one, _ := p.declare(PARAM, lit)
|
||||
mul = append(mul, one)
|
||||
}
|
||||
|
||||
if p.is(tok, MODEL) {
|
||||
one, _ := p.declare(MODEL, lit)
|
||||
mul = append(mul, one)
|
||||
}
|
||||
mul = append(mul, exp)
|
||||
|
||||
// Check to see if the next token is a comma
|
||||
// and if not, then break out of the loop,
|
||||
|
@ -67,6 +47,19 @@ func (p *parser) parseWhat() (mul []Expr, err error) {
|
|||
|
||||
}
|
||||
|
||||
func (p *parser) parseValue() (*Value, error) {
|
||||
|
||||
tok, lit, err := p.shouldBe(STRING, REGION)
|
||||
if err != nil {
|
||||
return nil, &ParseError{Found: lit, Expected: []string{"string"}}
|
||||
}
|
||||
|
||||
val, err := p.declare(tok, lit)
|
||||
|
||||
return val.(*Value), err
|
||||
|
||||
}
|
||||
|
||||
func (p *parser) parseIdent() (*Ident, error) {
|
||||
|
||||
_, lit, err := p.shouldBe(IDENT)
|
||||
|
@ -135,40 +128,6 @@ func (p *parser) parseTables() (mul Tables, err error) {
|
|||
|
||||
}
|
||||
|
||||
func (p *parser) parseThing() (*Thing, error) {
|
||||
|
||||
_, lit, err := p.shouldBe(THING)
|
||||
if err != nil {
|
||||
return nil, &ParseError{Found: lit, Expected: []string{"thing"}}
|
||||
}
|
||||
|
||||
val, err := p.declare(THING, lit)
|
||||
|
||||
return val.(*Thing), err
|
||||
|
||||
}
|
||||
|
||||
func (p *parser) parseThings() (mul Things, err error) {
|
||||
|
||||
for {
|
||||
|
||||
one, err := p.parseThing()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mul = append(mul, one)
|
||||
|
||||
if _, _, exi := p.mightBe(COMMA); !exi {
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
func (p *parser) parseIdiom() (*Ident, error) {
|
||||
|
||||
_, lit, err := p.shouldBe(IDENT, EXPR)
|
||||
|
@ -225,92 +184,6 @@ func (p *parser) parseCond() (exp Expr, err error) {
|
|||
//
|
||||
// --------------------------------------------------
|
||||
|
||||
func (p *parser) parseRand() (exp []byte, err error) {
|
||||
|
||||
exp = rand.New(128)
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
//
|
||||
// --------------------------------------------------
|
||||
|
||||
func (p *parser) parseArray() (Array, error) {
|
||||
|
||||
_, lit, err := p.shouldBe(ARRAY)
|
||||
if err != nil {
|
||||
return nil, &ParseError{Found: lit, Expected: []string{"array"}}
|
||||
}
|
||||
|
||||
val, err := p.declare(ARRAY, lit)
|
||||
|
||||
return val.(Array), err
|
||||
|
||||
}
|
||||
|
||||
func (p *parser) parseObject() (Object, error) {
|
||||
|
||||
_, lit, err := p.shouldBe(JSON)
|
||||
if err != nil {
|
||||
return nil, &ParseError{Found: lit, Expected: []string{"object"}}
|
||||
}
|
||||
|
||||
val, err := p.declare(JSON, lit)
|
||||
|
||||
return val.(Object), err
|
||||
|
||||
}
|
||||
|
||||
func (p *parser) parseNumber() (int64, error) {
|
||||
|
||||
_, lit, err := p.shouldBe(NUMBER)
|
||||
if err != nil {
|
||||
return int64(0), &ParseError{Found: lit, Expected: []string{"number"}}
|
||||
}
|
||||
|
||||
val, err := p.declare(NUMBER, lit)
|
||||
|
||||
return val.(int64), err
|
||||
|
||||
}
|
||||
|
||||
func (p *parser) parseDouble() (float64, error) {
|
||||
|
||||
_, lit, err := p.shouldBe(NUMBER, DOUBLE)
|
||||
if err != nil {
|
||||
return float64(0), &ParseError{Found: lit, Expected: []string{"number"}}
|
||||
}
|
||||
|
||||
val, err := p.declare(DOUBLE, lit)
|
||||
|
||||
return val.(float64), err
|
||||
|
||||
}
|
||||
|
||||
func (p *parser) parseString() (string, error) {
|
||||
|
||||
_, lit, err := p.shouldBe(STRING)
|
||||
if err != nil {
|
||||
return string(""), &ParseError{Found: lit, Expected: []string{"string"}}
|
||||
}
|
||||
|
||||
return lit, err
|
||||
|
||||
}
|
||||
|
||||
func (p *parser) parseRegion() (string, error) {
|
||||
|
||||
_, lit, err := p.shouldBe(STRING, REGION)
|
||||
if err != nil {
|
||||
return string(""), &ParseError{Found: lit, Expected: []string{"string"}}
|
||||
}
|
||||
|
||||
return lit, err
|
||||
|
||||
}
|
||||
|
||||
func (p *parser) parseBinary() ([]byte, error) {
|
||||
|
||||
_, lit, err := p.shouldBe(STRING, REGION)
|
||||
|
@ -322,40 +195,13 @@ func (p *parser) parseBinary() ([]byte, error) {
|
|||
|
||||
}
|
||||
|
||||
func (p *parser) parseScript() (string, error) {
|
||||
func (p *parser) parseTimeout() (time.Duration, error) {
|
||||
|
||||
_, lit, err := p.shouldBe(STRING, REGION)
|
||||
if err != nil {
|
||||
return string(""), &ParseError{Found: lit, Expected: []string{"script"}}
|
||||
if _, _, exi := p.mightBe(TIMEOUT); !exi {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
return lit, err
|
||||
|
||||
}
|
||||
|
||||
func (p *parser) parseRegexp() (string, error) {
|
||||
|
||||
tok, lit, err := p.shouldBe(REGEX)
|
||||
if err != nil {
|
||||
return string(""), &ParseError{Found: lit, Expected: []string{"regular expression"}}
|
||||
}
|
||||
|
||||
val, err := p.declare(tok, lit)
|
||||
|
||||
return val.(*regexp.Regexp).String(), err
|
||||
|
||||
}
|
||||
|
||||
func (p *parser) parseBoolean() (bool, error) {
|
||||
|
||||
tok, lit, err := p.shouldBe(TRUE, FALSE)
|
||||
if err != nil {
|
||||
return bool(false), &ParseError{Found: lit, Expected: []string{"boolean"}}
|
||||
}
|
||||
|
||||
val, err := p.declare(tok, lit)
|
||||
|
||||
return val.(bool), err
|
||||
return p.parseDuration()
|
||||
|
||||
}
|
||||
|
||||
|
@ -372,48 +218,69 @@ func (p *parser) parseDuration() (time.Duration, error) {
|
|||
|
||||
}
|
||||
|
||||
func (p *parser) parseTimeout() (time.Duration, error) {
|
||||
func (p *parser) parseType() (t, k string, err error) {
|
||||
|
||||
if _, _, exi := p.mightBe(TIMEOUT); !exi {
|
||||
return 0, nil
|
||||
_, t, err = p.shouldBe(IDENT, STRING)
|
||||
if err != nil {
|
||||
err = &ParseError{Found: t, Expected: allowedTypes}
|
||||
return
|
||||
}
|
||||
|
||||
return p.parseDuration()
|
||||
if !p.contains(t, allowedTypes) {
|
||||
err = &ParseError{Found: t, Expected: allowedTypes}
|
||||
return
|
||||
}
|
||||
|
||||
if t == "record" {
|
||||
if _, _, exi := p.mightBe(LPAREN); exi {
|
||||
if _, k, err = p.shouldBe(IDENT); err != nil {
|
||||
return
|
||||
}
|
||||
if _, _, err = p.shouldBe(RPAREN); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
func (p *parser) parseBcrypt() ([]byte, error) {
|
||||
func (p *parser) parseLanguage() (language.Tag, error) {
|
||||
|
||||
_, lit, err := p.shouldBe(STRING)
|
||||
_, lit, err := p.shouldBe(IDENT, STRING)
|
||||
if err != nil {
|
||||
return nil, &ParseError{Found: lit, Expected: []string{"string"}}
|
||||
return language.English, &ParseError{Found: lit, Expected: []string{"string"}}
|
||||
}
|
||||
|
||||
return bcrypt.GenerateFromPassword([]byte(lit), bcrypt.DefaultCost)
|
||||
tag, err := language.Parse(lit)
|
||||
if err != nil {
|
||||
return language.English, &ParseError{Found: lit, Expected: []string{"BCP47 language"}}
|
||||
}
|
||||
|
||||
if _, _, exi := p.mightBe(NUMERIC); exi {
|
||||
tag, _ = tag.SetTypeForKey("kn", "true")
|
||||
}
|
||||
|
||||
return tag, err
|
||||
|
||||
}
|
||||
|
||||
func (p *parser) parseAlgorithm() (string, error) {
|
||||
|
||||
expected := []string{
|
||||
"ES256", "ES384", "ES512",
|
||||
"HS256", "HS384", "HS512",
|
||||
"PS256", "PS384", "PS512",
|
||||
"RS256", "RS384", "RS512",
|
||||
}
|
||||
|
||||
_, lit, err := p.shouldBe(IDENT, STRING)
|
||||
if err != nil {
|
||||
return string(""), &ParseError{Found: lit, Expected: expected}
|
||||
return string(""), &ParseError{Found: lit, Expected: allowedAlgorithms}
|
||||
}
|
||||
|
||||
switch lit {
|
||||
case "ES256", "ES384", "ES512":
|
||||
case "HS256", "HS384", "HS512":
|
||||
case "PS256", "PS384", "PS512":
|
||||
case "RS256", "RS384", "RS512":
|
||||
case
|
||||
"ES256", "ES384", "ES512",
|
||||
"HS256", "HS384", "HS512",
|
||||
"PS256", "PS384", "PS512",
|
||||
"RS256", "RS384", "RS512":
|
||||
default:
|
||||
return string(""), &ParseError{Found: lit, Expected: expected}
|
||||
return string(""), &ParseError{Found: lit, Expected: allowedAlgorithms}
|
||||
}
|
||||
|
||||
return lit, err
|
||||
|
@ -426,28 +293,40 @@ func (p *parser) parseExpr() (exp Expr, err error) {
|
|||
|
||||
root := &BinaryExpression{}
|
||||
|
||||
// If the subsequent token is an in, out, or
|
||||
// multi way path expression, then parse all
|
||||
// following expressions as a path.
|
||||
// If the primary token is an in, out, or
|
||||
// multi way path expression, then follow
|
||||
// the path through to the end.
|
||||
|
||||
if tok, _, exi := p.mightBe(OEDGE, IEDGE, BEDGE); exi {
|
||||
return p.parsePath(tok)
|
||||
}
|
||||
|
||||
// Begin with parsing the first expression
|
||||
// as the root of the tree to start with.
|
||||
root.RHS, err = p.parsePath(tok)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
root.RHS, err = p.parsePart()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
|
||||
// If the subsequent token is an in, out, or
|
||||
// multi way path expression, then parse all
|
||||
// following expressions as a path.
|
||||
// Otherwise begin with parsing the first
|
||||
// expression, as the root of the tree.
|
||||
|
||||
root.RHS, err = p.parsePart()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// But if the subsequent token is an in, out,
|
||||
// or multi way path expression, then follow
|
||||
// the path through to the end.
|
||||
|
||||
if tok, _, exi := p.mightBe(DOT, OEDGE, IEDGE, BEDGE); exi {
|
||||
|
||||
root.RHS, err = p.parsePath(root.RHS, tok)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if tok, _, exi := p.mightBe(OEDGE, IEDGE, BEDGE); exi {
|
||||
return p.parsePath(root.RHS, tok)
|
||||
}
|
||||
|
||||
// Loop over the operations and expressions
|
||||
|
@ -548,7 +427,7 @@ func (p *parser) parseExpr() (exp Expr, err error) {
|
|||
// of the expression and add it to the right.
|
||||
|
||||
if rhs == nil {
|
||||
rhs, err = p.parsePart()
|
||||
rhs, err = p.parseExpr()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -562,6 +441,21 @@ func (p *parser) parseExpr() (exp Expr, err error) {
|
|||
|
||||
for node := root; ; {
|
||||
r, ok := node.RHS.(*BinaryExpression)
|
||||
// IMPORTANT fix binary OR/AND expressions
|
||||
/*if !ok {
|
||||
if node.Op.precedence() >= tok.precedence() {
|
||||
node.RHS = &BinaryExpression{LHS: node.RHS, Op: tok, RHS: rhs}
|
||||
break
|
||||
} else {
|
||||
r = &BinaryExpression{LHS: node, Op: tok, RHS: rhs}
|
||||
break
|
||||
}
|
||||
} else {
|
||||
if r.Op.precedence() >= tok.precedence() {
|
||||
node.RHS = &BinaryExpression{LHS: node.RHS, Op: tok, RHS: rhs}
|
||||
break
|
||||
}
|
||||
}*/
|
||||
if !ok || r.Op.precedence() >= tok.precedence() {
|
||||
node.RHS = &BinaryExpression{LHS: node.RHS, Op: tok, RHS: rhs}
|
||||
break
|
||||
|
@ -578,10 +472,10 @@ func (p *parser) parseExpr() (exp Expr, err error) {
|
|||
func (p *parser) parsePart() (exp Expr, err error) {
|
||||
|
||||
toks := []Token{
|
||||
MUL, ID, EXPR, IDENT, THING,
|
||||
MUL, EXPR, IDENT, THING, MODEL,
|
||||
NULL, VOID, EMPTY, MISSING,
|
||||
TRUE, FALSE, STRING, REGION, NUMBER, DOUBLE,
|
||||
NOW, DATE, TIME, DURATION, JSON, ARRAY, PARAM, LPAREN,
|
||||
DATE, TIME, DURATION, JSON, ARRAY, PARAM, LPAREN, IF,
|
||||
}
|
||||
|
||||
tok, lit, _ := p.scan()
|
||||
|
@ -595,6 +489,14 @@ func (p *parser) parsePart() (exp Expr, err error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// If the current token is a IF word clause
|
||||
// then we will parse anything from here on
|
||||
// as an IF expression clause.
|
||||
|
||||
if p.is(tok, IF) {
|
||||
return p.parseIfel()
|
||||
}
|
||||
|
||||
// If the current token is a left parenthesis
|
||||
// bracket, then we will parse this complete
|
||||
// expression part as a subquery.
|
||||
|
@ -628,33 +530,114 @@ func (p *parser) parseSubq() (sub *SubExpression, err error) {
|
|||
var exp Expr
|
||||
var tok Token
|
||||
|
||||
tok, _, _ = p.mightBe(SELECT, CREATE, UPDATE, DELETE, RELATE)
|
||||
tok, _, _ = p.mightBe(SELECT, CREATE, UPDATE, DELETE, RELATE, INSERT, UPSERT)
|
||||
|
||||
switch tok {
|
||||
default:
|
||||
exp, err = p.parseExpr()
|
||||
case SELECT:
|
||||
exp, err = p.parseSelectStatement()
|
||||
case CREATE:
|
||||
p.buf.rw = true
|
||||
exp, err = p.parseCreateStatement()
|
||||
case UPDATE:
|
||||
p.buf.rw = true
|
||||
exp, err = p.parseUpdateStatement()
|
||||
case DELETE:
|
||||
p.buf.rw = true
|
||||
exp, err = p.parseDeleteStatement()
|
||||
case RELATE:
|
||||
p.buf.rw = true
|
||||
exp, err = p.parseRelateStatement()
|
||||
case INSERT:
|
||||
p.buf.rw = true
|
||||
exp, err = p.parseInsertStatement()
|
||||
case UPSERT:
|
||||
p.buf.rw = true
|
||||
exp, err = p.parseUpsertStatement()
|
||||
default:
|
||||
exp, err = p.parseExpr()
|
||||
}
|
||||
|
||||
p.mightBe(RPAREN)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, _, err = p.shouldBe(RPAREN)
|
||||
|
||||
return &SubExpression{Expr: exp}, err
|
||||
|
||||
}
|
||||
|
||||
func (p *parser) parseIfel() (exp *IfelExpression, err error) {
|
||||
|
||||
exp = &IfelExpression{}
|
||||
|
||||
for {
|
||||
|
||||
var tok Token
|
||||
|
||||
if cond, err := p.parseExpr(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
exp.Cond = append(exp.Cond, cond)
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(THEN); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if then, err := p.parseExpr(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
exp.Then = append(exp.Then, then)
|
||||
}
|
||||
|
||||
// Check to see if the next token is an
|
||||
// ELSE keyword and if it is then check to
|
||||
// see if there is another if statement.
|
||||
|
||||
if tok, _, err = p.shouldBe(ELSE, END); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if tok == END {
|
||||
return
|
||||
}
|
||||
|
||||
if tok == ELSE {
|
||||
if _, _, exi := p.mightBe(IF); !exi {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if then, err := p.parseExpr(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
exp.Else = then
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(END); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
func (p *parser) parseCall(name string) (fnc *FuncExpression, err error) {
|
||||
|
||||
fnc = &FuncExpression{Name: name}
|
||||
|
||||
// Check to see if this is an aggregate
|
||||
// function, and if it is then mark it,
|
||||
// so we can process it correcyly in the
|
||||
// 'iterator' and 'document' layers.
|
||||
|
||||
if _, ok := aggrs[name]; ok {
|
||||
fnc.Aggr = true
|
||||
}
|
||||
|
||||
// Check to see if the immediate token
|
||||
// is a right parenthesis bracket, and if
|
||||
// it is then this function has no args.
|
||||
|
@ -702,13 +685,27 @@ func (p *parser) parseCall(name string) (fnc *FuncExpression, err error) {
|
|||
|
||||
}
|
||||
|
||||
// Check to see if this function is allowed to
|
||||
// have an undefined number of arguments, and
|
||||
// if it is then skip argument checking.
|
||||
|
||||
if _, ok := funcs[fnc.Name][-1]; ok {
|
||||
return
|
||||
}
|
||||
|
||||
// Check to see if the number of arguments
|
||||
// is correct for the specified function name,
|
||||
// and if not, then return an error.
|
||||
|
||||
if _, ok := funcs[fnc.Name][len(fnc.Args)]; !ok {
|
||||
|
||||
s, t := "", len(funcs[fnc.Name])
|
||||
s, a, t := "", []int{}, len(funcs[fnc.Name])
|
||||
|
||||
for i := range funcs[fnc.Name] {
|
||||
a = append(a, i)
|
||||
}
|
||||
|
||||
sort.Ints(a)
|
||||
|
||||
for i := 0; i < t; i++ {
|
||||
switch {
|
||||
|
@ -717,13 +714,13 @@ func (p *parser) parseCall(name string) (fnc *FuncExpression, err error) {
|
|||
case i > 0:
|
||||
s = s + ", "
|
||||
}
|
||||
s = s + fmt.Sprintf("%d", i)
|
||||
s = s + fmt.Sprintf("%d", a[i])
|
||||
}
|
||||
|
||||
switch {
|
||||
case t == 1:
|
||||
switch t {
|
||||
case 1:
|
||||
s = s + " argument"
|
||||
case t >= 2:
|
||||
default:
|
||||
s = s + " arguments"
|
||||
}
|
||||
|
||||
|
@ -740,6 +737,17 @@ func (p *parser) parseCall(name string) (fnc *FuncExpression, err error) {
|
|||
|
||||
func (p *parser) parsePath(expr ...Expr) (path *PathExpression, err error) {
|
||||
|
||||
defer func() {
|
||||
if val, ok := path.Expr[len(path.Expr)-1].(*JoinExpression); ok {
|
||||
if val.Join == DOT {
|
||||
err = &ParseError{
|
||||
Found: fmt.Sprintf("."),
|
||||
Expected: []string{"field expression"},
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
path = &PathExpression{}
|
||||
|
||||
// Take the previosuly scanned expression
|
||||
|
@ -820,7 +828,7 @@ func (p *parser) parsePath(expr ...Expr) (path *PathExpression, err error) {
|
|||
func (p *parser) parseJoin() (exp Expr, err error) {
|
||||
|
||||
toks := []Token{
|
||||
OEDGE, IEDGE, BEDGE,
|
||||
DOT, OEDGE, IEDGE, BEDGE,
|
||||
}
|
||||
|
||||
tok, _, _ := p.scan()
|
||||
|
@ -837,7 +845,7 @@ func (p *parser) parseJoin() (exp Expr, err error) {
|
|||
func (p *parser) parseStep() (exp Expr, err error) {
|
||||
|
||||
toks := []Token{
|
||||
QMARK, IDENT, THING, PARAM, LPAREN,
|
||||
QMARK, IDENT, THING, PARAM, LPAREN, EXPR, MUL,
|
||||
}
|
||||
|
||||
tok, lit, _ := p.scan()
|
||||
|
@ -876,6 +884,8 @@ func (p *parser) parseSubp() (stmt *SubpExpression, err error) {
|
|||
|
||||
stmt = &SubpExpression{}
|
||||
|
||||
// IMPORTANT maybe we should not accept any expression here
|
||||
|
||||
if stmt.What, err = p.parseWhat(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
88
sql/field.go
88
sql/field.go
|
@ -16,13 +16,13 @@ package sql
|
|||
|
||||
func (p *parser) parseDefineFieldStatement() (stmt *DefineFieldStatement, err error) {
|
||||
|
||||
stmt = &DefineFieldStatement{}
|
||||
stmt = &DefineFieldStatement{RW: true}
|
||||
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthDB); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stmt.Name, err = p.parseIdent(); err != nil {
|
||||
if stmt.Name, err = p.parseIdiom(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -36,108 +36,44 @@ func (p *parser) parseDefineFieldStatement() (stmt *DefineFieldStatement, err er
|
|||
|
||||
for {
|
||||
|
||||
tok, _, exi := p.mightBe(MIN, MAX, TYPE, ENUM, CODE, MATCH, DEFAULT, NOTNULL, READONLY, MANDATORY, VALIDATE, PERMISSIONS)
|
||||
tok, _, exi := p.mightBe(TYPE, VALUE, ASSERT, PERMISSIONS)
|
||||
if !exi {
|
||||
break
|
||||
}
|
||||
|
||||
if p.is(tok, MIN) {
|
||||
if stmt.Min, err = p.parseDouble(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if p.is(tok, MAX) {
|
||||
if stmt.Max, err = p.parseDouble(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if p.is(tok, TYPE) {
|
||||
if stmt.Type, err = p.parseType(); err != nil {
|
||||
if stmt.Type, stmt.Kind, err = p.parseType(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if p.is(tok, ENUM) {
|
||||
if stmt.Enum, err = p.parseArray(); err != nil {
|
||||
if p.is(tok, VALUE) {
|
||||
if stmt.Value, err = p.parseExpr(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if p.is(tok, CODE) {
|
||||
if stmt.Code, err = p.parseScript(); err != nil {
|
||||
if p.is(tok, ASSERT) {
|
||||
if stmt.Assert, err = p.parseExpr(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if p.is(tok, MATCH) {
|
||||
if stmt.Match, err = p.parseRegexp(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if p.is(tok, DEFAULT) {
|
||||
if stmt.Default, err = p.parseExpr(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if p.is(tok, NOTNULL) {
|
||||
stmt.Notnull = true
|
||||
if tok, _, exi := p.mightBe(TRUE, FALSE); exi {
|
||||
if tok == FALSE {
|
||||
stmt.Notnull = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if p.is(tok, READONLY) {
|
||||
stmt.Readonly = true
|
||||
if tok, _, exi := p.mightBe(TRUE, FALSE); exi {
|
||||
if tok == FALSE {
|
||||
stmt.Readonly = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if p.is(tok, MANDATORY) {
|
||||
stmt.Mandatory = true
|
||||
if tok, _, exi := p.mightBe(TRUE, FALSE); exi {
|
||||
if tok == FALSE {
|
||||
stmt.Mandatory = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if p.is(tok, VALIDATE) {
|
||||
stmt.Validate = true
|
||||
if tok, _, exi := p.mightBe(TRUE, FALSE); exi {
|
||||
if tok == FALSE {
|
||||
stmt.Validate = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if p.is(tok, PERMISSIONS) {
|
||||
if stmt.Perm, err = p.parsePerms(); err != nil {
|
||||
if stmt.Perms, err = p.parsePerms(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, SEMICOLON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
func (p *parser) parseRemoveFieldStatement() (stmt *RemoveFieldStatement, err error) {
|
||||
|
||||
stmt = &RemoveFieldStatement{}
|
||||
stmt = &RemoveFieldStatement{RW: true}
|
||||
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthDB); err != nil {
|
||||
return nil, err
|
||||
|
@ -155,10 +91,6 @@ func (p *parser) parseRemoveFieldStatement() (stmt *RemoveFieldStatement, err er
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, SEMICOLON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
|
433
sql/funcs.go
433
sql/funcs.go
|
@ -14,233 +14,272 @@
|
|||
|
||||
package sql
|
||||
|
||||
var funcs = map[string]map[int]bool{
|
||||
var rolls = map[string]bool{
|
||||
|
||||
"abs": {
|
||||
1: true,
|
||||
},
|
||||
"distinct": true,
|
||||
|
||||
"avg": {
|
||||
1: true,
|
||||
},
|
||||
// Count implementation
|
||||
|
||||
"ceil": {
|
||||
1: true,
|
||||
},
|
||||
"count": true,
|
||||
"count.if": true,
|
||||
"count.not": true,
|
||||
|
||||
"count": {
|
||||
1: true,
|
||||
},
|
||||
// Math implementation
|
||||
|
||||
"date": {
|
||||
0: true,
|
||||
1: true,
|
||||
},
|
||||
"geometricmean": true,
|
||||
"mean": true,
|
||||
"percentile": true,
|
||||
"stddev": true,
|
||||
"sum": true,
|
||||
"variance": true,
|
||||
|
||||
"day": {
|
||||
0: true,
|
||||
1: true,
|
||||
},
|
||||
// Math implementation
|
||||
|
||||
"derivative": {
|
||||
1: true,
|
||||
},
|
||||
"math.geometricmean": true,
|
||||
"math.mean": true,
|
||||
"math.percentile": true,
|
||||
"math.stddev": true,
|
||||
"math.sum": true,
|
||||
"math.variance": true,
|
||||
}
|
||||
|
||||
"difference": {
|
||||
1: true,
|
||||
2: true,
|
||||
3: true,
|
||||
4: true,
|
||||
5: true,
|
||||
6: true,
|
||||
7: true,
|
||||
8: true,
|
||||
9: true,
|
||||
},
|
||||
var aggrs = map[string]bool{
|
||||
|
||||
"distinct": {
|
||||
1: true,
|
||||
},
|
||||
"distinct": true,
|
||||
|
||||
"floor": {
|
||||
1: true,
|
||||
},
|
||||
// Count implementation
|
||||
|
||||
"hour": {
|
||||
0: true,
|
||||
1: true,
|
||||
},
|
||||
"count": true,
|
||||
"count.if": true,
|
||||
"count.not": true,
|
||||
|
||||
"intersect": {
|
||||
1: true,
|
||||
2: true,
|
||||
3: true,
|
||||
4: true,
|
||||
5: true,
|
||||
6: true,
|
||||
7: true,
|
||||
8: true,
|
||||
9: true,
|
||||
},
|
||||
// Math implementation
|
||||
|
||||
"max": {
|
||||
1: true,
|
||||
},
|
||||
"bottom": true,
|
||||
"geometricmean": true,
|
||||
"harmonicmean": true,
|
||||
"interquartile": true,
|
||||
"max": true,
|
||||
"mean": true,
|
||||
"median": true,
|
||||
"midhinge": true,
|
||||
"min": true,
|
||||
"mode": true,
|
||||
"percentile": true,
|
||||
"sample": true,
|
||||
"spread": true,
|
||||
"stddev": true,
|
||||
"sum": true,
|
||||
"top": true,
|
||||
"trimean": true,
|
||||
"variance": true,
|
||||
|
||||
"md5": {
|
||||
1: true,
|
||||
},
|
||||
// Math implementation
|
||||
|
||||
"mean": {
|
||||
1: true,
|
||||
},
|
||||
"math.bottom": true,
|
||||
"math.geometricmean": true,
|
||||
"math.harmonicmean": true,
|
||||
"math.interquartile": true,
|
||||
"math.max": true,
|
||||
"math.mean": true,
|
||||
"math.median": true,
|
||||
"math.midhinge": true,
|
||||
"math.min": true,
|
||||
"math.mode": true,
|
||||
"math.percentile": true,
|
||||
"math.sample": true,
|
||||
"math.spread": true,
|
||||
"math.stddev": true,
|
||||
"math.sum": true,
|
||||
"math.top": true,
|
||||
"math.trimean": true,
|
||||
"math.variance": true,
|
||||
}
|
||||
|
||||
"median": {
|
||||
1: true,
|
||||
},
|
||||
var funcs = map[string]map[int]interface{}{
|
||||
|
||||
"min": {
|
||||
1: true,
|
||||
},
|
||||
"batch": {2: nil},
|
||||
"binary": {1: nil},
|
||||
"difference": {-1: nil},
|
||||
"distinct": {1: nil},
|
||||
"get": {2: nil},
|
||||
"if": {3: nil},
|
||||
"intersect": {-1: nil},
|
||||
"model": {2: nil, 3: nil, 4: nil},
|
||||
"table": {1: nil},
|
||||
"thing": {2: nil},
|
||||
"union": {-1: nil},
|
||||
|
||||
"mins": {
|
||||
0: true,
|
||||
1: true,
|
||||
},
|
||||
// Count implementation
|
||||
|
||||
"mode": {
|
||||
1: true,
|
||||
},
|
||||
"count": {1: nil},
|
||||
"count.if": {2: nil},
|
||||
"count.not": {2: nil},
|
||||
|
||||
"month": {
|
||||
0: true,
|
||||
1: true,
|
||||
},
|
||||
// Json implementation
|
||||
"json.decode": {1: nil},
|
||||
"json.encode": {1: nil},
|
||||
|
||||
"now": {
|
||||
0: true,
|
||||
},
|
||||
// Geo implementation
|
||||
"geo.point": {1: nil, 2: nil},
|
||||
"geo.circle": {2: nil},
|
||||
"geo.polygon": {-1: nil},
|
||||
"geo.distance": {2: nil},
|
||||
"geo.inside": {2: nil},
|
||||
"geo.intersects": {2: nil},
|
||||
"geo.hash.decode": {1: nil},
|
||||
"geo.hash.encode": {2: nil},
|
||||
|
||||
"percentile": {
|
||||
1: true,
|
||||
},
|
||||
// Http implementation
|
||||
"http.head": {1: nil, 2: nil},
|
||||
"http.get": {1: nil, 2: nil},
|
||||
"http.put": {1: nil, 2: nil, 3: nil},
|
||||
"http.post": {1: nil, 2: nil, 3: nil},
|
||||
"http.patch": {1: nil, 2: nil, 3: nil},
|
||||
"http.delete": {1: nil, 2: nil},
|
||||
"http.async.head": {1: nil, 2: nil},
|
||||
"http.async.get": {1: nil, 2: nil},
|
||||
"http.async.put": {1: nil, 2: nil, 3: nil},
|
||||
"http.async.post": {1: nil, 2: nil, 3: nil},
|
||||
"http.async.patch": {1: nil, 2: nil, 3: nil},
|
||||
"http.async.delete": {1: nil, 2: nil},
|
||||
|
||||
"round": {
|
||||
1: true,
|
||||
},
|
||||
// Math implementation
|
||||
"abs": {1: nil},
|
||||
"bottom": {2: nil},
|
||||
"ceil": {1: nil},
|
||||
"correlation": {2: nil},
|
||||
"covariance": {2: nil},
|
||||
"floor": {1: nil},
|
||||
"geometricmean": {1: nil},
|
||||
"harmonicmean": {1: nil},
|
||||
"interquartile": {1: nil},
|
||||
"max": {1: nil},
|
||||
"mean": {1: nil},
|
||||
"median": {1: nil},
|
||||
"midhinge": {1: nil},
|
||||
"min": {1: nil},
|
||||
"mode": {1: nil},
|
||||
"percentile": {2: nil},
|
||||
"round": {2: nil},
|
||||
"sample": {2: nil},
|
||||
"spread": {1: nil},
|
||||
"stddev": {1: nil},
|
||||
"sum": {1: nil},
|
||||
"top": {2: nil},
|
||||
"trimean": {1: nil},
|
||||
"variance": {1: nil},
|
||||
"math.abs": {1: nil},
|
||||
"math.bottom": {2: nil},
|
||||
"math.ceil": {1: nil},
|
||||
"math.correlation": {2: nil},
|
||||
"math.covariance": {2: nil},
|
||||
"math.floor": {1: nil},
|
||||
"math.geometricmean": {1: nil},
|
||||
"math.harmonicmean": {1: nil},
|
||||
"math.interquartile": {1: nil},
|
||||
"math.max": {1: nil},
|
||||
"math.mean": {1: nil},
|
||||
"math.median": {1: nil},
|
||||
"math.midhinge": {1: nil},
|
||||
"math.min": {1: nil},
|
||||
"math.mode": {1: nil},
|
||||
"math.percentile": {2: nil},
|
||||
"math.round": {1: nil},
|
||||
"math.sample": {2: nil},
|
||||
"math.spread": {1: nil},
|
||||
"math.stddev": {1: nil},
|
||||
"math.sum": {1: nil},
|
||||
"math.top": {2: nil},
|
||||
"math.trimean": {1: nil},
|
||||
"math.variance": {1: nil},
|
||||
|
||||
"stddev": {
|
||||
1: true,
|
||||
},
|
||||
// String implementation
|
||||
"string.concat": {-1: nil},
|
||||
"string.contains": {2: nil},
|
||||
"string.endsWith": {2: nil},
|
||||
"string.format": {-1: nil},
|
||||
"string.includes": {2: nil},
|
||||
"string.join": {-1: nil},
|
||||
"string.length": {1: nil},
|
||||
"string.lowercase": {1: nil},
|
||||
"string.repeat": {2: nil},
|
||||
"string.replace": {3: nil},
|
||||
"string.reverse": {3: nil},
|
||||
"string.search": {2: nil},
|
||||
"string.slice": {3: nil},
|
||||
"string.split": {2: nil},
|
||||
"string.startsWith": {2: nil},
|
||||
"string.substr": {3: nil},
|
||||
"string.trim": {1: nil},
|
||||
"string.uppercase": {1: nil},
|
||||
"string.words": {1: nil},
|
||||
|
||||
"sum": {
|
||||
1: true,
|
||||
},
|
||||
// Hash implementation
|
||||
"hash.md5": {1: nil},
|
||||
"hash.sha1": {1: nil},
|
||||
"hash.sha256": {1: nil},
|
||||
"hash.sha512": {1: nil},
|
||||
|
||||
"table": {
|
||||
1: true,
|
||||
},
|
||||
// Time implementation
|
||||
"time.now": {0: nil},
|
||||
"time.add": {2: nil},
|
||||
"time.age": {2: nil},
|
||||
"time.floor": {2: nil},
|
||||
"time.round": {2: nil},
|
||||
"time.day": {0: nil, 1: nil},
|
||||
"time.hour": {0: nil, 1: nil},
|
||||
"time.mins": {0: nil, 1: nil},
|
||||
"time.month": {0: nil, 1: nil},
|
||||
"time.nano": {0: nil, 1: nil},
|
||||
"time.secs": {0: nil, 1: nil},
|
||||
"time.unix": {0: nil, 1: nil},
|
||||
"time.year": {0: nil, 1: nil},
|
||||
|
||||
"thing": {
|
||||
2: true,
|
||||
},
|
||||
|
||||
"union": {
|
||||
1: true,
|
||||
2: true,
|
||||
3: true,
|
||||
4: true,
|
||||
5: true,
|
||||
6: true,
|
||||
7: true,
|
||||
8: true,
|
||||
9: true,
|
||||
},
|
||||
|
||||
"unixtime": {
|
||||
0: true,
|
||||
1: true,
|
||||
},
|
||||
|
||||
"uuid": {
|
||||
0: true,
|
||||
},
|
||||
|
||||
"variance": {
|
||||
1: true,
|
||||
},
|
||||
|
||||
"year": {
|
||||
0: true,
|
||||
1: true,
|
||||
},
|
||||
|
||||
// HOTP implementation
|
||||
|
||||
"hotp.compare": {
|
||||
2: true,
|
||||
},
|
||||
|
||||
"hotp.generate": {
|
||||
1: true,
|
||||
},
|
||||
|
||||
// TOTP implementation
|
||||
|
||||
"totp.compare": {
|
||||
2: true,
|
||||
},
|
||||
|
||||
"totp.generate": {
|
||||
1: true,
|
||||
},
|
||||
// Email implementation
|
||||
"email.user": {1: nil},
|
||||
"email.domain": {1: nil},
|
||||
"email.valid": {1: nil},
|
||||
|
||||
// Bcrypt implementation
|
||||
|
||||
"bcrypt.compare": {
|
||||
2: true,
|
||||
},
|
||||
|
||||
"bcrypt.generate": {
|
||||
1: true,
|
||||
},
|
||||
"bcrypt.compare": {2: nil},
|
||||
"bcrypt.generate": {1: nil},
|
||||
|
||||
// Scrypt implementation
|
||||
"scrypt.compare": {2: nil},
|
||||
"scrypt.generate": {1: nil},
|
||||
|
||||
"scrypt.compare": {
|
||||
2: true,
|
||||
},
|
||||
|
||||
"scrypt.generate": {
|
||||
1: true,
|
||||
},
|
||||
|
||||
// Pbkdf2 implementation
|
||||
|
||||
"pbkdf2.compare": {
|
||||
2: true,
|
||||
},
|
||||
|
||||
"pbkdf2.generate": {
|
||||
1: true,
|
||||
},
|
||||
|
||||
// Yubikey implementation
|
||||
|
||||
"yubikey.id": {
|
||||
1: true,
|
||||
},
|
||||
|
||||
"yubikey.ctr": {
|
||||
1: true,
|
||||
},
|
||||
|
||||
"yubikey.use": {
|
||||
1: true,
|
||||
},
|
||||
|
||||
"yubikey.verify": {
|
||||
2: true, // yubikey.verify(AUTHSERV, $otp)
|
||||
3: true, // yubikey.verify(CLIENTID, SECRET, $otp)
|
||||
},
|
||||
// Random implementation
|
||||
"rand": {0: nil},
|
||||
"uuid": {0: nil},
|
||||
"rand.bool": {0: nil},
|
||||
"rand.uuid": {0: nil},
|
||||
"rand.enum": {-1: nil},
|
||||
"rand.time": {0: nil, 2: nil},
|
||||
"rand.string": {0: nil, 1: nil, 2: nil},
|
||||
"rand.integer": {0: nil, 2: nil},
|
||||
"rand.decimal": {0: nil, 2: nil},
|
||||
"rand.sentence": {0: nil, 2: nil},
|
||||
"rand.paragraph": {0: nil, 2: nil},
|
||||
"rand.person.email": {0: nil},
|
||||
"rand.person.phone": {0: nil},
|
||||
"rand.person.fullname": {0: nil},
|
||||
"rand.person.firstname": {0: nil},
|
||||
"rand.person.lastname": {0: nil},
|
||||
"rand.person.username": {0: nil},
|
||||
"rand.person.jobtitle": {0: nil},
|
||||
"rand.company.name": {0: nil},
|
||||
"rand.company.industry": {0: nil},
|
||||
"rand.location.name": {0: nil},
|
||||
"rand.location.address": {0: nil},
|
||||
"rand.location.street": {0: nil},
|
||||
"rand.location.city": {0: nil},
|
||||
"rand.location.state": {0: nil},
|
||||
"rand.location.county": {0: nil},
|
||||
"rand.location.zipcode": {0: nil},
|
||||
"rand.location.postcode": {0: nil},
|
||||
"rand.location.country": {0: nil},
|
||||
"rand.location.altitude": {0: nil},
|
||||
"rand.location.latitude": {0: nil},
|
||||
"rand.location.longitude": {0: nil},
|
||||
}
|
||||
|
|
|
@ -17,3 +17,7 @@ package sql
|
|||
//go:generate go get -u github.com/abcum/tmpl
|
||||
//go:generate tmpl -file=auth.gen.json auth.gen.go.tmpl
|
||||
//go:generate tmpl -file=kill.gen.json kill.gen.go.tmpl
|
||||
//go:generate tmpl -file=rdwr.gen.json rdwr.gen.go.tmpl
|
||||
|
||||
//go:generate go get -u github.com/ugorji/go/codec/codecgen
|
||||
//go:generate codecgen -o ast.gen.go ast.go
|
||||
|
|
83
sql/if.go
Normal file
83
sql/if.go
Normal file
|
@ -0,0 +1,83 @@
|
|||
// 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 sql
|
||||
|
||||
func (p *parser) parseIfStatement() (stmt *IfStatement, err error) {
|
||||
|
||||
stmt = &IfStatement{}
|
||||
|
||||
for {
|
||||
|
||||
var tok Token
|
||||
|
||||
if cond, err := p.parseExpr(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
stmt.Cond = append(stmt.Cond, cond)
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(THEN); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if then, err := p.parseExpr(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
stmt.Then = append(stmt.Then, then)
|
||||
}
|
||||
|
||||
// Check to see if the next token is an
|
||||
// ELSE keyword and if it is then check to
|
||||
// see if there is another if statement.
|
||||
|
||||
if tok, _, err = p.shouldBe(ELSE, END); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if tok == END {
|
||||
return
|
||||
}
|
||||
|
||||
if tok == ELSE {
|
||||
if _, _, exi := p.mightBe(IF); !exi {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Check to see if the next token is an
|
||||
// ELSE keyword and if it is then check to
|
||||
// see if there is another if statement.
|
||||
|
||||
if then, err := p.parseExpr(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
stmt.Else = then
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(END); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If this query has any subqueries which
|
||||
// need to alter the database then mark
|
||||
// this query as a writeable statement.
|
||||
|
||||
stmt.RW = p.buf.rw
|
||||
|
||||
return
|
||||
|
||||
}
|
12
sql/index.go
12
sql/index.go
|
@ -16,7 +16,7 @@ package sql
|
|||
|
||||
func (p *parser) parseDefineIndexStatement() (stmt *DefineIndexStatement, err error) {
|
||||
|
||||
stmt = &DefineIndexStatement{}
|
||||
stmt = &DefineIndexStatement{RW: true}
|
||||
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthDB); err != nil {
|
||||
return nil, err
|
||||
|
@ -44,17 +44,13 @@ func (p *parser) parseDefineIndexStatement() (stmt *DefineIndexStatement, err er
|
|||
|
||||
_, _, stmt.Uniq = p.mightBe(UNIQUE)
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, SEMICOLON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
func (p *parser) parseRemoveIndexStatement() (stmt *RemoveIndexStatement, err error) {
|
||||
|
||||
stmt = &RemoveIndexStatement{}
|
||||
stmt = &RemoveIndexStatement{RW: true}
|
||||
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthDB); err != nil {
|
||||
return nil, err
|
||||
|
@ -72,10 +68,6 @@ func (p *parser) parseRemoveIndexStatement() (stmt *RemoveIndexStatement, err er
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, SEMICOLON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ package sql
|
|||
|
||||
func (p *parser) parseInfoStatement() (stmt *InfoStatement, err error) {
|
||||
|
||||
stmt = &InfoStatement{}
|
||||
stmt = &InfoStatement{RW: false}
|
||||
|
||||
if _, _, err = p.shouldBe(FOR); err != nil {
|
||||
return nil, err
|
||||
|
@ -47,10 +47,6 @@ func (p *parser) parseInfoStatement() (stmt *InfoStatement, err error) {
|
|||
}
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, SEMICOLON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
|
49
sql/insert.go
Normal file
49
sql/insert.go
Normal file
|
@ -0,0 +1,49 @@
|
|||
// 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 sql
|
||||
|
||||
func (p *parser) parseInsertStatement() (stmt *InsertStatement, err error) {
|
||||
|
||||
stmt = &InsertStatement{RW: true}
|
||||
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthNO); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stmt.Data, err = p.parseExpr(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(INTO); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, _, _ = p.mightBe(TABLE)
|
||||
|
||||
if stmt.Into, err = p.parseTable(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stmt.Echo, err = p.parseEcho(AFTER); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stmt.Timeout, err = p.parseTimeout(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
184
sql/kill.gen.go
184
sql/kill.gen.go
|
@ -22,202 +22,30 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
func (s *SelectStatement) Begin() {
|
||||
if s.Timeout == 0 {
|
||||
return
|
||||
}
|
||||
if s.killable.closer == nil {
|
||||
s.killable.closer = make(chan struct{})
|
||||
}
|
||||
s.killable.ticker = time.AfterFunc(s.Timeout, func() {
|
||||
s.killable.ticker.Stop()
|
||||
s.killable.ticker = nil
|
||||
close(s.killable.closer)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *SelectStatement) Cease() {
|
||||
if s.Timeout == 0 {
|
||||
return
|
||||
}
|
||||
if s.killable.closer == nil {
|
||||
s.killable.closer = make(chan struct{})
|
||||
}
|
||||
if s.killable.ticker != nil {
|
||||
s.killable.ticker.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SelectStatement) Duration() time.Duration {
|
||||
return s.Timeout
|
||||
}
|
||||
|
||||
func (s *SelectStatement) Timedout() <-chan struct{} {
|
||||
if s.Timeout == 0 {
|
||||
return nil
|
||||
}
|
||||
if s.killable.closer == nil {
|
||||
s.killable.closer = make(chan struct{})
|
||||
}
|
||||
return s.killable.closer
|
||||
}
|
||||
|
||||
func (s *CreateStatement) Begin() {
|
||||
if s.Timeout == 0 {
|
||||
return
|
||||
}
|
||||
if s.killable.closer == nil {
|
||||
s.killable.closer = make(chan struct{})
|
||||
}
|
||||
s.killable.ticker = time.AfterFunc(s.Timeout, func() {
|
||||
s.killable.ticker.Stop()
|
||||
s.killable.ticker = nil
|
||||
close(s.killable.closer)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *CreateStatement) Cease() {
|
||||
if s.Timeout == 0 {
|
||||
return
|
||||
}
|
||||
if s.killable.closer == nil {
|
||||
s.killable.closer = make(chan struct{})
|
||||
}
|
||||
if s.killable.ticker != nil {
|
||||
s.killable.ticker.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *CreateStatement) Duration() time.Duration {
|
||||
return s.Timeout
|
||||
}
|
||||
|
||||
func (s *CreateStatement) Timedout() <-chan struct{} {
|
||||
if s.Timeout == 0 {
|
||||
return nil
|
||||
}
|
||||
if s.killable.closer == nil {
|
||||
s.killable.closer = make(chan struct{})
|
||||
}
|
||||
return s.killable.closer
|
||||
}
|
||||
|
||||
func (s *UpdateStatement) Begin() {
|
||||
if s.Timeout == 0 {
|
||||
return
|
||||
}
|
||||
if s.killable.closer == nil {
|
||||
s.killable.closer = make(chan struct{})
|
||||
}
|
||||
s.killable.ticker = time.AfterFunc(s.Timeout, func() {
|
||||
s.killable.ticker.Stop()
|
||||
s.killable.ticker = nil
|
||||
close(s.killable.closer)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *UpdateStatement) Cease() {
|
||||
if s.Timeout == 0 {
|
||||
return
|
||||
}
|
||||
if s.killable.closer == nil {
|
||||
s.killable.closer = make(chan struct{})
|
||||
}
|
||||
if s.killable.ticker != nil {
|
||||
s.killable.ticker.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *UpdateStatement) Duration() time.Duration {
|
||||
return s.Timeout
|
||||
}
|
||||
|
||||
func (s *UpdateStatement) Timedout() <-chan struct{} {
|
||||
if s.Timeout == 0 {
|
||||
return nil
|
||||
}
|
||||
if s.killable.closer == nil {
|
||||
s.killable.closer = make(chan struct{})
|
||||
}
|
||||
return s.killable.closer
|
||||
}
|
||||
|
||||
func (s *DeleteStatement) Begin() {
|
||||
if s.Timeout == 0 {
|
||||
return
|
||||
}
|
||||
if s.killable.closer == nil {
|
||||
s.killable.closer = make(chan struct{})
|
||||
}
|
||||
s.killable.ticker = time.AfterFunc(s.Timeout, func() {
|
||||
s.killable.ticker.Stop()
|
||||
s.killable.ticker = nil
|
||||
close(s.killable.closer)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *DeleteStatement) Cease() {
|
||||
if s.Timeout == 0 {
|
||||
return
|
||||
}
|
||||
if s.killable.closer == nil {
|
||||
s.killable.closer = make(chan struct{})
|
||||
}
|
||||
if s.killable.ticker != nil {
|
||||
s.killable.ticker.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DeleteStatement) Duration() time.Duration {
|
||||
return s.Timeout
|
||||
}
|
||||
|
||||
func (s *DeleteStatement) Timedout() <-chan struct{} {
|
||||
if s.Timeout == 0 {
|
||||
return nil
|
||||
}
|
||||
if s.killable.closer == nil {
|
||||
s.killable.closer = make(chan struct{})
|
||||
}
|
||||
return s.killable.closer
|
||||
}
|
||||
|
||||
func (s *RelateStatement) Begin() {
|
||||
if s.Timeout == 0 {
|
||||
return
|
||||
}
|
||||
if s.killable.closer == nil {
|
||||
s.killable.closer = make(chan struct{})
|
||||
}
|
||||
s.killable.ticker = time.AfterFunc(s.Timeout, func() {
|
||||
s.killable.ticker.Stop()
|
||||
s.killable.ticker = nil
|
||||
close(s.killable.closer)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *RelateStatement) Cease() {
|
||||
if s.Timeout == 0 {
|
||||
return
|
||||
}
|
||||
if s.killable.closer == nil {
|
||||
s.killable.closer = make(chan struct{})
|
||||
}
|
||||
if s.killable.ticker != nil {
|
||||
s.killable.ticker.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *RelateStatement) Duration() time.Duration {
|
||||
return s.Timeout
|
||||
}
|
||||
|
||||
func (s *RelateStatement) Timedout() <-chan struct{} {
|
||||
if s.Timeout == 0 {
|
||||
return nil
|
||||
}
|
||||
if s.killable.closer == nil {
|
||||
s.killable.closer = make(chan struct{})
|
||||
}
|
||||
return s.killable.closer
|
||||
func (s *InsertStatement) Duration() time.Duration {
|
||||
return s.Timeout
|
||||
}
|
||||
|
||||
func (s *UpsertStatement) Duration() time.Duration {
|
||||
return s.Timeout
|
||||
}
|
||||
|
|
|
@ -20,44 +20,8 @@ import (
|
|||
|
||||
{{with $types := .}}{{range $k := $types}}
|
||||
|
||||
func (s *{{$k.name}}Statement) Begin() {
|
||||
if s.Timeout == 0 {
|
||||
return
|
||||
}
|
||||
if s.killable.closer == nil {
|
||||
s.killable.closer = make(chan struct{})
|
||||
}
|
||||
s.killable.ticker = time.AfterFunc(s.Timeout, func() {
|
||||
s.killable.ticker.Stop()
|
||||
s.killable.ticker = nil
|
||||
close(s.killable.closer)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *{{$k.name}}Statement) Cease() {
|
||||
if s.Timeout == 0 {
|
||||
return
|
||||
}
|
||||
if s.killable.closer == nil {
|
||||
s.killable.closer = make(chan struct{})
|
||||
}
|
||||
if s.killable.ticker != nil {
|
||||
s.killable.ticker.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *{{$k.name}}Statement) Duration() time.Duration {
|
||||
return s.Timeout
|
||||
}
|
||||
|
||||
func (s *{{$k.name}}Statement) Timedout() <-chan struct{} {
|
||||
if s.Timeout == 0 {
|
||||
return nil
|
||||
}
|
||||
if s.killable.closer == nil {
|
||||
s.killable.closer = make(chan struct{})
|
||||
}
|
||||
return s.killable.closer
|
||||
}
|
||||
|
||||
{{end}}{{end}}
|
||||
|
|
|
@ -3,5 +3,7 @@
|
|||
{ "name": "Create" },
|
||||
{ "name": "Update" },
|
||||
{ "name": "Delete" },
|
||||
{ "name": "Relate" }
|
||||
{ "name": "Relate" },
|
||||
{ "name": "Insert" },
|
||||
{ "name": "Upsert" }
|
||||
]
|
||||
|
|
65
sql/kill_test.go
Normal file
65
sql/kill_test.go
Normal file
|
@ -0,0 +1,65 @@
|
|||
// Code generated by https://github.com/abcum/tmpl
|
||||
// Source file: kill.gen.go.tmpl
|
||||
// DO NOT EDIT!
|
||||
|
||||
// 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 sql
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestKill(t *testing.T) {
|
||||
|
||||
Convey("SelectStatement should have duration", t, func() {
|
||||
So((&SelectStatement{}).Duration(), ShouldEqual, 0)
|
||||
So((&SelectStatement{Timeout: 1 * time.Second}).Duration(), ShouldEqual, 1*time.Second)
|
||||
})
|
||||
|
||||
Convey("CreateStatement should have duration", t, func() {
|
||||
So((&CreateStatement{}).Duration(), ShouldEqual, 0)
|
||||
So((&CreateStatement{Timeout: 1 * time.Second}).Duration(), ShouldEqual, 1*time.Second)
|
||||
})
|
||||
|
||||
Convey("UpdateStatement should have duration", t, func() {
|
||||
So((&UpdateStatement{}).Duration(), ShouldEqual, 0)
|
||||
So((&UpdateStatement{Timeout: 1 * time.Second}).Duration(), ShouldEqual, 1*time.Second)
|
||||
})
|
||||
|
||||
Convey("DeleteStatement should have duration", t, func() {
|
||||
So((&DeleteStatement{}).Duration(), ShouldEqual, 0)
|
||||
So((&DeleteStatement{Timeout: 1 * time.Second}).Duration(), ShouldEqual, 1*time.Second)
|
||||
})
|
||||
|
||||
Convey("RelateStatement should have duration", t, func() {
|
||||
So((&RelateStatement{}).Duration(), ShouldEqual, 0)
|
||||
So((&RelateStatement{Timeout: 1 * time.Second}).Duration(), ShouldEqual, 1*time.Second)
|
||||
})
|
||||
|
||||
Convey("InsertStatement should have duration", t, func() {
|
||||
So((&InsertStatement{}).Duration(), ShouldEqual, 0)
|
||||
So((&InsertStatement{Timeout: 1 * time.Second}).Duration(), ShouldEqual, 1*time.Second)
|
||||
})
|
||||
|
||||
Convey("UpsertStatement should have duration", t, func() {
|
||||
So((&UpsertStatement{}).Duration(), ShouldEqual, 0)
|
||||
So((&UpsertStatement{Timeout: 1 * time.Second}).Duration(), ShouldEqual, 1*time.Second)
|
||||
})
|
||||
|
||||
}
|
30
sql/let.go
30
sql/let.go
|
@ -14,8 +14,6 @@
|
|||
|
||||
package sql
|
||||
|
||||
import "time"
|
||||
|
||||
func (p *parser) parseLetStatement() (stmt *LetStatement, err error) {
|
||||
|
||||
stmt = &LetStatement{}
|
||||
|
@ -51,31 +49,11 @@ func (p *parser) parseLetStatement() (stmt *LetStatement, err error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// If the defined paramater is a basic type,
|
||||
// then instead of defining it at a later
|
||||
// stage, convert it to that type here.
|
||||
// If this query has any subqueries which
|
||||
// need to alter the database then mark
|
||||
// this query as a writeable statement.
|
||||
|
||||
switch stmt.What.(type) {
|
||||
case bool, int64, float64, string:
|
||||
p.v[stmt.Name.ID] = stmt.What
|
||||
case []interface{}, map[string]interface{}:
|
||||
p.v[stmt.Name.ID] = stmt.What
|
||||
case time.Time, time.Duration:
|
||||
p.v[stmt.Name.ID] = stmt.What
|
||||
case Array, Object:
|
||||
p.v[stmt.Name.ID] = stmt.What
|
||||
case *Null, *Void, *Empty:
|
||||
p.v[stmt.Name.ID] = stmt.What
|
||||
case *Table, *Thing, *Param, *Ident, *Value:
|
||||
p.v[stmt.Name.ID] = stmt.What
|
||||
}
|
||||
|
||||
// Check that we have reached the end of the
|
||||
// statement with either a ';' or EOF.
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, SEMICOLON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stmt.RW = p.buf.rw
|
||||
|
||||
return
|
||||
|
||||
|
|
71
sql/live.go
Normal file
71
sql/live.go
Normal file
|
@ -0,0 +1,71 @@
|
|||
// 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 sql
|
||||
|
||||
func (p *parser) parseLiveStatement() (stmt *LiveStatement, err error) {
|
||||
|
||||
stmt = &LiveStatement{RW: true}
|
||||
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthSC); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, _, err = p.shouldBe(SELECT)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, _, stmt.Diff = p.mightBe(DIFF)
|
||||
|
||||
if stmt.Diff == false {
|
||||
|
||||
if stmt.Expr, err = p.parseFields(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_, _, err = p.shouldBe(FROM)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stmt.What, err = p.parseTable(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stmt.Cond, err = p.parseCond(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
func (p *parser) parseKillStatement() (stmt *KillStatement, err error) {
|
||||
|
||||
stmt = &KillStatement{RW: true}
|
||||
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthSC); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stmt.Name, err = p.parseValue(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
12
sql/login.go
12
sql/login.go
|
@ -16,7 +16,7 @@ package sql
|
|||
|
||||
func (p *parser) parseDefineLoginStatement() (stmt *DefineLoginStatement, err error) {
|
||||
|
||||
stmt = &DefineLoginStatement{}
|
||||
stmt = &DefineLoginStatement{RW: true}
|
||||
|
||||
if stmt.User, err = p.parseIdent(); err != nil {
|
||||
return nil, err
|
||||
|
@ -50,17 +50,13 @@ func (p *parser) parseDefineLoginStatement() (stmt *DefineLoginStatement, err er
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, SEMICOLON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
func (p *parser) parseRemoveLoginStatement() (stmt *RemoveLoginStatement, err error) {
|
||||
|
||||
stmt = &RemoveLoginStatement{}
|
||||
stmt = &RemoveLoginStatement{RW: true}
|
||||
|
||||
if stmt.User, err = p.parseIdent(); err != nil {
|
||||
return nil, err
|
||||
|
@ -86,10 +82,6 @@ func (p *parser) parseRemoveLoginStatement() (stmt *RemoveLoginStatement, err er
|
|||
}
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, SEMICOLON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ package sql
|
|||
|
||||
func (p *parser) parseDefineNamespaceStatement() (stmt *DefineNamespaceStatement, err error) {
|
||||
|
||||
stmt = &DefineNamespaceStatement{}
|
||||
stmt = &DefineNamespaceStatement{RW: true}
|
||||
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthKV); err != nil {
|
||||
return nil, err
|
||||
|
@ -32,7 +32,7 @@ func (p *parser) parseDefineNamespaceStatement() (stmt *DefineNamespaceStatement
|
|||
|
||||
func (p *parser) parseRemoveNamespaceStatement() (stmt *RemoveNamespaceStatement, err error) {
|
||||
|
||||
stmt = &RemoveNamespaceStatement{}
|
||||
stmt = &RemoveNamespaceStatement{RW: true}
|
||||
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthKV); err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -73,9 +73,15 @@ func (o *options) ns(ns string) (err error) {
|
|||
// Check to see that the current user has
|
||||
// the necessary authentication privileges
|
||||
// to be able to specify this namespace.
|
||||
// This is only run if we are using the
|
||||
// KV, NS, or DB authentication levels, as
|
||||
// SC authentication levels make use of
|
||||
// table and field permissions instead.
|
||||
|
||||
if o.auth.Possible.NS != "*" && o.auth.Possible.NS != ns {
|
||||
return &PermsError{Resource: ns}
|
||||
if o.auth.Kind < cnf.Kind(AuthSC) {
|
||||
if o.auth.Possible.NS != "*" && o.auth.Possible.NS != ns {
|
||||
return &PermsError{Resource: ns}
|
||||
}
|
||||
}
|
||||
|
||||
// Specify the NS on the context session, so
|
||||
|
@ -93,9 +99,15 @@ func (o *options) db(db string) (err error) {
|
|||
// Check to see that the current user has
|
||||
// the necessary authentication privileges
|
||||
// to be able to specify this namespace.
|
||||
// This is only run if we are using the
|
||||
// KV, NS, or DB authentication levels, as
|
||||
// SC authentication levels make use of
|
||||
// table and field permissions instead.
|
||||
|
||||
if o.auth.Possible.DB != "*" && o.auth.Possible.DB != db {
|
||||
return &PermsError{Resource: db}
|
||||
if o.auth.Kind < cnf.Kind(AuthSC) {
|
||||
if o.auth.Possible.DB != "*" && o.auth.Possible.DB != db {
|
||||
return &PermsError{Resource: db}
|
||||
}
|
||||
}
|
||||
|
||||
// Specify the DB on the context session, so
|
||||
|
|
132
sql/parser.go
132
sql/parser.go
|
@ -29,9 +29,9 @@ type parser struct {
|
|||
s *scanner
|
||||
o *options
|
||||
c *fibre.Context
|
||||
v map[string]interface{}
|
||||
buf struct {
|
||||
n int // buffer size
|
||||
rw bool // writeable
|
||||
txn bool // inside txn
|
||||
tok Token // last read token
|
||||
lit string // last read literal
|
||||
|
@ -40,51 +40,47 @@ type parser struct {
|
|||
}
|
||||
|
||||
// Parse parses sql from a []byte, string, or io.Reader.
|
||||
func Parse(c *fibre.Context, i interface{}, v map[string]interface{}) (*Query, error) {
|
||||
func Parse(c *fibre.Context, i interface{}) (*Query, error) {
|
||||
|
||||
defer trace.FromContext(c.Context()).NewChild("sql.Parse").Finish()
|
||||
|
||||
if v == nil {
|
||||
v = make(map[string]interface{})
|
||||
}
|
||||
|
||||
switch x := i.(type) {
|
||||
default:
|
||||
return nil, &EmptyError{}
|
||||
case []byte:
|
||||
return parseBytes(c, x, v)
|
||||
return parseBytes(c, x)
|
||||
case string:
|
||||
return parseString(c, x, v)
|
||||
return parseString(c, x)
|
||||
case io.Reader:
|
||||
return parseBuffer(c, x, v)
|
||||
return parseBuffer(c, x)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// newParser returns a new instance of Parser.
|
||||
func newParser(c *fibre.Context, v map[string]interface{}) *parser {
|
||||
return &parser{c: c, v: v, o: newOptions(c)}
|
||||
func newParser(c *fibre.Context) *parser {
|
||||
return &parser{c: c, o: newOptions(c)}
|
||||
}
|
||||
|
||||
// parseBytes parses a byte array.
|
||||
func parseBytes(c *fibre.Context, i []byte, v map[string]interface{}) (*Query, error) {
|
||||
func parseBytes(c *fibre.Context, i []byte) (*Query, error) {
|
||||
p := newParser(c)
|
||||
r := bytes.NewReader(i)
|
||||
p := newParser(c, v)
|
||||
p.s = newScanner(p, r)
|
||||
return p.parse()
|
||||
}
|
||||
|
||||
// parseString parses a string.
|
||||
func parseString(c *fibre.Context, i string, v map[string]interface{}) (*Query, error) {
|
||||
func parseString(c *fibre.Context, i string) (*Query, error) {
|
||||
p := newParser(c)
|
||||
r := strings.NewReader(i)
|
||||
p := newParser(c, v)
|
||||
p.s = newScanner(p, r)
|
||||
return p.parse()
|
||||
}
|
||||
|
||||
// parseBuffer parses a buffer.
|
||||
func parseBuffer(c *fibre.Context, r io.Reader, v map[string]interface{}) (*Query, error) {
|
||||
p := newParser(c, v)
|
||||
func parseBuffer(c *fibre.Context, r io.Reader) (*Query, error) {
|
||||
p := newParser(c)
|
||||
p.s = newScanner(p, r)
|
||||
return p.parse()
|
||||
}
|
||||
|
@ -97,40 +93,91 @@ func (p *parser) parse() (*Query, error) {
|
|||
// parseMulti parses multiple SQL SELECT statements.
|
||||
func (p *parser) parseMulti() (*Query, error) {
|
||||
|
||||
var statements Statements
|
||||
|
||||
var semi bool
|
||||
var text bool
|
||||
|
||||
var stmts Statements
|
||||
|
||||
for {
|
||||
if tok, _, _ := p.scan(); tok == EOF {
|
||||
if !text {
|
||||
return nil, &EmptyError{}
|
||||
|
||||
// If the next token is an EOF then
|
||||
// check to see if the query is empty
|
||||
// or return the parsed statements.
|
||||
|
||||
if _, _, exi := p.mightBe(EOF); exi {
|
||||
if len(stmts) == 0 {
|
||||
return nil, new(EmptyError)
|
||||
}
|
||||
return &Query{Statements: statements}, nil
|
||||
} else if !semi && tok == SEMICOLON {
|
||||
semi = true
|
||||
} else {
|
||||
text = true
|
||||
p.unscan()
|
||||
s, err := p.parseSingle()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
statements = append(statements, s)
|
||||
semi = false
|
||||
return &Query{Statements: stmts}, nil
|
||||
}
|
||||
|
||||
// If this is a multi statement query
|
||||
// and there is no semicolon separating
|
||||
// the statements, then return an error.
|
||||
|
||||
if len(stmts) > 0 {
|
||||
switch semi {
|
||||
case true:
|
||||
_, _, exi := p.mightBe(SEMICOLON)
|
||||
if exi {
|
||||
continue
|
||||
}
|
||||
case false:
|
||||
_, _, err := p.shouldBe(SEMICOLON)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
semi = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the next token as a statement
|
||||
// and append it to the statements
|
||||
// array for the current sql query.
|
||||
|
||||
stmt, err := p.parseSingle()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stmts = append(stmts, stmt)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// parseSingle parses a single SQL SELECT statement.
|
||||
func (p *parser) parseSingle() (Statement, error) {
|
||||
func (p *parser) parseSingle() (stmt Statement, err error) {
|
||||
|
||||
tok, _, err := p.shouldBe(USE, INFO, BEGIN, CANCEL, COMMIT, LET, RETURN, SELECT, CREATE, UPDATE, DELETE, RELATE, DEFINE, REMOVE)
|
||||
p.buf.rw = false
|
||||
|
||||
tok, _, err := p.shouldBe(
|
||||
USE,
|
||||
INFO,
|
||||
BEGIN,
|
||||
CANCEL,
|
||||
COMMIT,
|
||||
IF,
|
||||
LET,
|
||||
RETURN,
|
||||
LIVE,
|
||||
KILL,
|
||||
SELECT,
|
||||
CREATE,
|
||||
UPDATE,
|
||||
DELETE,
|
||||
RELATE,
|
||||
INSERT,
|
||||
UPSERT,
|
||||
DEFINE,
|
||||
REMOVE,
|
||||
)
|
||||
|
||||
switch tok {
|
||||
|
||||
case IF:
|
||||
return p.parseIfStatement()
|
||||
|
||||
case USE:
|
||||
return p.parseUseStatement()
|
||||
|
||||
|
@ -140,12 +187,18 @@ func (p *parser) parseSingle() (Statement, error) {
|
|||
case INFO:
|
||||
return p.parseInfoStatement()
|
||||
|
||||
case LIVE:
|
||||
return p.parseLiveStatement()
|
||||
case KILL:
|
||||
return p.parseKillStatement()
|
||||
|
||||
case BEGIN:
|
||||
return p.parseBeginStatement()
|
||||
case CANCEL:
|
||||
return p.parseCancelStatement()
|
||||
case COMMIT:
|
||||
return p.parseCommitStatement()
|
||||
|
||||
case RETURN:
|
||||
return p.parseReturnStatement()
|
||||
|
||||
|
@ -160,6 +213,11 @@ func (p *parser) parseSingle() (Statement, error) {
|
|||
case RELATE:
|
||||
return p.parseRelateStatement()
|
||||
|
||||
case INSERT:
|
||||
return p.parseInsertStatement()
|
||||
case UPSERT:
|
||||
return p.parseUpsertStatement()
|
||||
|
||||
case DEFINE:
|
||||
return p.parseDefineStatement()
|
||||
case REMOVE:
|
||||
|
|
|
@ -21,7 +21,6 @@ func (p *parser) parsePerms() (exp *PermExpression, err error) {
|
|||
Create: false,
|
||||
Update: false,
|
||||
Delete: false,
|
||||
Relate: false,
|
||||
}
|
||||
|
||||
tok, _, err := p.shouldBe(FOR, NONE, FULL, WHERE)
|
||||
|
@ -48,7 +47,6 @@ func (p *parser) parsePerms() (exp *PermExpression, err error) {
|
|||
exp.Create = expr
|
||||
exp.Update = expr
|
||||
exp.Delete = expr
|
||||
exp.Relate = expr
|
||||
|
||||
return
|
||||
|
||||
|
@ -62,7 +60,7 @@ func (p *parser) parsePerms() (exp *PermExpression, err error) {
|
|||
var when []Token
|
||||
|
||||
for {
|
||||
tok, _, err := p.shouldBe(SELECT, CREATE, UPDATE, DELETE, RELATE)
|
||||
tok, _, err := p.shouldBe(SELECT, CREATE, UPDATE, DELETE)
|
||||
if err != nil {
|
||||
return exp, err
|
||||
}
|
||||
|
@ -98,8 +96,6 @@ func (p *parser) parsePerms() (exp *PermExpression, err error) {
|
|||
exp.Update = expr
|
||||
case DELETE:
|
||||
exp.Delete = expr
|
||||
case RELATE:
|
||||
exp.Relate = expr
|
||||
}
|
||||
}
|
||||
|
||||
|
|
143
sql/rdwr.gen.go
Normal file
143
sql/rdwr.gen.go
Normal file
|
@ -0,0 +1,143 @@
|
|||
// Code generated by https://github.com/abcum/tmpl
|
||||
// Source file: rdwr.gen.go.tmpl
|
||||
// DO NOT EDIT!
|
||||
|
||||
// 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 sql
|
||||
|
||||
func (s *InfoStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *IfStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *LetStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *ReturnStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *LiveStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *KillStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *SelectStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *CreateStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *UpdateStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *DeleteStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *RelateStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *InsertStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *UpsertStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *DefineNamespaceStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *RemoveNamespaceStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *DefineDatabaseStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *RemoveDatabaseStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *DefineLoginStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *RemoveLoginStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *DefineTokenStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *RemoveTokenStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *DefineScopeStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *RemoveScopeStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *DefineTableStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *RemoveTableStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *DefineEventStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *RemoveEventStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *DefineFieldStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *RemoveFieldStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *DefineIndexStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
func (s *RemoveIndexStatement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
|
@ -14,19 +14,10 @@
|
|||
|
||||
package sql
|
||||
|
||||
func (p *parser) parseType() (exp string, err error) {
|
||||
|
||||
allowed := []string{"any", "url", "uuid", "color", "email", "phone", "array", "object", "domain", "record", "string", "number", "double", "custom", "boolean", "password", "datetime", "latitude", "longitude"}
|
||||
|
||||
_, lit, err := p.shouldBe(IDENT)
|
||||
if err != nil {
|
||||
return string(""), &ParseError{Found: lit, Expected: allowed}
|
||||
}
|
||||
|
||||
if !p.contains(lit, allowed) {
|
||||
return string(""), &ParseError{Found: lit, Expected: allowed}
|
||||
}
|
||||
|
||||
return lit, err
|
||||
{{with $types := .}}{{range $k := $types}}
|
||||
|
||||
func (s *{{$k.name}}Statement) Writeable() bool {
|
||||
return s.RW
|
||||
}
|
||||
|
||||
{{end}}{{end}}
|
36
sql/rdwr.gen.json
Normal file
36
sql/rdwr.gen.json
Normal file
|
@ -0,0 +1,36 @@
|
|||
[
|
||||
{ "name": "Info" },
|
||||
|
||||
{ "name": "If" },
|
||||
{ "name": "Let" },
|
||||
{ "name": "Return" },
|
||||
|
||||
{ "name": "Live" },
|
||||
{ "name": "Kill" },
|
||||
{ "name": "Select" },
|
||||
{ "name": "Create" },
|
||||
{ "name": "Update" },
|
||||
{ "name": "Delete" },
|
||||
{ "name": "Relate" },
|
||||
{ "name": "Insert" },
|
||||
{ "name": "Upsert" },
|
||||
|
||||
{ "name": "DefineNamespace" },
|
||||
{ "name": "RemoveNamespace" },
|
||||
{ "name": "DefineDatabase" },
|
||||
{ "name": "RemoveDatabase" },
|
||||
{ "name": "DefineLogin" },
|
||||
{ "name": "RemoveLogin" },
|
||||
{ "name": "DefineToken" },
|
||||
{ "name": "RemoveToken" },
|
||||
{ "name": "DefineScope" },
|
||||
{ "name": "RemoveScope" },
|
||||
{ "name": "DefineTable" },
|
||||
{ "name": "RemoveTable" },
|
||||
{ "name": "DefineEvent" },
|
||||
{ "name": "RemoveEvent" },
|
||||
{ "name": "DefineField" },
|
||||
{ "name": "RemoveField" },
|
||||
{ "name": "DefineIndex" },
|
||||
{ "name": "RemoveIndex" }
|
||||
]
|
215
sql/rdwr_test.go
Normal file
215
sql/rdwr_test.go
Normal file
|
@ -0,0 +1,215 @@
|
|||
// Code generated by https://github.com/abcum/tmpl
|
||||
// Source file: auth.gen.go.tmpl
|
||||
// DO NOT EDIT!
|
||||
|
||||
// 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 sql
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestRdwr(t *testing.T) {
|
||||
|
||||
Convey("InfoStatement should auth correctly", t, func() {
|
||||
s := &InfoStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("IfStatement should auth correctly", t, func() {
|
||||
s := &IfStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("LetStatement should auth correctly", t, func() {
|
||||
s := &LetStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("ReturnStatement should auth correctly", t, func() {
|
||||
s := &ReturnStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("LiveStatement should auth correctly", t, func() {
|
||||
s := &LiveStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("KillStatement should auth correctly", t, func() {
|
||||
s := &KillStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("SelectStatement should auth correctly", t, func() {
|
||||
s := &SelectStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("CreateStatement should auth correctly", t, func() {
|
||||
s := &CreateStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("UpdateStatement should auth correctly", t, func() {
|
||||
s := &UpdateStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("DeleteStatement should auth correctly", t, func() {
|
||||
s := &DeleteStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("RelateStatement should auth correctly", t, func() {
|
||||
s := &RelateStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("InsertStatement should auth correctly", t, func() {
|
||||
s := &InsertStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("UpsertStatement should auth correctly", t, func() {
|
||||
s := &UpsertStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("DefineNamespaceStatement should auth correctly", t, func() {
|
||||
s := &DefineNamespaceStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("RemoveNamespaceStatement should auth correctly", t, func() {
|
||||
s := &RemoveNamespaceStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("DefineDatabaseStatement should auth correctly", t, func() {
|
||||
s := &DefineDatabaseStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("RemoveDatabaseStatement should auth correctly", t, func() {
|
||||
s := &RemoveDatabaseStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("DefineLoginStatement should auth correctly", t, func() {
|
||||
s := &DefineLoginStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("RemoveLoginStatement should auth correctly", t, func() {
|
||||
s := &RemoveLoginStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("DefineTokenStatement should auth correctly", t, func() {
|
||||
s := &DefineTokenStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("RemoveTokenStatement should auth correctly", t, func() {
|
||||
s := &RemoveTokenStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("DefineScopeStatement should auth correctly", t, func() {
|
||||
s := &DefineScopeStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("RemoveScopeStatement should auth correctly", t, func() {
|
||||
s := &RemoveScopeStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("DefineTableStatement should auth correctly", t, func() {
|
||||
s := &DefineTableStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("RemoveTableStatement should auth correctly", t, func() {
|
||||
s := &RemoveTableStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("DefineEventStatement should auth correctly", t, func() {
|
||||
s := &DefineEventStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("RemoveEventStatement should auth correctly", t, func() {
|
||||
s := &RemoveEventStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("DefineFieldStatement should auth correctly", t, func() {
|
||||
s := &DefineFieldStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("RemoveFieldStatement should auth correctly", t, func() {
|
||||
s := &RemoveFieldStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("DefineIndexStatement should auth correctly", t, func() {
|
||||
s := &DefineIndexStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("RemoveIndexStatement should auth correctly", t, func() {
|
||||
s := &RemoveIndexStatement{RW: true}
|
||||
w := s.Writeable()
|
||||
So(w, ShouldEqual, true)
|
||||
})
|
||||
|
||||
}
|
|
@ -16,9 +16,9 @@ package sql
|
|||
|
||||
func (p *parser) parseRelateStatement() (stmt *RelateStatement, err error) {
|
||||
|
||||
stmt = &RelateStatement{}
|
||||
stmt = &RelateStatement{RW: true}
|
||||
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthSC); err != nil {
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthNO); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -56,10 +56,6 @@ func (p *parser) parseRelateStatement() (stmt *RelateStatement, err error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, RPAREN, SEMICOLON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ package sql
|
|||
func (p *parser) parseRemoveStatement() (Statement, error) {
|
||||
|
||||
// Inspect the next token.
|
||||
tok, _, err := p.shouldBe(NAMESPACE, DATABASE, LOGIN, TOKEN, SCOPE, TABLE, FIELD, INDEX, VIEW)
|
||||
tok, _, err := p.shouldBe(NAMESPACE, DATABASE, LOGIN, TOKEN, SCOPE, TABLE, EVENT, FIELD, INDEX)
|
||||
|
||||
switch tok {
|
||||
case NAMESPACE:
|
||||
|
@ -32,12 +32,12 @@ func (p *parser) parseRemoveStatement() (Statement, error) {
|
|||
return p.parseRemoveScopeStatement()
|
||||
case TABLE:
|
||||
return p.parseRemoveTableStatement()
|
||||
case EVENT:
|
||||
return p.parseRemoveEventStatement()
|
||||
case FIELD:
|
||||
return p.parseRemoveFieldStatement()
|
||||
case INDEX:
|
||||
return p.parseRemoveIndexStatement()
|
||||
case VIEW:
|
||||
return p.parseRemoveViewStatement()
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -26,17 +26,16 @@ func (p *parser) parseReturnStatement() (stmt *ReturnStatement, err error) {
|
|||
// including a parenthesised expression or a
|
||||
// binary expression so handle accordingly.
|
||||
|
||||
stmt.What, err = p.parseExpr()
|
||||
stmt.What, err = p.parseWhat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check that we have reached the end of the
|
||||
// statement with either a ';' or EOF.
|
||||
// If this query has any subqueries which
|
||||
// need to alter the database then mark
|
||||
// this query as a writeable statement.
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, SEMICOLON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stmt.RW = p.buf.rw
|
||||
|
||||
return
|
||||
|
||||
|
|
164
sql/scanner.go
164
sql/scanner.go
|
@ -17,7 +17,6 @@ package sql
|
|||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
@ -51,7 +50,7 @@ func (s *scanner) scan() (tok Token, lit string, val interface{}) {
|
|||
|
||||
// If we see a letter then consume as a string.
|
||||
if isLetter(ch) {
|
||||
return s.scanIdent(ch)
|
||||
return s.scanIdiom(ch)
|
||||
}
|
||||
|
||||
// If we see a number then consume as a number.
|
||||
|
@ -351,7 +350,11 @@ func (s *scanner) scanCommentMultiple(chp ...rune) (tok Token, lit string, val i
|
|||
|
||||
func (s *scanner) scanParams(chp ...rune) (tok Token, lit string, val interface{}) {
|
||||
|
||||
tok, lit, _ = s.scanIdent()
|
||||
tok, lit, _ = s.scanIdiom()
|
||||
|
||||
if s.p.is(tok, THING) {
|
||||
return ILLEGAL, lit, val
|
||||
}
|
||||
|
||||
if s.p.is(tok, REGION) {
|
||||
return ILLEGAL, lit, val
|
||||
|
@ -367,6 +370,49 @@ func (s *scanner) scanParams(chp ...rune) (tok Token, lit string, val interface{
|
|||
|
||||
func (s *scanner) scanQuoted(chp ...rune) (tok Token, lit string, val interface{}) {
|
||||
|
||||
var tbv string
|
||||
var idv interface{}
|
||||
|
||||
// Create a buffer
|
||||
var buf bytes.Buffer
|
||||
|
||||
tok, lit, _ = s.scanString(chp...)
|
||||
|
||||
if s.p.is(tok, REGION) {
|
||||
return ILLEGAL, lit, val
|
||||
}
|
||||
|
||||
if s.p.is(tok, ILLEGAL) {
|
||||
return ILLEGAL, lit, val
|
||||
}
|
||||
|
||||
if ch := s.next(); ch == ':' {
|
||||
|
||||
tbv = lit
|
||||
|
||||
buf.WriteString(lit)
|
||||
|
||||
buf.WriteRune(ch)
|
||||
|
||||
if tok, lit, idv = s.part(); tok == ILLEGAL {
|
||||
buf.WriteString(lit)
|
||||
return ILLEGAL, buf.String(), val
|
||||
} else {
|
||||
buf.WriteString(lit)
|
||||
}
|
||||
|
||||
return THING, buf.String(), NewThing(tbv, idv)
|
||||
|
||||
} else if ch != eof {
|
||||
s.undo()
|
||||
}
|
||||
|
||||
return IDENT, lit, val
|
||||
|
||||
}
|
||||
|
||||
func (s *scanner) scanSection(chp ...rune) (tok Token, lit string, val interface{}) {
|
||||
|
||||
tok, lit, _ = s.scanString(chp...)
|
||||
|
||||
if s.p.is(tok, REGION) {
|
||||
|
@ -394,6 +440,48 @@ func (s *scanner) scanIdent(chp ...rune) (tok Token, lit string, val interface{}
|
|||
buf.WriteRune(ch)
|
||||
}
|
||||
|
||||
// Read subsequent characters
|
||||
for {
|
||||
if ch := s.next(); ch == eof {
|
||||
break
|
||||
} else if isIdentChar(ch) {
|
||||
buf.WriteRune(ch)
|
||||
} else {
|
||||
s.undo()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// If the string matches a keyword then return that keyword.
|
||||
if tok := keywords[strings.ToUpper(buf.String())]; tok > 0 {
|
||||
return tok, buf.String(), val
|
||||
}
|
||||
|
||||
if val, err := time.ParseDuration(buf.String()); err == nil {
|
||||
return DURATION, buf.String(), val
|
||||
}
|
||||
|
||||
// Otherwise return as a regular identifier.
|
||||
return tok, buf.String(), val
|
||||
|
||||
}
|
||||
|
||||
// scanIdiom consumes the current rune and all contiguous ident runes.
|
||||
func (s *scanner) scanIdiom(chp ...rune) (tok Token, lit string, val interface{}) {
|
||||
|
||||
tok = IDENT
|
||||
|
||||
var tbv string
|
||||
var idv interface{}
|
||||
|
||||
// Create a buffer
|
||||
var buf bytes.Buffer
|
||||
|
||||
// Read passed in runes
|
||||
for _, ch := range chp {
|
||||
buf.WriteRune(ch)
|
||||
}
|
||||
|
||||
// Read subsequent characters
|
||||
for {
|
||||
if ch := s.next(); ch == eof {
|
||||
|
@ -403,6 +491,26 @@ func (s *scanner) scanIdent(chp ...rune) (tok Token, lit string, val interface{}
|
|||
} else if isExprsChar(ch) {
|
||||
tok = EXPR
|
||||
buf.WriteRune(ch)
|
||||
} else if ch == ':' {
|
||||
|
||||
if tok == EXPR {
|
||||
s.undo()
|
||||
break
|
||||
}
|
||||
|
||||
tbv = buf.String()
|
||||
|
||||
buf.WriteRune(ch)
|
||||
|
||||
if tok, lit, idv = s.part(); tok == ILLEGAL {
|
||||
buf.WriteString(lit)
|
||||
return ILLEGAL, buf.String(), val
|
||||
} else {
|
||||
buf.WriteString(lit)
|
||||
}
|
||||
|
||||
return THING, buf.String(), NewThing(tbv, idv)
|
||||
|
||||
} else {
|
||||
s.undo()
|
||||
break
|
||||
|
@ -640,6 +748,16 @@ func (s *scanner) scanNumber(chp ...rune) (tok Token, lit string, val interface{
|
|||
tok = IDENT
|
||||
buf.WriteRune(ch)
|
||||
switch ch {
|
||||
case 'e', 'E':
|
||||
if chn := s.next(); chn == '+' {
|
||||
tok = DOUBLE
|
||||
buf.WriteRune(chn)
|
||||
} else if ch == '-' {
|
||||
tok = DOUBLE
|
||||
buf.WriteRune(chn)
|
||||
} else {
|
||||
s.undo()
|
||||
}
|
||||
case 's', 'h', 'd', 'w':
|
||||
tok = DURATION
|
||||
case 'n', 'u', 'µ', 'm':
|
||||
|
@ -692,10 +810,6 @@ func (s *scanner) scanString(chp ...rune) (tok Token, lit string, val interface{
|
|||
end = '⟩'
|
||||
}
|
||||
|
||||
if beg == '{' {
|
||||
end = '}'
|
||||
}
|
||||
|
||||
tok = STRING
|
||||
|
||||
// Create a buffer
|
||||
|
@ -744,14 +858,6 @@ func (s *scanner) scanString(chp ...rune) (tok Token, lit string, val interface{
|
|||
return TIME, buf.String(), val.UTC()
|
||||
}
|
||||
|
||||
if val, err := time.Parse(RFCNorm, buf.String()); err == nil {
|
||||
return TIME, buf.String(), val.UTC()
|
||||
}
|
||||
|
||||
if val, err := time.Parse(RFCText, buf.String()); err == nil {
|
||||
return TIME, buf.String(), val.UTC()
|
||||
}
|
||||
|
||||
return tok, buf.String(), val
|
||||
|
||||
}
|
||||
|
@ -850,6 +956,10 @@ func (s *scanner) scanObject(chp ...rune) (tok Token, lit string, val interface{
|
|||
|
||||
}
|
||||
|
||||
func (s *scanner) scanPart() {
|
||||
|
||||
}
|
||||
|
||||
func (s *scanner) part() (tok Token, lit string, val interface{}) {
|
||||
|
||||
if ch := s.next(); isLetter(ch) {
|
||||
|
@ -857,33 +967,15 @@ func (s *scanner) part() (tok Token, lit string, val interface{}) {
|
|||
} else if isNumber(ch) {
|
||||
tok, lit, _ = s.scanNumber(ch)
|
||||
} else if ch == '`' {
|
||||
tok, lit, _ = s.scanQuoted(ch)
|
||||
} else if ch == '{' {
|
||||
tok, lit, _ = s.scanQuoted(ch)
|
||||
tok, lit, _ = s.scanSection(ch)
|
||||
} else if ch == '⟨' {
|
||||
tok, lit, _ = s.scanQuoted(ch)
|
||||
} else if ch == '$' {
|
||||
tok, lit, _ = s.scanParams(ch)
|
||||
if p, ok := s.p.v[lit]; ok {
|
||||
switch v := p.(type) {
|
||||
case bool, int64, float64, string:
|
||||
val, lit = v, fmt.Sprint(v)
|
||||
case *Ident:
|
||||
lit = v.ID
|
||||
case *Value:
|
||||
lit = v.ID
|
||||
default:
|
||||
tok = ILLEGAL
|
||||
}
|
||||
} else {
|
||||
tok = ILLEGAL
|
||||
}
|
||||
tok, lit, _ = s.scanSection(ch)
|
||||
} else {
|
||||
s.undo()
|
||||
tok = ILLEGAL
|
||||
}
|
||||
|
||||
if tok != IDENT && tok != PARAM && tok != NUMBER && tok != DOUBLE {
|
||||
if tok != IDENT && tok != NUMBER && tok != DOUBLE {
|
||||
tok = ILLEGAL
|
||||
}
|
||||
|
||||
|
|
19
sql/scope.go
19
sql/scope.go
|
@ -16,7 +16,7 @@ package sql
|
|||
|
||||
func (p *parser) parseDefineScopeStatement() (stmt *DefineScopeStatement, err error) {
|
||||
|
||||
stmt = &DefineScopeStatement{}
|
||||
stmt = &DefineScopeStatement{RW: true}
|
||||
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthDB); err != nil {
|
||||
return nil, err
|
||||
|
@ -28,7 +28,7 @@ func (p *parser) parseDefineScopeStatement() (stmt *DefineScopeStatement, err er
|
|||
|
||||
for {
|
||||
|
||||
tok, _, exi := p.mightBe(SESSION, SIGNUP, SIGNIN)
|
||||
tok, _, exi := p.mightBe(SESSION, SIGNUP, SIGNIN, CONNECT)
|
||||
if !exi {
|
||||
break
|
||||
}
|
||||
|
@ -53,10 +53,13 @@ func (p *parser) parseDefineScopeStatement() (stmt *DefineScopeStatement, err er
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
if p.is(tok, CONNECT) {
|
||||
_, _, _ = p.mightBe(AS)
|
||||
if stmt.Connect, err = p.parseExpr(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, SEMICOLON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
|
@ -65,7 +68,7 @@ func (p *parser) parseDefineScopeStatement() (stmt *DefineScopeStatement, err er
|
|||
|
||||
func (p *parser) parseRemoveScopeStatement() (stmt *RemoveScopeStatement, err error) {
|
||||
|
||||
stmt = &RemoveScopeStatement{}
|
||||
stmt = &RemoveScopeStatement{RW: true}
|
||||
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthDB); err != nil {
|
||||
return nil, err
|
||||
|
@ -75,10 +78,6 @@ func (p *parser) parseRemoveScopeStatement() (stmt *RemoveScopeStatement, err er
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, SEMICOLON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ func (p *parser) parseSelectStatement() (stmt *SelectStatement, err error) {
|
|||
|
||||
stmt = &SelectStatement{}
|
||||
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthSC); err != nil {
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthNO); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -63,19 +63,22 @@ func (p *parser) parseSelectStatement() (stmt *SelectStatement, err error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, RPAREN, SEMICOLON); err != nil {
|
||||
if err = checkExpression(aggrs, stmt.Expr, stmt.Group); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return stmt, nil
|
||||
// If this query has any subqueries which
|
||||
// need to alter the database then mark
|
||||
// this query as a writeable statement.
|
||||
|
||||
stmt.RW = p.buf.rw
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
func (p *parser) parseFields() (mul Fields, err error) {
|
||||
|
||||
var lit string
|
||||
var exi bool
|
||||
|
||||
for {
|
||||
|
||||
one := &Field{}
|
||||
|
@ -89,10 +92,25 @@ func (p *parser) parseFields() (mul Fields, err error) {
|
|||
// clause, and if it is read the defined
|
||||
// field alias name from the scanner.
|
||||
|
||||
if _, _, exi = p.mightBe(AS); exi {
|
||||
if _, _, exi := p.mightBe(AS); exi {
|
||||
|
||||
if one.Alias, err = p.parseIdent(); err != nil {
|
||||
return nil, &ParseError{Found: lit, Expected: []string{"alias name"}}
|
||||
if _, one.Alias, err = p.shouldBe(IDENT); err != nil {
|
||||
return nil, &ParseError{Found: one.Alias, Expected: []string{"alias name"}}
|
||||
}
|
||||
|
||||
one.Field = one.Alias
|
||||
|
||||
} else {
|
||||
|
||||
switch v := one.Expr.(type) {
|
||||
case *Param:
|
||||
one.Field = v.ID
|
||||
case *Value:
|
||||
one.Field = v.ID
|
||||
case *Ident:
|
||||
one.Field = v.ID
|
||||
default:
|
||||
one.Field = one.String()
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -106,7 +124,7 @@ func (p *parser) parseFields() (mul Fields, err error) {
|
|||
// and if not, then break out of the loop,
|
||||
// otherwise repeat until we find no comma.
|
||||
|
||||
if _, _, exi = p.mightBe(COMMA); !exi {
|
||||
if _, _, exi := p.mightBe(COMMA); !exi {
|
||||
break
|
||||
}
|
||||
|
||||
|
@ -116,20 +134,6 @@ func (p *parser) parseFields() (mul Fields, err error) {
|
|||
|
||||
}
|
||||
|
||||
func (p *parser) parseWhere() (exp Expr, err error) {
|
||||
|
||||
// The next token that we expect to see is a
|
||||
// WHERE token, and if we don't find one then
|
||||
// return nil, with no error.
|
||||
|
||||
if _, _, exi := p.mightBe(WHERE); !exi {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return p.parseExpr()
|
||||
|
||||
}
|
||||
|
||||
func (p *parser) parseGroup() (mul Groups, err error) {
|
||||
|
||||
// The next token that we expect to see is a
|
||||
|
@ -153,7 +157,7 @@ func (p *parser) parseGroup() (mul Groups, err error) {
|
|||
|
||||
one := &Group{}
|
||||
|
||||
tok, lit, err = p.shouldBe(IDENT, ID)
|
||||
tok, lit, err = p.shouldBe(IDENT, EXPR)
|
||||
if err != nil {
|
||||
return nil, &ParseError{Found: lit, Expected: []string{"field name"}}
|
||||
}
|
||||
|
@ -206,23 +210,38 @@ func (p *parser) parseOrder() (mul Orders, err error) {
|
|||
|
||||
one := &Order{}
|
||||
|
||||
tok, lit, err = p.shouldBe(IDENT, ID)
|
||||
tok, lit, err = p.shouldBe(IDENT, EXPR, RAND)
|
||||
if err != nil {
|
||||
return nil, &ParseError{Found: lit, Expected: []string{"field name"}}
|
||||
}
|
||||
|
||||
one.Expr, err = p.declare(tok, lit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
switch tok {
|
||||
default:
|
||||
one.Expr, err = p.declare(tok, lit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case RAND:
|
||||
one.Expr = &FuncExpression{Name: "rand"}
|
||||
if _, _, exi = p.mightBe(LPAREN); exi {
|
||||
_, _, err = p.shouldBe(RPAREN)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if tok, lit, exi = p.mightBe(ASC, DESC); !exi {
|
||||
tok = ASC
|
||||
if _, _, exi = p.mightBe(COLLATE); exi {
|
||||
one.Tag, err = p.parseLanguage()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
one.Dir, err = p.declare(tok, lit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if tok, _, exi = p.mightBe(ASC, DESC); exi {
|
||||
one.Dir = (tok == ASC)
|
||||
} else {
|
||||
one.Dir = true
|
||||
}
|
||||
|
||||
// Append the single expression to the array
|
||||
|
@ -302,7 +321,7 @@ func (p *parser) parseVersion() (Expr, error) {
|
|||
|
||||
tok, lit, err := p.shouldBe(DATE, TIME, PARAM)
|
||||
if err != nil {
|
||||
return nil, &ParseError{Found: lit, Expected: []string{"timestamp"}}
|
||||
return nil, &ParseError{Found: lit, Expected: []string{"version date or time"}}
|
||||
}
|
||||
|
||||
return p.declare(tok, lit)
|
||||
|
|
19
sql/sql.go
19
sql/sql.go
|
@ -30,3 +30,22 @@ const (
|
|||
// Parsing format for readable text format date times
|
||||
RFCText = "2006-01-02 15:04:05.999999999 -0700 MST"
|
||||
)
|
||||
|
||||
var (
|
||||
allowedTypes = []string{
|
||||
"array", "boolean", "circle",
|
||||
"color", "datetime", "domain",
|
||||
"double", "email", "latitude",
|
||||
"longitude", "number", "object",
|
||||
"password", "phone", "point",
|
||||
"polygon", "record", "string",
|
||||
"url", "uuid",
|
||||
}
|
||||
|
||||
allowedAlgorithms = []string{
|
||||
"ES256", "ES384", "ES512",
|
||||
"HS256", "HS384", "HS512",
|
||||
"PS256", "PS384", "PS512",
|
||||
"RS256", "RS384", "RS512",
|
||||
}
|
||||
)
|
||||
|
|
2695
sql/sql_test.go
2695
sql/sql_test.go
File diff suppressed because it is too large
Load diff
726
sql/string.go
726
sql/string.go
File diff suppressed because it is too large
Load diff
58
sql/table.go
58
sql/table.go
|
@ -16,7 +16,7 @@ package sql
|
|||
|
||||
func (p *parser) parseDefineTableStatement() (stmt *DefineTableStatement, err error) {
|
||||
|
||||
stmt = &DefineTableStatement{}
|
||||
stmt = &DefineTableStatement{RW: true}
|
||||
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthDB); err != nil {
|
||||
return nil, err
|
||||
|
@ -28,11 +28,15 @@ func (p *parser) parseDefineTableStatement() (stmt *DefineTableStatement, err er
|
|||
|
||||
for {
|
||||
|
||||
tok, _, exi := p.mightBe(SCHEMAFULL, SCHEMALESS, PERMISSIONS)
|
||||
tok, _, exi := p.mightBe(DROP, SCHEMAFULL, SCHEMALESS, PERMISSIONS, AS)
|
||||
if !exi {
|
||||
break
|
||||
}
|
||||
|
||||
if p.is(tok, DROP) {
|
||||
stmt.Drop = true
|
||||
}
|
||||
|
||||
if p.is(tok, SCHEMAFULL) {
|
||||
stmt.Full = true
|
||||
}
|
||||
|
@ -42,15 +46,51 @@ func (p *parser) parseDefineTableStatement() (stmt *DefineTableStatement, err er
|
|||
}
|
||||
|
||||
if p.is(tok, PERMISSIONS) {
|
||||
if stmt.Perm, err = p.parsePerms(); err != nil {
|
||||
if stmt.Perms, err = p.parsePerms(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if p.is(tok, AS) {
|
||||
|
||||
stmt.Lock = true
|
||||
|
||||
_, _, _ = p.mightBe(LPAREN)
|
||||
|
||||
_, _, err = p.shouldBe(SELECT)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stmt.Expr, err = p.parseFields(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, _, err = p.shouldBe(FROM)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stmt.From, err = p.parseTables(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stmt.Cond, err = p.parseCond(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stmt.Group, err = p.parseGroup(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, _, _ = p.mightBe(RPAREN)
|
||||
|
||||
if err = checkExpression(rolls, stmt.Expr, stmt.Group); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, SEMICOLON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
|
@ -59,7 +99,7 @@ func (p *parser) parseDefineTableStatement() (stmt *DefineTableStatement, err er
|
|||
|
||||
func (p *parser) parseRemoveTableStatement() (stmt *RemoveTableStatement, err error) {
|
||||
|
||||
stmt = &RemoveTableStatement{}
|
||||
stmt = &RemoveTableStatement{RW: true}
|
||||
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthDB); err != nil {
|
||||
return nil, err
|
||||
|
@ -69,10 +109,6 @@ func (p *parser) parseRemoveTableStatement() (stmt *RemoveTableStatement, err er
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, SEMICOLON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
|
18
sql/token.go
18
sql/token.go
|
@ -16,7 +16,7 @@ package sql
|
|||
|
||||
func (p *parser) parseDefineTokenStatement() (stmt *DefineTokenStatement, err error) {
|
||||
|
||||
stmt = &DefineTokenStatement{}
|
||||
stmt = &DefineTokenStatement{RW: true}
|
||||
|
||||
if stmt.Name, err = p.parseIdent(); err != nil {
|
||||
return nil, err
|
||||
|
@ -70,15 +70,11 @@ func (p *parser) parseDefineTokenStatement() (stmt *DefineTokenStatement, err er
|
|||
}
|
||||
|
||||
if stmt.Type == "" {
|
||||
return nil, &ParseError{Found: ";", Expected: []string{"TYPE"}}
|
||||
return nil, &ParseError{Found: "", Expected: []string{"TYPE"}}
|
||||
}
|
||||
|
||||
if stmt.Code == nil {
|
||||
return nil, &ParseError{Found: ";", Expected: []string{"VALUE"}}
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, SEMICOLON); err != nil {
|
||||
return nil, err
|
||||
if len(stmt.Code) == 0 {
|
||||
return nil, &ParseError{Found: "", Expected: []string{"VALUE"}}
|
||||
}
|
||||
|
||||
return
|
||||
|
@ -87,7 +83,7 @@ func (p *parser) parseDefineTokenStatement() (stmt *DefineTokenStatement, err er
|
|||
|
||||
func (p *parser) parseRemoveTokenStatement() (stmt *RemoveTokenStatement, err error) {
|
||||
|
||||
stmt = &RemoveTokenStatement{}
|
||||
stmt = &RemoveTokenStatement{RW: true}
|
||||
|
||||
if stmt.Name, err = p.parseIdent(); err != nil {
|
||||
return nil, err
|
||||
|
@ -119,10 +115,6 @@ func (p *parser) parseRemoveTokenStatement() (stmt *RemoveTokenStatement, err er
|
|||
}
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, SEMICOLON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
|
|
@ -91,26 +91,26 @@ const (
|
|||
|
||||
operatorEnd
|
||||
|
||||
// literals
|
||||
// keywords
|
||||
|
||||
keywordsBeg
|
||||
|
||||
ACCEPT
|
||||
AFTER
|
||||
ALL
|
||||
ALLCONTAINEDIN
|
||||
AND
|
||||
AS
|
||||
ASC
|
||||
ASSERT
|
||||
AT
|
||||
BEFORE
|
||||
BEGIN
|
||||
BOTH
|
||||
BY
|
||||
CANCEL
|
||||
CODE
|
||||
COLLATE
|
||||
COLUMNS
|
||||
COMMIT
|
||||
CONNECT
|
||||
CONTAINS
|
||||
CONTAINSALL
|
||||
CONTAINSNONE
|
||||
|
@ -119,15 +119,15 @@ const (
|
|||
CREATE
|
||||
DATABASE
|
||||
DB
|
||||
DEFAULT
|
||||
DEFINE
|
||||
DELETE
|
||||
DESC
|
||||
DIFF
|
||||
DISTINCT
|
||||
DROP
|
||||
ELSE
|
||||
EMPTY
|
||||
ENUM
|
||||
EXISTS
|
||||
END
|
||||
EVENT
|
||||
EXPUNGE
|
||||
FALSE
|
||||
FIELD
|
||||
|
@ -135,38 +135,34 @@ const (
|
|||
FROM
|
||||
FULL
|
||||
GROUP
|
||||
ID
|
||||
IF
|
||||
IN
|
||||
INDEX
|
||||
INFO
|
||||
INSERT
|
||||
INTO
|
||||
IS
|
||||
KILL
|
||||
LET
|
||||
LIMIT
|
||||
LIVE
|
||||
LOGIN
|
||||
MANDATORY
|
||||
MATCH
|
||||
MAX
|
||||
MERGE
|
||||
MIN
|
||||
MISSING
|
||||
NAMESPACE
|
||||
NONE
|
||||
NONECONTAINEDIN
|
||||
NOT
|
||||
NOTNULL
|
||||
NOW
|
||||
NS
|
||||
NULL
|
||||
OFFSET
|
||||
NUMERIC
|
||||
ON
|
||||
OR
|
||||
ORDER
|
||||
PASSWORD
|
||||
PERMISSIONS
|
||||
READONLY
|
||||
REJECT
|
||||
RAND
|
||||
RELATE
|
||||
REMOVE
|
||||
RETURN
|
||||
|
@ -181,6 +177,7 @@ const (
|
|||
SOMECONTAINEDIN
|
||||
START
|
||||
TABLE
|
||||
THEN
|
||||
TIMEOUT
|
||||
TO
|
||||
TOKEN
|
||||
|
@ -191,11 +188,10 @@ const (
|
|||
UPDATE
|
||||
UPSERT
|
||||
USE
|
||||
VALIDATE
|
||||
VALUE
|
||||
VERSION
|
||||
VIEW
|
||||
VOID
|
||||
WHEN
|
||||
WHERE
|
||||
WITH
|
||||
|
||||
|
@ -266,22 +262,22 @@ var tokens = [...]string{
|
|||
|
||||
// keywords
|
||||
|
||||
ACCEPT: "ACCEPT",
|
||||
AFTER: "AFTER",
|
||||
ALL: "ALL",
|
||||
ALLCONTAINEDIN: "ALLCONTAINEDIN",
|
||||
AND: "AND",
|
||||
AS: "AS",
|
||||
ASC: "ASC",
|
||||
ASSERT: "ASSERT",
|
||||
AT: "AT",
|
||||
BEFORE: "BEFORE",
|
||||
BEGIN: "BEGIN",
|
||||
BOTH: "BOTH",
|
||||
BY: "BY",
|
||||
CANCEL: "CANCEL",
|
||||
CODE: "CODE",
|
||||
COLLATE: "COLLATE",
|
||||
COLUMNS: "COLUMNS",
|
||||
COMMIT: "COMMIT",
|
||||
CONNECT: "CONNECT",
|
||||
CONTAINS: "CONTAINS",
|
||||
CONTAINSALL: "CONTAINSALL",
|
||||
CONTAINSNONE: "CONTAINSNONE",
|
||||
|
@ -290,15 +286,15 @@ var tokens = [...]string{
|
|||
CREATE: "CREATE",
|
||||
DATABASE: "DATABASE",
|
||||
DB: "DB",
|
||||
DEFAULT: "DEFAULT",
|
||||
DEFINE: "DEFINE",
|
||||
DELETE: "DELETE",
|
||||
DESC: "DESC",
|
||||
DIFF: "DIFF",
|
||||
DISTINCT: "DISTINCT",
|
||||
DROP: "DROP",
|
||||
ELSE: "ELSE",
|
||||
EMPTY: "EMPTY",
|
||||
ENUM: "ENUM",
|
||||
EXISTS: "EXISTS",
|
||||
END: "END",
|
||||
EVENT: "EVENT",
|
||||
EXPUNGE: "EXPUNGE",
|
||||
FALSE: "FALSE",
|
||||
FIELD: "FIELD",
|
||||
|
@ -306,37 +302,34 @@ var tokens = [...]string{
|
|||
FROM: "FROM",
|
||||
FULL: "FULL",
|
||||
GROUP: "GROUP",
|
||||
ID: "ID",
|
||||
IF: "IF",
|
||||
IN: "IN",
|
||||
INDEX: "INDEX",
|
||||
INFO: "INFO",
|
||||
INSERT: "INSERT",
|
||||
INTO: "INTO",
|
||||
IS: "IS",
|
||||
KILL: "KILL",
|
||||
LET: "LET",
|
||||
LIMIT: "LIMIT",
|
||||
LIVE: "LIVE",
|
||||
LOGIN: "LOGIN",
|
||||
MANDATORY: "MANDATORY",
|
||||
MATCH: "MATCH",
|
||||
MAX: "MAX",
|
||||
MERGE: "MERGE",
|
||||
MIN: "MIN",
|
||||
MISSING: "MISSING",
|
||||
NAMESPACE: "NAMESPACE",
|
||||
NONE: "NONE",
|
||||
NONECONTAINEDIN: "NONECONTAINEDIN",
|
||||
NOT: "NOT",
|
||||
NOTNULL: "NOTNULL",
|
||||
NOW: "NOW",
|
||||
NS: "NS",
|
||||
NULL: "NULL",
|
||||
NUMERIC: "NUMERIC",
|
||||
ON: "ON",
|
||||
OR: "OR",
|
||||
ORDER: "ORDER",
|
||||
PASSWORD: "PASSWORD",
|
||||
PERMISSIONS: "PERMISSIONS",
|
||||
READONLY: "READONLY",
|
||||
REJECT: "REJECT",
|
||||
RAND: "RAND",
|
||||
RELATE: "RELATE",
|
||||
REMOVE: "REMOVE",
|
||||
RETURN: "RETURN",
|
||||
|
@ -351,6 +344,7 @@ var tokens = [...]string{
|
|||
SOMECONTAINEDIN: "SOMECONTAINEDIN",
|
||||
START: "START",
|
||||
TABLE: "TABLE",
|
||||
THEN: "THEN",
|
||||
TIMEOUT: "TIMEOUT",
|
||||
TO: "TO",
|
||||
TOKEN: "TOKEN",
|
||||
|
@ -361,11 +355,10 @@ var tokens = [...]string{
|
|||
UPDATE: "UPDATE",
|
||||
UPSERT: "UPSERT",
|
||||
USE: "USE",
|
||||
VALIDATE: "VALIDATE",
|
||||
VALUE: "VALUE",
|
||||
VERSION: "VERSION",
|
||||
VIEW: "VIEW",
|
||||
VOID: "VOID",
|
||||
WHEN: "WHEN",
|
||||
WHERE: "WHERE",
|
||||
WITH: "WITH",
|
||||
}
|
||||
|
@ -430,10 +423,12 @@ func (tok Token) String() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func newToken(str string) Token {
|
||||
func newToken(s string) Token {
|
||||
for k, v := range tokens {
|
||||
if v == strings.ToUpper(str) {
|
||||
return Token(k)
|
||||
if len(v) == len(s) {
|
||||
if strings.EqualFold(v, s) {
|
||||
return Token(k)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ILLEGAL
|
||||
|
|
12
sql/trans.go
12
sql/trans.go
|
@ -20,10 +20,6 @@ func (p *parser) parseBeginStatement() (stmt *BeginStatement, err error) {
|
|||
|
||||
_, _, _ = p.mightBe(TRANSACTION)
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, SEMICOLON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p.buf.txn = true
|
||||
|
||||
return
|
||||
|
@ -36,10 +32,6 @@ func (p *parser) parseCancelStatement() (stmt *CancelStatement, err error) {
|
|||
|
||||
_, _, _ = p.mightBe(TRANSACTION)
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, SEMICOLON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p.buf.txn = false
|
||||
|
||||
return
|
||||
|
@ -52,10 +44,6 @@ func (p *parser) parseCommitStatement() (stmt *CommitStatement, err error) {
|
|||
|
||||
_, _, _ = p.mightBe(TRANSACTION)
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, SEMICOLON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p.buf.txn = false
|
||||
|
||||
return
|
||||
|
|
|
@ -16,19 +16,12 @@ package sql
|
|||
|
||||
func (p *parser) parseUpdateStatement() (stmt *UpdateStatement, err error) {
|
||||
|
||||
stmt = &UpdateStatement{}
|
||||
stmt = &UpdateStatement{RW: true}
|
||||
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthSC); err != nil {
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthNO); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, _, exi := p.mightBe(AND); exi {
|
||||
if _, _, err = p.shouldBe(UPSERT); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stmt.Hard = true
|
||||
}
|
||||
|
||||
if stmt.What, err = p.parseWhat(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -49,10 +42,6 @@ func (p *parser) parseUpdateStatement() (stmt *UpdateStatement, err error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, RPAREN, SEMICOLON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
|
49
sql/upsert.go
Normal file
49
sql/upsert.go
Normal file
|
@ -0,0 +1,49 @@
|
|||
// 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 sql
|
||||
|
||||
func (p *parser) parseUpsertStatement() (stmt *UpsertStatement, err error) {
|
||||
|
||||
stmt = &UpsertStatement{RW: true}
|
||||
|
||||
if stmt.KV, stmt.NS, stmt.DB, err = p.o.get(AuthNO); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stmt.Data, err = p.parseExpr(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(INTO); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, _, _ = p.mightBe(TABLE)
|
||||
|
||||
if stmt.Into, err = p.parseTable(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stmt.Echo, err = p.parseEcho(AFTER); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stmt.Timeout, err = p.parseTimeout(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
30
sql/use.go
30
sql/use.go
|
@ -21,22 +21,27 @@ func (p *parser) parseUseStatement() (stmt *UseStatement, err error) {
|
|||
var tok Token
|
||||
var exi bool
|
||||
|
||||
tok, _, err = p.shouldBe(NAMESPACE, NS, DATABASE, DB)
|
||||
if p.buf.txn {
|
||||
return nil, &TransError{}
|
||||
}
|
||||
|
||||
tok, _, err = p.shouldBe(NAMESPACE, DATABASE, NS, DB)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for {
|
||||
|
||||
var val *Ident
|
||||
|
||||
if p.is(tok, NAMESPACE, NS) {
|
||||
|
||||
if val, err = p.parseIdent(); err != nil {
|
||||
return nil, err
|
||||
_, stmt.NS, err = p.shouldBe(IDENT, STRING, NUMBER, DOUBLE, DATE, TIME)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
stmt.NS = val.ID
|
||||
if len(stmt.NS) == 0 {
|
||||
return nil, &ParseError{Expected: []string{"namespace name"}, Found: stmt.NS}
|
||||
}
|
||||
|
||||
if err = p.o.ns(stmt.NS); err != nil {
|
||||
return nil, err
|
||||
|
@ -46,11 +51,14 @@ func (p *parser) parseUseStatement() (stmt *UseStatement, err error) {
|
|||
|
||||
if p.is(tok, DATABASE, DB) {
|
||||
|
||||
if val, err = p.parseIdent(); err != nil {
|
||||
return nil, err
|
||||
_, stmt.DB, err = p.shouldBe(IDENT, STRING, NUMBER, DOUBLE, DATE, TIME)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
stmt.DB = val.ID
|
||||
if len(stmt.DB) == 0 {
|
||||
return nil, &ParseError{Expected: []string{"database name"}, Found: stmt.DB}
|
||||
}
|
||||
|
||||
if err = p.o.db(stmt.DB); err != nil {
|
||||
return nil, err
|
||||
|
@ -65,10 +73,6 @@ func (p *parser) parseUseStatement() (stmt *UseStatement, err error) {
|
|||
|
||||
}
|
||||
|
||||
if _, _, err = p.shouldBe(EOF, SEMICOLON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
|
58
sql/util.go
58
sql/util.go
|
@ -18,6 +18,7 @@ import (
|
|||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
json "github.com/hjson/hjson-go"
|
||||
|
@ -67,15 +68,15 @@ func (p *parser) declare(tok Token, lit string) (interface{}, error) {
|
|||
|
||||
switch tok {
|
||||
|
||||
case NULL:
|
||||
return nil, nil
|
||||
|
||||
case TRUE:
|
||||
return true, nil
|
||||
|
||||
case FALSE:
|
||||
return false, nil
|
||||
|
||||
case NULL:
|
||||
return &Null{}, nil
|
||||
|
||||
case VOID:
|
||||
return &Void{}, nil
|
||||
|
||||
|
@ -91,19 +92,13 @@ func (p *parser) declare(tok Token, lit string) (interface{}, error) {
|
|||
case QMARK:
|
||||
return &Any{}, nil
|
||||
|
||||
case ASC:
|
||||
return &Asc{}, nil
|
||||
|
||||
case DESC:
|
||||
return &Desc{}, nil
|
||||
|
||||
case STRING:
|
||||
return &Value{lit}, nil
|
||||
|
||||
case REGION:
|
||||
return &Value{lit}, nil
|
||||
|
||||
case ID:
|
||||
case EXPR:
|
||||
return &Ident{lit}, nil
|
||||
|
||||
case IDENT:
|
||||
|
@ -112,35 +107,50 @@ func (p *parser) declare(tok Token, lit string) (interface{}, error) {
|
|||
case TABLE:
|
||||
return &Table{lit}, nil
|
||||
|
||||
case NOW:
|
||||
return time.Now().UTC(), nil
|
||||
case PARAM:
|
||||
return &Param{lit}, nil
|
||||
|
||||
case DATE:
|
||||
return time.Parse("2006-01-02", lit)
|
||||
return time.Parse(RFCDate, lit)
|
||||
|
||||
case TIME:
|
||||
return time.Parse(time.RFC3339, lit)
|
||||
return time.Parse(RFCTime, lit)
|
||||
|
||||
case REGEX:
|
||||
return regexp.Compile(lit)
|
||||
|
||||
case NUMBER:
|
||||
return strconv.ParseInt(lit, 10, 64)
|
||||
val, err := strconv.ParseFloat(lit, 64)
|
||||
if err != nil {
|
||||
return val, fmt.Errorf("Invalid number: %s", lit)
|
||||
}
|
||||
return val, nil
|
||||
|
||||
case DOUBLE:
|
||||
return strconv.ParseFloat(lit, 64)
|
||||
val, err := strconv.ParseFloat(lit, 64)
|
||||
if err != nil {
|
||||
return val, fmt.Errorf("Invalid number: %s", lit)
|
||||
}
|
||||
return val, nil
|
||||
|
||||
case DURATION:
|
||||
return time.ParseDuration(lit)
|
||||
|
||||
case PARAM:
|
||||
if p, ok := p.v[lit]; ok {
|
||||
return p, nil
|
||||
var mul time.Duration
|
||||
switch {
|
||||
default:
|
||||
mul = 1
|
||||
case strings.HasSuffix(lit, "d"):
|
||||
mul, lit = 24, strings.Replace(lit, "d", "h", -1)
|
||||
case strings.HasSuffix(lit, "w"):
|
||||
mul, lit = 168, strings.Replace(lit, "w", "h", -1)
|
||||
}
|
||||
return &Param{lit}, nil
|
||||
val, err := time.ParseDuration(lit)
|
||||
if err != nil {
|
||||
return val, fmt.Errorf("Invalid duration: %s", lit)
|
||||
}
|
||||
return val * mul, nil
|
||||
|
||||
case ARRAY:
|
||||
var j Array
|
||||
var j []interface{}
|
||||
json.Unmarshal([]byte(lit), &j)
|
||||
if j == nil {
|
||||
return j, fmt.Errorf("Invalid JSON: %s", lit)
|
||||
|
@ -148,7 +158,7 @@ func (p *parser) declare(tok Token, lit string) (interface{}, error) {
|
|||
return j, nil
|
||||
|
||||
case JSON:
|
||||
var j Object
|
||||
var j map[string]interface{}
|
||||
json.Unmarshal([]byte(lit), &j)
|
||||
if j == nil {
|
||||
return j, fmt.Errorf("Invalid JSON: %s", lit)
|
||||
|
|
Loading…
Reference in a new issue