github.com/cayleygraph/cayley@v0.7.7/query/mql/mql_test.go (about) 1 // Copyright 2014 The Cayley Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package mql 16 17 import ( 18 "context" 19 "encoding/json" 20 "testing" 21 22 "github.com/stretchr/testify/require" 23 24 "github.com/cayleygraph/cayley/graph" 25 "github.com/cayleygraph/cayley/graph/graphtest/testutil" 26 _ "github.com/cayleygraph/cayley/graph/memstore" 27 "github.com/cayleygraph/cayley/query" 28 _ "github.com/cayleygraph/cayley/writer" 29 "github.com/cayleygraph/quad" 30 ) 31 32 // This is a simple test graph. 33 // 34 // +---+ +---+ 35 // | A |------- ->| F |<-- 36 // +---+ \------>+---+-/ +---+ \--+---+ 37 // ------>|#B#| | | E | 38 // +---+-------/ >+---+ | +---+ 39 // | C | / v 40 // +---+ -/ +---+ 41 // ---- +---+/ |#G#| 42 // \-->|#D#|------------->+---+ 43 // +---+ 44 // 45 46 func makeTestSession(data []quad.Quad) *Session { 47 qs, _ := graph.NewQuadStore("memstore", "", nil) 48 w, _ := graph.NewQuadWriter("single", qs, nil) 49 for _, t := range data { 50 w.AddQuad(t) 51 } 52 return NewSession(qs) 53 } 54 55 var testQueries = []struct { 56 message string 57 query string 58 tag string 59 expect string 60 }{ 61 { 62 message: "get all IDs in the database", 63 query: `[{"id": null}]`, 64 expect: ` 65 [ 66 {"id": "<alice>"}, 67 {"id": "<follows>"}, 68 {"id": "<bob>"}, 69 {"id": "<fred>"}, 70 {"id": "<status>"}, 71 {"id": "cool_person"}, 72 {"id": "<dani>"}, 73 {"id": "<charlie>"}, 74 {"id": "<greg>"}, 75 {"id": "<emily>"}, 76 {"id": "<predicates>"}, 77 {"id": "<are>"}, 78 {"id": "smart_person"}, 79 {"id": "<smart_graph>"} 80 ] 81 `, 82 }, 83 { 84 message: "get nodes by status", 85 query: `[{"id": null, "<status>": "cool_person"}]`, 86 expect: ` 87 [ 88 {"id": "<bob>", "<status>": "cool_person"}, 89 {"id": "<dani>", "<status>": "cool_person"}, 90 {"id": "<greg>", "<status>": "cool_person"} 91 ] 92 `, 93 }, 94 { 95 message: "show correct null semantics", 96 query: `[{"id": "cool_person", "status": null}]`, 97 expect: ` 98 [ 99 {"id": "cool_person", "status": null} 100 ] 101 `, 102 }, 103 { 104 message: "get correct follows list", 105 query: `[{"id": "<charlie>", "<follows>": []}]`, 106 expect: ` 107 [ 108 {"id": "<charlie>", "<follows>": ["<bob>", "<dani>"]} 109 ] 110 `, 111 }, 112 { 113 message: "get correct reverse follows list", 114 query: `[{"id": "<fred>", "!<follows>": []}]`, 115 expect: ` 116 [ 117 {"id": "<fred>", "!<follows>": ["<bob>", "<emily>"]} 118 ] 119 `, 120 }, 121 { 122 message: "get correct follows struct", 123 query: `[{"id": null, "<follows>": {"id": null, "<status>": "cool_person"}}]`, 124 expect: ` 125 [ 126 {"id": "<alice>", "<follows>": {"id": "<bob>", "<status>": "cool_person"}}, 127 {"id": "<dani>", "<follows>": {"id": "<greg>", "<status>": "cool_person"}}, 128 {"id": "<charlie>", "<follows>": {"id": "<dani>", "<status>": "cool_person"}}, 129 {"id": "<fred>", "<follows>": {"id": "<greg>", "<status>": "cool_person"}} 130 ] 131 `, 132 }, 133 { 134 message: "get correct reverse follows struct", 135 query: `[{"id": null, "!<follows>": [{"id": null, "<status>" : "cool_person"}]}]`, 136 expect: ` 137 [ 138 {"id": "<fred>", "!<follows>": [{"id": "<bob>", "<status>": "cool_person"}]}, 139 {"id": "<bob>", "!<follows>": [{"id": "<dani>", "<status>": "cool_person"}]}, 140 {"id": "<greg>", "!<follows>": [{"id": "<dani>", "<status>": "cool_person"}]} 141 ] 142 `, 143 }, 144 { 145 message: "get correct co-follows", 146 query: `[{"id": null, "@A:<follows>": "<bob>", "@B:<follows>": "<dani>"}]`, 147 expect: ` 148 [ 149 {"id": "<charlie>", "@A:<follows>": "<bob>", "@B:<follows>": "<dani>"} 150 ] 151 `, 152 }, 153 { 154 message: "get correct reverse co-follows", 155 query: `[{"id": null, "!<follows>": {"id": "<charlie>"}, "@A:!<follows>": "<dani>"}]`, 156 expect: ` 157 [ 158 {"id": "<bob>", "!<follows>": {"id": "<charlie>"}, "@A:!<follows>": "<dani>"} 159 ] 160 `, 161 }, 162 } 163 164 func runQuery(t testing.TB, g []quad.Quad, qu string) interface{} { 165 s := makeTestSession(g) 166 ctx := context.TODO() 167 it, err := s.Execute(ctx, qu, query.Options{Collation: query.JSON}) 168 if err != nil { 169 t.Fatal(err) 170 } 171 defer it.Close() 172 var out []interface{} 173 for it.Next(ctx) { 174 out = append(out, it.Result()) 175 } 176 return out 177 } 178 179 func TestMQL(t *testing.T) { 180 simpleGraph := testutil.LoadGraph(t, "../../data/testdata.nq") 181 for _, test := range testQueries { 182 t.Run(test.message, func(t *testing.T) { 183 got := runQuery(t, simpleGraph, test.query) 184 var expect interface{} 185 json.Unmarshal([]byte(test.expect), &expect) 186 require.Equal(t, expect, got) 187 }) 188 } 189 }