GEORADIUS key x y radius unit [WITHDIST] [WITHHASH] [WITHCOORD] [ASC|DESC] * [COUNT count [ANY]] [STORE key] [STOREDIST key] * GEORADIUSBYMEMBER key member radius unit ... options ... * GEOSEARCH key [FROMMEMBER member] [FROMLONLAT long lat] [BYRADIUS radius unit] * [BYBOX width height unit] [WITHCOORD] [WITHDIST] [WITHASH] [COUNT count [ANY]] [ASC|D
| 514 | * [BYBOX width height unit] [WITHCORD] [WITHDIST] [WITHASH] [COUNT count [ANY]] [ASC|DESC] [STOREDIST] |
| 515 | * */ |
| 516 | void georadiusGeneric(client *c, int srcKeyIndex, int flags) { |
| 517 | robj *storekey = NULL; |
| 518 | int storedist = 0; /* 0 for STORE, 1 for STOREDIST. */ |
| 519 | |
| 520 | /* Look up the requested zset */ |
| 521 | robj_roptr zobj = lookupKeyRead(c->db, c->argv[srcKeyIndex]); |
| 522 | if (checkType(c, zobj, OBJ_ZSET)) return; |
| 523 | |
| 524 | /* Find long/lat to use for radius or box search based on inquiry type */ |
| 525 | int base_args; |
| 526 | GeoShape shape = {0}; |
| 527 | if (flags & RADIUS_COORDS) { |
| 528 | /* GEORADIUS or GEORADIUS_RO */ |
| 529 | base_args = 6; |
| 530 | shape.type = CIRCULAR_TYPE; |
| 531 | if (extractLongLatOrReply(c, c->argv + 2, shape.xy) == C_ERR) return; |
| 532 | if (extractDistanceOrReply(c, c->argv+base_args-2, &shape.conversion, &shape.t.radius) != C_OK) return; |
| 533 | } else if ((flags & RADIUS_MEMBER) && !zobj) { |
| 534 | /* We don't have a source key, but we need to proceed with argument |
| 535 | * parsing, so we know which reply to use depending on the STORE flag. */ |
| 536 | base_args = 5; |
| 537 | } else if (flags & RADIUS_MEMBER) { |
| 538 | /* GEORADIUSBYMEMBER or GEORADIUSBYMEMBER_RO */ |
| 539 | base_args = 5; |
| 540 | shape.type = CIRCULAR_TYPE; |
| 541 | robj *member = c->argv[2]; |
| 542 | if (longLatFromMember(zobj, member, shape.xy) == C_ERR) { |
| 543 | addReplyError(c, "could not decode requested zset member"); |
| 544 | return; |
| 545 | } |
| 546 | if (extractDistanceOrReply(c, c->argv+base_args-2, &shape.conversion, &shape.t.radius) != C_OK) return; |
| 547 | } else if (flags & GEOSEARCH) { |
| 548 | /* GEOSEARCH or GEOSEARCHSTORE */ |
| 549 | base_args = 2; |
| 550 | if (flags & GEOSEARCHSTORE) { |
| 551 | base_args = 3; |
| 552 | storekey = c->argv[1]; |
| 553 | } |
| 554 | } else { |
| 555 | addReplyError(c, "Unknown georadius search type"); |
| 556 | return; |
| 557 | } |
| 558 | |
| 559 | /* Discover and populate all optional parameters. */ |
| 560 | int withdist = 0, withhash = 0, withcoords = 0; |
| 561 | int frommember = 0, fromloc = 0, byradius = 0, bybox = 0; |
| 562 | int sort = SORT_NONE; |
| 563 | int any = 0; /* any=1 means a limited search, stop as soon as enough results were found. */ |
| 564 | long long count = 0; /* Max number of results to return. 0 means unlimited. */ |
| 565 | if (c->argc > base_args) { |
| 566 | int remaining = c->argc - base_args; |
| 567 | for (int i = 0; i < remaining; i++) { |
| 568 | char *arg = szFromObj(c->argv[base_args + i]); |
| 569 | if (!strcasecmp(arg, "withdist")) { |
| 570 | withdist = 1; |
| 571 | } else if (!strcasecmp(arg, "withhash")) { |
| 572 | withhash = 1; |
| 573 | } else if (!strcasecmp(arg, "withcoord")) { |
no test coverage detected