Module: X::Resources::UserFinders

Includes:
BatchFinders
Included in:
User
Defined in:
x-resources/lib/x/resources/user_finders.rb

Overview

Class methods that look users up by identifier or username, and the authenticated user, extended into User

Internal to x-resources: the methods it gives User, such as X::User.find_by_username, are public API, but the module is only how they are shared, and which classes extend or include it can change within 1.x.

Instance Method Summary collapse

Instance Method Details

#current(client:, **params) {|problem| ... } ⇒ User?

Look up the authenticated user

Its path names no user, so a 404 to it is no user that is missing, and raises X::NotFound as any request does.

Examples:

Look up the authenticated user

X::User.current(client: client)

Parameters:

  • client (Object) —

    the client used to make the request

  • params (Hash) —

    query parameters merged over the default parameters

Yield Parameters:

  • problem (Problem) —

    each problem the API reported

Returns:

  • (User, nil) —

    the authenticated user



221
222
223
# File 'x-resources/lib/x/resources/user_finders.rb', line 221

def current(client:, **params, &)
  lookup("users/me", client:, **params, &) #: User?
end

#current!(client:, **params) ⇒ User

Look up the authenticated user, who must be found

Examples:

Look up the authenticated user

X::User.current!(client: client)

Parameters:

  • client (Object) —

    the client used to make the request

  • params (Hash) —

    query parameters merged over the default parameters

Returns:

  • (User) —

    the authenticated user

Raises:



234
235
236
237
# File 'x-resources/lib/x/resources/user_finders.rb', line 234

def current!(client:, **params)
  problems = [] #: Array[Problem]
  current(client:, **params) { |problem| problems << problem } || raise(MissingResource.new("users/me returned no user", problems:))
end

#find(id_or_username, client:, **params) {|problem| ... } ⇒ User?

Look up a user by identifier or username

An Integer or a user is looked up by identifier, and a String by username, with or without a leading at sign.

Examples:

Look up a user by username

X::User.find("sferik", client: client)

Parameters:

  • id_or_username (Integer, User, String) —

    an identifier or a user, or a username

  • client (Object) —

    the client used to make the request

  • params (Hash) —

    query parameters merged over the default parameters

Yield Parameters:

  • problem (Problem) —

    each problem the API reported, such as a user that was not found

Returns:

  • (User, nil) —

    the user or nil if the user was not found, whether the API answers 200 with no data or a 404 that reports the user as not found

Raises:

  • (X::NotFound) —

    if the API answers any other 404, such as one from a client pointed at the wrong host or API version

  • (ArgumentError) —

    if the value is neither an identifier nor a username



34
35
36
37
38
# File 'x-resources/lib/x/resources/user_finders.rb', line 34

def find(id_or_username, client:, **params, &)
  return super if Utils.id?(id_or_username)

  find_by_username(_ = id_or_username, client:, **params, &)
end

#find!(id_or_username, client:, **params) ⇒ User

Look up a user by identifier or username, which must exist

An Integer or a user is looked up by identifier, and a String by username, as find looks them up, so the error it raises names a username as find_by_username! names one, with the at sign of a handle.

Examples:

Look up a user by username

X::User.find!("sferik", client: client)

Parameters:

  • id_or_username (Integer, User, String) —

    an identifier or a user, or a username

  • client (Object) —

    the client used to make the request

  • params (Hash) —

    query parameters merged over the default parameters

Returns:

  • (User) —

    the user

Raises:

  • (ArgumentError) —

    if the value is neither an identifier nor a username

  • (MissingResource) —

    if the user was not found, whether the API answers 200 with no data or a 404 that reports the user as not found

  • (X::NotFound) —

    if the API answers any other 404, such as one from a client pointed at the wrong host or API version



57
58
59
60
61
# File 'x-resources/lib/x/resources/user_finders.rb', line 57

def find!(id_or_username, client:, **params)
  return super if Utils.id?(id_or_username)

  find_by_username!(_ = id_or_username, client:, **params)
end

#find_all(ids_or_usernames, client:, concurrency: DEFAULT_CONCURRENCY, **params) {|problem| ... } ⇒ Array<User>

Look up many users by identifier or username, in parallel batches

Integers and users are looked up by identifier, and Strings by username. The users come back in the order they were asked for, one for each value that was found, so a user asked for twice, by identifier or by username, comes back twice, without the ones that were not found. Every username is checked before any request, so one that is not a username raises before the identifiers are looked up, and billed.

Examples:

Look up many users by username

X::User.find_all(["sferik", "gem"], client: client)

Parameters:

  • ids_or_usernames (Array<Integer, User, String>) —

    identifiers or users, or usernames

  • client (Object) —

    the client used to make the requests

  • concurrency (Integer) (defaults to: DEFAULT_CONCURRENCY) —

    the number of batches looked up at once, which must be at least one; the identifiers and the usernames are looked up one kind after the other, each kind that many batches at a time

  • params (Hash) —

    query parameters merged over the default parameters

Yield Parameters:

  • problem (Problem) —

    each problem the API reported, such as a user that was not found

