From 66f09db9f5cc01a490f78ba8f799a41fc8f53355 Mon Sep 17 00:00:00 2001 From: Tobie Morgan Hitchcock Date: Wed, 21 Sep 2016 00:36:37 +0100 Subject: [PATCH] Add SQL VIEWs --- db/info.go | 15 +++++++-- sql/ast.go | 24 ++++++++++++++ sql/define.go | 4 ++- sql/remove.go | 4 ++- sql/token.go | 2 ++ sql/view.go | 86 +++++++++++++++++++++++++++++++++++++++++++++++++ util/keys/vw.go | 54 +++++++++++++++++++++++++++++++ 7 files changed, 185 insertions(+), 4 deletions(-) create mode 100644 sql/view.go create mode 100644 util/keys/vw.go diff --git a/db/info.go b/db/info.go index 11106e13..099ce0d1 100644 --- a/db/info.go +++ b/db/info.go @@ -42,13 +42,24 @@ func executeInfoStatement(txn kvs.TX, ast *sql.InfoStatement) (out []interface{} // Get the table definitions tbeg := &keys.TB{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: keys.Prefix} tend := &keys.TB{KV: ast.KV, NS: ast.NS, DB: ast.DB, TB: keys.Suffix} - kvs, _ := txn.RGet(tbeg.Encode(), tend.Encode(), 0) - for _, kv := range kvs { + tkvs, _ := txn.RGet(tbeg.Encode(), tend.Encode(), 0) + for _, kv := range tkvs { key := &keys.TB{} key.Decode(kv.Key()) res.Inc(key.TB, "tables") } + // Get the table definitions + vbeg := &keys.VW{KV: ast.KV, NS: ast.NS, DB: ast.DB, VW: keys.Prefix} + vend := &keys.VW{KV: ast.KV, NS: ast.NS, DB: ast.DB, VW: keys.Suffix} + vkvs, _ := txn.RGet(vbeg.Encode(), vend.Encode(), 0) + for _, kv := range vkvs { + key, val := &keys.VW{}, &sql.DefineViewStatement{} + key.Decode(kv.Key()) + pack.Decode(kv.Val(), val) + res.Inc(val, "views") + } + out = append(out, res.Data()) } else { diff --git a/sql/ast.go b/sql/ast.go index 1e707cc6..ac52493d 100644 --- a/sql/ast.go +++ b/sql/ast.go @@ -257,6 +257,30 @@ type RemoveIndexStatement struct { What []string `codec:"-"` } +// -------------------------------------------------- +// View +// -------------------------------------------------- + +// DefineViewStatement represents an SQL DEFINE VIEW statement. +type DefineViewStatement struct { + KV string `codec:"-"` + NS string `codec:"-"` + DB string `codec:"-"` + Name string `codec:"name"` + Expr []*Field `codec:"expr"` + What []Expr `codec:"what"` + Cond []Expr `codec:"cond"` + Group []*Group `codec:"group"` +} + +// RemoveViewStatement represents an SQL REMOVE VIEW statement. +type RemoveViewStatement struct { + KV string `codec:"-"` + NS string `codec:"-"` + DB string `codec:"-"` + Name string `codec:"-"` +} + // -------------------------------------------------- // Literals // -------------------------------------------------- diff --git a/sql/define.go b/sql/define.go index 4edb0d6e..a00c17a6 100644 --- a/sql/define.go +++ b/sql/define.go @@ -17,7 +17,7 @@ package sql func (p *parser) parseDefineStatement() (Statement, error) { // Inspect the next token. - tok, _, err := p.shouldBe(TABLE, RULES, FIELD, INDEX) + tok, _, err := p.shouldBe(TABLE, RULES, FIELD, INDEX, VIEW) switch tok { case TABLE: @@ -28,6 +28,8 @@ func (p *parser) parseDefineStatement() (Statement, error) { return p.parseDefineFieldStatement() case INDEX: return p.parseDefineIndexStatement() + case VIEW: + return p.parseDefineViewStatement() default: return nil, err } diff --git a/sql/remove.go b/sql/remove.go index 66cbf02d..fbd1d3f4 100644 --- a/sql/remove.go +++ b/sql/remove.go @@ -17,7 +17,7 @@ package sql func (p *parser) parseRemoveStatement() (Statement, error) { // Inspect the next token. - tok, _, err := p.shouldBe(TABLE, RULES, FIELD, INDEX) + tok, _, err := p.shouldBe(TABLE, RULES, FIELD, INDEX, VIEW) switch tok { case TABLE: @@ -28,6 +28,8 @@ func (p *parser) parseRemoveStatement() (Statement, error) { return p.parseRemoveFieldStatement() case INDEX: return p.parseRemoveIndexStatement() + case VIEW: + return p.parseRemoveViewStatement() default: return nil, err } diff --git a/sql/token.go b/sql/token.go index 415f8ee4..2ec6e5e8 100644 --- a/sql/token.go +++ b/sql/token.go @@ -182,6 +182,7 @@ const ( USE VALIDATE VERSION + VIEW VOID WHERE @@ -340,6 +341,7 @@ var tokens = [...]string{ USE: "USE", VALIDATE: "VALIDATE", VERSION: "VERSION", + VIEW: "VIEW", VOID: "VOID", WHERE: "WHERE", } diff --git a/sql/view.go b/sql/view.go new file mode 100644 index 00000000..746fedd2 --- /dev/null +++ b/sql/view.go @@ -0,0 +1,86 @@ +// 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) parseDefineViewStatement() (stmt *DefineViewStatement, err error) { + + stmt = &DefineViewStatement{} + + stmt.KV = p.c.Get("KV").(string) + stmt.NS = p.c.Get("NS").(string) + stmt.DB = p.c.Get("DB").(string) + + if stmt.Name, err = p.parseName(); err != nil { + return nil, err + } + + _, _, err = p.shouldBe(AS) + if err != nil { + return nil, err + } + + _, _, err = p.shouldBe(SELECT) + if err != nil { + return nil, err + } + + if stmt.Expr, err = p.parseExpr(); err != nil { + return nil, err + } + + _, _, err = p.shouldBe(FROM) + if err != nil { + return nil, err + } + + if stmt.What, err = p.parseWhat(); 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 { + return nil, err + } + + return + +} + +func (p *parser) parseRemoveViewStatement() (stmt *RemoveViewStatement, err error) { + + stmt = &RemoveViewStatement{} + + stmt.KV = p.c.Get("KV").(string) + stmt.NS = p.c.Get("NS").(string) + stmt.DB = p.c.Get("DB").(string) + + if stmt.Name, err = p.parseName(); err != nil { + return nil, err + } + + if _, _, err = p.shouldBe(EOF, SEMICOLON); err != nil { + return nil, err + } + + return + +} diff --git a/util/keys/vw.go b/util/keys/vw.go new file mode 100644 index 00000000..36313978 --- /dev/null +++ b/util/keys/vw.go @@ -0,0 +1,54 @@ +// 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 keys + +import ( + "fmt" +) + +// VW ... +type VW struct { + KV interface{} + CF interface{} + TK interface{} + NS interface{} + DB interface{} + VW interface{} +} + +// init initialises the key +func (k *VW) init() *VW { + k.CF = "!" + k.TK = "v" + return k +} + +// Encode encodes the key into binary +func (k *VW) Encode() []byte { + k.init() + return encode(k.KV, k.CF, k.TK, k.NS, k.DB, k.VW) +} + +// Decode decodes the key from binary +func (k *VW) Decode(data []byte) { + k.init() + decode(data, &k.KV, &k.CF, &k.TK, &k.NS, &k.DB, &k.VW) +} + +// String returns a string representation of the key +func (k *VW) String() string { + k.init() + return fmt.Sprintf("/%s/%s/%s/%s/%s/%s", k.KV, k.CF, k.TK, k.NS, k.DB, k.VW) +}