diff --git a/db/error.go b/db/error.go index 801e7fa4..af6d56c6 100644 --- a/db/error.go +++ b/db/error.go @@ -21,10 +21,17 @@ import ( "github.com/abcum/surreal/sql" ) -// QueryError occurs when a query can not be run. -type QueryError struct { +// OptsError occurs when a query can not be run. +type OptsError struct{} + +// Error returns the string representation of the error. +func (e *OptsError) Error() string { + return fmt.Sprintf("Unable to set database options.") } +// QueryError occurs when a query can not be run. +type QueryError struct{} + // Error returns the string representation of the error. func (e *QueryError) Error() string { return fmt.Sprintf("Unable to perform live query.") diff --git a/db/event.go b/db/event.go index f1f27445..ddccd69b 100644 --- a/db/event.go +++ b/db/event.go @@ -25,6 +25,10 @@ import ( // table, and executes them in name order. func (d *document) event(ctx context.Context, met method) (err error) { + if !d.i.e.opts.events { + return nil + } + // Check if this query has been run // in forced mode, because of an // index or foreign table update. diff --git a/db/executor.go b/db/executor.go index e5686215..a9687a6a 100644 --- a/db/executor.go +++ b/db/executor.go @@ -32,6 +32,7 @@ type executor struct { dbo *mem.Cache time int64 lock *mutex + opts *options send chan *Response cache *cache } @@ -42,6 +43,8 @@ func newExecutor() (e *executor) { e.dbo = mem.New() + e.opts = newOptions() + e.send = make(chan *Response) e.cache = new(cache) diff --git a/db/merge.go b/db/merge.go index fc583ded..090d71ef 100644 --- a/db/merge.go +++ b/db/merge.go @@ -322,7 +322,7 @@ func (d *document) mrgFld(ctx context.Context, met method) (err error) { // We are setting the value of the field - if fd.Value != nil { + if fd.Value != nil && d.i.e.opts.fields { // Reset the variables @@ -342,7 +342,7 @@ func (d *document) mrgFld(ctx context.Context, met method) (err error) { // We are checking the value of the field - if fd.Assert != nil { + if fd.Assert != nil && d.i.e.opts.fields { // Reset the variables diff --git a/db/opt.go b/db/opt.go new file mode 100644 index 00000000..cb5a32cf --- /dev/null +++ b/db/opt.go @@ -0,0 +1,69 @@ +// Copyright © 2016 Abcum Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package db + +import ( + "context" + "strings" + + "github.com/abcum/surreal/cnf" + "github.com/abcum/surreal/sql" +) + +type options struct { + fields bool + events bool + tables bool +} + +func newOptions() *options { + return &options{ + fields: true, + events: true, + tables: true, + } +} + +func (e *executor) executeOpt(ctx context.Context, stm *sql.OptStatement) (out []interface{}, err error) { + + if k, ok := ctx.Value(ctxKeyKind).(cnf.Kind); ok { + if k >= cnf.AuthSC { + return nil, new(OptsError) + } + } + + switch strings.ToUpper(stm.Name) { + case "PROCESS_FIELD_QUERIES": + e.opts.fields = stm.What + case "TRIGGER_EVENT_QUERIES": + e.opts.events = stm.What + case "TRIGGER_TABLE_QUERIES": + e.opts.tables = stm.What + case "IMPORT": + switch stm.What { + case true: + e.opts.fields = false // Set field queries + e.opts.events = false // Set event queries + e.opts.tables = true // Set table queries + case false: + e.opts.fields = true // Set field queries + e.opts.events = true // Set event queries + e.opts.tables = true // Set table queries + } + } + + return + +} diff --git a/db/table.go b/db/table.go index d14f5fb0..610749df 100644 --- a/db/table.go +++ b/db/table.go @@ -29,6 +29,10 @@ import ( // this table, and executes them in name order. func (d *document) table(ctx context.Context, when method) (err error) { + if !d.i.e.opts.tables { + return nil + } + // Check if this query has been run // in forced mode, because of an // index or foreign table update. diff --git a/sql/ast.go b/sql/ast.go index a4a1bdc7..9ee92e11 100644 --- a/sql/ast.go +++ b/sql/ast.go @@ -53,19 +53,6 @@ type WriteableStatement interface { Writeable() bool } -// -------------------------------------------------- -// Trans -// -------------------------------------------------- - -// UseStatement represents a SQL BEGIN TRANSACTION statement. -type BeginStatement struct{} - -// UseStatement represents a SQL CANCEL TRANSACTION statement. -type CancelStatement struct{} - -// UseStatement represents a SQL COMMIT TRANSACTION statement. -type CommitStatement struct{} - // -------------------------------------------------- // Use // -------------------------------------------------- @@ -76,6 +63,29 @@ type UseStatement struct { DB string } +// -------------------------------------------------- +// Options +// -------------------------------------------------- + +// OptStatement represents a SQL OPTION statement. +type OptStatement struct { + Name string + What bool +} + +// -------------------------------------------------- +// Trans +// -------------------------------------------------- + +// BeginStatement represents a SQL BEGIN TRANSACTION statement. +type BeginStatement struct{} + +// CancelStatement represents a SQL CANCEL TRANSACTION statement. +type CancelStatement struct{} + +// CommitStatement represents a SQL COMMIT TRANSACTION statement. +type CommitStatement struct{} + // -------------------------------------------------- // Info // -------------------------------------------------- diff --git a/sql/exprs.go b/sql/exprs.go index bbbeaa75..67a6c1b0 100644 --- a/sql/exprs.go +++ b/sql/exprs.go @@ -184,6 +184,19 @@ func (p *parser) parseCond() (exp Expr, err error) { // // -------------------------------------------------- +func (p *parser) parseBool() (bool, error) { + + tok, lit, err := p.shouldBe(TRUE, FALSE) + if err != nil { + return false, &ParseError{Found: lit, Expected: []string{"true", "false"}} + } + + val, err := p.declare(tok, lit) + + return val.(bool), err + +} + func (p *parser) parseBinary() ([]byte, error) { _, lit, err := p.shouldBe(STRING, REGION) diff --git a/sql/option.go b/sql/option.go new file mode 100644 index 00000000..4627c7d7 --- /dev/null +++ b/sql/option.go @@ -0,0 +1,51 @@ +// 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) parseOptionStatement() (stmt *OptStatement, err error) { + + stmt = &OptStatement{What: true} + + if _, _, _, err = p.a.get(AuthDB); err != nil { + return nil, err + } + + _, lit, err := p.shouldBe(IDENT, STRING) + if err != nil { + return nil, &ParseError{Found: lit, Expected: []string{"name"}} + } + + // The first part of a SET expression must + // always be an identifier, specifying a + // variable name to set. + + stmt.Name = lit + + // The next part might be a = operator, + // which mist be followed by a TRUE or + // FALSE boolean value. + + if _, _, exi := p.mightBe(EQ); exi { + + stmt.What, err = p.parseBool() + if err != nil { + return nil, err + } + + } + + return + +} diff --git a/sql/parser.go b/sql/parser.go index cc27ee79..fb8ad419 100644 --- a/sql/parser.go +++ b/sql/parser.go @@ -167,6 +167,7 @@ func (p *parser) parseSingle() (stmt Statement, err error) { UPSERT, DEFINE, REMOVE, + OPTION, ) switch tok { @@ -218,6 +219,8 @@ func (p *parser) parseSingle() (stmt Statement, err error) { return p.parseDefineStatement() case REMOVE: return p.parseRemoveStatement() + case OPTION: + return p.parseOptionStatement() default: return nil, err diff --git a/sql/sql_test.go b/sql/sql_test.go index f19fa177..ceac5fbe 100644 --- a/sql/sql_test.go +++ b/sql/sql_test.go @@ -269,7 +269,7 @@ func Test_Parse_Queries_Malformed(t *testing.T) { }, { sql: `!`, - err: "Found `!` but expected `USE, INFO, BEGIN, CANCEL, COMMIT, IF, LET, RETURN, LIVE, KILL, SELECT, CREATE, UPDATE, DELETE, RELATE, INSERT, UPSERT, DEFINE, REMOVE`", + err: "Found `!` but expected `USE, INFO, BEGIN, CANCEL, COMMIT, IF, LET, RETURN, LIVE, KILL, SELECT, CREATE, UPDATE, DELETE, RELATE, INSERT, UPSERT, DEFINE, REMOVE, OPTION`", }, } diff --git a/sql/string.go b/sql/string.go index e0753dcc..c01ee3a0 100644 --- a/sql/string.go +++ b/sql/string.go @@ -140,16 +140,11 @@ func toQuote(s string) bool { // Statements // --------------------------------------------- -func (this BeginStatement) String() string { - return "BEGIN TRANSACTION" -} - -func (this CancelStatement) String() string { - return "CANCEL TRANSACTION" -} - -func (this CommitStatement) String() string { - return "COMMIT TRANSACTION" +func (this OptStatement) String() string { + return print("OPTION %v%v", + quote(this.Name), + maybe(this.What == false, print(" = %v", this.What)), + ) } func (this UseStatement) String() string { @@ -163,6 +158,18 @@ func (this UseStatement) String() string { } } +func (this BeginStatement) String() string { + return "BEGIN TRANSACTION" +} + +func (this CancelStatement) String() string { + return "CANCEL TRANSACTION" +} + +func (this CommitStatement) String() string { + return "COMMIT TRANSACTION" +} + func (this InfoStatement) String() string { switch this.Kind { case ALL: diff --git a/sql/tokens.go b/sql/tokens.go index eeb486e2..55221b01 100644 --- a/sql/tokens.go +++ b/sql/tokens.go @@ -162,6 +162,7 @@ const ( NULL NUMERIC ON + OPTION OR ORDER PARALLEL @@ -340,6 +341,7 @@ var tokens = [...]string{ NULL: "NULL", NUMERIC: "NUMERIC", ON: "ON", + OPTION: "OPTION", OR: "OR", ORDER: "ORDER", PARALLEL: "PARALLEL",