Returns:

  • (Array<User>) —

    the users that were found, one for each value that names one, frozen

Raises:

  • (ArgumentError) —

    if a String is not a username, or if the concurrency is less than one, before any request



81
82
83
84
85
86
# File 'x-resources/lib/x/resources/user_finders.rb', line 81

def find_all(ids_or_usernames, client:, concurrency: DEFAULT_CONCURRENCY, **params, &)
  ids, usernames = ids_or_usernames.partition { |value| Utils.id?(value) }
  usernames.each { |username| Utils.username!(username) }
  found = super(ids, client:, concurrency:, **params) #: Array[User]
  in_order(found + find_all_by_username(_ = usernames, client:, concurrency:, **params, &), ids_or_usernames)
end

#find_all_by_id(ids, client:, concurrency: DEFAULT_CONCURRENCY, **params) {|problem| ... } ⇒ Array<User>

Look up many users by identifier, in parallel batches

A String of digits is an identifier, as it is read from a response or an environment variable, so this looks the accounts those numbers identify up, where find_all would take them for usernames. The users come back in the order they were asked for, one for each identifier that was found, as find_all returns them.

Examples:

Look up many users by identifier, read as Strings

X::User.find_all_by_id(ENV.fetch("USER_IDS").split(","), client: client)

Parameters:

  • ids (Array<String, Integer, User>) —

    the identifiers, or users

  • client (Object) —

    the client used to make the requests

  • concurrency (Integer) (defaults to: DEFAULT_CONCURRENCY) —

    the number of batches looked up at once, which must be at least one

  • params (Hash) —

    query parameters merged over the default parameters

Yield Parameters:

  • problem (Problem) —

    each problem the API reported, such as an identifier that was not found

Returns:

  • (Array<User>) —

    the users that were found, one for each identifier that names one, frozen

Raises:

  • (ArgumentError) —

    if a value is not an identifier, or if the concurrency is less than one



104
105
106
107
# File 'x-resources/lib/x/resources/user_finders.rb', line 104

def find_all_by_id(ids, client:, concurrency: DEFAULT_CONCURRENCY, **params, &)
  ids = ids.map { |id| Utils.id_of(id, self) }
  in_order_of(lookup_in_batches(endpoint!, batch_key, ids, client:, concurrency:, **params, &), ids) #: Array[User]
end

#find_all_by_username(usernames, client:, concurrency: DEFAULT_CONCURRENCY, **params) {|problem| ... } ⇒ Array<User>

Look up many users by username, in parallel batches

The users come back in the order they were asked for, one for each username that was found, whatever its case, as find_all returns them, and each username is asked for once, however often, and in whatever case, it is given.

Examples:

Look up many users by username

X::User.find_all_by_username(["sferik", "gem"], client: client)

Parameters:

  • usernames (Array<String>) —

    the usernames, with or without leading at signs

  • client (Object) —

    the client used to make the requests

  • concurrency (Integer) (defaults to: DEFAULT_CONCURRENCY) —

    the number of batches looked up at once, which must be at least one

  • params (Hash) —

    query parameters merged over the default parameters

Yield Parameters:

  • problem (Problem) —

    each problem the API reported, such as a username that was not found

Returns:

  • (Array<User>) —

    the users that were found, one for each username that names one, frozen

Raises:

  • (ArgumentError) —

    if a value is not a username, or if the concurrency is less than one



165
166
167
168
169
# File 'x-resources/lib/x/resources/user_finders.rb', line 165

def find_all_by_username(usernames, client:, concurrency: DEFAULT_CONCURRENCY, **params, &)
  usernames = usernames.map { |username| normalize(Utils.username!(username)) }
  found = lookup_in_batches("users/by", :usernames, usernames, client:, concurrency:, **params, &) #: Array[User]
  in_order(found, usernames)
end

#find_by_id(id, client:, **params) {|problem| ... } ⇒ User?

Look up a user by identifier

A String of digits is an identifier, as it is read from a response or an environment variable, so this looks the account that number identifies up, where find would take it for a username.

Examples:

Look up a user by an identifier read as a String

X::User.find_by_id(ENV.fetch("USER_ID"), client: client)

Parameters:

  • id (String, Integer, User) —

    the identifier, or a user

  • client (Object) —

    the client used to make the request

  • params (Hash) —

    query parameters merged over the default parameters

Yield Parameters:

  • problem (Problem) —

    each problem the API reported, such as a user that was not found

Returns:

  • (User, nil) —

    the user or nil if the user was not found, whether the API answers 200 with no data or a 404 that reports the user as not found

Raises:

  • (X::NotFound) —

    if the API answers any other 404, such as one from a client pointed at the wrong host or API version

  • (ArgumentError) —

    if the value is not an identifier



126
127
128
# File 'x-resources/lib/x/resources/user_finders.rb', line 126

def find_by_id(id, client:, **params, &)
  locate("#{endpoint!}/#{Utils.id_of(id, self)}", client:, **params, &) #: User?
end

#find_by_id!(id, client:, **params) ⇒ User

