mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
Homogenize manager search methods to return querysets. Resolve #2384.
This commit is contained in:
parent
01af303457
commit
9c0b44e13a
7 changed files with 65 additions and 39 deletions
|
|
@ -139,6 +139,7 @@ Up requirements to Django 3.2+, Twisted 21+
|
|||
- Add support for `$dbref()` and `$search` when assigning an Attribute value
|
||||
with the `set` command. This allows assigning real objects from in-game.
|
||||
- Add ability to examine `/script` and `/channel` entities with `examine` command.
|
||||
- Homogenize manager search methods to return querysets and not lists.
|
||||
|
||||
|
||||
### Evennia 0.9.5 (2019-2020)
|
||||
|
|
|
|||
|
|
@ -156,14 +156,17 @@ class AccountDBManager(TypedObjectManager, UserManager):
|
|||
(non-case-sensitive fuzzy match).
|
||||
typeclass (str or Typeclass, optional): Limit the search only to
|
||||
accounts of this typeclass.
|
||||
Returns:
|
||||
Queryset: A queryset (an iterable) with 0, 1 or more matches.
|
||||
|
||||
"""
|
||||
dbref = self.dbref(ostring)
|
||||
if dbref or dbref == 0:
|
||||
# bref search is always exact
|
||||
matches = self.filter(id=dbref)
|
||||
if matches:
|
||||
return matches
|
||||
# dbref search is always exact
|
||||
dbref_match = self.search_dbref(dbref)
|
||||
if dbref_match:
|
||||
return dbref_match
|
||||
|
||||
query = {"username__iexact" if exact else "username__icontains": ostring}
|
||||
if typeclass:
|
||||
# we accept both strings and actual typeclasses
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ class MsgManager(TypedObjectManager):
|
|||
always gives only one match.
|
||||
|
||||
Returns:
|
||||
Queryset: Message matches.
|
||||
Queryset: Iterable with 0, 1 or more matches.
|
||||
|
||||
"""
|
||||
# unique msg id
|
||||
|
|
@ -420,13 +420,16 @@ class ChannelDBManager(TypedObjectManager):
|
|||
exact (bool, optional): Require an exact (but not
|
||||
case sensitive) match.
|
||||
|
||||
Returns:
|
||||
Queryset: Iterable with 0, 1 or more matches.
|
||||
|
||||
"""
|
||||
dbref = self.dbref(ostring)
|
||||
if dbref:
|
||||
try:
|
||||
return [self.get(id=dbref)]
|
||||
except self.model.DoesNotExist:
|
||||
pass
|
||||
dbref_match = self.search_dbref(dbref)
|
||||
if dbref_match:
|
||||
return dbref_match
|
||||
|
||||
if exact:
|
||||
channels = self.filter(
|
||||
Q(db_key__iexact=ostring)
|
||||
|
|
|
|||
|
|
@ -146,6 +146,9 @@ class HelpEntryManager(TypedObjectManager):
|
|||
ostring (str): The help topic to look for.
|
||||
category (str): Limit the search to a particular help topic
|
||||
|
||||
Returns:
|
||||
Queryset: An iterable with 0, 1 or more matches.
|
||||
|
||||
"""
|
||||
ostring = ostring.strip().lower()
|
||||
if help_category:
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class ObjectDBManager(TypedObjectManager):
|
|||
Querysets or database objects).
|
||||
|
||||
dbref (converter)
|
||||
get_id (alias: dbref_search)
|
||||
dbref_search
|
||||
get_dbref_range
|
||||
object_totals
|
||||
typeclass_search
|
||||
|
|
@ -162,8 +162,8 @@ class ObjectDBManager(TypedObjectManager):
|
|||
typeclasses (list, optional): Python pats to restrict matches with.
|
||||
|
||||
Returns:
|
||||
matches (query): Objects fullfilling both the `attribute_name` and
|
||||
`attribute_value` criterions.
|
||||
Queryset: Iterable with 0, 1 or more matches fullfilling both the `attribute_name` and
|
||||
`attribute_value` criterions.
|
||||
|
||||
Notes:
|
||||
This uses the Attribute's PickledField to transparently search the database by matching
|
||||
|
|
@ -222,6 +222,9 @@ class ObjectDBManager(TypedObjectManager):
|
|||
candidates (list, optional): List of objects to limit search to.
|
||||
typeclasses (list, optional): List of typeclass-path strings to restrict matches with
|
||||
|
||||
Returns:
|
||||
Queryset: Iterable with 0, 1 or more matches.
|
||||
|
||||
"""
|
||||
if isinstance(property_name, str):
|
||||
if not property_name.startswith("db_"):
|
||||
|
|
@ -234,11 +237,10 @@ class ObjectDBManager(TypedObjectManager):
|
|||
)
|
||||
type_restriction = typeclasses and Q(db_typeclass_path__in=make_iter(typeclasses)) or Q()
|
||||
try:
|
||||
return list(
|
||||
self.filter(cand_restriction & type_restriction & Q(**querykwargs)).order_by("id")
|
||||
)
|
||||
return self.filter(
|
||||
cand_restriction & type_restriction & Q(**querykwargs)).order_by("id")
|
||||
except exceptions.FieldError:
|
||||
return []
|
||||
return self.none()
|
||||
except ValueError:
|
||||
from evennia.utils import logger
|
||||
|
||||
|
|
@ -246,7 +248,7 @@ class ObjectDBManager(TypedObjectManager):
|
|||
"The property '%s' does not support search criteria of the type %s."
|
||||
% (property_name, type(property_value))
|
||||
)
|
||||
return []
|
||||
return self.none()
|
||||
|
||||
def get_contents(self, location, excludeobj=None):
|
||||
"""
|
||||
|
|
@ -258,7 +260,8 @@ class ObjectDBManager(TypedObjectManager):
|
|||
to exclude from the match.
|
||||
|
||||
Returns:
|
||||
contents (query): Matching contents, without excludeobj, if given.
|
||||
Queryset: Iterable with 0, 1 or more matches.
|
||||
|
||||
"""
|
||||
exclude_restriction = (
|
||||
Q(pk__in=[_GA(obj, "id") for obj in make_iter(excludeobj)]) if excludeobj else Q()
|
||||
|
|
@ -276,17 +279,18 @@ class ObjectDBManager(TypedObjectManager):
|
|||
typeclasses (list): Only match objects with typeclasses having thess path strings.
|
||||
|
||||
Returns:
|
||||
matches (query): A list of matches of length 0, 1 or more.
|
||||
Queryset: An iterable with 0, 1 or more matches.
|
||||
|
||||
"""
|
||||
if not isinstance(ostring, str):
|
||||
if hasattr(ostring, "key"):
|
||||
ostring = ostring.key
|
||||
else:
|
||||
return []
|
||||
return self.none()
|
||||
if is_iter(candidates) and not len(candidates):
|
||||
# if candidates is an empty iterable there can be no matches
|
||||
# Exit early.
|
||||
return []
|
||||
return self.none()
|
||||
|
||||
# build query objects
|
||||
candidates_id = [_GA(obj, "id") for obj in make_iter(candidates) if obj]
|
||||
|
|
@ -327,10 +331,12 @@ class ObjectDBManager(TypedObjectManager):
|
|||
# fuzzy matching
|
||||
key_strings = search_candidates.values_list("db_key", flat=True).order_by("id")
|
||||
|
||||
match_ids = []
|
||||
index_matches = string_partial_matching(key_strings, ostring, ret_index=True)
|
||||
if index_matches:
|
||||
# a match by key
|
||||
return [obj for ind, obj in enumerate(search_candidates) if ind in index_matches]
|
||||
match_ids = [obj.id for ind, obj in enumerate(search_candidates)
|
||||
if ind in index_matches]
|
||||
else:
|
||||
# match by alias rather than by key
|
||||
search_candidates = search_candidates.filter(
|
||||
|
|
@ -346,8 +352,10 @@ class ObjectDBManager(TypedObjectManager):
|
|||
index_matches = string_partial_matching(alias_strings, ostring, ret_index=True)
|
||||
if index_matches:
|
||||
# it's possible to have multiple matches to the same Object, we must weed those out
|
||||
return list({alias_candidates[ind] for ind in index_matches})
|
||||
return []
|
||||
match_ids = [alias_candidates[ind].id for ind in index_matches]
|
||||
# TODO - not ideal to have to do a second lookup here, but we want to return a queryset
|
||||
# rather than a list ... maybe the above queries can be improved.
|
||||
return self.filter(id__in=match_ids)
|
||||
|
||||
# main search methods and helper functions
|
||||
|
||||
|
|
@ -422,7 +430,7 @@ class ObjectDBManager(TypedObjectManager):
|
|||
)
|
||||
|
||||
if not searchdata and searchdata != 0:
|
||||
return []
|
||||
return self.none()
|
||||
|
||||
if typeclass:
|
||||
# typeclass may also be a list
|
||||
|
|
@ -450,10 +458,11 @@ class ObjectDBManager(TypedObjectManager):
|
|||
# Easiest case - dbref matching (always exact)
|
||||
dbref_match = self.dbref_search(dbref)
|
||||
if dbref_match:
|
||||
if not candidates or dbref_match in candidates:
|
||||
return [dbref_match]
|
||||
dmatch = dbref_match[0]
|
||||
if not candidates or dmatch in candidates:
|
||||
return dbref_match
|
||||
else:
|
||||
return []
|
||||
return self.none()
|
||||
|
||||
# Search through all possibilities.
|
||||
match_number = None
|
||||
|
|
@ -478,15 +487,16 @@ class ObjectDBManager(TypedObjectManager):
|
|||
# this indicates trying to get a single match with a match-number
|
||||
# targeting some higher-number match (like 2-box when there is only
|
||||
# one box in the room). This leads to a no-match.
|
||||
matches = []
|
||||
matches = self.none()
|
||||
elif len(matches) > 1 and match_number is not None:
|
||||
# multiple matches, but a number was given to separate them
|
||||
if 0 <= match_number < len(matches):
|
||||
# limit to one match
|
||||
matches = [matches[match_number]]
|
||||
# limit to one match (we still want a queryset back)
|
||||
# TODO: Can we do this some other way and avoid a second lookup?
|
||||
matches = self.filter(id=matches[match_number].id)
|
||||
else:
|
||||
# a number was given outside of range. This means a no-match.
|
||||
matches = []
|
||||
matches = self.none()
|
||||
|
||||
# return a list (possibly empty)
|
||||
return matches
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class ScriptDBManager(TypedObjectManager):
|
|||
Querysets or database objects).
|
||||
|
||||
dbref (converter)
|
||||
get_id (or dbref_search)
|
||||
dbref_search
|
||||
get_dbref_range
|
||||
object_totals
|
||||
typeclass_search
|
||||
|
|
@ -138,6 +138,9 @@ class ScriptDBManager(TypedObjectManager):
|
|||
on a timer.
|
||||
typeclass (class or str): Typeclass or path to typeclass.
|
||||
|
||||
Returns:
|
||||
Queryset: An iterable with 0, 1 or more results.
|
||||
|
||||
"""
|
||||
|
||||
ostring = ostring.strip()
|
||||
|
|
@ -146,10 +149,10 @@ class ScriptDBManager(TypedObjectManager):
|
|||
if dbref:
|
||||
# this is a dbref, try to find the script directly
|
||||
dbref_match = self.dbref_search(dbref)
|
||||
if dbref_match and not (
|
||||
(obj and obj != dbref_match.obj) or (only_timed and dbref_match.interval)
|
||||
):
|
||||
return [dbref_match]
|
||||
if dbref_match:
|
||||
dmatch = dbref_match[0]
|
||||
if not (obj and obj != dmatch.obj) or (only_timed and dmatch.interval):
|
||||
return dbref_match
|
||||
|
||||
if typeclass:
|
||||
if callable(typeclass):
|
||||
|
|
|
|||
|
|
@ -464,10 +464,13 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
|
|||
dbref (str or int): The id to search for.
|
||||
|
||||
Returns:
|
||||
object (TypedObject): The matched object.
|
||||
Queryset: Queryset with 0 or 1 match.
|
||||
|
||||
"""
|
||||
return self.get_id(dbref)
|
||||
dbref = self.dbref(dbref, reqhash=False)
|
||||
if dbref:
|
||||
return self.filter(id=dbref)
|
||||
return self.none()
|
||||
|
||||
def get_dbref_range(self, min_dbref=None, max_dbref=None):
|
||||
"""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue