Use functional opts for searches
Signed-off-by: Vartan Benohanian <vartanbeno@gmail.com>
This commit is contained in:
parent
2696d8e32c
commit
7b83e8366a
3 changed files with 378 additions and 161 deletions
404
search.go
404
search.go
|
@ -3,7 +3,6 @@ package geddit
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -12,10 +11,12 @@ import (
|
||||||
// IMPORTANT: for searches to include NSFW results, the
|
// IMPORTANT: for searches to include NSFW results, the
|
||||||
// user must check the following in their preferences:
|
// user must check the following in their preferences:
|
||||||
// "include not safe for work (NSFW) search results in searches"
|
// "include not safe for work (NSFW) search results in searches"
|
||||||
|
// Note: The "limit" parameter in searches is prone to inconsistent
|
||||||
|
// behaviour.
|
||||||
type SearchService interface {
|
type SearchService interface {
|
||||||
Posts(query string) *PostSearchBuilder
|
Posts(query string, opts ...SearchOpt) *PostSearcher
|
||||||
Subreddits(query string) *SubredditSearchBuilder
|
Subreddits(query string, opts ...SearchOpt) *SubredditSearcher
|
||||||
Users(query string) *UserSearchBuilder
|
Users(query string, opts ...SearchOpt) *UserSearcher
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchServiceOp implements the VoteService interface
|
// SearchServiceOp implements the VoteService interface
|
||||||
|
@ -27,115 +28,58 @@ var _ SearchService = &SearchServiceOp{}
|
||||||
|
|
||||||
// Posts searches for posts.
|
// Posts searches for posts.
|
||||||
// By default, it searches for the most relevant posts of all time.
|
// By default, it searches for the most relevant posts of all time.
|
||||||
// To change the sorting, use PostSearchBuilder.Sort().
|
func (s *SearchServiceOp) Posts(query string, opts ...SearchOpt) *PostSearcher {
|
||||||
// Possible sort options: relevance, hot, top, new, comments.
|
sr := new(PostSearcher)
|
||||||
// To change the timespan, use PostSearchBuilder.Timespan().
|
sr.client = s.client
|
||||||
// Possible timespan options: hour, day, week, month, year, all.
|
sr.opts.Query = query
|
||||||
func (s *SearchServiceOp) Posts(query string) *PostSearchBuilder {
|
sr.opts.Type = "link"
|
||||||
b := new(PostSearchBuilder)
|
sr.opts.Sort = SortRelevance.String()
|
||||||
b.client = s.client
|
sr.opts.Timespan = TimespanAll.String()
|
||||||
b.opts.Query = query
|
for _, opt := range opts {
|
||||||
b.opts.Type = "link"
|
opt(sr)
|
||||||
return b.Sort(SortRelevance).Timespan(TimespanAll)
|
}
|
||||||
|
return sr
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subreddits searches for subreddits.
|
// Subreddits searches for subreddits.
|
||||||
func (s *SearchServiceOp) Subreddits(query string) *SubredditSearchBuilder {
|
func (s *SearchServiceOp) Subreddits(query string, opts ...SearchOpt) *SubredditSearcher {
|
||||||
b := new(SubredditSearchBuilder)
|
sr := new(SubredditSearcher)
|
||||||
b.client = s.client
|
sr.client = s.client
|
||||||
b.opts.Query = query
|
sr.opts.Query = query
|
||||||
b.opts.Type = "sr"
|
sr.opts.Type = "sr"
|
||||||
return b
|
for _, opt := range opts {
|
||||||
|
opt(sr)
|
||||||
|
}
|
||||||
|
return sr
|
||||||
}
|
}
|
||||||
|
|
||||||
// Users searches for users.
|
// Users searches for users.
|
||||||
func (s *SearchServiceOp) Users(query string) *UserSearchBuilder {
|
func (s *SearchServiceOp) Users(query string, opts ...SearchOpt) *UserSearcher {
|
||||||
b := new(UserSearchBuilder)
|
sr := new(UserSearcher)
|
||||||
b.client = s.client
|
sr.client = s.client
|
||||||
b.opts.Query = query
|
sr.opts.Query = query
|
||||||
b.opts.Type = "user"
|
sr.opts.Type = "user"
|
||||||
return b
|
for _, opt := range opts {
|
||||||
|
opt(sr)
|
||||||
|
}
|
||||||
|
return sr
|
||||||
}
|
}
|
||||||
|
|
||||||
type searchOpts struct {
|
// PostSearcher helps conducts searches that return posts.
|
||||||
Query string `url:"q"`
|
type PostSearcher struct {
|
||||||
Type string `url:"type,omitempty"`
|
clientSearcher
|
||||||
After string `url:"after,omitempty"`
|
|
||||||
Before string `url:"before,omitempty"`
|
|
||||||
Limit int `url:"limit,omitempty"`
|
|
||||||
RestrictSubreddits bool `url:"restrict_sr,omitempty"`
|
|
||||||
Sort string `url:"sort,omitempty"`
|
|
||||||
Timespan string `url:"t,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// PostSearchBuilder helps conducts searches that return posts.
|
|
||||||
type PostSearchBuilder struct {
|
|
||||||
client *Client
|
|
||||||
subreddits []string
|
subreddits []string
|
||||||
opts searchOpts
|
after string
|
||||||
|
Results []Link
|
||||||
}
|
}
|
||||||
|
|
||||||
// After sets the after option.
|
func (s *PostSearcher) search(ctx context.Context) (*Links, *Response, error) {
|
||||||
func (b *PostSearchBuilder) After(after string) *PostSearchBuilder {
|
|
||||||
b.opts.After = after
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// Before sets the before option.
|
|
||||||
func (b *PostSearchBuilder) Before(before string) *PostSearchBuilder {
|
|
||||||
b.opts.Before = before
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// Limit sets the limit option.
|
|
||||||
func (b *PostSearchBuilder) Limit(limit int) *PostSearchBuilder {
|
|
||||||
b.opts.Limit = limit
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromSubreddits restricts the search to happen in the specified subreddits only.
|
|
||||||
func (b *PostSearchBuilder) FromSubreddits(subreddits ...string) *PostSearchBuilder {
|
|
||||||
b.subreddits = subreddits
|
|
||||||
b.opts.RestrictSubreddits = len(subreddits) > 0
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromAll runs the search against r/all.
|
|
||||||
func (b *PostSearchBuilder) FromAll() *PostSearchBuilder {
|
|
||||||
return b.FromSubreddits()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort sets the sort option.
|
|
||||||
func (b *PostSearchBuilder) Sort(sort Sort) *PostSearchBuilder {
|
|
||||||
b.opts.Sort = sort.String()
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// Timespan sets the timespan option.
|
|
||||||
func (b *PostSearchBuilder) Timespan(timespan Timespan) *PostSearchBuilder {
|
|
||||||
b.opts.Timespan = timespan.String()
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do conducts the search.
|
|
||||||
func (b *PostSearchBuilder) Do(ctx context.Context) (*Links, *Response, error) {
|
|
||||||
path := "search"
|
path := "search"
|
||||||
if len(b.subreddits) > 0 {
|
if len(s.subreddits) > 0 {
|
||||||
path = fmt.Sprintf("r/%s/search", strings.Join(b.subreddits, "+"))
|
path = fmt.Sprintf("r/%s/search", strings.Join(s.subreddits, "+"))
|
||||||
}
|
}
|
||||||
|
|
||||||
path, err := addOptions(path, b.opts)
|
root, resp, err := s.clientSearcher.Do(ctx, path)
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
req, err := b.client.NewRequest(http.MethodGet, path, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
root := new(rootListing)
|
|
||||||
resp, err := b.client.Do(ctx, req, root)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, resp, err
|
return nil, resp, err
|
||||||
}
|
}
|
||||||
|
@ -143,94 +87,232 @@ func (b *PostSearchBuilder) Do(ctx context.Context) (*Links, *Response, error) {
|
||||||
return root.getLinks(), resp, nil
|
return root.getLinks(), resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubredditSearchBuilder helps conducts searches that return subreddits.
|
// Search runs the searcher.
|
||||||
type SubredditSearchBuilder struct {
|
// The first return value tells the user if there are
|
||||||
client *Client
|
// more results that were cut off (due to the limit).
|
||||||
opts searchOpts
|
func (s *PostSearcher) Search(ctx context.Context) (bool, *Response, error) {
|
||||||
|
root, resp, err := s.search(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return false, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Results = root.Links
|
||||||
|
s.after = root.After
|
||||||
|
|
||||||
|
// if the "after" value is non-empty, it
|
||||||
|
// means there are more results to come.
|
||||||
|
moreResultsExist := s.after != ""
|
||||||
|
|
||||||
|
return moreResultsExist, resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// After sets the after option.
|
// More runs the searcher again and adds to the results.
|
||||||
func (b *SubredditSearchBuilder) After(after string) *SubredditSearchBuilder {
|
// The first return value tells the user if there are
|
||||||
b.opts.After = after
|
// more results that were cut off (due to the limit).
|
||||||
return b
|
func (s *PostSearcher) More(ctx context.Context) (bool, *Response, error) {
|
||||||
|
if s.after == "" {
|
||||||
|
return s.Search(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.setAfter(s.after)
|
||||||
|
|
||||||
|
root, resp, err := s.search(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return false, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Results = append(s.Results, root.Links...)
|
||||||
|
s.after = root.After
|
||||||
|
|
||||||
|
// if the "after" value is non-empty, it
|
||||||
|
// means there are more results to come.
|
||||||
|
moreResultsExist := s.after != ""
|
||||||
|
|
||||||
|
return moreResultsExist, resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Before sets the before option.
|
// All runs the searcher until it yields no more results.
|
||||||
func (b *SubredditSearchBuilder) Before(before string) *SubredditSearchBuilder {
|
// The limit is set to 100, just to make the least amount
|
||||||
b.opts.Before = before
|
// of requests possible. It is reset to its original value after.
|
||||||
return b
|
func (s *PostSearcher) All(ctx context.Context) error {
|
||||||
|
limit := s.opts.Limit
|
||||||
|
|
||||||
|
s.setLimit(100)
|
||||||
|
defer s.setLimit(limit)
|
||||||
|
|
||||||
|
var ok = true
|
||||||
|
var err error
|
||||||
|
|
||||||
|
for ok {
|
||||||
|
ok, _, err = s.More(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Limit sets the limit option.
|
// SubredditSearcher helps conducts searches that return subreddits.
|
||||||
func (b *SubredditSearchBuilder) Limit(limit int) *SubredditSearchBuilder {
|
type SubredditSearcher struct {
|
||||||
b.opts.Limit = limit
|
clientSearcher
|
||||||
return b
|
after string
|
||||||
|
Results []Subreddit
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do conducts the search.
|
func (s *SubredditSearcher) search(ctx context.Context) (*Subreddits, *Response, error) {
|
||||||
func (b *SubredditSearchBuilder) Do(ctx context.Context) (*Subreddits, *Response, error) {
|
|
||||||
path := "search"
|
path := "search"
|
||||||
path, err := addOptions(path, b.opts)
|
root, resp, err := s.clientSearcher.Do(ctx, path)
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
req, err := b.client.NewRequest(http.MethodGet, path, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
root := new(rootListing)
|
|
||||||
resp, err := b.client.Do(ctx, req, root)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, resp, err
|
return nil, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return root.getSubreddits(), resp, nil
|
return root.getSubreddits(), resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserSearchBuilder helps conducts searches that return posts.
|
// Search runs the searcher.
|
||||||
type UserSearchBuilder struct {
|
// The first return value tells the user if there are
|
||||||
client *Client
|
// more results that were cut off (due to the limit).
|
||||||
opts searchOpts
|
func (s *SubredditSearcher) Search(ctx context.Context) (bool, *Response, error) {
|
||||||
|
root, resp, err := s.search(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return false, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Results = root.Subreddits
|
||||||
|
s.after = root.After
|
||||||
|
|
||||||
|
// if the "after" value is non-empty, it
|
||||||
|
// means there are more results to come.
|
||||||
|
moreResultsExist := s.after != ""
|
||||||
|
|
||||||
|
return moreResultsExist, resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// After sets the after option.
|
// More runs the searcher again and adds to the results.
|
||||||
func (b *UserSearchBuilder) After(after string) *UserSearchBuilder {
|
// The first return value tells the user if there are
|
||||||
b.opts.After = after
|
// more results that were cut off (due to the limit).
|
||||||
return b
|
func (s *SubredditSearcher) More(ctx context.Context) (bool, *Response, error) {
|
||||||
|
if s.after == "" {
|
||||||
|
return s.Search(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.setAfter(s.after)
|
||||||
|
|
||||||
|
root, resp, err := s.search(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return false, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Results = append(s.Results, root.Subreddits...)
|
||||||
|
s.after = root.After
|
||||||
|
|
||||||
|
// if the "after" value is non-empty, it
|
||||||
|
// means there are more results to come.
|
||||||
|
moreResultsExist := s.after != ""
|
||||||
|
|
||||||
|
return moreResultsExist, resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Before sets the before option.
|
// All runs the searcher until it yields no more results.
|
||||||
func (b *UserSearchBuilder) Before(before string) *UserSearchBuilder {
|
// The limit is set to 100, just to make the least amount
|
||||||
b.opts.Before = before
|
// of requests possible. It is reset to its original value after.
|
||||||
return b
|
func (s *SubredditSearcher) All(ctx context.Context) error {
|
||||||
|
limit := s.opts.Limit
|
||||||
|
|
||||||
|
s.setLimit(100)
|
||||||
|
defer s.setLimit(limit)
|
||||||
|
|
||||||
|
var ok = true
|
||||||
|
var err error
|
||||||
|
|
||||||
|
for ok {
|
||||||
|
ok, _, err = s.More(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Limit sets the limit option.
|
// UserSearcher helps conducts searches that return users.
|
||||||
func (b *UserSearchBuilder) Limit(limit int) *UserSearchBuilder {
|
type UserSearcher struct {
|
||||||
b.opts.Limit = limit
|
clientSearcher
|
||||||
return b
|
after string
|
||||||
|
Results []User
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do conducts the search.
|
func (s *UserSearcher) search(ctx context.Context) (*Users, *Response, error) {
|
||||||
func (b *UserSearchBuilder) Do(ctx context.Context) (*Users, *Response, error) {
|
|
||||||
path := "search"
|
path := "search"
|
||||||
path, err := addOptions(path, b.opts)
|
root, resp, err := s.clientSearcher.Do(ctx, path)
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
req, err := b.client.NewRequest(http.MethodGet, path, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
root := new(rootListing)
|
|
||||||
resp, err := b.client.Do(ctx, req, root)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, resp, err
|
return nil, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return root.getUsers(), resp, nil
|
return root.getUsers(), resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Search runs the searcher.
|
||||||
|
// The first return value tells the user if there are
|
||||||
|
// more results that were cut off (due to the limit).
|
||||||
|
func (s *UserSearcher) Search(ctx context.Context) (bool, *Response, error) {
|
||||||
|
root, resp, err := s.search(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return false, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Results = root.Users
|
||||||
|
s.after = root.After
|
||||||
|
|
||||||
|
// if the "after" value is non-empty, it
|
||||||
|
// means there are more results to come.
|
||||||
|
moreResultsExist := s.after != ""
|
||||||
|
|
||||||
|
return moreResultsExist, resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// More runs the searcher again and adds to the results.
|
||||||
|
// The first return value tells the user if there are
|
||||||
|
// more results that were cut off (due to the limit).
|
||||||
|
func (s *UserSearcher) More(ctx context.Context) (bool, *Response, error) {
|
||||||
|
if s.after == "" {
|
||||||
|
return s.Search(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.setAfter(s.after)
|
||||||
|
|
||||||
|
root, resp, err := s.search(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return false, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Results = append(s.Results, root.Users...)
|
||||||
|
s.after = root.After
|
||||||
|
|
||||||
|
// if the "after" value is non-empty, it
|
||||||
|
// means there are more results to come.
|
||||||
|
moreResultsExist := s.after != ""
|
||||||
|
|
||||||
|
return moreResultsExist, resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// All runs the searcher until it yields no more results.
|
||||||
|
// The limit is set to 100, just to make the least amount
|
||||||
|
// of requests possible. It is reset to its original value after.
|
||||||
|
func (s *UserSearcher) All(ctx context.Context) error {
|
||||||
|
limit := s.opts.Limit
|
||||||
|
|
||||||
|
s.setLimit(100)
|
||||||
|
defer s.setLimit(limit)
|
||||||
|
|
||||||
|
var ok = true
|
||||||
|
var err error
|
||||||
|
|
||||||
|
for ok {
|
||||||
|
ok, _, err = s.More(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
134
searcher.go
Normal file
134
searcher.go
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
package geddit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// todo: query parameter "show" = "all"
|
||||||
|
|
||||||
|
// Searcher defines some parameters common to all requests
|
||||||
|
// used to conduct searches against the Reddit API.
|
||||||
|
type Searcher interface {
|
||||||
|
setAfter(string)
|
||||||
|
setBefore(string)
|
||||||
|
setLimit(int)
|
||||||
|
setSort(Sort)
|
||||||
|
setTimespan(Timespan)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contains all options used for searching.
|
||||||
|
// Not all are used for every search endpoint.
|
||||||
|
// For example, for getting a user's posts, "q" is not used.
|
||||||
|
// After/Before are used as the anchor points for subsequent searches.
|
||||||
|
// Limit is the maximum number of items to be returned (default: 25, max: 100).
|
||||||
|
// Sort: hot, new, top, controversial, etc.
|
||||||
|
// Timespan: hour, day, week, month, year, all.
|
||||||
|
type searchOpts struct {
|
||||||
|
Query string `url:"q,omitempty"`
|
||||||
|
Type string `url:"type,omitempty"`
|
||||||
|
After string `url:"after,omitempty"`
|
||||||
|
Before string `url:"before,omitempty"`
|
||||||
|
Limit int `url:"limit,omitempty"`
|
||||||
|
RestrictSubreddits bool `url:"restrict_sr,omitempty"`
|
||||||
|
Sort string `url:"sort,omitempty"`
|
||||||
|
Timespan string `url:"t,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type clientSearcher struct {
|
||||||
|
client *Client
|
||||||
|
opts searchOpts
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Searcher = &clientSearcher{}
|
||||||
|
|
||||||
|
func (s *clientSearcher) setAfter(v string) {
|
||||||
|
s.opts.After = v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *clientSearcher) setBefore(v string) {
|
||||||
|
s.opts.Before = v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *clientSearcher) setLimit(v int) {
|
||||||
|
s.opts.Limit = v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *clientSearcher) setSort(v Sort) {
|
||||||
|
s.opts.Sort = v.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *clientSearcher) setTimespan(v Timespan) {
|
||||||
|
s.opts.Timespan = v.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *clientSearcher) Do(ctx context.Context, path string) (*rootListing, *Response, error) {
|
||||||
|
path, err := addOptions(path, s.opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
root := new(rootListing)
|
||||||
|
resp, err := s.client.Do(ctx, req, root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return root, resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SearchOpt sets search options.
|
||||||
|
type SearchOpt func(s Searcher)
|
||||||
|
|
||||||
|
// SetAfter sets the after option.
|
||||||
|
func SetAfter(v string) SearchOpt {
|
||||||
|
return func(s Searcher) {
|
||||||
|
s.setAfter(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBefore sets the before option.
|
||||||
|
func SetBefore(v string) SearchOpt {
|
||||||
|
return func(s Searcher) {
|
||||||
|
s.setBefore(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLimit sets the limit option.
|
||||||
|
func SetLimit(v int) SearchOpt {
|
||||||
|
return func(s Searcher) {
|
||||||
|
s.setLimit(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSort sets the sort option.
|
||||||
|
func SetSort(v Sort) SearchOpt {
|
||||||
|
return func(s Searcher) {
|
||||||
|
s.setSort(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTimespan sets the timespan option.
|
||||||
|
func SetTimespan(v Timespan) SearchOpt {
|
||||||
|
return func(s Searcher) {
|
||||||
|
s.setTimespan(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromSubreddits is an option that restricts the
|
||||||
|
// search to happen in the specified subreddits.
|
||||||
|
// If none are specified, it's like searching r/all.
|
||||||
|
// This option is only applicable to the PostSearcher.
|
||||||
|
func FromSubreddits(subreddits ...string) SearchOpt {
|
||||||
|
return func(s Searcher) {
|
||||||
|
if ps, ok := s.(*PostSearcher); ok {
|
||||||
|
ps.subreddits = subreddits
|
||||||
|
ps.opts.RestrictSubreddits = len(subreddits) > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
user.go
1
user.go
|
@ -55,6 +55,7 @@ type User struct {
|
||||||
IsEmployee bool `json:"is_employee"`
|
IsEmployee bool `json:"is_employee"`
|
||||||
HasVerifiedEmail bool `json:"has_verified_email"`
|
HasVerifiedEmail bool `json:"has_verified_email"`
|
||||||
NSFW bool `json:"over_18"`
|
NSFW bool `json:"over_18"`
|
||||||
|
IsSuspended bool `json:"is_suspended"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserShort represents a Reddit user, but contains fewer pieces of information
|
// UserShort represents a Reddit user, but contains fewer pieces of information
|
||||||
|
|
Loading…
Reference in a new issue