Look up a user by identifier, which must exist

Examples:

Look up a user by an identifier read as a String

X::User.find_by_id!("7505382", client: client)

Parameters:

  • id (String, Integer, User) —

    the identifier, or a user

  • client (Object) —

    the client used to make the request

  • params (Hash) —

    query parameters merged over the default parameters

Returns:

  • (User) —

    the user

Raises:

  • (ArgumentError) —

    if the value is not an identifier

  • (MissingResource) —

    if the user was not found, whether the API answers 200 with no data or a 404 that reports the user as not found

  • (X::NotFound) —

    if the API answers any other 404, such as one from a client pointed at the wrong host or API version



144
145
146
147
# File 'x-resources/lib/x/resources/user_finders.rb', line 144

def find_by_id!(id, client:, **params)
  name = Utils.id_of(id, self)
  locate!("#{endpoint!}/#{name}", name, client:, **params) #: User
end

#find_by_username(username, client:, **params) {|problem| ... } ⇒ User?

Look up a user by username

It looks every value up as a username, a String of digits as the account whose handle is that number, as find looks up any String, so code that reads a value from elsewhere says which it means, as find_by_id does.

Examples:

Look up a user by username

X::User.find_by_username("sferik", client: client)

Parameters:

  • username (String) —

    the username, with or without a leading at sign

  • client (Object) —

    the client used to make the request

  • params (Hash) —

    query parameters merged over the default parameters

Yield Parameters:

  • problem (Problem) —

    each problem the API reported, such as a user that was not found

Returns:

  • (User, nil) —

    the user or nil if the user was not found, whether the API answers 200 with no data or a 404 that reports the user as not found

Raises:

  • (X::NotFound) —

    if the API answers any other 404, such as one from a client pointed at the wrong host or API version

  • (ArgumentError) —

    if the value is not a username



188
189
190
# File 'x-resources/lib/x/resources/user_finders.rb', line 188

def find_by_username(username, client:, **params, &)
  locate("users/by/username/#{Utils.username!(username)}", client:, **params, &) #: User?
end

#find_by_username!(username, client:, **params) ⇒ User

Look up a user by username, which must exist

Examples:

Look up a user by username

X::User.find_by_username!("sferik", client: client)

Parameters:

  • username (String) —

    the username, with or without a leading at sign

  • client (Object) —

    the client used to make the request

  • params (Hash) —

    query parameters merged over the default parameters

Returns:

  • (User) —

    the user

Raises:

  • (ArgumentError) —

    if the value is not a username

  • (MissingResource) —

    if the user was not found, whether the API answers 200 with no data or a 404 that reports the user as not found

  • (X::NotFound) —

    if the API answers any other 404, such as one from a client pointed at the wrong host or API version



206
207
208
# File 'x-resources/lib/x/resources/user_finders.rb', line 206

def find_by_username!(username, client:, **params)
  locate!("users/by/username/#{Utils.username!(username)}", "@#{Utils.username(username)}", client:, **params) #: User
end

#hydrate_all(resources, client:, concurrency: DEFAULT_CONCURRENCY, **params) {|problem| ... } ⇒ Array<Resource> Originally defined in module BatchFinders

Replace the resources that are not hydrated with the full resources

A resource that hydrate would look up is looked up, which is a stub and also a resource a response included without every field, so what comes back is hydrated throughout. A resource that was not found is dropped, as is nil, which a reference to no resource reads as, such as the author of a post whose response named none, and a hydrated resource is kept as it is, so resources that are all hydrated need no lookup. What was found is stored in each original, so hydrating one of them afterwards costs no request, unless params override a default field or expansion parameter: what such a lookup found is not the full resource, so it is returned without being stored, and hydrating an original fetches the full resource. A resource that holds what hydrate returns, because hydrate or an earlier hydrate_all stored it, is replaced with that, and looked up again by no request, since the API bills each resource a lookup returns.

Examples:

Look up every field of the authors of posts, the ones a search included among them

X::User.hydrate_all(posts.map(&:author), client: client)

Expand only the authors a search did not include, which the API bills for alone

X::User.hydrate_all(posts.filter_map(&:author).select(&:stub?), client: client)

Parameters:

  • resources (Array<Resource, nil>) —

    the resources, some of which may not be hydrated, and some nil

  • client (Object) —

    the client used to make the requests

  • concurrency (Integer) (defaults to: DEFAULT_CONCURRENCY) —

    the number of batch lookups made at once, four by default, which must be at least one

  • params (Hash) —

    query parameters merged over the default parameters; one that overrides a default field or expansion parameter to leave some out builds resources that are not hydrated, so hydrate fetches the rest

Yield Parameters:

  • problem (Problem) —

    each problem the API reported, such as a resource that was not found

Returns:

  • (Array<Resource>) —

    the resources, in order, with the ones that were not hydrated replaced, frozen

Raises:

  • (ArgumentError) —

    if the concurrency is less than one

  • (ArgumentError) —

    if a resource is not of this class, which a lookup of its identifier would find another resource for, before a request