Skip to content

Commit

Permalink
Create indexes instances only when needed
Browse files Browse the repository at this point in the history
For this we use a @cached_property decorator from django
  • Loading branch information
twidi committed Jan 26, 2018
1 parent d62bb2e commit f5809cf
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 14 deletions.
39 changes: 26 additions & 13 deletions limpyd/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from redis.exceptions import RedisError

from limpyd.database import Lock
from limpyd.utils import make_key, normalize
from limpyd.utils import cached_property, make_key, normalize
from limpyd.exceptions import *

log = getLogger(__name__)
Expand Down Expand Up @@ -196,13 +196,10 @@ def __init__(self, *args, **kwargs):
raise ImplementationError('Cannot set "default" and "unique" together!')
self.indexable = True

self._indexes = []

self.index_classes = kwargs.get('indexes', [])
if self.index_classes:
if not self.indexable:
raise ImplementationError('Cannot pass indexes if not indexable')
self._indexes = [index_class(field=self) for index_class in self.index_classes]

# keep fields ordered
self._creation_order = RedisField._creation_order
Expand Down Expand Up @@ -358,22 +355,41 @@ def exists(self):
else:
return self.connection.exists(key)

def _attach_default_indexes(self):
self.index_classes = self.get_default_indexes()[::1]
@cached_property
def _indexes(self):
"""Instantiate the indexes only when asked
Returns
-------
list
An empty list if the field is not indexable, else a list of all indexes
tied to the field.
If no indexes where passed when creating the field, the default indexes
from the field/model/database will be used.
If still no index classes, it will raise
Raises
------
ImplementationError
If no index classes available for this field
"""
if not self.indexable:
return []
if not self.index_classes:
self.index_classes = self.get_default_indexes()[::1]
if not self.index_classes:
raise ImplementationError('%s field is indexable but has no indexes attached' %
self.__class__.__name__)
self._indexes = [index_class(field=self) for index_class in self.index_classes]

return [index_class(field=self) for index_class in self.index_classes]

def _attach_to_model(self, model):
"""
Attach the current field to a model. Can be overriden to do something
when a model is set
"""
self._model = model
# add indexes for the fields at the model level (for collection)
if self.indexable and not self.index_classes:
self._attach_default_indexes()

def _attach_to_instance(self, instance):
"""
Expand All @@ -382,9 +398,6 @@ def _attach_to_instance(self, instance):
"""
self._instance = instance
self.lockable = self.lockable and instance.lockable
# add indexes for the field at the instance level (for indexing)
if self.indexable and not self.index_classes:
self._attach_default_indexes()

def _call_command(self, name, *args, **kwargs):
"""
Expand Down
23 changes: 22 additions & 1 deletion limpyd/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
from future.builtins import str, bytes
from future.builtins import str, bytes, object

import uuid

Expand Down Expand Up @@ -32,3 +32,24 @@ def normalize(value):
if value and isinstance(value, bytes):
value = value.decode('utf-8')
return value


class cached_property(object):
"""
Decorator that converts a method with a single self argument into a
property cached on the instance.
Optional ``name`` argument allows you to make cached properties of other
methods. (e.g. url = cached_property(get_absolute_url, name='url') )
From https://github.com/django/django/blob/27793431cf21a82809c0c39a7c0188a2d83bf475/django/utils/functional.py#L15
"""
def __init__(self, func, name=None):
self.func = func
self.__doc__ = getattr(func, '__doc__')
self.name = name or func.__name__

def __get__(self, instance, cls=None):
if instance is None:
return self
res = instance.__dict__[self.name] = self.func(instance)
return res

0 comments on commit f5809cf

Please sign in to comment.