Source code for anyblok.bloks.anyblok_core.system.cache
# This file is a part of the AnyBlok project
#
# Copyright (C) 2014 Jean-Sebastien SUZANNE <jssuzanne@anybox.fr>
#
# This Source Code Form is subject to the terms of the Mozilla Public License,
# v. 2.0. If a copy of the MPL was not distributed with this file,You can
# obtain one at http://mozilla.org/MPL/2.0/.
from sqlalchemy import func
from anyblok.column import Integer, ModelSelection, String
from anyblok.declarations import Declarations
from ..exceptions import CacheException
register = Declarations.register
System = Declarations.Model.System
[docs]@register(System)
class Cache:
last_cache_id = None
id = Integer(primary_key=True)
registry_name = ModelSelection(nullable=False)
method = String(nullable=False)
[docs] @classmethod
def get_last_id(cls):
"""Return the last primary key ``id`` value"""
res = cls.query("id").order_by(cls.id.desc()).limit(1).first()
if res:
return res[0]
return 0 # pragma: no cover
[docs] @classmethod
def initialize_model(cls):
"""Initialize the last_cache_id known"""
super(Cache, cls).initialize_model()
cls.last_cache_id = cls.get_last_id()
@classmethod
def invalidate_all(cls):
res = []
for registry_name, methods in cls.anyblok.caches.items():
for method, caches in methods.items():
res.append(dict(registry_name=registry_name, method=method))
for cache in caches:
cache.cache_clear()
if res:
instances = cls.multi_insert(*res)
cls.last_cache_id = max(i.id for i in instances)
[docs] @classmethod
def invalidate(cls, registry_name, method):
"""Call the invalidation for a specific method cached on a model
:param registry_name: namespace of the model
:param method: name of the method on the model
:exception: CacheException
"""
caches = cls.anyblok.caches
if hasattr(registry_name, "__registry_name__"):
registry_name = registry_name.__registry_name__
if registry_name in caches:
if method in caches[registry_name]:
cls.last_cache_id = cls.insert(
registry_name=registry_name, method=method
).id
for cache in caches[registry_name][method]:
cache.cache_clear()
else:
raise CacheException( # pragma: no cover
"Unknown cached method %r" % method
)
else:
raise CacheException("Unknown cached model %r" % registry_name)
[docs] @classmethod
def get_invalidation(cls):
"""Return the pointer of the method to invalidate"""
res = []
query = cls.select_sql_statement(
func.max(cls.id).label("id"),
cls.registry_name,
cls.method,
)
query = query.group_by(cls.registry_name, cls.method)
query = query.where(cls.id > cls.last_cache_id)
query_res = cls.execute_sql_statement(query)
caches = cls.anyblok.caches
for id_, registry_name, method in query_res:
res.extend(caches[registry_name][method])
cls.last_cache_id = max(cls.last_cache_id, id_)
return res
[docs] @classmethod
def clear_invalidate_cache(cls):
"""Invalidate the cache that needs to be invalidated"""
for cache in cls.get_invalidation():
cache.cache_clear()