github.com/ravendb/ravendb-go-client@v0.0.0-20240229102137-4474ee7aa0fa/abstract_document_query.go (about) 1 package ravendb 2 3 import ( 4 "reflect" 5 "strconv" 6 "strings" 7 "time" 8 ) 9 10 // Note: Java's IAbstractDocumentQuery is abstractDocumentQuery 11 12 type abstractDocumentQuery struct { 13 aliasToGroupByFieldName map[string]string 14 defaultOperator QueryOperator 15 16 // Note: rootTypes is not used in Go because we only have one ID property 17 18 negate bool 19 indexName string 20 collectionName string 21 currentClauseDepth int 22 queryRaw string 23 queryParameters Parameters 24 25 isIntersect bool 26 isGroupBy bool 27 28 theSession *InMemoryDocumentSessionOperations 29 30 pageSize *int 31 32 selectTokens []queryToken 33 fromToken *fromToken 34 declareToken *declareToken 35 loadTokens []*loadToken 36 fieldsToFetchToken *fieldsToFetchToken 37 38 whereTokens []queryToken 39 groupByTokens []queryToken 40 orderByTokens []queryToken 41 42 start int 43 conventions *DocumentConventions 44 45 timeout time.Duration 46 47 theWaitForNonStaleResults bool 48 49 includes []string 50 51 queryStats *QueryStatistics 52 53 disableEntitiesTracking bool 54 55 disableCaching bool 56 57 isInMoreLikeThis bool 58 59 // Go doesn't allow comparing functions so to remove we use index returned 60 // by add() function. We maintain stable index by never shrinking 61 // callback arrays. We assume there is no high churn of adding/removing 62 // callbacks 63 beforeQueryExecutedCallback []func(*IndexQuery) 64 afterQueryExecutedCallback []func(*QueryResult) 65 afterStreamExecutedCallback []func(map[string]interface{}) 66 67 queryOperation *queryOperation 68 69 // to allow "fluid" API, in many methods instead of returning an error, we 70 // remember it here and return in GetResults() 71 err error 72 } 73 74 func (q *abstractDocumentQuery) Err() error { 75 return q.err 76 } 77 78 func (q *abstractDocumentQuery) isDistinct() bool { 79 if len(q.selectTokens) == 0 { 80 return false 81 } 82 _, ok := q.selectTokens[0].(*distinctToken) 83 return ok 84 } 85 86 func (q *abstractDocumentQuery) getSession() *InMemoryDocumentSessionOperations { 87 return q.theSession 88 } 89 90 func (q *abstractDocumentQuery) isDynamicMapReduce() bool { 91 return len(q.groupByTokens) > 0 92 } 93 94 func getQueryDefaultTimeout() time.Duration { 95 return time.Second * 15 96 } 97 98 // at this point we assume all 99 func newAbstractDocumentQuery(opts *DocumentQueryOptions) *abstractDocumentQuery { 100 res := &abstractDocumentQuery{ 101 defaultOperator: QueryOperatorAnd, 102 isGroupBy: opts.isGroupBy, 103 indexName: opts.IndexName, 104 collectionName: opts.CollectionName, 105 declareToken: opts.declareToken, 106 loadTokens: opts.loadTokens, 107 theSession: opts.session, 108 aliasToGroupByFieldName: make(map[string]string), 109 queryParameters: make(map[string]interface{}), 110 queryStats: NewQueryStatistics(), 111 queryRaw: opts.rawQuery, 112 } 113 114 if opts.session == nil { 115 res.err = newIllegalArgumentError("session must be provided") 116 return res 117 } 118 119 if res.queryRaw == "" { 120 if opts.IndexName == "" && opts.CollectionName == "" { 121 res.err = newIllegalArgumentError("Either indexName or collectionName must be specified") 122 return res 123 } 124 res.fromToken = createFromToken(opts.IndexName, opts.CollectionName, opts.fromAlias) 125 } 126 127 f := func(queryResult *QueryResult) { 128 res.updateStatsAndHighlightings(queryResult) 129 } 130 res.addAfterQueryExecutedListener(f) 131 if opts.session == nil { 132 res.conventions = NewDocumentConventions() 133 } else { 134 res.conventions = opts.session.GetConventions() 135 } 136 return res 137 } 138 139 func (q *abstractDocumentQuery) usingDefaultOperator(operator QueryOperator) error { 140 if len(q.whereTokens) > 0 { 141 return newIllegalStateError("Default operator can only be set before any where clause is added.") 142 } 143 144 q.defaultOperator = operator 145 return nil 146 } 147 148 func (q *abstractDocumentQuery) waitForNonStaleResults(waitTimeout time.Duration) { 149 q.theWaitForNonStaleResults = true 150 if waitTimeout == 0 { 151 waitTimeout = getQueryDefaultTimeout() 152 } 153 q.timeout = waitTimeout 154 } 155 156 func (q *abstractDocumentQuery) initializeQueryOperation() (*queryOperation, error) { 157 indexQuery, err := q.GetIndexQuery() 158 if err != nil { 159 return nil, err 160 } 161 162 return newQueryOperation(q.theSession, q.indexName, indexQuery, q.fieldsToFetchToken, q.disableEntitiesTracking, false, false) 163 } 164 165 func (q *abstractDocumentQuery) GetIndexQuery() (*IndexQuery, error) { 166 query, err := q.string() 167 if err != nil { 168 return nil, err 169 } 170 indexQuery := q.generateIndexQuery(query) 171 q.invokeBeforeQueryExecuted(indexQuery) 172 return indexQuery, nil 173 } 174 175 func (q *abstractDocumentQuery) getProjectionFields() []string { 176 177 if q.fieldsToFetchToken != nil && q.fieldsToFetchToken.projections != nil { 178 return q.fieldsToFetchToken.projections 179 } 180 return nil 181 } 182 183 func (q *abstractDocumentQuery) randomOrdering() error { 184 if err := q.assertNoRawQuery(); err != nil { 185 return err 186 } 187 188 q.noCaching() 189 q.orderByTokens = append(q.orderByTokens, orderByTokenRandom) 190 return nil 191 } 192 193 func (q *abstractDocumentQuery) randomOrderingWithSeed(seed string) error { 194 err := q.assertNoRawQuery() 195 if err != nil { 196 return err 197 } 198 199 if stringIsBlank(seed) { 200 err = q.randomOrdering() 201 if err != nil { 202 return err 203 } 204 return nil 205 } 206 207 q.noCaching() 208 q.orderByTokens = append(q.orderByTokens, orderByTokenCreateRandom(seed)) 209 return nil 210 } 211 212 func (q *abstractDocumentQuery) addGroupByAlias(fieldName string, projectedName string) { 213 q.aliasToGroupByFieldName[projectedName] = fieldName 214 } 215 216 func (q *abstractDocumentQuery) assertNoRawQuery() error { 217 if q.queryRaw != "" { 218 return newIllegalStateError("RawQuery was called, cannot modify this query by calling on operations that would modify the query (such as Where, Select, OrderBy, GroupBy, etc)") 219 } 220 return nil 221 } 222 223 func (q *abstractDocumentQuery) addParameter(name string, value interface{}) error { 224 name = strings.TrimPrefix(name, "$") 225 if _, ok := q.queryParameters[name]; ok { 226 return newIllegalStateError("The parameter " + name + " was already added") 227 } 228 229 q.queryParameters[name] = value 230 return nil 231 } 232 233 func (q *abstractDocumentQuery) groupBy(fieldName string, fieldNames ...string) error { 234 var mapping []*GroupBy 235 for _, x := range fieldNames { 236 el := NewGroupByField(x) 237 mapping = append(mapping, el) 238 } 239 return q.groupByFieldWithMethod(NewGroupByField(fieldName), mapping...) 240 } 241 242 func (q *abstractDocumentQuery) groupByFieldWithMethod(field *GroupBy, fields ...*GroupBy) error { 243 // TODO: if q.fromToken is nil, needs to do this check in ToList() 244 if q.fromToken != nil && !q.fromToken.isDynamic { 245 return newIllegalStateError("groupBy only works with dynamic queries") 246 } 247 248 if err := q.assertNoRawQuery(); err != nil { 249 return err 250 } 251 q.isGroupBy = true 252 253 fieldName, err := q.ensureValidFieldName(field.Field, false) 254 if err != nil { 255 return err 256 } 257 258 q.groupByTokens = append(q.groupByTokens, createGroupByToken(fieldName, field.Method)) 259 260 if len(fields) == 0 { 261 return nil 262 } 263 264 for _, item := range fields { 265 fieldName, err = q.ensureValidFieldName(item.Field, false) 266 if err != nil { 267 return err 268 } 269 q.groupByTokens = append(q.groupByTokens, createGroupByToken(fieldName, item.Method)) 270 } 271 return nil 272 } 273 274 func (q *abstractDocumentQuery) groupByKey(fieldName string, projectedName string) error { 275 if err := q.assertNoRawQuery(); err != nil { 276 return err 277 } 278 q.isGroupBy = true 279 280 _, hasProjectedName := q.aliasToGroupByFieldName[projectedName] 281 _, hasFieldName := q.aliasToGroupByFieldName[fieldName] 282 283 if projectedName != "" && hasProjectedName { 284 aliasedFieldName := q.aliasToGroupByFieldName[projectedName] 285 if fieldName == "" || strings.EqualFold(fieldName, projectedName) { 286 fieldName = aliasedFieldName 287 } 288 } else if fieldName != "" && hasFieldName { 289 aliasedFieldName := q.aliasToGroupByFieldName[fieldName] 290 fieldName = aliasedFieldName 291 } 292 293 q.selectTokens = append(q.selectTokens, createGroupByKeyToken(fieldName, projectedName)) 294 return nil 295 } 296 297 // projectedName is optional 298 func (q *abstractDocumentQuery) groupBySum(fieldName string, projectedName string) error { 299 if err := q.assertNoRawQuery(); err != nil { 300 return err 301 } 302 q.isGroupBy = true 303 304 var err error 305 fieldName, err = q.ensureValidFieldName(fieldName, false) 306 if err != nil { 307 return err 308 } 309 q.selectTokens = append(q.selectTokens, createGroupBySumToken(fieldName, projectedName)) 310 return nil 311 } 312 313 // projectedName is optional 314 func (q *abstractDocumentQuery) groupByCount(projectedName string) error { 315 if err := q.assertNoRawQuery(); err != nil { 316 return err 317 } 318 q.isGroupBy = true 319 320 t := &groupByCountToken{ 321 fieldName: projectedName, 322 } 323 q.selectTokens = append(q.selectTokens, t) 324 return nil 325 } 326 327 func (q *abstractDocumentQuery) whereTrue() error { 328 tokensRef, err := q.getCurrentWhereTokensRef() 329 if err != nil { 330 return err 331 } 332 err = q.appendOperatorIfNeeded(tokensRef) 333 if err != nil { 334 return err 335 } 336 err = q.negateIfNeeded(tokensRef, "") 337 if err != nil { 338 return err 339 } 340 341 tokens := *tokensRef 342 tokens = append(tokens, trueTokenInstance) 343 *tokensRef = tokens 344 return nil 345 } 346 347 func (q *abstractDocumentQuery) moreLikeThis() (*moreLikeThisScope, error) { 348 err := q.appendOperatorIfNeeded(&q.whereTokens) 349 if err != nil { 350 return nil, err 351 } 352 353 token := newMoreLikeThisToken() 354 q.whereTokens = append(q.whereTokens, token) 355 356 q.isInMoreLikeThis = true 357 add := func(o interface{}) string { 358 return q.addQueryParameter(o) 359 } 360 onDispose := func() { 361 q.isInMoreLikeThis = false 362 } 363 return newMoreLikeThisScope(token, add, onDispose), nil 364 } 365 366 func (q *abstractDocumentQuery) include(path string) { 367 q.includes = append(q.includes, path) 368 } 369 370 func (q *abstractDocumentQuery) take(count int) { 371 q.pageSize = &count 372 } 373 374 func (q *abstractDocumentQuery) skip(count int) { 375 q.start = count 376 } 377 378 func (q *abstractDocumentQuery) whereLucene(fieldName string, whereClause string) error { 379 var err error 380 fieldName, err = q.ensureValidFieldName(fieldName, false) 381 if err != nil { 382 return err 383 } 384 tokensRef, err := q.getCurrentWhereTokensRef() 385 if err != nil { 386 return err 387 } 388 tokens := *tokensRef 389 err = q.appendOperatorIfNeeded(tokensRef) 390 if err != nil { 391 return err 392 } 393 err = q.negateIfNeeded(tokensRef, fieldName) 394 if err != nil { 395 return err 396 } 397 398 whereToken := createWhereTokenWithOptions(whereOperatorLucene, fieldName, q.addQueryParameter(whereClause), nil) 399 tokens = append(tokens, whereToken) 400 *tokensRef = tokens 401 return nil 402 } 403 404 func (q *abstractDocumentQuery) openSubclause() error { 405 q.currentClauseDepth++ 406 407 tokensRef, err := q.getCurrentWhereTokensRef() 408 if err != nil { 409 return err 410 } 411 err = q.appendOperatorIfNeeded(tokensRef) 412 if err != nil { 413 return err 414 } 415 err = q.negateIfNeeded(tokensRef, "") 416 if err != nil { 417 return err 418 } 419 420 tokens := *tokensRef 421 tokens = append(tokens, openSubclauseTokenInstance) 422 *tokensRef = tokens 423 return nil 424 } 425 426 func (q *abstractDocumentQuery) closeSubclause() error { 427 q.currentClauseDepth-- 428 429 tokensRef, err := q.getCurrentWhereTokensRef() 430 if err != nil { 431 return err 432 } 433 tokens := *tokensRef 434 tokens = append(tokens, closeSubclauseTokenInstance) 435 *tokensRef = tokens 436 return nil 437 } 438 439 func (q *abstractDocumentQuery) where(fieldName string, op string, value interface{}) error { 440 op = strings.TrimSpace(op) 441 switch op { 442 case "=", "==": 443 return q.whereEquals(fieldName, value) 444 case "!=": 445 return q.whereNotEquals(fieldName, value) 446 case "<": 447 return q.whereLessThan(fieldName, value) 448 case "<=": 449 return q.whereLessThanOrEqual(fieldName, value) 450 case ">": 451 return q.whereGreaterThan(fieldName, value) 452 case ">=": 453 return q.whereGreaterThanOrEqual(fieldName, value) 454 default: 455 return newIllegalArgumentError("'%s' is not a valid op", op) 456 } 457 } 458 459 func (q *abstractDocumentQuery) whereEquals(fieldName string, value interface{}) error { 460 params := &whereParams{ 461 fieldName: fieldName, 462 value: value, 463 } 464 return q.whereEqualsWithParams(params) 465 } 466 467 func (q *abstractDocumentQuery) whereEqualsWithMethodCall(fieldName string, method MethodCall) error { 468 return q.whereEquals(fieldName, method) 469 } 470 471 func (q *abstractDocumentQuery) whereEqualsWithParams(whereParams *whereParams) error { 472 if q.negate { 473 q.negate = false 474 return q.whereNotEqualsWithParams(whereParams) 475 } 476 477 var err error 478 whereParams.fieldName, err = q.ensureValidFieldName(whereParams.fieldName, whereParams.isNestedPath) 479 if err != nil { 480 return err 481 } 482 483 tokensRef, err := q.getCurrentWhereTokensRef() 484 if err != nil { 485 return err 486 } 487 err = q.appendOperatorIfNeeded(tokensRef) 488 if err != nil { 489 return err 490 } 491 492 if q.ifValueIsMethod(whereOperatorEquals, whereParams, tokensRef) { 493 return nil 494 } 495 496 transformToEqualValue := q.transformValue(whereParams) 497 addQueryParameter := q.addQueryParameter(transformToEqualValue) 498 whereToken := createWhereTokenWithOptions(whereOperatorEquals, whereParams.fieldName, addQueryParameter, newWhereOptionsWithExact(whereParams.isExact)) 499 500 tokens := *tokensRef 501 tokens = append(tokens, whereToken) 502 *tokensRef = tokens 503 return nil 504 } 505 506 func (q *abstractDocumentQuery) ifValueIsMethod(op whereOperator, whereParams *whereParams, tokensRef *[]queryToken) bool { 507 if mc, ok := whereParams.value.(*CmpXchg); ok { 508 n := len(mc.args) 509 args := make([]string, n) 510 for i := 0; i < n; i++ { 511 args[i] = q.addQueryParameter(mc.args[i]) 512 } 513 514 opts := newWhereOptionsWithMethod(MethodsTypeCmpXChg, args, mc.accessPath, whereParams.isExact) 515 token := createWhereTokenWithOptions(op, whereParams.fieldName, "", opts) 516 517 tokens := *tokensRef 518 tokens = append(tokens, token) 519 *tokensRef = tokens 520 return true 521 } 522 523 // add more if there are more types that "derive" from MethodCall 524 // (by embedding MethodCallData) 525 526 return false 527 } 528 529 func (q *abstractDocumentQuery) whereNotEquals(fieldName string, value interface{}) error { 530 params := &whereParams{ 531 fieldName: fieldName, 532 value: value, 533 } 534 535 return q.whereNotEqualsWithParams(params) 536 } 537 538 func (q *abstractDocumentQuery) whereNotEqualsWithMethod(fieldName string, method MethodCall) error { 539 return q.whereNotEquals(fieldName, method) 540 } 541 542 func (q *abstractDocumentQuery) whereNotEqualsWithParams(whereParams *whereParams) error { 543 if q.negate { 544 q.negate = false 545 return q.whereEqualsWithParams(whereParams) 546 } 547 548 transformToEqualValue := q.transformValue(whereParams) 549 550 tokensRef, err := q.getCurrentWhereTokensRef() 551 if err != nil { 552 return err 553 } 554 err = q.appendOperatorIfNeeded(tokensRef) 555 if err != nil { 556 return err 557 } 558 559 whereParams.fieldName, err = q.ensureValidFieldName(whereParams.fieldName, whereParams.isNestedPath) 560 if err != nil { 561 return err 562 } 563 564 if q.ifValueIsMethod(whereOperatorNotEquals, whereParams, tokensRef) { 565 return nil 566 } 567 568 whereToken := createWhereTokenWithOptions(whereOperatorNotEquals, whereParams.fieldName, q.addQueryParameter(transformToEqualValue), newWhereOptionsWithExact(whereParams.isExact)) 569 tokens := *tokensRef 570 tokens = append(tokens, whereToken) 571 *tokensRef = tokens 572 return nil 573 } 574 575 func (q *abstractDocumentQuery) negateNext() { 576 q.negate = !q.negate 577 } 578 579 // mark last created token as exact. only applies to select number of tokens. 580 // it allows fluid APIs like .Where().Exact() 581 // will panic if last token wasn't of compatible type as that is considered 582 // invalid use of API and returning an error would break fluid API 583 func (q *abstractDocumentQuery) markLastTokenExact() error { 584 tokensRef, err := q.getCurrentWhereTokensRef() 585 if err != nil { 586 return err 587 } 588 tokens := *tokensRef 589 n := len(tokens) 590 lastToken := tokens[n-1] 591 switch tok := lastToken.(type) { 592 case *whereToken: 593 if tok.options == nil { 594 tok.options = newWhereOptionsWithExact(true) 595 } else { 596 tok.options.exact = true 597 } 598 default: 599 return newIllegalStateError("expected whereToken, got %T", lastToken) 600 } 601 602 *tokensRef = tokens 603 return nil 604 } 605 606 func (q *abstractDocumentQuery) whereIn(fieldName string, values []interface{}) error { 607 var err error 608 fieldName, err = q.ensureValidFieldName(fieldName, false) 609 if err != nil { 610 return err 611 } 612 613 tokensRef, err := q.getCurrentWhereTokensRef() 614 if err != nil { 615 return err 616 } 617 err = q.appendOperatorIfNeeded(tokensRef) 618 if err != nil { 619 return err 620 } 621 err = q.negateIfNeeded(tokensRef, fieldName) 622 if err != nil { 623 return err 624 } 625 626 whereToken := createWhereToken(whereOperatorIn, fieldName, q.addQueryParameter(q.transformCollection(fieldName, abstractDocumentQueryUnpackCollection(values)))) 627 628 tokens := *tokensRef 629 tokens = append(tokens, whereToken) 630 *tokensRef = tokens 631 return nil 632 } 633 634 func (q *abstractDocumentQuery) whereStartsWith(fieldName string, value interface{}) error { 635 whereParams := &whereParams{ 636 fieldName: fieldName, 637 value: value, 638 allowWildcards: true, 639 } 640 641 transformToEqualValue := q.transformValue(whereParams) 642 643 tokensRef, err := q.getCurrentWhereTokensRef() 644 if err != nil { 645 return err 646 } 647 err = q.appendOperatorIfNeeded(tokensRef) 648 if err != nil { 649 return err 650 } 651 652 whereParams.fieldName, err = q.ensureValidFieldName(whereParams.fieldName, whereParams.isNestedPath) 653 if err != nil { 654 return err 655 } 656 err = q.negateIfNeeded(tokensRef, whereParams.fieldName) 657 if err != nil { 658 return err 659 } 660 661 whereToken := createWhereToken(whereOperatorStartsWith, whereParams.fieldName, q.addQueryParameter(transformToEqualValue)) 662 663 tokens := *tokensRef 664 tokens = append(tokens, whereToken) 665 *tokensRef = tokens 666 return nil 667 } 668 669 func (q *abstractDocumentQuery) whereEndsWith(fieldName string, value interface{}) error { 670 whereParams := &whereParams{ 671 fieldName: fieldName, 672 value: value, 673 allowWildcards: true, 674 } 675 676 transformToEqualValue := q.transformValue(whereParams) 677 678 tokensRef, err := q.getCurrentWhereTokensRef() 679 if err != nil { 680 return err 681 } 682 err = q.appendOperatorIfNeeded(tokensRef) 683 if err != nil { 684 return err 685 } 686 687 whereParams.fieldName, err = q.ensureValidFieldName(whereParams.fieldName, whereParams.isNestedPath) 688 if err != nil { 689 return err 690 } 691 err = q.negateIfNeeded(tokensRef, whereParams.fieldName) 692 if err != nil { 693 return err 694 } 695 696 whereToken := createWhereToken(whereOperatorEndsWith, whereParams.fieldName, q.addQueryParameter(transformToEqualValue)) 697 698 tokens := *tokensRef 699 tokens = append(tokens, whereToken) 700 *tokensRef = tokens 701 return nil 702 } 703 704 func (q *abstractDocumentQuery) whereBetween(fieldName string, start interface{}, end interface{}) error { 705 var err error 706 fieldName, err = q.ensureValidFieldName(fieldName, false) 707 if err != nil { 708 return err 709 } 710 711 tokensRef, err := q.getCurrentWhereTokensRef() 712 if err != nil { 713 return err 714 } 715 err = q.appendOperatorIfNeeded(tokensRef) 716 if err != nil { 717 return err 718 } 719 err = q.negateIfNeeded(tokensRef, fieldName) 720 if err != nil { 721 return err 722 } 723 724 startParams := &whereParams{ 725 value: start, 726 fieldName: fieldName, 727 } 728 729 endParams := &whereParams{ 730 value: end, 731 fieldName: fieldName, 732 } 733 734 fromParam := interface{}("*") 735 if start != nil { 736 fromParam = q.transformValueWithRange(startParams, true) 737 } 738 fromParameterName := q.addQueryParameter(fromParam) 739 740 toParam := interface{}("NULL") 741 if end != nil { 742 toParam = q.transformValueWithRange(endParams, true) 743 } 744 toParameterName := q.addQueryParameter(toParam) 745 746 whereToken := createWhereTokenWithOptions(whereOperatorBetween, fieldName, "", newWhereOptionsWithFromTo(false, fromParameterName, toParameterName)) 747 748 tokens := *tokensRef 749 tokens = append(tokens, whereToken) 750 *tokensRef = tokens 751 return nil 752 } 753 754 func (q *abstractDocumentQuery) whereGreaterThan(fieldName string, value interface{}) error { 755 var err error 756 fieldName, err = q.ensureValidFieldName(fieldName, false) 757 if err != nil { 758 return err 759 } 760 761 tokensRef, err := q.getCurrentWhereTokensRef() 762 if err != nil { 763 return err 764 } 765 err = q.appendOperatorIfNeeded(tokensRef) 766 if err != nil { 767 return err 768 } 769 err = q.negateIfNeeded(tokensRef, fieldName) 770 if err != nil { 771 return err 772 } 773 774 whereParams := &whereParams{ 775 value: value, 776 fieldName: fieldName, 777 } 778 779 paramValue := interface{}("*") 780 if value != nil { 781 paramValue = q.transformValueWithRange(whereParams, true) 782 } 783 parameter := q.addQueryParameter(paramValue) 784 785 whereToken := createWhereTokenWithOptions(whereOperatorGreaterThan, fieldName, parameter, nil) 786 787 tokens := *tokensRef 788 tokens = append(tokens, whereToken) 789 *tokensRef = tokens 790 return nil 791 } 792 793 func (q *abstractDocumentQuery) whereGreaterThanOrEqual(fieldName string, value interface{}) error { 794 var err error 795 fieldName, err = q.ensureValidFieldName(fieldName, false) 796 if err != nil { 797 return err 798 } 799 800 tokensRef, err := q.getCurrentWhereTokensRef() 801 if err != nil { 802 return err 803 } 804 err = q.appendOperatorIfNeeded(tokensRef) 805 if err != nil { 806 return err 807 } 808 err = q.negateIfNeeded(tokensRef, fieldName) 809 if err != nil { 810 return err 811 } 812 813 whereParams := &whereParams{ 814 value: value, 815 fieldName: fieldName, 816 } 817 818 paramValue := interface{}("*") 819 if value != nil { 820 paramValue = q.transformValueWithRange(whereParams, true) 821 } 822 823 parameter := q.addQueryParameter(paramValue) 824 825 whereToken := createWhereTokenWithOptions(whereOperatorGreaterThanOrEqual, fieldName, parameter, nil) 826 827 tokens := *tokensRef 828 tokens = append(tokens, whereToken) 829 *tokensRef = tokens 830 return nil 831 } 832 833 func (q *abstractDocumentQuery) whereLessThan(fieldName string, value interface{}) error { 834 var err error 835 fieldName, err = q.ensureValidFieldName(fieldName, false) 836 if err != nil { 837 return err 838 } 839 840 tokensRef, err := q.getCurrentWhereTokensRef() 841 if err != nil { 842 return err 843 } 844 err = q.appendOperatorIfNeeded(tokensRef) 845 if err != nil { 846 return err 847 } 848 err = q.negateIfNeeded(tokensRef, fieldName) 849 if err != nil { 850 return err 851 } 852 853 whereParams := &whereParams{ 854 value: value, 855 fieldName: fieldName, 856 } 857 858 paramValue := interface{}("NULL") 859 if value != nil { 860 paramValue = q.transformValueWithRange(whereParams, true) 861 } 862 parameter := q.addQueryParameter(paramValue) 863 whereToken := createWhereTokenWithOptions(whereOperatorLessThan, fieldName, parameter, nil) 864 865 tokens := *tokensRef 866 tokens = append(tokens, whereToken) 867 *tokensRef = tokens 868 return nil 869 } 870 871 func (q *abstractDocumentQuery) whereLessThanOrEqual(fieldName string, value interface{}) error { 872 tokensRef, err := q.getCurrentWhereTokensRef() 873 if err != nil { 874 return err 875 } 876 err = q.appendOperatorIfNeeded(tokensRef) 877 if err != nil { 878 return err 879 } 880 err = q.negateIfNeeded(tokensRef, fieldName) 881 if err != nil { 882 return err 883 } 884 885 whereParams := &whereParams{ 886 value: value, 887 fieldName: fieldName, 888 } 889 890 paramValue := interface{}("NULL") 891 if value != nil { 892 paramValue = q.transformValueWithRange(whereParams, true) 893 } 894 parameter := q.addQueryParameter(paramValue) 895 whereToken := createWhereTokenWithOptions(whereOperatorLessThanOrEqual, fieldName, parameter, nil) 896 897 tokens := *tokensRef 898 tokens = append(tokens, whereToken) 899 *tokensRef = tokens 900 return nil 901 } 902 903 func (q *abstractDocumentQuery) whereRegex(fieldName string, pattern string) error { 904 tokensRef, err := q.getCurrentWhereTokensRef() 905 if err != nil { 906 return err 907 } 908 err = q.appendOperatorIfNeeded(tokensRef) 909 if err != nil { 910 return err 911 } 912 err = q.negateIfNeeded(tokensRef, fieldName) 913 if err != nil { 914 return err 915 } 916 917 whereParams := &whereParams{ 918 value: pattern, 919 fieldName: fieldName, 920 } 921 922 parameter := q.addQueryParameter(q.transformValue(whereParams)) 923 924 whereToken := createWhereToken(whereOperatorRegex, fieldName, parameter) 925 926 tokens := *tokensRef 927 tokens = append(tokens, whereToken) 928 *tokensRef = tokens 929 return nil 930 } 931 932 func (q *abstractDocumentQuery) andAlso() error { 933 tokensRef, err := q.getCurrentWhereTokensRef() 934 if err != nil { 935 return err 936 } 937 tokens := *tokensRef 938 939 n := len(tokens) 940 if n == 0 { 941 return nil 942 } 943 944 lastToken := tokens[n-1] 945 if _, ok := lastToken.(*queryOperatorToken); ok { 946 return newIllegalStateError("Cannot add AND, previous token was already an operator token.") 947 } 948 949 tokens = append(tokens, queryOperatorTokenAnd) 950 *tokensRef = tokens 951 return nil 952 } 953 954 func (q *abstractDocumentQuery) orElse() error { 955 tokensRef, err := q.getCurrentWhereTokensRef() 956 if err != nil { 957 return err 958 } 959 tokens := *tokensRef 960 n := len(tokens) 961 if n == 0 { 962 return nil 963 } 964 965 lastToken := tokens[n-1] 966 if _, ok := lastToken.(*queryOperatorToken); ok { 967 return newIllegalStateError("Cannot add OR, previous token was already an operator token.") 968 } 969 970 tokens = append(tokens, queryOperatorTokenOr) 971 *tokensRef = tokens 972 return nil 973 } 974 975 func (q *abstractDocumentQuery) boost(boost float64) error { 976 if boost == 1.0 { 977 return nil 978 } 979 980 tokens, err := q.getCurrentWhereTokens() 981 if err != nil { 982 return err 983 } 984 n := len(tokens) 985 if n == 0 { 986 return newIllegalStateError("Missing where clause") 987 } 988 989 maybeWhereToken := tokens[n-1] 990 whereToken, ok := maybeWhereToken.(*whereToken) 991 if !ok { 992 return newIllegalStateError("Missing where clause") 993 } 994 995 if boost <= 0.0 { 996 return newIllegalArgumentError("Boost factor must be a positive number") 997 } 998 999 whereToken.options.boost = boost 1000 return nil 1001 } 1002 1003 func (q *abstractDocumentQuery) fuzzy(fuzzy float64) error { 1004 tokens, err := q.getCurrentWhereTokens() 1005 if err != nil { 1006 return err 1007 } 1008 n := len(tokens) 1009 if n == 0 { 1010 return newIllegalStateError("Missing where clause") 1011 } 1012 1013 maybeWhereToken := tokens[n-1] 1014 whereToken, ok := maybeWhereToken.(*whereToken) 1015 if !ok { 1016 return newIllegalStateError("Missing where clause") 1017 } 1018 1019 if fuzzy < 0.0 || fuzzy > 1.0 { 1020 return newIllegalArgumentError("Fuzzy distance must be between 0.0 and 1.0") 1021 } 1022 1023 whereToken.options.fuzzy = fuzzy 1024 return nil 1025 } 1026 1027 func (q *abstractDocumentQuery) proximity(proximity int) error { 1028 tokens, err := q.getCurrentWhereTokens() 1029 if err != nil { 1030 return err 1031 } 1032 1033 n := len(tokens) 1034 if n == 0 { 1035 return newIllegalStateError("Missing where clause") 1036 } 1037 1038 maybeWhereToken := tokens[n-1] 1039 whereToken, ok := maybeWhereToken.(*whereToken) 1040 if !ok { 1041 return newIllegalStateError("Missing where clause") 1042 } 1043 1044 if proximity < 1 { 1045 return newIllegalArgumentError("Proximity distance must be a positive number") 1046 } 1047 1048 whereToken.options.proximity = proximity 1049 return nil 1050 } 1051 1052 func (q *abstractDocumentQuery) orderBy(field string) error { 1053 return q.orderByWithOrdering(field, OrderingTypeString) 1054 } 1055 1056 func (q *abstractDocumentQuery) orderByWithOrdering(field string, ordering OrderingType) error { 1057 if err := q.assertNoRawQuery(); err != nil { 1058 return err 1059 } 1060 f, err := q.ensureValidFieldName(field, false) 1061 if err != nil { 1062 return err 1063 } 1064 q.orderByTokens = append(q.orderByTokens, orderByTokenCreateAscending(f, ordering)) 1065 return nil 1066 } 1067 1068 func (q *abstractDocumentQuery) orderByDescending(field string) error { 1069 return q.orderByDescendingWithOrdering(field, OrderingTypeString) 1070 } 1071 1072 func (q *abstractDocumentQuery) orderByDescendingWithOrdering(field string, ordering OrderingType) error { 1073 if err := q.assertNoRawQuery(); err != nil { 1074 return err 1075 } 1076 f, err := q.ensureValidFieldName(field, false) 1077 if err != nil { 1078 return err 1079 } 1080 q.orderByTokens = append(q.orderByTokens, orderByTokenCreateDescending(f, ordering)) 1081 return nil 1082 } 1083 1084 func (q *abstractDocumentQuery) orderByScore() error { 1085 if err := q.assertNoRawQuery(); err != nil { 1086 return err 1087 } 1088 1089 q.orderByTokens = append(q.orderByTokens, orderByTokenScoreAscending) 1090 return nil 1091 } 1092 1093 func (q *abstractDocumentQuery) orderByScoreDescending() error { 1094 if err := q.assertNoRawQuery(); err != nil { 1095 return err 1096 } 1097 q.orderByTokens = append(q.orderByTokens, orderByTokenScoreDescending) 1098 return nil 1099 } 1100 1101 func (q *abstractDocumentQuery) statistics(stats **QueryStatistics) { 1102 *stats = q.queryStats 1103 } 1104 1105 func (q *abstractDocumentQuery) invokeAfterQueryExecuted(result *QueryResult) { 1106 for _, cb := range q.afterQueryExecutedCallback { 1107 if cb != nil { 1108 cb(result) 1109 } 1110 } 1111 } 1112 1113 func (q *abstractDocumentQuery) invokeBeforeQueryExecuted(query *IndexQuery) { 1114 for _, cb := range q.beforeQueryExecutedCallback { 1115 if cb != nil { 1116 cb(query) 1117 } 1118 } 1119 } 1120 1121 func (q *abstractDocumentQuery) invokeAfterStreamExecuted(result map[string]interface{}) { 1122 for _, cb := range q.afterStreamExecutedCallback { 1123 if cb != nil { 1124 cb(result) 1125 } 1126 } 1127 } 1128 1129 func (q *abstractDocumentQuery) generateIndexQuery(query string) *IndexQuery { 1130 indexQuery := NewIndexQuery("") 1131 indexQuery.query = query 1132 indexQuery.start = q.start 1133 indexQuery.waitForNonStaleResults = q.theWaitForNonStaleResults 1134 indexQuery.waitForNonStaleResultsTimeout = q.timeout 1135 indexQuery.queryParameters = q.queryParameters 1136 indexQuery.disableCaching = q.disableCaching 1137 1138 if q.pageSize != nil { 1139 indexQuery.pageSize = *q.pageSize 1140 } 1141 return indexQuery 1142 } 1143 1144 func (q *abstractDocumentQuery) search(fieldName string, searchTerms string) error { 1145 return q.searchWithOperator(fieldName, searchTerms, SearchOperatorOr) 1146 } 1147 1148 func (q *abstractDocumentQuery) searchWithOperator(fieldName string, searchTerms string, operator SearchOperator) error { 1149 tokensRef, err := q.getCurrentWhereTokensRef() 1150 if err != nil { 1151 return err 1152 } 1153 err = q.appendOperatorIfNeeded(tokensRef) 1154 if err != nil { 1155 return err 1156 } 1157 1158 fieldName, err = q.ensureValidFieldName(fieldName, false) 1159 if err != nil { 1160 return err 1161 } 1162 err = q.negateIfNeeded(tokensRef, fieldName) 1163 if err != nil { 1164 return err 1165 } 1166 1167 whereToken := createWhereTokenWithOptions(whereOperatorSearch, fieldName, q.addQueryParameter(searchTerms), newWhereOptionsWithOperator(operator)) 1168 1169 tokens := *tokensRef 1170 tokens = append(tokens, whereToken) 1171 *tokensRef = tokens 1172 return nil 1173 } 1174 1175 func (q *abstractDocumentQuery) string() (string, error) { 1176 if q.queryRaw != "" { 1177 return q.queryRaw, nil 1178 } 1179 1180 if q.currentClauseDepth != 0 { 1181 return "", newIllegalStateError("A clause was not closed correctly within this query, current clause depth = %d", q.currentClauseDepth) 1182 } 1183 1184 queryText := &strings.Builder{} 1185 1186 err := q.buildDeclare(queryText) 1187 if err != nil { 1188 return "", err 1189 } 1190 err = q.buildFrom(queryText) 1191 if err != nil { 1192 return "", err 1193 } 1194 err = q.buildGroupBy(queryText) 1195 if err != nil { 1196 return "", err 1197 } 1198 err = q.buildWhere(queryText) 1199 if err != nil { 1200 return "", err 1201 } 1202 err = q.buildOrderBy(queryText) 1203 1204 err = q.buildLoad(queryText) 1205 if err != nil { 1206 return "", err 1207 } 1208 err = q.buildSelect(queryText) 1209 if err != nil { 1210 return "", err 1211 } 1212 err = q.buildInclude(queryText) 1213 if err != nil { 1214 return "", err 1215 } 1216 1217 return queryText.String(), nil 1218 } 1219 1220 func (q *abstractDocumentQuery) buildInclude(queryText *strings.Builder) error { 1221 if len(q.includes) == 0 { 1222 return nil 1223 } 1224 1225 q.includes = stringArrayRemoveDuplicates(q.includes) 1226 queryText.WriteString(" include ") 1227 for i, include := range q.includes { 1228 if i > 0 { 1229 queryText.WriteString(",") 1230 } 1231 1232 requiredQuotes := false 1233 1234 for _, ch := range include { 1235 if !isLetterOrDigit(ch) && ch != '_' && ch != '.' { 1236 requiredQuotes = true 1237 break 1238 } 1239 } 1240 1241 if requiredQuotes { 1242 s := strings.Replace(include, "'", "\\'", -1) 1243 queryText.WriteString("'") 1244 queryText.WriteString(s) 1245 queryText.WriteString("'") 1246 } else { 1247 queryText.WriteString(include) 1248 } 1249 } 1250 return nil 1251 } 1252 1253 func (q *abstractDocumentQuery) intersect() error { 1254 1255 tokensRef, err := q.getCurrentWhereTokensRef() 1256 if err != nil { 1257 return err 1258 } 1259 tokens := *tokensRef 1260 n := len(tokens) 1261 if n > 0 { 1262 last := tokens[n-1] 1263 _, isWhere := last.(*whereToken) 1264 _, isClose := last.(*closeSubclauseToken) 1265 if isWhere || isClose { 1266 q.isIntersect = true 1267 1268 tokens = append(tokens, intersectMarkerTokenInstance) 1269 *tokensRef = tokens 1270 return nil 1271 } 1272 } 1273 1274 return newIllegalStateError("Cannot add INTERSECT at this point.") 1275 } 1276 1277 func (q *abstractDocumentQuery) whereExists(fieldName string) error { 1278 var err error 1279 fieldName, err = q.ensureValidFieldName(fieldName, false) 1280 if err != nil { 1281 return err 1282 } 1283 1284 tokensRef, err := q.getCurrentWhereTokensRef() 1285 if err != nil { 1286 return err 1287 } 1288 err = q.appendOperatorIfNeeded(tokensRef) 1289 if err != nil { 1290 return err 1291 } 1292 err = q.negateIfNeeded(tokensRef, fieldName) 1293 if err != nil { 1294 return err 1295 } 1296 1297 tokens := *tokensRef 1298 tokens = append(tokens, createWhereToken(whereOperatorExists, fieldName, "")) 1299 *tokensRef = tokens 1300 return nil 1301 } 1302 1303 func (q *abstractDocumentQuery) containsAny(fieldName string, values []interface{}) error { 1304 var err error 1305 fieldName, err = q.ensureValidFieldName(fieldName, false) 1306 if err != nil { 1307 return err 1308 } 1309 1310 tokensRef, err := q.getCurrentWhereTokensRef() 1311 if err != nil { 1312 return err 1313 } 1314 err = q.appendOperatorIfNeeded(tokensRef) 1315 if err != nil { 1316 return err 1317 } 1318 err = q.negateIfNeeded(tokensRef, fieldName) 1319 if err != nil { 1320 return err 1321 } 1322 1323 array := q.transformCollection(fieldName, abstractDocumentQueryUnpackCollection(values)) 1324 whereToken := createWhereTokenWithOptions(whereOperatorIn, fieldName, q.addQueryParameter(array), newWhereOptionsWithExact(false)) 1325 1326 tokens := *tokensRef 1327 tokens = append(tokens, whereToken) 1328 *tokensRef = tokens 1329 return nil 1330 } 1331 1332 func (q *abstractDocumentQuery) containsAll(fieldName string, values []interface{}) error { 1333 var err error 1334 fieldName, err = q.ensureValidFieldName(fieldName, false) 1335 if err != nil { 1336 return err 1337 } 1338 1339 tokensRef, err := q.getCurrentWhereTokensRef() 1340 if err != nil { 1341 return err 1342 } 1343 err = q.appendOperatorIfNeeded(tokensRef) 1344 if err != nil { 1345 return err 1346 } 1347 err = q.negateIfNeeded(tokensRef, fieldName) 1348 if err != nil { 1349 return err 1350 } 1351 1352 array := q.transformCollection(fieldName, abstractDocumentQueryUnpackCollection(values)) 1353 1354 tokens := *tokensRef 1355 if len(array) == 0 { 1356 tokens = append(tokens, trueTokenInstance) 1357 } else { 1358 whereToken := createWhereToken(whereOperatorAllIn, fieldName, q.addQueryParameter(array)) 1359 tokens = append(tokens, whereToken) 1360 } 1361 *tokensRef = tokens 1362 return nil 1363 } 1364 1365 func (q *abstractDocumentQuery) distinct() error { 1366 if q.isDistinct() { 1367 return newIllegalStateError("The is already a distinct query") 1368 } 1369 1370 if len(q.selectTokens) == 0 { 1371 q.selectTokens = []queryToken{distinctTokenInstance} 1372 return nil 1373 } 1374 q.selectTokens = append([]queryToken{distinctTokenInstance}, q.selectTokens...) 1375 return nil 1376 } 1377 1378 func (q *abstractDocumentQuery) updateStatsAndHighlightings(queryResult *QueryResult) { 1379 q.queryStats.UpdateQueryStats(queryResult) 1380 //TBD 4.1 Highlightings.Update(queryResult); 1381 } 1382 1383 func (q *abstractDocumentQuery) buildSelect(writer *strings.Builder) error { 1384 if len(q.selectTokens) == 0 { 1385 return nil 1386 } 1387 1388 writer.WriteString(" select ") 1389 1390 if len(q.selectTokens) == 1 { 1391 tok := q.selectTokens[0] 1392 if dtok, ok := tok.(*distinctToken); ok { 1393 if err := dtok.writeTo(writer); err != nil { 1394 return err 1395 } 1396 writer.WriteString(" *") 1397 return nil 1398 } 1399 } 1400 1401 for i, token := range q.selectTokens { 1402 if i > 0 { 1403 prevToken := q.selectTokens[i-1] 1404 if _, ok := prevToken.(*distinctToken); !ok { 1405 writer.WriteString(",") 1406 } 1407 } 1408 1409 var prevToken queryToken 1410 if i > 0 { 1411 prevToken = q.selectTokens[i-1] 1412 } 1413 documentQueryHelperAddSpaceIfNeeded(prevToken, token, writer) 1414 1415 if err := token.writeTo(writer); err != nil { 1416 return err 1417 } 1418 } 1419 return nil 1420 } 1421 1422 func (q *abstractDocumentQuery) buildFrom(writer *strings.Builder) error { 1423 return q.fromToken.writeTo(writer) 1424 } 1425 1426 func (q *abstractDocumentQuery) buildDeclare(writer *strings.Builder) error { 1427 if q.declareToken != nil { 1428 return q.declareToken.writeTo(writer) 1429 } 1430 return nil 1431 } 1432 1433 func (q *abstractDocumentQuery) buildLoad(writer *strings.Builder) error { 1434 if len(q.loadTokens) == 0 { 1435 return nil 1436 } 1437 1438 writer.WriteString(" load ") 1439 1440 for i, tok := range q.loadTokens { 1441 if i != 0 { 1442 writer.WriteString(", ") 1443 } 1444 1445 if err := tok.writeTo(writer); err != nil { 1446 return err 1447 } 1448 } 1449 return nil 1450 } 1451 1452 func (q *abstractDocumentQuery) buildWhere(writer *strings.Builder) error { 1453 if len(q.whereTokens) == 0 { 1454 return nil 1455 } 1456 1457 writer.WriteString(" where ") 1458 1459 if q.isIntersect { 1460 writer.WriteString("intersect(") 1461 } 1462 1463 for i, tok := range q.whereTokens { 1464 var prevToken queryToken 1465 if i > 0 { 1466 prevToken = q.whereTokens[i-1] 1467 } 1468 documentQueryHelperAddSpaceIfNeeded(prevToken, tok, writer) 1469 if err := tok.writeTo(writer); err != nil { 1470 return err 1471 } 1472 } 1473 1474 if q.isIntersect { 1475 writer.WriteString(") ") 1476 } 1477 return nil 1478 } 1479 1480 func (q *abstractDocumentQuery) buildGroupBy(writer *strings.Builder) error { 1481 if len(q.groupByTokens) == 0 { 1482 return nil 1483 } 1484 1485 writer.WriteString(" group by ") 1486 1487 for i, token := range q.groupByTokens { 1488 if i > 0 { 1489 writer.WriteString(", ") 1490 } 1491 if err := token.writeTo(writer); err != nil { 1492 return err 1493 } 1494 } 1495 return nil 1496 } 1497 1498 func (q *abstractDocumentQuery) buildOrderBy(writer *strings.Builder) error { 1499 if len(q.orderByTokens) == 0 { 1500 return nil 1501 } 1502 1503 writer.WriteString(" order by ") 1504 1505 for i, token := range q.orderByTokens { 1506 if i > 0 { 1507 writer.WriteString(", ") 1508 } 1509 1510 if err := token.writeTo(writer); err != nil { 1511 return err 1512 } 1513 } 1514 return nil 1515 } 1516 1517 func (q *abstractDocumentQuery) appendOperatorIfNeeded(tokensRef *[]queryToken) error { 1518 tokens := *tokensRef 1519 if err := q.assertNoRawQuery(); err != nil { 1520 return err 1521 } 1522 1523 n := len(tokens) 1524 if len(tokens) == 0 { 1525 return nil 1526 } 1527 1528 lastToken := tokens[n-1] 1529 _, isWhereToken := lastToken.(*whereToken) 1530 _, isCloseSubclauseToken := lastToken.(*closeSubclauseToken) 1531 if !isWhereToken && !isCloseSubclauseToken { 1532 return nil 1533 } 1534 1535 var lastWhere *whereToken 1536 1537 for i := n - 1; i >= 0; i-- { 1538 tok := tokens[i] 1539 if maybeLastWhere, ok := tok.(*whereToken); ok { 1540 lastWhere = maybeLastWhere 1541 break 1542 } 1543 } 1544 1545 var token *queryOperatorToken 1546 if q.defaultOperator == QueryOperatorAnd { 1547 token = queryOperatorTokenAnd 1548 } else { 1549 token = queryOperatorTokenOr 1550 } 1551 1552 if lastWhere != nil && lastWhere.options.searchOperator != SearchOperatorUnset { 1553 token = queryOperatorTokenOr // default to OR operator after search if AND was not specified explicitly 1554 } 1555 1556 tokens = append(tokens, token) 1557 *tokensRef = tokens 1558 return nil 1559 } 1560 1561 func (q *abstractDocumentQuery) transformCollection(fieldName string, values []interface{}) []interface{} { 1562 var result []interface{} 1563 for _, value := range values { 1564 if collectionValue, ok := value.([]interface{}); ok { 1565 tmp := q.transformCollection(fieldName, collectionValue) 1566 result = append(result, tmp...) 1567 } else { 1568 nestedWhereParams := &whereParams{ 1569 allowWildcards: true, 1570 fieldName: fieldName, 1571 value: value, 1572 } 1573 tmp := q.transformValue(nestedWhereParams) 1574 result = append(result, tmp) 1575 } 1576 } 1577 return result 1578 } 1579 1580 func (q *abstractDocumentQuery) negateIfNeeded(tokensRef *[]queryToken, fieldName string) error { 1581 var err error 1582 if !q.negate { 1583 return nil 1584 } 1585 1586 q.negate = false 1587 1588 tokens := *tokensRef 1589 1590 n := len(tokens) 1591 isOpenSubclauseToken := false 1592 if n > 0 { 1593 _, isOpenSubclauseToken = tokens[n-1].(*openSubclauseToken) 1594 } 1595 if n == 0 || isOpenSubclauseToken { 1596 if fieldName != "" { 1597 err = q.whereExists(fieldName) 1598 if err != nil { 1599 return err 1600 } 1601 } else { 1602 err = q.whereTrue() 1603 if err != nil { 1604 return err 1605 } 1606 } 1607 err = q.andAlso() 1608 if err != nil { 1609 return err 1610 } 1611 } 1612 1613 tokens = append(tokens, negateTokenInstance) 1614 *tokensRef = tokens 1615 return nil 1616 } 1617 1618 func abstractDocumentQueryUnpackCollection(items []interface{}) []interface{} { 1619 var results []interface{} 1620 1621 for _, item := range items { 1622 if itemCollection, ok := item.([]interface{}); ok { 1623 els := abstractDocumentQueryUnpackCollection(itemCollection) 1624 results = append(results, els...) 1625 } else { 1626 results = append(results, item) 1627 } 1628 } 1629 1630 return results 1631 } 1632 1633 func (q *abstractDocumentQuery) ensureValidFieldName(fieldName string, isNestedPath bool) (string, error) { 1634 if q.theSession == nil || q.theSession.GetConventions() == nil || isNestedPath || q.isGroupBy { 1635 return queryFieldUtilEscapeIfNecessary(fieldName), nil 1636 } 1637 1638 if fieldName == documentConventionsIdentityPropertyName { 1639 return IndexingFieldNameDocumentID, nil 1640 } 1641 1642 return queryFieldUtilEscapeIfNecessary(fieldName), nil 1643 } 1644 1645 func (q *abstractDocumentQuery) transformValue(whereParams *whereParams) interface{} { 1646 return q.transformValueWithRange(whereParams, false) 1647 } 1648 1649 func (q *abstractDocumentQuery) transformValueWithRange(whereParams *whereParams, forRange bool) interface{} { 1650 if whereParams.value == nil { 1651 return nil 1652 } 1653 1654 if "" == whereParams.value { 1655 return "" 1656 } 1657 1658 var stringValueReference string 1659 if q.conventions.TryConvertValueForQuery(whereParams.fieldName, whereParams.value, forRange, &stringValueReference) { 1660 return stringValueReference 1661 } 1662 1663 val := whereParams.value 1664 switch v := val.(type) { 1665 case time.Time, string, int, int32, int64, float32, float64, bool: 1666 return val 1667 case time.Duration: 1668 n := int64(v/time.Nanosecond) / 100 1669 return n 1670 } 1671 return whereParams.value 1672 } 1673 1674 func (q *abstractDocumentQuery) addQueryParameter(value interface{}) string { 1675 parameterName := "p" + strconv.Itoa(len(q.queryParameters)) 1676 q.queryParameters[parameterName] = value 1677 return parameterName 1678 } 1679 1680 func (q *abstractDocumentQuery) getCurrentWhereTokens() ([]queryToken, error) { 1681 if !q.isInMoreLikeThis { 1682 return q.whereTokens, nil 1683 } 1684 1685 n := len(q.whereTokens) 1686 1687 if n == 0 { 1688 return nil, newIllegalStateError("Cannot get moreLikeThisToken because there are no where token specified.") 1689 } 1690 1691 lastToken := q.whereTokens[n-1] 1692 1693 if moreLikeThisToken, ok := lastToken.(*moreLikeThisToken); ok { 1694 return moreLikeThisToken.whereTokens, nil 1695 } 1696 return nil, newIllegalStateError("Last token is not moreLikeThisToken") 1697 } 1698 1699 func (q *abstractDocumentQuery) getCurrentWhereTokensRef() (*[]queryToken, error) { 1700 if !q.isInMoreLikeThis { 1701 return &q.whereTokens, nil 1702 } 1703 1704 n := len(q.whereTokens) 1705 1706 if n == 0 { 1707 return nil, newIllegalStateError("Cannot get moreLikeThisToken because there are no where token specified.") 1708 } 1709 1710 lastToken := q.whereTokens[n-1] 1711 1712 if moreLikeThisToken, ok := lastToken.(*moreLikeThisToken); ok { 1713 return &moreLikeThisToken.whereTokens, nil 1714 } 1715 return nil, newIllegalStateError("Last token is not moreLikeThisToken") 1716 } 1717 1718 func (q *abstractDocumentQuery) updateFieldsToFetchToken(fieldsToFetch *fieldsToFetchToken) { 1719 q.fieldsToFetchToken = fieldsToFetch 1720 1721 if len(q.selectTokens) == 0 { 1722 q.selectTokens = append(q.selectTokens, fieldsToFetch) 1723 return 1724 } 1725 1726 for _, x := range q.selectTokens { 1727 if _, ok := x.(*fieldsToFetchToken); ok { 1728 for idx, tok := range q.selectTokens { 1729 if tok == x { 1730 q.selectTokens[idx] = fieldsToFetch 1731 } 1732 } 1733 return 1734 } 1735 } 1736 q.selectTokens = append(q.selectTokens, fieldsToFetch) 1737 } 1738 1739 func getSourceAliasIfExists(clazz reflect.Type, queryData *QueryData, fields []string) string { 1740 if len(fields) != 1 || fields[0] == "" { 1741 return "" 1742 } 1743 1744 if clazz != reflect.TypeOf("") && !isPrimitiveOrWrapper(clazz) { 1745 return "" 1746 } 1747 indexOf := strings.Index(fields[0], ".") 1748 if indexOf == -1 { 1749 return "" 1750 } 1751 1752 possibleAlias := fields[0][:indexOf] 1753 if queryData.fromAlias == possibleAlias { 1754 return possibleAlias 1755 } 1756 1757 if len(queryData.loadTokens) == 0 { 1758 return "" 1759 } 1760 1761 // TODO: is this the logic? 1762 for _, x := range queryData.loadTokens { 1763 if x.alias == possibleAlias { 1764 return possibleAlias 1765 } 1766 } 1767 return "" 1768 } 1769 1770 func (q *abstractDocumentQuery) addBeforeQueryExecutedListener(action func(*IndexQuery)) int { 1771 q.beforeQueryExecutedCallback = append(q.beforeQueryExecutedCallback, action) 1772 return len(q.beforeQueryExecutedCallback) - 1 1773 } 1774 1775 func (q *abstractDocumentQuery) removeBeforeQueryExecutedListener(idx int) { 1776 q.beforeQueryExecutedCallback[idx] = nil 1777 } 1778 1779 func (q *abstractDocumentQuery) addAfterQueryExecutedListener(action func(*QueryResult)) int { 1780 q.afterQueryExecutedCallback = append(q.afterQueryExecutedCallback, action) 1781 return len(q.afterQueryExecutedCallback) - 1 1782 } 1783 1784 func (q *abstractDocumentQuery) removeAfterQueryExecutedListener(idx int) { 1785 q.afterQueryExecutedCallback[idx] = nil 1786 } 1787 1788 func (q *abstractDocumentQuery) addAfterStreamExecutedListener(action func(map[string]interface{})) int { 1789 q.afterStreamExecutedCallback = append(q.afterStreamExecutedCallback, action) 1790 return len(q.afterStreamExecutedCallback) - 1 1791 } 1792 1793 func (q *abstractDocumentQuery) removeAfterStreamExecutedListener(idx int) { 1794 q.afterStreamExecutedCallback[idx] = nil 1795 } 1796 1797 func (q *abstractDocumentQuery) noTracking() { 1798 q.disableEntitiesTracking = true 1799 } 1800 1801 func (q *abstractDocumentQuery) noCaching() { 1802 q.disableCaching = true 1803 } 1804 1805 func (q *abstractDocumentQuery) withinRadiusOf(fieldName string, radius float64, latitude float64, longitude float64, radiusUnits SpatialUnits, distErrorPercent float64) error { 1806 var err error 1807 fieldName, err = q.ensureValidFieldName(fieldName, false) 1808 if err != nil { 1809 return err 1810 } 1811 1812 tokensRef, err := q.getCurrentWhereTokensRef() 1813 if err != nil { 1814 return err 1815 } 1816 err = q.appendOperatorIfNeeded(tokensRef) 1817 if err != nil { 1818 return err 1819 } 1820 err = q.negateIfNeeded(tokensRef, fieldName) 1821 if err != nil { 1822 return err 1823 } 1824 1825 shape := shapeTokenCircle(q.addQueryParameter(radius), q.addQueryParameter(latitude), q.addQueryParameter(longitude), radiusUnits) 1826 opts := newWhereOptionsWithTokenAndDistance(shape, distErrorPercent) 1827 whereToken := createWhereTokenWithOptions(whereOperatorSpatialWithin, fieldName, "", opts) 1828 1829 tokens := *tokensRef 1830 tokens = append(tokens, whereToken) 1831 *tokensRef = tokens 1832 return nil 1833 } 1834 1835 func (q *abstractDocumentQuery) spatial(fieldName string, shapeWkt string, relation SpatialRelation, distErrorPercent float64) error { 1836 var err error 1837 fieldName, err = q.ensureValidFieldName(fieldName, false) 1838 if err != nil { 1839 return err 1840 } 1841 1842 tokensRef, err := q.getCurrentWhereTokensRef() 1843 if err != nil { 1844 return err 1845 } 1846 err = q.appendOperatorIfNeeded(tokensRef) 1847 if err != nil { 1848 return err 1849 } 1850 err = q.negateIfNeeded(tokensRef, fieldName) 1851 if err != nil { 1852 return err 1853 } 1854 1855 wktToken := shapeTokenWkt(q.addQueryParameter(shapeWkt)) 1856 1857 var whereOperator whereOperator 1858 switch relation { 1859 case SpatialRelationWithin: 1860 whereOperator = whereOperatorSpatialWithin 1861 case SpatialRelationContains: 1862 whereOperator = whereOperatorSpatialContains 1863 case SpatialRelationDisjoin: 1864 whereOperator = whereOperatorSpatialDisjoint 1865 case SpatialRelationIntersects: 1866 whereOperator = whereOperatorSpatialIntersects 1867 default: 1868 return newIllegalArgumentError("unknown relation %s", relation) 1869 } 1870 1871 tokens := *tokensRef 1872 opts := newWhereOptionsWithTokenAndDistance(wktToken, distErrorPercent) 1873 tok := createWhereTokenWithOptions(whereOperator, fieldName, "", opts) 1874 tokens = append(tokens, tok) 1875 *tokensRef = tokens 1876 return nil 1877 } 1878 1879 func (q *abstractDocumentQuery) spatial2(dynamicField DynamicSpatialField, criteria SpatialCriteria) error { 1880 if err := q.assertIsDynamicQuery(dynamicField, "spatial"); err != nil { 1881 return err 1882 } 1883 1884 tokensRef, err := q.getCurrentWhereTokensRef() 1885 if err != nil { 1886 return err 1887 } 1888 err = q.appendOperatorIfNeeded(tokensRef) 1889 if err != nil { 1890 return err 1891 } 1892 err = q.negateIfNeeded(tokensRef, "") 1893 if err != nil { 1894 return err 1895 } 1896 1897 ensure := func(fieldName string, isNestedPath bool) (string, error) { 1898 return q.ensureValidFieldName(fieldName, isNestedPath) 1899 } 1900 fieldName, err := dynamicField.ToField(ensure) 1901 if err != nil { 1902 return err 1903 } 1904 add := func(value interface{}) string { 1905 return q.addQueryParameter(value) 1906 } 1907 tok := criteria.ToQueryToken(fieldName, add) 1908 tokens := *tokensRef 1909 tokens = append(tokens, tok) 1910 *tokensRef = tokens 1911 return nil 1912 } 1913 1914 func (q *abstractDocumentQuery) spatial3(fieldName string, criteria SpatialCriteria) error { 1915 var err error 1916 fieldName, err = q.ensureValidFieldName(fieldName, false) 1917 if err != nil { 1918 return err 1919 } 1920 1921 tokensRef, err := q.getCurrentWhereTokensRef() 1922 if err != nil { 1923 return err 1924 } 1925 err = q.appendOperatorIfNeeded(tokensRef) 1926 if err != nil { 1927 return err 1928 } 1929 err = q.negateIfNeeded(tokensRef, fieldName) 1930 if err != nil { 1931 return err 1932 } 1933 1934 tokens := *tokensRef 1935 add := func(value interface{}) string { 1936 return q.addQueryParameter(value) 1937 } 1938 tok := criteria.ToQueryToken(fieldName, add) 1939 tokens = append(tokens, tok) 1940 *tokensRef = tokens 1941 return nil 1942 } 1943 1944 func (q *abstractDocumentQuery) orderByDistanceLatLongDynamic(field DynamicSpatialField, latitude float64, longitude float64) error { 1945 if field == nil { 1946 return newIllegalArgumentError("Field cannot be null") 1947 } 1948 if err := q.assertIsDynamicQuery(field, "orderByDistance"); err != nil { 1949 return err 1950 } 1951 1952 ensure := func(fieldName string, isNestedPath bool) (string, error) { 1953 return q.ensureValidFieldName(fieldName, isNestedPath) 1954 } 1955 fieldName, err := field.ToField(ensure) 1956 if err != nil { 1957 return err 1958 } 1959 return q.orderByDistanceLatLong("'"+fieldName+"'", latitude, longitude) 1960 } 1961 1962 func (q *abstractDocumentQuery) orderByDistanceLatLong(fieldName string, latitude float64, longitude float64) error { 1963 tok := orderByTokenCreateDistanceAscending(fieldName, q.addQueryParameter(latitude), q.addQueryParameter(longitude)) 1964 q.orderByTokens = append(q.orderByTokens, tok) 1965 return nil 1966 } 1967 1968 func (q *abstractDocumentQuery) orderByDistanceWktDynamic(field DynamicSpatialField, shapeWkt string) error { 1969 if field == nil { 1970 return newIllegalArgumentError("Field cannot be null") 1971 } 1972 err := q.assertIsDynamicQuery(field, "orderByDistance2") 1973 if err != nil { 1974 return err 1975 } 1976 1977 ensure := func(fieldName string, isNestedPath bool) (string, error) { 1978 return q.ensureValidFieldName(fieldName, isNestedPath) 1979 } 1980 fieldName, err := field.ToField(ensure) 1981 if err != nil { 1982 return err 1983 } 1984 return q.orderByDistance3("'"+fieldName+"'", shapeWkt) 1985 } 1986 1987 func (q *abstractDocumentQuery) orderByDistance3(fieldName string, shapeWkt string) error { 1988 tok := orderByTokenCreateDistanceAscending2(fieldName, q.addQueryParameter(shapeWkt)) 1989 q.orderByTokens = append(q.orderByTokens, tok) 1990 return nil 1991 } 1992 1993 func (q *abstractDocumentQuery) orderByDistanceDescendingLatLongDynamic(field DynamicSpatialField, latitude float64, longitude float64) error { 1994 if field == nil { 1995 return newIllegalArgumentError("Field cannot be null") 1996 } 1997 err := q.assertIsDynamicQuery(field, "orderByDistanceDescending") 1998 if err != nil { 1999 return err 2000 } 2001 ensure := func(fieldName string, isNestedPath bool) (string, error) { 2002 return q.ensureValidFieldName(fieldName, isNestedPath) 2003 } 2004 fieldName, err := field.ToField(ensure) 2005 if err != nil { 2006 return err 2007 } 2008 return q.orderByDistanceDescendingLatLong("'"+fieldName+"'", latitude, longitude) 2009 } 2010 2011 func (q *abstractDocumentQuery) orderByDistanceDescendingLatLong(fieldName string, latitude float64, longitude float64) error { 2012 tok := orderByTokenCreateDistanceDescending(fieldName, q.addQueryParameter(latitude), q.addQueryParameter(longitude)) 2013 q.orderByTokens = append(q.orderByTokens, tok) 2014 return nil 2015 } 2016 2017 func (q *abstractDocumentQuery) orderByDistanceDescendingWktDynamic(field DynamicSpatialField, shapeWkt string) error { 2018 if field == nil { 2019 return newIllegalArgumentError("Field cannot be null") 2020 } 2021 err := q.assertIsDynamicQuery(field, "orderByDistanceDescending2") 2022 if err != nil { 2023 return err 2024 } 2025 ensure := func(fieldName string, isNestedPath bool) (string, error) { 2026 return q.ensureValidFieldName(fieldName, isNestedPath) 2027 } 2028 fieldName, err := field.ToField(ensure) 2029 if err != nil { 2030 return err 2031 } 2032 return q.orderByDistanceDescendingWkt("'"+fieldName+"'", shapeWkt) 2033 } 2034 2035 func (q *abstractDocumentQuery) orderByDistanceDescendingWkt(fieldName string, shapeWkt string) error { 2036 tok := orderByTokenCreateDistanceDescending2(fieldName, q.addQueryParameter(shapeWkt)) 2037 q.orderByTokens = append(q.orderByTokens, tok) 2038 return nil 2039 } 2040 2041 func (q *abstractDocumentQuery) assertIsDynamicQuery(dynamicField DynamicSpatialField, methodName string) error { 2042 if q.fromToken != nil && !q.fromToken.isDynamic { 2043 f := func(s string, f bool) (string, error) { 2044 return q.ensureValidFieldName(s, f) 2045 } 2046 fld, err := dynamicField.ToField(f) 2047 if err != nil { 2048 return err 2049 } 2050 return newIllegalStateError("Cannot execute query method '" + methodName + "'. Field '" + fld + "' cannot be used when static index '" + q.fromToken.indexName + "' is queried. Dynamic spatial fields can only be used with dynamic queries, " + "for static index queries please use valid spatial fields defined in index definition.") 2051 } 2052 return nil 2053 } 2054 2055 func (q *abstractDocumentQuery) initSync() error { 2056 if q.queryOperation != nil { 2057 return nil 2058 } 2059 2060 delegate := &DocumentQueryCustomization{ 2061 query: q, 2062 } 2063 beforeQueryEventArgs := &BeforeQueryEventArgs{ 2064 Session: q.theSession, 2065 QueryCustomization: delegate, 2066 } 2067 q.theSession.onBeforeQueryInvoke(beforeQueryEventArgs) 2068 2069 var err error 2070 q.queryOperation, err = q.initializeQueryOperation() 2071 if err != nil { 2072 return err 2073 } 2074 return q.executeActualQuery() 2075 } 2076 2077 func (q *abstractDocumentQuery) executeActualQuery() error { 2078 { 2079 context := q.queryOperation.enterQueryContext() 2080 defer func() { 2081 _ = context.Close() 2082 }() 2083 2084 command, err := q.queryOperation.createRequest() 2085 if err != nil { 2086 return err 2087 } 2088 if err = q.theSession.GetRequestExecutor().ExecuteCommand(command, q.theSession.sessionInfo); err != nil { 2089 return err 2090 } 2091 if err = q.queryOperation.setResult(command.Result); err != nil { 2092 return err 2093 } 2094 } 2095 q.invokeAfterQueryExecuted(q.queryOperation.currentQueryResults) 2096 return nil 2097 } 2098 2099 // GetQueryResult returns results of a query 2100 func (q *abstractDocumentQuery) getQueryResult() (*QueryResult, error) { 2101 err := q.initSync() 2102 if err != nil { 2103 return nil, err 2104 } 2105 2106 return q.queryOperation.currentQueryResults.createSnapshot(), nil 2107 } 2108 2109 // check if v is a valid argument to query GetResults(). 2110 // it must be map[string]*<type> where <type> is struct 2111 func checkValidGetResultsArg(v interface{}, argName string) error { 2112 return checkIsPtrSlice(v, argName) 2113 } 2114 2115 // GetResults executes the query and sets results to returned values. 2116 // results should be of type *[]<type> 2117 func (q *abstractDocumentQuery) GetResults(results interface{}) error { 2118 // Note: in Java it's called ToList 2119 if q.err != nil { 2120 return q.err 2121 } 2122 if q.err = checkValidGetResultsArg(results, "results"); q.err != nil { 2123 return q.err 2124 } 2125 return q.executeQueryOperation(results, -1) 2126 } 2127 2128 func checkValidSingleArg(v interface{}, argName string) error { 2129 if v == nil { 2130 return newIllegalArgumentError("%s can't be nil", argName) 2131 } 2132 return checkIsPtrPtrStruct(v, argName) 2133 } 2134 2135 // First runs a query and returns a first result. 2136 func (q *abstractDocumentQuery) First(result interface{}) error { 2137 if q.err != nil { 2138 return q.err 2139 } 2140 2141 if q.err = checkValidSingleArg(result, "result"); q.err != nil { 2142 return q.err 2143 } 2144 2145 tp := reflect.TypeOf(result) 2146 // **struct => *struct 2147 if tp.Kind() == reflect.Ptr && tp.Elem().Kind() == reflect.Ptr { 2148 tp = tp.Elem() 2149 } 2150 // create a pointer to a slice. executeQueryOperation creates the actual slice 2151 sliceType := reflect.SliceOf(tp) 2152 slicePtr := reflect.New(sliceType) 2153 err := q.executeQueryOperation(slicePtr.Interface(), 1) 2154 if err != nil { 2155 return err 2156 } 2157 slice := slicePtr.Elem() 2158 if slice.Len() == 0 { 2159 return nil 2160 } 2161 el := slice.Index(0) 2162 return setInterfaceToValue(result, el.Interface()) 2163 } 2164 2165 // Single runs a query that expects only a single result. 2166 // If there is more than one result, it returns IllegalStateError. 2167 func (q *abstractDocumentQuery) Single(result interface{}) error { 2168 if q.err != nil { 2169 return q.err 2170 } 2171 2172 if q.err = checkValidSingleArg(result, "result"); q.err != nil { 2173 return q.err 2174 } 2175 2176 tp := reflect.TypeOf(result) 2177 // **struct => *struct 2178 if tp.Kind() == reflect.Ptr && tp.Elem().Kind() == reflect.Ptr { 2179 tp = tp.Elem() 2180 } 2181 // create a pointer to a slice. executeQueryOperation creates the actual slice 2182 sliceType := reflect.SliceOf(tp) 2183 slicePtr := reflect.New(sliceType) 2184 err := q.executeQueryOperation(slicePtr.Interface(), 2) 2185 if err != nil { 2186 return err 2187 } 2188 slice := slicePtr.Elem() 2189 if slice.Len() != 1 { 2190 return newIllegalStateError("Expected single result, got: %d", slice.Len()) 2191 } 2192 el := slice.Index(0) 2193 return setInterfaceToValue(result, el.Interface()) 2194 } 2195 2196 func (q *abstractDocumentQuery) Count() (int, error) { 2197 if q.err != nil { 2198 return 0, q.err 2199 } 2200 q.take(0) 2201 queryResult, err := q.getQueryResult() 2202 if err != nil { 2203 return 0, err 2204 } 2205 return queryResult.TotalResults, nil 2206 } 2207 2208 // Any returns true if query returns at least one result 2209 func (q *abstractDocumentQuery) Any() (bool, error) { 2210 if q.err != nil { 2211 return false, q.err 2212 } 2213 if q.isDistinct() { 2214 // for distinct it is cheaper to do count 1 2215 2216 q.take(1) 2217 2218 err := q.initSync() 2219 if err != nil { 2220 return false, err 2221 } 2222 return q.queryOperation.currentQueryResults.TotalResults > 0, nil 2223 } 2224 2225 q.take(0) 2226 queryResult, err := q.getQueryResult() 2227 if err != nil { 2228 return false, err 2229 } 2230 return queryResult.TotalResults > 0, nil 2231 } 2232 2233 func (q *abstractDocumentQuery) executeQueryOperation(results interface{}, take int) error { 2234 if take != -1 && (q.pageSize == nil || *q.pageSize > take) { 2235 q.take(take) 2236 } 2237 2238 err := q.initSync() 2239 if err != nil { 2240 return err 2241 } 2242 2243 return q.queryOperation.complete(results) 2244 } 2245 2246 func (q *abstractDocumentQuery) aggregateBy(facet FacetBase) error { 2247 for _, token := range q.selectTokens { 2248 if _, ok := token.(*facetToken); ok { 2249 continue 2250 } 2251 2252 return newIllegalStateError("Aggregation query can select only facets while it got %T token", token) 2253 } 2254 2255 add := func(o interface{}) string { 2256 return q.addQueryParameter(o) 2257 } 2258 t, err := createFacetTokenWithFacetBase(facet, add) 2259 if err != nil { 2260 return err 2261 } 2262 q.selectTokens = append(q.selectTokens, t) 2263 return nil 2264 } 2265 2266 func (q *abstractDocumentQuery) aggregateUsing(facetSetupDocumentID string) error { 2267 token, err := createFacetToken(facetSetupDocumentID) 2268 if err != nil { 2269 return err 2270 } 2271 q.selectTokens = append(q.selectTokens, token) 2272 return nil 2273 } 2274 2275 func (q *abstractDocumentQuery) Lazily() (*Lazy, error) { 2276 if q.err != nil { 2277 return nil, q.err 2278 } 2279 if q.queryOperation == nil { 2280 q.queryOperation, q.err = q.initializeQueryOperation() 2281 if q.err != nil { 2282 return nil, q.err 2283 } 2284 } 2285 2286 lazyQueryOperation := newLazyQueryOperation(q.theSession.GetConventions(), q.queryOperation, q.afterQueryExecutedCallback) 2287 return q.theSession.session.addLazyOperation(lazyQueryOperation, nil, nil), nil 2288 } 2289 2290 // CountLazily returns a lazy operation that returns number of results in a query. It'll set *count to 2291 // number of results after Lazy.GetResult() is called. 2292 // results should be of type []<type> and is only provided so that we know this is a query for <type> 2293 // TODO: figure out better API. 2294 func (q *abstractDocumentQuery) CountLazily() (*Lazy, error) { 2295 if q.queryOperation == nil { 2296 q.take(0) 2297 var err error 2298 q.queryOperation, err = q.initializeQueryOperation() 2299 if err != nil { 2300 return nil, err 2301 } 2302 } 2303 2304 lazyQueryOperation := newLazyQueryOperation(q.theSession.GetConventions(), q.queryOperation, q.afterQueryExecutedCallback) 2305 return q.theSession.session.addLazyCountOperation(lazyQueryOperation), nil 2306 } 2307 2308 // suggestUsing adds a query part for suggestions 2309 func (q *abstractDocumentQuery) suggestUsing(suggestion SuggestionBase) error { 2310 if suggestion == nil { 2311 return newIllegalArgumentError("suggestion cannot be null") 2312 } 2313 2314 if err := q.assertCanSuggest(); err != nil { 2315 return err 2316 } 2317 2318 var token *suggestToken 2319 2320 if term, ok := suggestion.(*SuggestionWithTerm); ok { 2321 token = &suggestToken{ 2322 fieldName: term.Field, 2323 termParameterName: q.addQueryParameter(term.Term), 2324 optionsParameterName: q.getOptionsParameterName(term.Options), 2325 } 2326 } else if terms, ok := suggestion.(*SuggestionWithTerms); ok { 2327 token = &suggestToken{ 2328 fieldName: terms.Field, 2329 termParameterName: q.addQueryParameter(terms.Terms), 2330 optionsParameterName: q.getOptionsParameterName(terms.Options), 2331 } 2332 } else { 2333 return newUnsupportedOperationError("Unknown type of suggestion: %T", suggestion) 2334 } 2335 q.selectTokens = append(q.selectTokens, token) 2336 return nil 2337 } 2338 2339 func (q *abstractDocumentQuery) getOptionsParameterName(options *SuggestionOptions) string { 2340 optionsParameterName := "" 2341 if options != nil && options != SuggestionOptionsDefaultOptions { 2342 optionsParameterName = q.addQueryParameter(options) 2343 } 2344 2345 return optionsParameterName 2346 } 2347 2348 func (q *abstractDocumentQuery) assertCanSuggest() error { 2349 if len(q.whereTokens) > 0 { 2350 return newIllegalStateError("Cannot add suggest when WHERE statements are present.") 2351 } 2352 2353 if len(q.selectTokens) > 0 { 2354 return newIllegalStateError("Cannot add suggest when SELECT statements are present.") 2355 } 2356 2357 if len(q.orderByTokens) > 0 { 2358 return newIllegalStateError("Cannot add suggest when ORDER BY statements are present.") 2359 } 2360 return nil 2361 }