From 6e62d346c948a3a9b9044963200587e8a5784f86 Mon Sep 17 00:00:00 2001 From: bcleenders Date: Tue, 23 Dec 2014 23:20:30 +0100 Subject: [PATCH 1/5] Prevents repl panic --- AUTHORS | 1 + CONTRIBUTORS | 1 + db/repl.go | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 7035a5b..16d19a7 100644 --- a/AUTHORS +++ b/AUTHORS @@ -9,6 +9,7 @@ # Please keep the list sorted. Alexander Peters +Bram Leenders Google Inc. Jay Graves Jeremy Jay diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 10ae14f..fdc75b4 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -13,6 +13,7 @@ Alexander Peters Barak Michener +Bram Leenders Jay Graves Jeremy Jay Pius Uzamere diff --git a/db/repl.go b/db/repl.go index da3aff9..6722299 100644 --- a/db/repl.go +++ b/db/repl.go @@ -124,7 +124,7 @@ func Repl(h *graph.Handle, queryLanguage string, cfg *config.Config) error { fmt.Println("Debug Toggled") continue - case strings.HasPrefix(line, ":a"): + case strings.HasPrefix(line, ":a "): quad, err := cquads.Parse(line[3:]) if !quad.IsValid() { if err != nil { @@ -135,7 +135,7 @@ func Repl(h *graph.Handle, queryLanguage string, cfg *config.Config) error { h.QuadWriter.AddQuad(quad) continue - case strings.HasPrefix(line, ":d"): + case strings.HasPrefix(line, ":d "): quad, err := cquads.Parse(line[3:]) if !quad.IsValid() { if err != nil { From 1177852de76b2dcf42cf43b48d5394b92f0974d9 Mon Sep 17 00:00:00 2001 From: bcleenders Date: Wed, 24 Dec 2014 01:12:20 +0100 Subject: [PATCH 2/5] Adds adding/removing using repl to docs --- docs/Overview.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/Overview.md b/docs/Overview.md index ff99777..f327ead 100644 --- a/docs/Overview.md +++ b/docs/Overview.md @@ -50,6 +50,18 @@ Now it's loaded. We can use Cayley now to connect to the graph. As you might hav Where you'll be given a `cayley>` prompt. It's expecting Gremlin/JS, but that can also be configured with a flag. +New nodes and links can be added with the following command: + +```bash +cayley> :a object predicate subject label +``` + +Removing links works similarly: + +```bash +cayley> :d object predicate subject label +``` + This is great for testing, and ultimately also for scripting, but the real workhorse is the next step. ### Serve Your Graph From 8efb94d2b79799236f8c2848f8a73073f1025956 Mon Sep 17 00:00:00 2001 From: bcleenders Date: Mon, 29 Dec 2014 00:00:31 +0100 Subject: [PATCH 3/5] Implements helper to split command from arguments Also tests the helper function (ofc...) --- db/repl.go | 47 ++++++++++++++++++++++++++++------------ db/repl_test.go | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 14 deletions(-) create mode 100644 db/repl_test.go diff --git a/db/repl.go b/db/repl.go index 6722299..afddf80 100644 --- a/db/repl.go +++ b/db/repl.go @@ -118,29 +118,28 @@ func Repl(h *graph.Handle, queryLanguage string, cfg *config.Config) error { } if code == "" { - switch { - case strings.HasPrefix(line, ":debug"): + command, arguments := splitLine(line) + + switch command { + case ":debug": ses.ToggleDebug() fmt.Println("Debug Toggled") continue - case strings.HasPrefix(line, ":a "): - quad, err := cquads.Parse(line[3:]) - if !quad.IsValid() { - if err != nil { - fmt.Printf("not a valid quad: %v\n", err) - } + case ":a": + quad, err := cquads.Parse(arguments) + if err != nil { + fmt.Printf("Error: not a valid quad: %v\n", err) continue } + h.QuadWriter.AddQuad(quad) continue - case strings.HasPrefix(line, ":d "): - quad, err := cquads.Parse(line[3:]) - if !quad.IsValid() { - if err != nil { - fmt.Printf("not a valid quad: %v\n", err) - } + case ":d": + quad, err := cquads.Parse(arguments) + if err != nil { + fmt.Printf("Error: not a valid quad: %v\n", err) continue } h.QuadWriter.RemoveQuad(quad) @@ -163,6 +162,26 @@ func Repl(h *graph.Handle, queryLanguage string, cfg *config.Config) error { } } +// Splits a line into a command and its arguments +// e.g. ":a b c d ." will be split into ":a" and " b c d ." +func splitLine(line string) (string, string) { + var command, arguments string + + line = strings.TrimSpace(line) + + // An empty line/a line consisting of whitespace contains neither command nor arguments + if len(line) > 0 { + command = strings.Fields(line)[0] + + // A line containing only a command has no arguments + if len(line) > len(command) { + arguments = line[len(command):] + } + } + + return command, arguments +} + func terminal(path string) (*liner.State, error) { term := liner.NewLiner() diff --git a/db/repl_test.go b/db/repl_test.go new file mode 100644 index 0000000..412796c --- /dev/null +++ b/db/repl_test.go @@ -0,0 +1,66 @@ +// Copyright 2014 The Cayley Authors. All rights reserved. +// +// 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 ( + "testing" +) + +var testSplitLines = []struct { + line string + expectedCommand string + expectedArguments string + err error +}{ + { + line: ":a arg1 arg2 arg3 .", + expectedCommand: ":a", + expectedArguments: " arg1 arg2 arg3 .", + }, + { + line: ":debug", + expectedCommand: ":debug", + // expectedArguments is nil + }, + { + line: "", + // expectedCommand is nil + // expectedArguments is nil + }, + { + line: `:d . # comments here`, + expectedCommand: ":d", + expectedArguments: ` . # comments here`, + }, + { + line: ` :a subject "predicate with spaces" object . `, + expectedCommand: ":a", + expectedArguments: ` subject "predicate with spaces" object .`, + }, +} + +func TestSplitLines(t *testing.T) { + for _, testcase := range testSplitLines { + command, arguments := splitLine(testcase.line) + + if testcase.expectedCommand != command { + t.Errorf("Error splitting lines: got: %v expected: %v", command, testcase.expectedCommand) + } + + if testcase.expectedArguments != arguments { + t.Errorf("Error splitting lines: got: %v expected: %v", arguments, testcase.expectedArguments) + } + } +} From 07167998ab2715c35929a55515b3a5363437bac3 Mon Sep 17 00:00:00 2001 From: bcleenders Date: Mon, 29 Dec 2014 00:12:37 +0100 Subject: [PATCH 4/5] Update docs Quads must end with a dot ("."), as specified in the grammar --- docs/Overview.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Overview.md b/docs/Overview.md index f327ead..0eeb61f 100644 --- a/docs/Overview.md +++ b/docs/Overview.md @@ -53,13 +53,13 @@ Where you'll be given a `cayley>` prompt. It's expecting Gremlin/JS, but that ca New nodes and links can be added with the following command: ```bash -cayley> :a object predicate subject label +cayley> :a object predicate subject label . ``` Removing links works similarly: ```bash -cayley> :d object predicate subject label +cayley> :d object predicate subject . ``` This is great for testing, and ultimately also for scripting, but the real workhorse is the next step. From 1a1904d9438782a4bff45f98495d0fb11016d9ca Mon Sep 17 00:00:00 2001 From: bcleenders Date: Mon, 29 Dec 2014 11:02:20 +0100 Subject: [PATCH 5/5] Adds default for unknown commands --- db/repl.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/db/repl.go b/db/repl.go index afddf80..9307345 100644 --- a/db/repl.go +++ b/db/repl.go @@ -144,6 +144,12 @@ func Repl(h *graph.Handle, queryLanguage string, cfg *config.Config) error { } h.QuadWriter.RemoveQuad(quad) continue + + default: + if command[0] == ':' { + fmt.Printf("Unknown command: %q\n", command) + continue + } } }