github.com/unigraph-dev/dgraph@v1.1.1-0.20200923154953-8b52b426f765/query/query3_test.go (about) 1 /* 2 * Copyright 2018 Dgraph Labs, Inc. and Contributors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package query 18 19 import ( 20 "context" 21 "encoding/json" 22 "fmt" 23 "strings" 24 "testing" 25 26 "github.com/stretchr/testify/require" 27 "google.golang.org/grpc/metadata" 28 ) 29 30 func TestRecurseError(t *testing.T) { 31 query := ` 32 { 33 me(func: uid(0x01)) @recurse(loop: true) { 34 nonexistent_pred 35 friend 36 name 37 } 38 }` 39 40 _, err := processQuery(context.Background(), t, query) 41 require.Error(t, err) 42 require.Contains(t, err.Error(), "Depth must be > 0 when loop is true for recurse query") 43 } 44 45 func TestRecurseNestedError1(t *testing.T) { 46 query := ` 47 { 48 me(func: uid(0x01)) @recurse { 49 friend { 50 name 51 } 52 name 53 } 54 }` 55 56 _, err := processQuery(context.Background(), t, query) 57 require.Error(t, err) 58 require.Contains(t, err.Error(), 59 "recurse queries require that all predicates are specified in one level") 60 } 61 62 func TestRecurseNestedError2(t *testing.T) { 63 query := ` 64 { 65 me(func: uid(0x01)) @recurse { 66 friend { 67 pet { 68 name 69 } 70 } 71 } 72 }` 73 74 _, err := processQuery(context.Background(), t, query) 75 require.Error(t, err) 76 require.Contains(t, err.Error(), 77 "recurse queries require that all predicates are specified in one level") 78 } 79 80 func TestRecurseQuery(t *testing.T) { 81 82 query := ` 83 { 84 me(func: uid(0x01)) @recurse { 85 nonexistent_pred 86 friend 87 name 88 } 89 }` 90 js := processQueryNoErr(t, query) 91 require.JSONEq(t, 92 `{"data": {"me":[{"name":"Michonne", "friend":[{"name":"Rick Grimes", "friend":[{"name":"Michonne"}]},{"name":"Glenn Rhee"},{"name":"Daryl Dixon"},{"name":"Andrea", "friend":[{"name":"Glenn Rhee"}]}]}]}}`, js) 93 } 94 95 func TestRecurseExpand(t *testing.T) { 96 97 query := ` 98 { 99 me(func: uid(32)) @recurse { 100 expand(_all_) 101 } 102 }` 103 js := processQueryNoErr(t, query) 104 require.JSONEq(t, `{"data":{"me":[{"school":[{"name":"San Mateo High School","district":[{"name":"San Mateo School District","county":[{"state":[{"name":"California","abbr":"CA"}],"name":"San Mateo County"}]}]}]}]}}`, js) 105 } 106 107 func TestRecurseExpandRepeatedPredError(t *testing.T) { 108 109 query := ` 110 { 111 me(func: uid(32)) @recurse { 112 name 113 expand(_all_) 114 } 115 }` 116 117 _, err := processQuery(context.Background(), t, query) 118 require.Error(t, err) 119 require.Contains(t, err.Error(), "Repeated subgraph: [name] while using expand()") 120 } 121 122 func TestRecurseQueryOrder(t *testing.T) { 123 124 query := ` 125 { 126 me(func: uid(0x01)) @recurse { 127 friend(orderdesc: dob) 128 dob 129 name 130 } 131 }` 132 js := processQueryNoErr(t, query) 133 require.JSONEq(t, 134 `{"data": {"me":[{"dob":"1910-01-01T00:00:00Z","friend":[{"dob":"1910-01-02T00:00:00Z","friend":[{"dob":"1910-01-01T00:00:00Z","name":"Michonne"}],"name":"Rick Grimes"},{"dob":"1909-05-05T00:00:00Z","name":"Glenn Rhee"},{"dob":"1909-01-10T00:00:00Z","name":"Daryl Dixon"},{"dob":"1901-01-15T00:00:00Z","friend":[{"dob":"1909-05-05T00:00:00Z","name":"Glenn Rhee"}],"name":"Andrea"}],"name":"Michonne"}]}}`, 135 js) 136 } 137 138 func TestRecurseQueryAllowLoop(t *testing.T) { 139 140 query := ` 141 { 142 me(func: uid(0x01)) @recurse { 143 friend 144 dob 145 name 146 } 147 }` 148 js := processQueryNoErr(t, query) 149 require.JSONEq(t, `{"data":{"me":[{"friend":[{"friend":[{"dob":"1910-01-01T00:00:00Z","name":"Michonne"}],"dob":"1910-01-02T00:00:00Z","name":"Rick Grimes"},{"dob":"1909-05-05T00:00:00Z","name":"Glenn Rhee"},{"dob":"1909-01-10T00:00:00Z","name":"Daryl Dixon"},{"friend":[{"dob":"1909-05-05T00:00:00Z","name":"Glenn Rhee"}],"dob":"1901-01-15T00:00:00Z","name":"Andrea"}],"dob":"1910-01-01T00:00:00Z","name":"Michonne"}]}}`, js) 150 } 151 152 func TestRecurseQueryAllowLoop2(t *testing.T) { 153 154 query := ` 155 { 156 me(func: uid(0x01)) @recurse(depth: 4,loop: true) { 157 friend 158 dob 159 name 160 } 161 }` 162 js := processQueryNoErr(t, query) 163 require.JSONEq(t, `{"data":{"me":[{"friend":[{"friend":[{"friend":[{"dob":"1910-01-02T00:00:00Z","name":"Rick Grimes"},{"dob":"1909-05-05T00:00:00Z","name":"Glenn Rhee"},{"dob":"1909-01-10T00:00:00Z","name":"Daryl Dixon"},{"dob":"1901-01-15T00:00:00Z","name":"Andrea"}],"dob":"1910-01-01T00:00:00Z","name":"Michonne"}],"dob":"1910-01-02T00:00:00Z","name":"Rick Grimes"},{"dob":"1909-05-05T00:00:00Z","name":"Glenn Rhee"},{"dob":"1909-01-10T00:00:00Z","name":"Daryl Dixon"},{"friend":[{"dob":"1909-05-05T00:00:00Z","name":"Glenn Rhee"}],"dob":"1901-01-15T00:00:00Z","name":"Andrea"}],"dob":"1910-01-01T00:00:00Z","name":"Michonne"}]}}`, js) 164 } 165 166 func TestRecurseQueryLimitDepth1(t *testing.T) { 167 168 query := ` 169 { 170 me(func: uid(0x01)) @recurse(depth: 2) { 171 friend 172 name 173 } 174 }` 175 js := processQueryNoErr(t, query) 176 require.JSONEq(t, 177 `{"data": {"me":[{"name":"Michonne", "friend":[{"name":"Rick Grimes"},{"name":"Glenn Rhee"},{"name":"Daryl Dixon"},{"name":"Andrea"}]}]}}`, js) 178 } 179 180 func TestRecurseQueryLimitDepth2(t *testing.T) { 181 182 query := ` 183 { 184 me(func: uid(0x01)) @recurse(depth: 2) { 185 uid 186 non_existent 187 friend 188 name 189 } 190 }` 191 js := processQueryNoErr(t, query) 192 require.JSONEq(t, 193 `{"data": {"me":[{"uid":"0x1","friend":[{"uid":"0x17","name":"Rick Grimes"},{"uid":"0x18","name":"Glenn Rhee"},{"uid":"0x19","name":"Daryl Dixon"},{"uid":"0x1f","name":"Andrea"},{"uid":"0x65"}],"name":"Michonne"}]}}`, js) 194 } 195 196 func TestRecurseVariable(t *testing.T) { 197 198 query := ` 199 { 200 var(func: uid(0x01)) @recurse { 201 a as friend 202 } 203 204 me(func: uid(a)) { 205 name 206 } 207 } 208 ` 209 210 js := processQueryNoErr(t, query) 211 require.JSONEq(t, `{"data": {"me":[{"name":"Michonne"},{"name":"Rick Grimes"},{"name":"Glenn Rhee"},{"name":"Daryl Dixon"},{"name":"Andrea"}]}}`, js) 212 } 213 214 func TestRecurseVariableUid(t *testing.T) { 215 216 query := ` 217 { 218 var(func: uid(0x01)) @recurse { 219 friend 220 a as uid 221 } 222 223 me(func: uid(a)) { 224 name 225 } 226 } 227 ` 228 229 js := processQueryNoErr(t, query) 230 require.JSONEq(t, `{"data": {"me":[{"name":"Michonne"},{"name":"Rick Grimes"},{"name":"Glenn Rhee"},{"name":"Daryl Dixon"},{"name":"Andrea"}]}}`, js) 231 } 232 233 func TestRecurseVariableVar(t *testing.T) { 234 235 query := ` 236 { 237 var(func: uid(0x01)) @recurse { 238 friend 239 school 240 a as name 241 } 242 243 me(func: uid(a)) { 244 name 245 } 246 } 247 ` 248 249 js := processQueryNoErr(t, query) 250 require.JSONEq(t, `{"data":{"me":[{"name":"Michonne"},{"name":"Rick Grimes"},{"name":"Glenn Rhee"},{"name":"Daryl Dixon"},{"name":"Andrea"},{"name":"School A"},{"name":"School B"}]}}`, js) 251 } 252 253 func TestRecurseVariable2(t *testing.T) { 254 255 query := ` 256 { 257 258 var(func: uid(0x1)) @recurse { 259 f2 as friend 260 f as follow 261 } 262 263 me(func: uid(f)) { 264 name 265 } 266 267 me2(func: uid(f2)) { 268 name 269 } 270 } 271 ` 272 js := processQueryNoErr(t, query) 273 require.JSONEq(t, `{"data": {"me":[{"name":"Glenn Rhee"},{"name":"Andrea"},{"name":"Alice"},{"name":"Bob"},{"name":"Matt"},{"name":"John"}],"me2":[{"name":"Michonne"},{"name":"Rick Grimes"},{"name":"Glenn Rhee"},{"name":"Daryl Dixon"},{"name":"Andrea"}]}}`, js) 274 } 275 276 func TestShortestPath_ExpandError(t *testing.T) { 277 278 query := ` 279 { 280 A as shortest(from:0x01, to:101) { 281 expand(_all_) 282 } 283 284 me(func: uid( A)) { 285 name 286 } 287 }` 288 289 _, err := processQuery(context.Background(), t, query) 290 require.Error(t, err) 291 } 292 293 func TestShortestPath_NoPath(t *testing.T) { 294 295 query := ` 296 { 297 A as shortest(from:0x01, to:101) { 298 path 299 follow 300 } 301 302 me(func: uid(A)) { 303 name 304 } 305 }` 306 js := processQueryNoErr(t, query) 307 require.JSONEq(t, `{"data": {"me": []}}`, js) 308 } 309 310 func TestKShortestPath_NoPath(t *testing.T) { 311 312 query := ` 313 { 314 A as shortest(from:0x01, to:101, numpaths: 2) { 315 path 316 nonexistent_pred 317 follow 318 } 319 320 me(func: uid(A)) { 321 name 322 } 323 }` 324 js := processQueryNoErr(t, query) 325 require.JSONEq(t, `{"data": {"me": []}}`, js) 326 } 327 328 func TestKShortestPathWeighted(t *testing.T) { 329 330 query := ` 331 { 332 shortest(from: 1, to:1001, numpaths: 4) { 333 path @facets(weight) 334 } 335 }` 336 // We only get one path in this case as the facet is present only in one path. 337 js := processQueryNoErr(t, query) 338 require.JSONEq(t, 339 `{"data":{"_path_":[{"uid":"0x1","_weight_":0.3,"path":{"uid":"0x1f","path":{"uid":"0x3e8","path":{"uid":"0x3e9","path|weight":0.100000},"path|weight":0.100000},"path|weight":0.100000}}]}}`, 340 js) 341 } 342 343 func TestKShortestPathWeightedMinMaxNoEffect(t *testing.T) { 344 345 query := ` 346 { 347 shortest(from: 1, to:1001, numpaths: 4, minweight:0, maxweight: 1000) { 348 path @facets(weight) 349 } 350 }` 351 // We only get one path in this case as the facet is present only in one path. 352 // The path meets the weight requirements so it does not get filtered. 353 js := processQueryNoErr(t, query) 354 require.JSONEq(t, 355 `{"data":{"_path_":[{"uid":"0x1","_weight_":0.3,"path":{"uid":"0x1f","path":{"uid":"0x3e8","path":{"uid":"0x3e9","path|weight":0.100000},"path|weight":0.100000},"path|weight":0.100000}}]}}`, 356 js) 357 } 358 359 func TestKShortestPathWeightedMinWeight(t *testing.T) { 360 361 query := ` 362 { 363 shortest(from: 1, to:1001, numpaths: 4, minweight: 3) { 364 path @facets(weight) 365 } 366 }` 367 // We get no paths as the only path does not match the weight requirements. 368 js := processQueryNoErr(t, query) 369 require.JSONEq(t, `{"data":{}}`, js) 370 } 371 372 func TestKShortestPathWeightedMaxWeight(t *testing.T) { 373 374 query := ` 375 { 376 shortest(from: 1, to:1001, numpaths: 4, maxweight: 0.1) { 377 path @facets(weight) 378 } 379 }` 380 // We get no paths as the only path does not match the weight requirements. 381 js := processQueryNoErr(t, query) 382 require.JSONEq(t, `{"data":{}}`, js) 383 } 384 385 func TestKShortestPathWeighted_LimitDepth(t *testing.T) { 386 387 query := ` 388 { 389 shortest(from: 1, to:1001, depth:1, numpaths: 4) { 390 path @facets(weight) 391 } 392 }` 393 // We only get one path in this case as the facet is present only in one path. 394 js := processQueryNoErr(t, query) 395 require.JSONEq(t, 396 `{"data": {}}`, 397 js) 398 } 399 400 func TestKShortestPathWeighted1(t *testing.T) { 401 402 query := ` 403 { 404 shortest(from: 1, to:1003, numpaths: 3) { 405 path @facets(weight) 406 } 407 }` 408 js := processQueryNoErr(t, query) 409 require.JSONEq(t, 410 `{"data":{"_path_":[ 411 {"uid":"0x1","_weight_":1,"path":{"uid":"0x1f","path":{"uid":"0x3e8","path":{"uid":"0x3e9","path":{"uid":"0x3ea","path":{"uid":"0x3eb","path|weight":0.600000},"path|weight":0.100000},"path|weight":0.100000},"path|weight":0.100000},"path|weight":0.100000}}, 412 {"uid":"0x1","_weight_":1.5,"path":{"uid":"0x1f","path":{"uid":"0x3e8","path":{"uid":"0x3ea","path":{"uid":"0x3eb","path|weight":0.600000},"path|weight":0.700000},"path|weight":0.100000},"path|weight":0.100000}}, 413 {"uid":"0x1","_weight_":1.8,"path":{"uid":"0x1f","path":{"uid":"0x3e8","path":{"uid":"0x3e9","path":{"uid":"0x3eb","path|weight":1.500000},"path|weight":0.100000},"path|weight":0.100000},"path|weight":0.100000}}]}}`, 414 js) 415 } 416 417 func TestKShortestPathWeighted1MinMaxWeight(t *testing.T) { 418 419 query := ` 420 { 421 shortest(from: 1, to:1003, numpaths: 3, minweight: 1.3, maxweight: 1.5) { 422 path @facets(weight) 423 } 424 }` 425 js := processQueryNoErr(t, query) 426 require.JSONEq(t, 427 `{"data":{"_path_":[{"uid":"0x1","_weight_":1.5,"path":{"uid":"0x1f","path":{"uid":"0x3e8","path":{"uid":"0x3ea","path":{"uid":"0x3eb","path|weight":0.600000},"path|weight":0.700000},"path|weight":0.100000},"path|weight":0.100000}}]}}`, 428 js) 429 } 430 431 func TestTwoShortestPath(t *testing.T) { 432 433 query := ` 434 { 435 A as shortest(from: 1, to:1002, numpaths: 2) { 436 path 437 } 438 439 me(func: uid( A)) { 440 name 441 } 442 }` 443 js := processQueryNoErr(t, query) 444 require.JSONEq(t, 445 `{"data": {"_path_":[ 446 {"uid":"0x1","_weight_":3,"path":{"uid":"0x1f","path":{"uid":"0x3e8","path":{"uid":"0x3ea"}}}}, 447 {"uid":"0x1","_weight_":4,"path":{"uid":"0x1f","path":{"uid":"0x3e8","path":{"uid":"0x3e9","path":{"uid":"0x3ea"}}}}}], 448 "me":[{"name":"Michonne"},{"name":"Andrea"},{"name":"Alice"},{"name":"Matt"}]}}`, 449 js) 450 } 451 452 func TestTwoShortestPathMaxWeight(t *testing.T) { 453 454 query := ` 455 { 456 A as shortest(from: 1, to:1002, numpaths: 2, maxweight:1) { 457 path 458 } 459 460 me(func: uid( A)) { 461 name 462 } 463 }` 464 js := processQueryNoErr(t, query) 465 require.JSONEq(t, `{"data": {"me":[]}}`, js) 466 } 467 468 func TestTwoShortestPathMinWeight(t *testing.T) { 469 470 query := ` 471 { 472 A as shortest(from: 1, to:1002, numpaths: 2, minweight:10) { 473 path 474 } 475 476 me(func: uid( A)) { 477 name 478 } 479 }` 480 js := processQueryNoErr(t, query) 481 require.JSONEq(t, `{"data": {"me":[]}}`, js) 482 } 483 484 func TestShortestPath(t *testing.T) { 485 query := ` 486 { 487 A as shortest(from:0x01, to:31) { 488 friend 489 } 490 491 me(func: uid( A)) { 492 name 493 } 494 }` 495 js := processQueryNoErr(t, query) 496 require.JSONEq(t, 497 `{"data": {"_path_":[{"uid":"0x1", "_weight_": 1, "friend":{"uid":"0x1f"}}],"me":[{"name":"Michonne"},{"name":"Andrea"}]}}`, 498 js) 499 } 500 501 func TestShortestPathRev(t *testing.T) { 502 503 query := ` 504 { 505 A as shortest(from:23, to:1) { 506 friend 507 } 508 509 me(func: uid( A)) { 510 name 511 } 512 }` 513 js := processQueryNoErr(t, query) 514 require.JSONEq(t, 515 `{"data": {"_path_":[{"uid":"0x17","_weight_":1, "friend":{"uid":"0x1"}}],"me":[{"name":"Rick Grimes"},{"name":"Michonne"}]}}`, 516 js) 517 } 518 519 // Regression test for https://github.com/dgraph-io/dgraph/issues/3657. 520 func TestShortestPathPassword(t *testing.T) { 521 query := ` 522 { 523 A as shortest(from:0x01, to:31) { 524 password 525 friend 526 } 527 528 me(func: uid( A)) { 529 name 530 } 531 }` 532 js := processQueryNoErr(t, query) 533 require.JSONEq(t, 534 `{"data": {"_path_":[{"uid":"0x1", "_weight_": 1, "friend":{"uid":"0x1f"}}], 535 "me":[{"name":"Michonne"},{"name":"Andrea"}]}}`, js) 536 } 537 538 func TestShortestPathWithUidVariable(t *testing.T) { 539 query := ` 540 { 541 a as var(func: uid(0x01)) 542 b as var(func: uid(31)) 543 544 shortest(from: uid(a), to: uid(b)) { 545 password 546 friend 547 } 548 }` 549 js := processQueryNoErr(t, query) 550 require.JSONEq(t, 551 `{"data": {"_path_":[{"uid":"0x1", "_weight_": 1, "friend":{"uid":"0x1f"}}]}}`, js) 552 } 553 554 func TestShortestPathWithUidVariableAndFunc(t *testing.T) { 555 query := ` 556 { 557 a as var(func: eq(name, "Michonne")) 558 b as var(func: eq(name, "Andrea")) 559 560 shortest(from: uid(a), to: uid(b)) { 561 password 562 friend 563 } 564 }` 565 js := processQueryNoErr(t, query) 566 require.JSONEq(t, 567 `{"data": {"_path_":[{"uid":"0x1", "_weight_": 1, "friend":{"uid":"0x1f"}}]}}`, js) 568 } 569 570 func TestShortestPathWithUidVariableError(t *testing.T) { 571 query := ` 572 { 573 a as var(func: eq(name, "Alice")) 574 b as var(func: eq(name, "Andrea")) 575 576 shortest(from: uid(a), to: uid(b)) { 577 password 578 friend 579 } 580 }` 581 582 _, err := processQuery(context.Background(), t, query) 583 require.Error(t, err) 584 } 585 586 func TestShortestPathWithUidVariableNoMatch(t *testing.T) { 587 query := ` 588 { 589 a as var(func: eq(name, "blah blah")) 590 b as var(func: eq(name, "foo bar")) 591 592 shortest(from: uid(a), to: uid(b)) { 593 password 594 friend 595 } 596 }` 597 js := processQueryNoErr(t, query) 598 require.JSONEq(t, `{"data":{}}`, js) 599 } 600 601 func TestShortestPathWithUidVariableNoMatchForFrom(t *testing.T) { 602 query := ` 603 { 604 a as var(func: eq(name, "blah blah")) 605 b as var(func: eq(name, "Michonne")) 606 607 shortest(from: uid(a), to: uid(b)) { 608 password 609 friend 610 } 611 }` 612 js := processQueryNoErr(t, query) 613 require.JSONEq(t, `{"data":{}}`, js) 614 } 615 616 func TestFacetVarRetrieval(t *testing.T) { 617 618 query := ` 619 { 620 var(func: uid(1)) { 621 path @facets(f as weight) 622 } 623 624 me(func: uid( 24)) { 625 val(f) 626 } 627 }` 628 js := processQueryNoErr(t, query) 629 require.JSONEq(t, 630 `{"data": {"me":[{"val(f)":0.200000}]}}`, 631 js) 632 } 633 634 func TestFacetVarRetrieveOrder(t *testing.T) { 635 636 query := ` 637 { 638 var(func: uid(1)) { 639 path @facets(f as weight) 640 } 641 642 me(func: uid(f), orderasc: val(f)) { 643 name 644 nonexistent_pred 645 val(f) 646 } 647 }` 648 js := processQueryNoErr(t, query) 649 require.JSONEq(t, 650 `{"data": {"me":[{"name":"Andrea","val(f)":0.100000},{"name":"Glenn Rhee","val(f)":0.200000}]}}`, 651 js) 652 } 653 654 func TestShortestPathWeightsMultiFacet_Error(t *testing.T) { 655 656 query := ` 657 { 658 A as shortest(from:1, to:1002) { 659 path @facets(weight, weight1) 660 } 661 662 me(func: uid( A)) { 663 name 664 } 665 }` 666 667 _, err := processQuery(context.Background(), t, query) 668 require.Error(t, err) 669 } 670 671 func TestShortestPathWeights(t *testing.T) { 672 673 query := ` 674 { 675 A as shortest(from:1, to:1002) { 676 path @facets(weight) 677 } 678 679 me(func: uid( A)) { 680 name 681 } 682 }` 683 js := processQueryNoErr(t, query) 684 require.JSONEq(t, 685 `{"data":{"me":[{"name":"Michonne"},{"name":"Andrea"},{"name":"Alice"},{"name":"Bob"},{"name":"Matt"}],"_path_":[{"uid":"0x1","_weight_":0.4,"path":{"uid":"0x1f","path":{"uid":"0x3e8","path":{"uid":"0x3e9","path":{"uid":"0x3ea","path|weight":0.100000},"path|weight":0.100000},"path|weight":0.100000},"path|weight":0.100000}}]}}`, 686 js) 687 } 688 689 func TestShortestPath2(t *testing.T) { 690 691 query := ` 692 { 693 A as shortest(from:0x01, to:1000) { 694 path 695 } 696 697 me(func: uid( A)) { 698 name 699 } 700 }` 701 js := processQueryNoErr(t, query) 702 require.JSONEq(t, 703 `{"data": {"_path_":[{"uid":"0x1","_weight_":2,"path":{"uid":"0x1f","path":{"uid":"0x3e8"}}}],"me":[{"name":"Michonne"},{"name":"Andrea"},{"name":"Alice"}]}} 704 `, 705 js) 706 } 707 708 func TestShortestPath4(t *testing.T) { 709 710 query := ` 711 { 712 A as shortest(from:1, to:1003) { 713 path 714 follow 715 } 716 717 me(func: uid( A)) { 718 name 719 } 720 }` 721 js := processQueryNoErr(t, query) 722 require.JSONEq(t, 723 `{"data": {"_path_":[{"uid":"0x1","_weight_":3,"follow":{"uid":"0x1f","follow":{"uid":"0x3e9","follow":{"uid":"0x3eb"}}}}],"me":[{"name":"Michonne"},{"name":"Andrea"},{"name":"Bob"},{"name":"John"}]}}`, 724 js) 725 } 726 727 func TestShortestPath_filter(t *testing.T) { 728 729 query := ` 730 { 731 A as shortest(from:1, to:1002) { 732 path @filter(not anyofterms(name, "alice")) 733 follow 734 } 735 736 me(func: uid(A)) { 737 name 738 } 739 }` 740 js := processQueryNoErr(t, query) 741 require.JSONEq(t, 742 `{"data": {"_path_":[{"uid":"0x1","_weight_":3,"follow":{"uid":"0x1f","follow":{"uid":"0x3e9","path":{"uid":"0x3ea"}}}}],"me":[{"name":"Michonne"},{"name":"Andrea"},{"name":"Bob"},{"name":"Matt"}]}}`, 743 js) 744 } 745 746 func TestShortestPath_filter2(t *testing.T) { 747 748 query := ` 749 { 750 A as shortest(from:1, to:1002) { 751 path @filter(not anyofterms(name, "alice")) 752 follow @filter(not anyofterms(name, "bob")) 753 } 754 755 me(func: uid(A)) { 756 name 757 } 758 }` 759 js := processQueryNoErr(t, query) 760 require.JSONEq(t, `{"data": { "me": []}}`, js) 761 } 762 763 func TestTwoShortestPathVariable(t *testing.T) { 764 765 query := ` 766 { 767 a as var(func: uid(1)) 768 b as var(func: uid(1002)) 769 770 A as shortest(from: uid(a), to: uid(b), numpaths: 2) { 771 path 772 } 773 774 me(func: uid(A)) { 775 name 776 } 777 }` 778 js := processQueryNoErr(t, query) 779 require.JSONEq(t, 780 `{"data": {"_path_":[ 781 {"uid":"0x1","_weight_":3,"path":{"uid":"0x1f","path":{"uid":"0x3e8", 782 "path":{"uid":"0x3ea"}}}}, {"uid":"0x1","_weight_":4, 783 "path":{"uid":"0x1f","path":{"uid":"0x3e8","path":{"uid":"0x3e9", 784 "path":{"uid":"0x3ea"}}}}}], "me":[{"name":"Michonne"},{"name":"Andrea"} 785 ,{"name":"Alice"},{"name":"Matt"}]}}`, 786 js) 787 } 788 789 func TestUseVarsFilterMultiId(t *testing.T) { 790 791 query := ` 792 { 793 var(func: uid(0x01)) { 794 L as friend { 795 friend 796 } 797 } 798 799 var(func: uid(31)) { 800 G as friend 801 } 802 803 friend(func:anyofterms(name, "Michonne Andrea Glenn")) @filter(uid(G, L)) { 804 name 805 } 806 } 807 ` 808 js := processQueryNoErr(t, query) 809 require.JSONEq(t, 810 `{"data": {"friend":[{"name":"Glenn Rhee"},{"name":"Andrea"}]}}`, 811 js) 812 } 813 814 func TestUseVarsMultiFilterId(t *testing.T) { 815 816 query := ` 817 { 818 var(func: uid(0x01)) { 819 L as friend 820 } 821 822 var(func: uid(31)) { 823 G as friend 824 } 825 826 friend(func: uid(L)) @filter(uid(G)) { 827 name 828 } 829 } 830 ` 831 js := processQueryNoErr(t, query) 832 require.JSONEq(t, 833 `{"data": {"friend":[{"name":"Glenn Rhee"}]}}`, 834 js) 835 } 836 837 func TestUseVarsCascade(t *testing.T) { 838 839 query := ` 840 { 841 var(func: uid(0x01)) @cascade { 842 L as friend { 843 friend 844 } 845 } 846 847 me(func: uid(L)) { 848 name 849 } 850 } 851 ` 852 js := processQueryNoErr(t, query) 853 require.JSONEq(t, 854 `{"data": {"me":[{"name":"Rick Grimes"}, {"name":"Andrea"} ]}}`, 855 js) 856 } 857 858 func TestUseVars(t *testing.T) { 859 860 query := ` 861 { 862 var(func: uid(0x01)) { 863 L as friend 864 } 865 866 me(func: uid(L)) { 867 name 868 } 869 } 870 ` 871 js := processQueryNoErr(t, query) 872 require.JSONEq(t, 873 `{"data": {"me":[{"name":"Rick Grimes"},{"name":"Glenn Rhee"},{"name":"Daryl Dixon"},{"name":"Andrea"}]}}`, 874 js) 875 } 876 877 func TestGetUIDCount(t *testing.T) { 878 879 query := ` 880 { 881 me(func: uid(0x01)) { 882 name 883 uid 884 gender 885 alive 886 count(friend) 887 } 888 } 889 ` 890 js := processQueryNoErr(t, query) 891 require.JSONEq(t, 892 `{"data": {"me":[{"uid":"0x1","alive":true,"count(friend)":5,"gender":"female","name":"Michonne"}]}}`, 893 js) 894 } 895 896 func TestDebug1(t *testing.T) { 897 898 // Alright. Now we have everything set up. Let's create the query. 899 query := ` 900 { 901 me(func: uid(0x01)) { 902 name 903 gender 904 alive 905 count(friend) 906 } 907 } 908 ` 909 910 md := metadata.Pairs("debug", "true") 911 ctx := context.Background() 912 ctx = metadata.NewOutgoingContext(ctx, md) 913 914 buf, _ := processQuery(ctx, t, query) 915 916 var mp map[string]interface{} 917 require.NoError(t, json.Unmarshal([]byte(buf), &mp)) 918 919 data := mp["data"].(map[string]interface{}) 920 resp := data["me"] 921 uid := resp.([]interface{})[0].(map[string]interface{})["uid"].(string) 922 require.EqualValues(t, "0x1", uid) 923 } 924 925 func TestDebug2(t *testing.T) { 926 927 query := ` 928 { 929 me(func: uid(0x01)) { 930 name 931 gender 932 alive 933 count(friend) 934 } 935 } 936 ` 937 938 js := processQueryNoErr(t, query) 939 var mp map[string]interface{} 940 require.NoError(t, json.Unmarshal([]byte(js), &mp)) 941 942 resp := mp["data"].(map[string]interface{})["me"] 943 uid, ok := resp.([]interface{})[0].(map[string]interface{})["uid"].(string) 944 require.False(t, ok, "No uid expected but got one %s", uid) 945 } 946 947 func TestDebug3(t *testing.T) { 948 949 // Alright. Now we have everything set up. Let's create the query. 950 query := ` 951 { 952 me(func: uid(1, 24)) @filter(ge(dob, "1910-01-01")) { 953 name 954 } 955 } 956 ` 957 md := metadata.Pairs("debug", "true") 958 ctx := context.Background() 959 ctx = metadata.NewOutgoingContext(ctx, md) 960 961 buf, err := processQuery(ctx, t, query) 962 require.NoError(t, err) 963 964 var mp map[string]interface{} 965 require.NoError(t, json.Unmarshal([]byte(buf), &mp)) 966 967 resp := mp["data"].(map[string]interface{})["me"] 968 require.NotNil(t, resp) 969 require.EqualValues(t, 1, len(resp.([]interface{}))) 970 uid := resp.([]interface{})[0].(map[string]interface{})["uid"].(string) 971 require.EqualValues(t, "0x1", uid) 972 } 973 974 func TestCount(t *testing.T) { 975 976 // Alright. Now we have everything set up. Let's create the query. 977 query := ` 978 { 979 me(func: uid(0x01)) { 980 name 981 gender 982 alive 983 count(friend) 984 } 985 } 986 ` 987 988 js := processQueryNoErr(t, query) 989 require.JSONEq(t, 990 `{"data": {"me":[{"alive":true,"count(friend)":5,"gender":"female","name":"Michonne"}]}}`, 991 js) 992 } 993 func TestCountAlias(t *testing.T) { 994 995 // Alright. Now we have everything set up. Let's create the query. 996 query := ` 997 { 998 me(func: uid(0x01)) { 999 name 1000 gender 1001 alive 1002 friendCount: count(friend) 1003 } 1004 } 1005 ` 1006 1007 js := processQueryNoErr(t, query) 1008 require.JSONEq(t, 1009 `{"data": {"me":[{"alive":true,"friendCount":5,"gender":"female","name":"Michonne"}]}}`, 1010 js) 1011 } 1012 1013 func TestCountError1(t *testing.T) { 1014 // Alright. Now we have everything set up. Let's create the query. 1015 query := ` 1016 { 1017 me(func: uid( 0x01)) { 1018 count(friend { 1019 name 1020 }) 1021 name 1022 gender 1023 alive 1024 } 1025 } 1026 ` 1027 _, err := processQuery(context.Background(), t, query) 1028 require.Error(t, err) 1029 } 1030 1031 func TestCountError2(t *testing.T) { 1032 // Alright. Now we have everything set up. Let's create the query. 1033 query := ` 1034 { 1035 me(func: uid( 0x01)) { 1036 count(friend { 1037 c { 1038 friend 1039 } 1040 }) 1041 name 1042 gender 1043 alive 1044 } 1045 } 1046 ` 1047 _, err := processQuery(context.Background(), t, query) 1048 require.Error(t, err) 1049 } 1050 1051 func TestCountError3(t *testing.T) { 1052 // Alright. Now we have everything set up. Let's create the query. 1053 query := ` 1054 { 1055 me(func: uid( 0x01)) { 1056 count(friend 1057 name 1058 gender 1059 alive 1060 } 1061 } 1062 ` 1063 _, err := processQuery(context.Background(), t, query) 1064 require.Error(t, err) 1065 } 1066 1067 func TestMultiCountSort(t *testing.T) { 1068 1069 // Alright. Now we have everything set up. Let's create the query. 1070 query := ` 1071 { 1072 f as var(func: anyofterms(name, "michonne rick andrea")) { 1073 n as count(friend) 1074 } 1075 1076 countorder(func: uid(f), orderasc: val(n)) { 1077 name 1078 count(friend) 1079 } 1080 } 1081 ` 1082 js := processQueryNoErr(t, query) 1083 require.JSONEq(t, 1084 `{"data": {"countorder":[{"count(friend)":0,"name":"Andrea With no friends"},{"count(friend)":1,"name":"Rick Grimes"},{"count(friend)":1,"name":"Andrea"},{"count(friend)":5,"name":"Michonne"}]}}`, 1085 js) 1086 } 1087 1088 func TestMultiLevelAgg(t *testing.T) { 1089 1090 // Alright. Now we have everything set up. Let's create the query. 1091 query := ` 1092 { 1093 sumorder(func: anyofterms(name, "michonne rick andrea")) { 1094 name 1095 friend { 1096 s as count(friend) 1097 } 1098 sum(val(s)) 1099 } 1100 } 1101 ` 1102 js := processQueryNoErr(t, query) 1103 require.JSONEq(t, 1104 `{"data": {"sumorder":[{"friend":[{"count(friend)":1},{"count(friend)":0},{"count(friend)":0},{"count(friend)":1},{"count(friend)":0}],"name":"Michonne","sum(val(s))":2},{"friend":[{"count(friend)":5}],"name":"Rick Grimes","sum(val(s))":5},{"friend":[{"count(friend)":0}],"name":"Andrea","sum(val(s))":0},{"name":"Andrea With no friends"}]}}`, 1105 js) 1106 } 1107 1108 func TestMultiLevelAgg1(t *testing.T) { 1109 1110 // Alright. Now we have everything set up. Let's create the query. 1111 query := ` 1112 { 1113 var(func: anyofterms(name, "michonne rick andrea")) @filter(gt(count(friend), 0)){ 1114 friend { 1115 s as count(friend) 1116 } 1117 ss as sum(val(s)) 1118 } 1119 1120 sumorder(func: uid(ss), orderasc: val(ss)) { 1121 name 1122 val(ss) 1123 } 1124 } 1125 ` 1126 js := processQueryNoErr(t, query) 1127 require.JSONEq(t, 1128 `{"data": {"sumorder":[{"name":"Andrea","val(ss)":0},{"name":"Michonne","val(ss)":2},{"name":"Rick Grimes","val(ss)":5}]}}`, 1129 js) 1130 } 1131 1132 func TestMultiLevelAgg1Error(t *testing.T) { 1133 1134 // Alright. Now we have everything set up. Let's create the query. 1135 query := ` 1136 { 1137 var(func: anyofterms(name, "michonne rick andrea")) @filter(gt(count(friend), 0)){ 1138 friend { 1139 s as count(friend) 1140 ss as sum(val(s)) 1141 } 1142 } 1143 1144 sumorder(func: uid(ss), orderasc: val(ss)) { 1145 name 1146 val(ss) 1147 } 1148 } 1149 ` 1150 _, err := processQuery(context.Background(), t, query) 1151 require.Error(t, err) 1152 } 1153 1154 func TestMultiAggSort(t *testing.T) { 1155 1156 // Alright. Now we have everything set up. Let's create the query. 1157 query := ` 1158 { 1159 f as var(func: anyofterms(name, "michonne rick andrea")) { 1160 name 1161 friend { 1162 x as dob 1163 } 1164 mindob as min(val(x)) 1165 maxdob as max(val(x)) 1166 } 1167 1168 maxorder(func: uid(f), orderasc: val(maxdob)) { 1169 name 1170 val(maxdob) 1171 } 1172 1173 minorder(func: uid(f), orderasc: val(mindob)) { 1174 name 1175 val(mindob) 1176 } 1177 } 1178 ` 1179 js := processQueryNoErr(t, query) 1180 require.JSONEq(t, 1181 `{"data": {"maxorder":[{"name":"Andrea","val(maxdob)":"1909-05-05T00:00:00Z"},{"name":"Rick Grimes","val(maxdob)":"1910-01-01T00:00:00Z"},{"name":"Michonne","val(maxdob)":"1910-01-02T00:00:00Z"}],"minorder":[{"name":"Michonne","val(mindob)":"1901-01-15T00:00:00Z"},{"name":"Andrea","val(mindob)":"1909-05-05T00:00:00Z"},{"name":"Rick Grimes","val(mindob)":"1910-01-01T00:00:00Z"}]}}`, 1182 js) 1183 } 1184 1185 func TestMinMulti(t *testing.T) { 1186 1187 // Alright. Now we have everything set up. Let's create the query. 1188 query := ` 1189 { 1190 me(func: anyofterms(name, "michonne rick andrea")) { 1191 name 1192 friend { 1193 x as dob 1194 } 1195 min(val(x)) 1196 max(val(x)) 1197 } 1198 } 1199 ` 1200 js := processQueryNoErr(t, query) 1201 require.JSONEq(t, 1202 `{"data": {"me":[{"friend":[{"dob":"1910-01-02T00:00:00Z"},{"dob":"1909-05-05T00:00:00Z"},{"dob":"1909-01-10T00:00:00Z"},{"dob":"1901-01-15T00:00:00Z"}],"max(val(x))":"1910-01-02T00:00:00Z","min(val(x))":"1901-01-15T00:00:00Z","name":"Michonne"},{"friend":[{"dob":"1910-01-01T00:00:00Z"}],"max(val(x))":"1910-01-01T00:00:00Z","min(val(x))":"1910-01-01T00:00:00Z","name":"Rick Grimes"},{"friend":[{"dob":"1909-05-05T00:00:00Z"}],"max(val(x))":"1909-05-05T00:00:00Z","min(val(x))":"1909-05-05T00:00:00Z","name":"Andrea"},{"name":"Andrea With no friends"}]}}`, 1203 js) 1204 } 1205 1206 func TestMinMultiAlias(t *testing.T) { 1207 1208 // Alright. Now we have everything set up. Let's create the query. 1209 query := ` 1210 { 1211 me(func: anyofterms(name, "michonne rick andrea")) { 1212 name 1213 friend { 1214 x as dob 1215 } 1216 mindob: min(val(x)) 1217 maxdob: max(val(x)) 1218 } 1219 } 1220 ` 1221 js := processQueryNoErr(t, query) 1222 require.JSONEq(t, 1223 `{"data": {"me":[{"friend":[{"dob":"1910-01-02T00:00:00Z"},{"dob":"1909-05-05T00:00:00Z"},{"dob":"1909-01-10T00:00:00Z"},{"dob":"1901-01-15T00:00:00Z"}],"maxdob":"1910-01-02T00:00:00Z","mindob":"1901-01-15T00:00:00Z","name":"Michonne"},{"friend":[{"dob":"1910-01-01T00:00:00Z"}],"maxdob":"1910-01-01T00:00:00Z","mindob":"1910-01-01T00:00:00Z","name":"Rick Grimes"},{"friend":[{"dob":"1909-05-05T00:00:00Z"}],"maxdob":"1909-05-05T00:00:00Z","mindob":"1909-05-05T00:00:00Z","name":"Andrea"},{"name":"Andrea With no friends"}]}}`, 1224 js) 1225 } 1226 1227 func TestMinSchema(t *testing.T) { 1228 1229 // Alright. Now we have everything set up. Let's create the query. 1230 query := ` 1231 { 1232 me(func: uid(0x01)) { 1233 name 1234 gender 1235 alive 1236 friend { 1237 x as survival_rate 1238 } 1239 min(val(x)) 1240 } 1241 } 1242 ` 1243 js := processQueryNoErr(t, query) 1244 require.JSONEq(t, 1245 `{"data": {"me":[{"name":"Michonne","gender":"female","alive":true,"friend":[{"survival_rate":1.600000},{"survival_rate":1.600000},{"survival_rate":1.600000},{"survival_rate":1.600000}],"min(val(x))":1.600000}]}}`, 1246 js) 1247 1248 setSchema(`survival_rate: int .`) 1249 1250 js = processQueryNoErr(t, query) 1251 require.JSONEq(t, 1252 `{"data": {"me":[{"name":"Michonne","gender":"female","alive":true,"friend":[{"survival_rate":1},{"survival_rate":1},{"survival_rate":1},{"survival_rate":1}],"min(val(x))":1}]}}`, 1253 js) 1254 setSchema(`survival_rate: float .`) 1255 } 1256 1257 func TestAvg(t *testing.T) { 1258 1259 query := ` 1260 { 1261 me(func: uid(0x01)) { 1262 name 1263 gender 1264 alive 1265 friend { 1266 x as shadow_deep 1267 } 1268 avg(val(x)) 1269 } 1270 } 1271 ` 1272 js := processQueryNoErr(t, query) 1273 require.JSONEq(t, 1274 `{"data": {"me":[{"alive":true,"avg(val(x))":9.000000,"friend":[{"shadow_deep":4},{"shadow_deep":14}],"gender":"female","name":"Michonne"}]}}`, 1275 js) 1276 } 1277 1278 func TestSum(t *testing.T) { 1279 1280 query := ` 1281 { 1282 me(func: uid(0x01)) { 1283 name 1284 gender 1285 alive 1286 friend { 1287 x as shadow_deep 1288 } 1289 sum(val(x)) 1290 } 1291 } 1292 ` 1293 js := processQueryNoErr(t, query) 1294 require.JSONEq(t, 1295 `{"data": {"me":[{"alive":true,"friend":[{"shadow_deep":4},{"shadow_deep":14}],"gender":"female","name":"Michonne","sum(val(x))":18}]}}`, 1296 js) 1297 } 1298 1299 func TestQueryPassword(t *testing.T) { 1300 1301 // Password is not fetchable 1302 query := ` 1303 { 1304 me(func: uid(0x01)) { 1305 name 1306 password 1307 } 1308 } 1309 ` 1310 js := processQueryNoErr(t, query) 1311 require.JSONEq(t, `{"data": {"me":[{"name":"Michonne"}]}}`, js) 1312 } 1313 1314 func TestPasswordExpandAll1(t *testing.T) { 1315 query := ` 1316 { 1317 me(func: uid(0x01)) { 1318 expand(_all_) 1319 } 1320 } 1321 ` 1322 js := processQueryNoErr(t, query) 1323 require.JSONEq(t, `{"data":{"me":[{"name":"Michonne"}]}}`, js) 1324 } 1325 1326 func TestPasswordExpandAll2(t *testing.T) { 1327 query := ` 1328 { 1329 me(func: uid(0x01)) { 1330 expand(_all_) 1331 checkpwd(password, "12345") 1332 } 1333 } 1334 ` 1335 js := processQueryNoErr(t, query) 1336 require.JSONEq(t, `{"data":{"me":[{"name":"Michonne", "checkpwd(password)":false}]}}`, js) 1337 } 1338 1339 func TestPasswordExpandError(t *testing.T) { 1340 query := ` 1341 { 1342 me(func: uid(0x01)) { 1343 expand(_all_) 1344 password 1345 } 1346 } 1347 ` 1348 1349 _, err := processQuery(context.Background(), t, query) 1350 require.Contains(t, err.Error(), "Repeated subgraph: [password]") 1351 } 1352 1353 func TestCheckPassword(t *testing.T) { 1354 query := ` 1355 { 1356 me(func: uid(0x01)) { 1357 name 1358 checkpwd(password, "123456") 1359 } 1360 } 1361 ` 1362 js := processQueryNoErr(t, query) 1363 require.JSONEq(t, `{"data": {"me":[{"name":"Michonne","checkpwd(password)":true}]}}`, js) 1364 } 1365 1366 func TestCheckPasswordIncorrect(t *testing.T) { 1367 query := ` 1368 { 1369 me(func: uid(0x01)) { 1370 name 1371 checkpwd(password, "654123") 1372 } 1373 } 1374 ` 1375 js := processQueryNoErr(t, query) 1376 require.JSONEq(t, `{"data": {"me":[{"name":"Michonne","checkpwd(password)":false}]}}`, js) 1377 } 1378 1379 // ensure, that old and deprecated form is not allowed 1380 func TestCheckPasswordParseError(t *testing.T) { 1381 query := ` 1382 { 1383 me(func: uid(0x01)) { 1384 name 1385 checkpwd("654123") 1386 } 1387 } 1388 ` 1389 _, err := processQuery(context.Background(), t, query) 1390 require.Error(t, err) 1391 } 1392 1393 func TestCheckPasswordDifferentAttr1(t *testing.T) { 1394 1395 query := ` 1396 { 1397 me(func: uid(23)) { 1398 name 1399 checkpwd(pass, "654321") 1400 } 1401 } 1402 ` 1403 js := processQueryNoErr(t, query) 1404 require.JSONEq(t, `{"data": {"me":[{"name":"Rick Grimes","checkpwd(pass)":true}]}}`, js) 1405 } 1406 1407 func TestCheckPasswordDifferentAttr2(t *testing.T) { 1408 1409 query := ` 1410 { 1411 me(func: uid(23)) { 1412 name 1413 checkpwd(pass, "invalid") 1414 } 1415 } 1416 ` 1417 js := processQueryNoErr(t, query) 1418 require.JSONEq(t, `{"data": {"me":[{"name":"Rick Grimes","checkpwd(pass)":false}]}}`, js) 1419 } 1420 1421 func TestCheckPasswordInvalidAttr(t *testing.T) { 1422 1423 query := ` 1424 { 1425 me(func: uid(0x1)) { 1426 name 1427 checkpwd(pass, "123456") 1428 } 1429 } 1430 ` 1431 js := processQueryNoErr(t, query) 1432 // for id:0x1 there is no pass attribute defined (there's only password attribute) 1433 require.JSONEq(t, `{"data": {"me":[{"name":"Michonne","checkpwd(pass)":false}]}}`, js) 1434 } 1435 1436 // test for old version of checkpwd with hardcoded attribute name 1437 func TestCheckPasswordQuery1(t *testing.T) { 1438 1439 query := ` 1440 { 1441 me(func: uid(0x1)) { 1442 name 1443 password 1444 } 1445 } 1446 ` 1447 js := processQueryNoErr(t, query) 1448 require.JSONEq(t, `{"data": {"me":[{"name":"Michonne"}]}}`, js) 1449 } 1450 1451 // test for improved version of checkpwd with custom attribute name 1452 func TestCheckPasswordQuery2(t *testing.T) { 1453 1454 query := ` 1455 { 1456 me(func: uid(23)) { 1457 name 1458 pass 1459 } 1460 } 1461 ` 1462 js := processQueryNoErr(t, query) 1463 require.JSONEq(t, `{"data": {"me":[{"name":"Rick Grimes"}]}}`, js) 1464 } 1465 1466 // test for improved version of checkpwd with alias for unknown attribute 1467 func TestCheckPasswordQuery3(t *testing.T) { 1468 1469 query := ` 1470 { 1471 me(func: uid(23)) { 1472 name 1473 secret: checkpwd(pass, "123456") 1474 } 1475 } 1476 ` 1477 js := processQueryNoErr(t, query) 1478 require.JSONEq(t, `{"data": {"me":[{"name":"Rick Grimes","secret":false}]}}`, js) 1479 } 1480 1481 // test for improved version of checkpwd with alias for known attribute 1482 func TestCheckPasswordQuery4(t *testing.T) { 1483 1484 query := ` 1485 { 1486 me(func: uid(0x01)) { 1487 name 1488 secreto: checkpwd(password, "123456") 1489 } 1490 } 1491 ` 1492 js := processQueryNoErr(t, query) 1493 require.JSONEq(t, `{"data": {"me":[{"name":"Michonne","secreto":true}]}}`, js) 1494 } 1495 1496 func TestToSubgraphInvalidFnName(t *testing.T) { 1497 query := ` 1498 { 1499 me(func:invalidfn1(name, "some cool name")) { 1500 name 1501 gender 1502 alive 1503 } 1504 } 1505 ` 1506 _, err := processQuery(context.Background(), t, query) 1507 require.Error(t, err) 1508 require.Contains(t, err.Error(), "Function name: invalidfn1 is not valid.") 1509 } 1510 1511 func TestToSubgraphInvalidFnName2(t *testing.T) { 1512 query := ` 1513 { 1514 me(func:anyofterms(name, "some cool name")) { 1515 name 1516 friend @filter(invalidfn2(name, "some name")) { 1517 name 1518 } 1519 } 1520 } 1521 ` 1522 _, err := processQuery(context.Background(), t, query) 1523 require.Error(t, err) 1524 } 1525 1526 func TestToSubgraphInvalidFnName3(t *testing.T) { 1527 query := ` 1528 { 1529 me(func:anyofterms(name, "some cool name")) { 1530 name 1531 friend @filter(anyofterms(name, "Andrea") or 1532 invalidfn3(name, "Andrea Rhee")){ 1533 name 1534 } 1535 } 1536 } 1537 ` 1538 _, err := processQuery(context.Background(), t, query) 1539 require.Error(t, err) 1540 } 1541 1542 func TestToSubgraphInvalidFnName4(t *testing.T) { 1543 query := ` 1544 { 1545 f as var(func:invalidfn4(name, "Michonne Rick Glenn")) { 1546 name 1547 } 1548 you(func:anyofterms(name, "Michonne")) { 1549 friend @filter(uid(f)) { 1550 name 1551 } 1552 } 1553 } 1554 ` 1555 _, err := processQuery(context.Background(), t, query) 1556 require.Error(t, err) 1557 require.Contains(t, err.Error(), "Function name: invalidfn4 is not valid.") 1558 } 1559 1560 func TestToSubgraphInvalidArgs1(t *testing.T) { 1561 query := ` 1562 { 1563 me(func: uid(0x01)) { 1564 name 1565 gender 1566 friend(disorderasc: dob) @filter(le(dob, "1909-03-20")) { 1567 name 1568 } 1569 } 1570 } 1571 ` 1572 _, err := processQuery(context.Background(), t, query) 1573 require.Error(t, err) 1574 require.Contains(t, err.Error(), "Got invalid keyword: disorderasc") 1575 } 1576 1577 func TestToSubgraphInvalidArgs2(t *testing.T) { 1578 query := ` 1579 { 1580 me(func: uid(0x01)) { 1581 name 1582 gender 1583 friend(offset:1, invalidorderasc:1) @filter(anyofterms(name, "Andrea")) { 1584 name 1585 } 1586 } 1587 } 1588 ` 1589 _, err := processQuery(context.Background(), t, query) 1590 require.Error(t, err) 1591 require.Contains(t, err.Error(), "Got invalid keyword: invalidorderasc") 1592 } 1593 1594 func TestToFastJSON(t *testing.T) { 1595 1596 // Alright. Now we have everything set up. Let's create the query. 1597 query := ` 1598 { 1599 me(func: uid(0x01)) { 1600 name 1601 gender 1602 alive 1603 friend { 1604 name 1605 } 1606 } 1607 } 1608 ` 1609 1610 js := processQueryNoErr(t, query) 1611 require.JSONEq(t, 1612 `{"data": {"me":[{"alive":true,"friend":[{"name":"Rick Grimes"},{"name":"Glenn Rhee"},{"name":"Daryl Dixon"},{"name":"Andrea"}],"gender":"female","name":"Michonne"}]}}`, 1613 js) 1614 } 1615 1616 func TestFieldAlias(t *testing.T) { 1617 1618 // Alright. Now we have everything set up. Let's create the query. 1619 query := ` 1620 { 1621 me(func: uid(0x01)) { 1622 MyName:name 1623 gender 1624 alive 1625 Buddies:friend { 1626 BudName:name 1627 } 1628 } 1629 } 1630 ` 1631 1632 js := processQueryNoErr(t, query) 1633 require.JSONEq(t, 1634 `{"data": {"me":[{"alive":true,"Buddies":[{"BudName":"Rick Grimes"},{"BudName":"Glenn Rhee"},{"BudName":"Daryl Dixon"},{"BudName":"Andrea"}],"gender":"female","MyName":"Michonne"}]}}`, 1635 js) 1636 } 1637 1638 func TestToFastJSONFilter(t *testing.T) { 1639 1640 query := ` 1641 { 1642 me(func: uid(0x01)) { 1643 name 1644 gender 1645 friend @filter(anyofterms(name, "Andrea SomethingElse")) { 1646 name 1647 } 1648 } 1649 } 1650 ` 1651 1652 js := processQueryNoErr(t, query) 1653 require.JSONEq(t, 1654 `{"data": {"me":[{"name":"Michonne","gender":"female","friend":[{"name":"Andrea"}]}]}}`, 1655 js) 1656 } 1657 1658 func TestToFastJSONFilterMissBrac(t *testing.T) { 1659 1660 query := ` 1661 { 1662 me(func: uid(0x01)) { 1663 name 1664 gender 1665 friend @filter(anyofterms(name, "Andrea SomethingElse") { 1666 name 1667 } 1668 } 1669 } 1670 ` 1671 _, err := processQuery(context.Background(), t, query) 1672 require.Error(t, err) 1673 } 1674 1675 func TestToFastJSONFilterallofterms(t *testing.T) { 1676 1677 query := ` 1678 { 1679 me(func: uid(0x01)) { 1680 name 1681 gender 1682 friend @filter(allofterms(name, "Andrea SomethingElse")) { 1683 name 1684 } 1685 } 1686 } 1687 ` 1688 1689 js := processQueryNoErr(t, query) 1690 require.JSONEq(t, 1691 `{"data": {"me":[{"name":"Michonne","gender":"female"}]}}`, js) 1692 } 1693 1694 func TestInvalidStringIndex(t *testing.T) { 1695 // no FTS index defined for name 1696 1697 query := ` 1698 { 1699 me(func: uid(0x01)) { 1700 name 1701 gender 1702 friend @filter(alloftext(name, "Andrea SomethingElse")) { 1703 name 1704 } 1705 } 1706 } 1707 ` 1708 1709 _, err := processQuery(context.Background(), t, query) 1710 require.Error(t, err) 1711 } 1712 1713 func TestValidFullTextIndex(t *testing.T) { 1714 // no FTS index defined for name 1715 1716 query := ` 1717 { 1718 me(func: uid(0x01)) { 1719 name 1720 friend @filter(alloftext(alias, "BOB")) { 1721 alias 1722 } 1723 } 1724 } 1725 ` 1726 1727 js := processQueryNoErr(t, query) 1728 require.JSONEq(t, 1729 `{"data": {"me":[{"name":"Michonne", "friend":[{"alias":"Bob Joe"}]}]}}`, js) 1730 } 1731 1732 // dob (date of birth) is not a string 1733 func TestFilterRegexError(t *testing.T) { 1734 1735 query := ` 1736 { 1737 me(func: uid(0x01)) { 1738 name 1739 friend @filter(regexp(dob, /^[a-z A-Z]+$/)) { 1740 name 1741 } 1742 } 1743 } 1744 ` 1745 1746 _, err := processQuery(context.Background(), t, query) 1747 require.Error(t, err) 1748 } 1749 1750 func TestFilterRegex1(t *testing.T) { 1751 1752 query := ` 1753 { 1754 me(func: uid(0x01)) { 1755 name 1756 friend @filter(regexp(name, /^[Glen Rh]+$/)) { 1757 name 1758 } 1759 } 1760 } 1761 ` 1762 1763 js := processQueryNoErr(t, query) 1764 require.JSONEq(t, 1765 `{"data": {"me":[{"name":"Michonne", "friend":[{"name":"Glenn Rhee"}]}]}}`, js) 1766 } 1767 1768 func TestFilterRegex2(t *testing.T) { 1769 1770 query := ` 1771 { 1772 me(func: uid(0x01)) { 1773 name 1774 friend @filter(regexp(name, /^[^ao]+$/)) { 1775 name 1776 } 1777 } 1778 } 1779 ` 1780 1781 js := processQueryNoErr(t, query) 1782 require.JSONEq(t, 1783 `{"data": {"me":[{"name":"Michonne", "friend":[{"name":"Rick Grimes"},{"name":"Glenn Rhee"}]}]}}`, js) 1784 } 1785 1786 func TestFilterRegex3(t *testing.T) { 1787 1788 query := ` 1789 { 1790 me(func: uid(0x01)) { 1791 name 1792 friend @filter(regexp(name, /^Rick/)) { 1793 name 1794 } 1795 } 1796 } 1797 ` 1798 1799 js := processQueryNoErr(t, query) 1800 require.JSONEq(t, 1801 `{"data": {"me":[{"name":"Michonne", "friend":[{"name":"Rick Grimes"}]}]}}`, js) 1802 } 1803 1804 func TestFilterRegex4(t *testing.T) { 1805 1806 query := ` 1807 { 1808 me(func: uid(0x01)) { 1809 name 1810 friend @filter(regexp(name, /((en)|(xo))n/)) { 1811 name 1812 } 1813 } 1814 } 1815 ` 1816 1817 js := processQueryNoErr(t, query) 1818 require.JSONEq(t, 1819 `{"data": {"me":[{"name":"Michonne", "friend":[{"name":"Glenn Rhee"},{"name":"Daryl Dixon"} ]}]}}`, js) 1820 } 1821 1822 func TestFilterRegex5(t *testing.T) { 1823 1824 query := ` 1825 { 1826 me(func: uid(0x01)) { 1827 name 1828 friend @filter(regexp(name, /^[a-zA-z]*[^Kk ]?[Nn]ight/)) { 1829 name 1830 } 1831 } 1832 } 1833 ` 1834 1835 js := processQueryNoErr(t, query) 1836 require.JSONEq(t, 1837 `{"data": {"me":[{"name":"Michonne"}]}}`, js) 1838 } 1839 1840 func TestFilterRegex6(t *testing.T) { 1841 query := ` 1842 { 1843 me(func: uid(0x1234)) { 1844 pattern @filter(regexp(value, /miss((issippi)|(ouri))/)) { 1845 value 1846 } 1847 } 1848 } 1849 ` 1850 1851 js := processQueryNoErr(t, query) 1852 require.JSONEq(t, 1853 `{"data": {"me":[{"pattern":[{"value":"mississippi"}, {"value":"missouri"}]}]}}`, js) 1854 } 1855 1856 func TestFilterRegex7(t *testing.T) { 1857 1858 query := ` 1859 { 1860 me(func: uid(0x1234)) { 1861 pattern @filter(regexp(value, /[aeiou]mission/)) { 1862 value 1863 } 1864 } 1865 } 1866 ` 1867 1868 js := processQueryNoErr(t, query) 1869 require.JSONEq(t, 1870 `{"data": {"me":[{"pattern":[{"value":"omission"}, {"value":"dimission"}]}]}}`, js) 1871 } 1872 1873 func TestFilterRegex8(t *testing.T) { 1874 1875 query := ` 1876 { 1877 me(func: uid(0x1234)) { 1878 pattern @filter(regexp(value, /^(trans)?mission/)) { 1879 value 1880 } 1881 } 1882 } 1883 ` 1884 1885 js := processQueryNoErr(t, query) 1886 require.JSONEq(t, 1887 `{"data": {"me":[{"pattern":[{"value":"mission"}, {"value":"missionary"}, {"value":"transmission"}]}]}}`, js) 1888 } 1889 1890 func TestFilterRegex9(t *testing.T) { 1891 1892 query := ` 1893 { 1894 me(func: uid(0x1234)) { 1895 pattern @filter(regexp(value, /s.{2,5}mission/)) { 1896 value 1897 } 1898 } 1899 } 1900 ` 1901 1902 js := processQueryNoErr(t, query) 1903 require.JSONEq(t, 1904 `{"data": {"me":[{"pattern":[{"value":"submission"}, {"value":"subcommission"}, {"value":"discommission"}]}]}}`, js) 1905 } 1906 1907 func TestFilterRegex10(t *testing.T) { 1908 1909 query := ` 1910 { 1911 me(func: uid(0x1234)) { 1912 pattern @filter(regexp(value, /[^m]iss/)) { 1913 value 1914 } 1915 } 1916 } 1917 ` 1918 1919 js := processQueryNoErr(t, query) 1920 require.JSONEq(t, 1921 `{"data": {"me":[{"pattern":[{"value":"mississippi"}, {"value":"whissle"}]}]}}`, js) 1922 } 1923 1924 func TestFilterRegex11(t *testing.T) { 1925 1926 query := ` 1927 { 1928 me(func: uid(0x1234)) { 1929 pattern @filter(regexp(value, /SUB[cm]/i)) { 1930 value 1931 } 1932 } 1933 } 1934 ` 1935 1936 js := processQueryNoErr(t, query) 1937 require.JSONEq(t, 1938 `{"data": {"me":[{"pattern":[{"value":"submission"}, {"value":"subcommission"}]}]}}`, js) 1939 } 1940 1941 // case insensitive mode may be turned on with modifier: 1942 // http://www.regular-expressions.info/modifiers.html - this is completely legal 1943 func TestFilterRegex12(t *testing.T) { 1944 1945 query := ` 1946 { 1947 me(func: uid(0x1234)) { 1948 pattern @filter(regexp(value, /(?i)SUB[cm]/)) { 1949 value 1950 } 1951 } 1952 } 1953 ` 1954 1955 js := processQueryNoErr(t, query) 1956 require.JSONEq(t, 1957 `{"data": {"me":[{"pattern":[{"value":"submission"}, {"value":"subcommission"}]}]}}`, js) 1958 } 1959 1960 // case insensitive mode may be turned on and off with modifier: 1961 // http://www.regular-expressions.info/modifiers.html - this is completely legal 1962 func TestFilterRegex13(t *testing.T) { 1963 1964 query := ` 1965 { 1966 me(func: uid(0x1234)) { 1967 pattern @filter(regexp(value, /(?i)SUB[cm](?-i)ISSION/)) { 1968 value 1969 } 1970 } 1971 } 1972 ` 1973 1974 // no results are returned, becaues case insensive mode is turned off before 'ISSION' 1975 js := processQueryNoErr(t, query) 1976 require.JSONEq(t, `{"data": {"me": []}}`, js) 1977 } 1978 1979 // invalid regexp modifier 1980 func TestFilterRegex14(t *testing.T) { 1981 1982 query := ` 1983 { 1984 me(func: uid(0x1234)) { 1985 pattern @filter(regexp(value, /pattern/x)) { 1986 value 1987 } 1988 } 1989 } 1990 ` 1991 1992 _, err := processQuery(context.Background(), t, query) 1993 require.Error(t, err) 1994 } 1995 1996 // multi-lang - simple 1997 func TestFilterRegex15(t *testing.T) { 1998 1999 query := ` 2000 { 2001 me(func:regexp(name@ru, /Барсук/)) { 2002 name@ru 2003 } 2004 } 2005 ` 2006 js := processQueryNoErr(t, query) 2007 require.JSONEq(t, 2008 `{"data": {"me":[{"name@ru":"Барсук"}]}}`, 2009 js) 2010 } 2011 2012 // multi-lang - test for bug (#945) - multi-byte runes 2013 func TestFilterRegex16(t *testing.T) { 2014 2015 query := ` 2016 { 2017 me(func:regexp(name@ru, /^артём/i)) { 2018 name@ru 2019 } 2020 } 2021 ` 2022 js := processQueryNoErr(t, query) 2023 require.JSONEq(t, 2024 `{"data": {"me":[{"name@ru":"Артём Ткаченко"}]}}`, 2025 js) 2026 } 2027 2028 func TestFilterRegex17(t *testing.T) { 2029 query := ` 2030 { 2031 me(func:regexp(name, "")) { 2032 name 2033 } 2034 } 2035 ` 2036 _, err := processQuery(context.Background(), t, query) 2037 require.Error(t, err) 2038 require.Contains(t, err.Error(), "Function 'regexp' requires 2 arguments,") 2039 } 2040 2041 func TestTypeFunction(t *testing.T) { 2042 query := ` 2043 { 2044 me(func: type(Person)) { 2045 uid 2046 } 2047 } 2048 ` 2049 js := processQueryNoErr(t, query) 2050 require.JSONEq(t, 2051 `{"data": {"me":[{"uid":"0x2"}, {"uid":"0x3"}, {"uid":"0x4"}]}}`, 2052 js) 2053 } 2054 2055 func TestTypeFunctionUnknownType(t *testing.T) { 2056 query := ` 2057 { 2058 me(func: type(UnknownType)) { 2059 uid 2060 } 2061 } 2062 ` 2063 js := processQueryNoErr(t, query) 2064 require.JSONEq(t, `{"data": {"me":[]}}`, js) 2065 } 2066 2067 func TestTypeFilter(t *testing.T) { 2068 query := ` 2069 { 2070 me(func: uid(0x2)) @filter(type(Person)) { 2071 uid 2072 } 2073 } 2074 ` 2075 js := processQueryNoErr(t, query) 2076 require.JSONEq(t, 2077 `{"data": {"me":[{"uid" :"0x2"}]}}`, 2078 js) 2079 } 2080 2081 func TestTypeFilterUnknownType(t *testing.T) { 2082 query := ` 2083 { 2084 me(func: uid(0x2)) @filter(type(UnknownType)) { 2085 uid 2086 } 2087 } 2088 ` 2089 js := processQueryNoErr(t, query) 2090 require.JSONEq(t, `{"data": {"me":[]}}`, js) 2091 } 2092 2093 func TestTypeDirectiveInPredicate(t *testing.T) { 2094 query := ` 2095 { 2096 me(func: uid(0x2)) { 2097 enemy @type(Person) { 2098 name 2099 } 2100 } 2101 } 2102 ` 2103 js := processQueryNoErr(t, query) 2104 require.JSONEq(t, `{"data": {"me":[{"enemy":[{"name":"Margaret"}, {"name":"Leonard"}]}]}}`, js) 2105 } 2106 2107 func TestMultipleTypeDirectivesInPredicate(t *testing.T) { 2108 query := ` 2109 { 2110 me(func: uid(0x2)) { 2111 enemy @type(Person) { 2112 name 2113 pet @type(Animal) { 2114 name 2115 } 2116 } 2117 } 2118 } 2119 ` 2120 js := processQueryNoErr(t, query) 2121 require.JSONEq(t, `{"data": {"me":[{"enemy":[{"name":"Margaret", "pet":[{"name":"Bear"}]}, {"name":"Leonard"}]}]}}`, js) 2122 } 2123 2124 func TestMaxPredicateSize(t *testing.T) { 2125 // Create a string that has more than than 2^16 chars. 2126 var b strings.Builder 2127 for i := 0; i < 10000; i++ { 2128 b.WriteString("abcdefg") 2129 } 2130 largePred := b.String() 2131 2132 query := fmt.Sprintf(` 2133 { 2134 me(func: uid(0x2)) { 2135 %s { 2136 name 2137 } 2138 } 2139 } 2140 `, largePred) 2141 2142 _, err := processQuery(context.Background(), t, query) 2143 require.Error(t, err) 2144 require.Contains(t, err.Error(), "Predicate name length cannot be bigger than 2^16") 2145 } 2146 2147 func TestQueryUnknownType(t *testing.T) { 2148 query := `schema(type: UnknownType) {}` 2149 js := processQueryNoErr(t, query) 2150 require.JSONEq(t, `{"data": {}}`, js) 2151 } 2152 2153 func TestQuerySingleType(t *testing.T) { 2154 query := `schema(type: Person) {}` 2155 js := processQueryNoErr(t, query) 2156 require.JSONEq(t, `{"data": {"types":[{"name":"Person", 2157 "fields":[{"name":"name", "type":"string"}, {"name":"pet", "type":"Animal"}]}]}}`, 2158 js) 2159 } 2160 2161 func TestQueryMultipleTypes(t *testing.T) { 2162 query := `schema(type: [Person, Animal]) {}` 2163 js := processQueryNoErr(t, query) 2164 require.JSONEq(t, `{"data": {"types":[{"name":"Animal", 2165 "fields":[{"name":"name", "type":"string"}]}, 2166 {"name":"Person", "fields":[{"name":"name", "type": "string"}, 2167 {"name":"pet", "type":"Animal"}]}]}}`, js) 2168 }