summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql/base.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2020-04-27 12:58:12 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2020-05-25 13:56:37 -0400
commit6930dfc032c3f9f474e71ab4e021c0ef8384930e (patch)
tree34b919a3c34edaffda1750f161a629fc5b9a8020 /lib/sqlalchemy/sql/base.py
parentdce8c7a125cb99fad62c76cd145752d5afefae36 (diff)
downloadsqlalchemy-6930dfc032c3f9f474e71ab4e021c0ef8384930e.tar.gz
Convert execution to move through Session
This patch replaces the ORM execution flow with a single pathway through Session.execute() for all queries, including Core and ORM. Currently included is full support for ORM Query, Query.from_statement(), select(), as well as the baked query and horizontal shard systems. Initial changes have also been made to the dogpile caching example, which like baked query makes use of a new ORM-specific execution hook that replaces the use of both QueryEvents.before_compile() as well as Query._execute_and_instances() as the central ORM interception hooks. select() and Query() constructs alike can be passed to Session.execute() where they will return ORM results in a Results object. This API is currently used internally by Query. Full support for Session.execute()->results to behave in a fully 2.0 fashion will be in later changesets. bulk update/delete with ORM support will also be delivered via the update() and delete() constructs, however these have not yet been adapted to the new system and may follow in a subsequent update. Performance is also beginning to lag as of this commit and some previous ones. It is hoped that a few central functions such as the coercions functions can be rewritten in C to re-gain performance. Additionally, query caching is now available and some subsequent patches will attempt to cache more of the per-execution work from the ORM layer, e.g. column getters and adapters. This patch also contains initial "turn on" of the caching system enginewide via the query_cache_size parameter to create_engine(). Still defaulting at zero for "no caching". The caching system still needs adjustments in order to gain adequate performance. Change-Id: I047a7ebb26aa85dc01f6789fac2bff561dcd555d
Diffstat (limited to 'lib/sqlalchemy/sql/base.py')
-rw-r--r--lib/sqlalchemy/sql/base.py80
1 files changed, 50 insertions, 30 deletions
diff --git a/lib/sqlalchemy/sql/base.py b/lib/sqlalchemy/sql/base.py
index 04cc34480..bb606a4d6 100644
--- a/lib/sqlalchemy/sql/base.py
+++ b/lib/sqlalchemy/sql/base.py
@@ -439,46 +439,53 @@ class CompileState(object):
plugins = {}
@classmethod
- def _create(cls, statement, compiler, **kw):
+ def create_for_statement(cls, statement, compiler, **kw):
# factory construction.
- if statement._compile_state_plugin is not None:
- constructor = cls.plugins.get(
- (
- statement._compile_state_plugin,
- statement.__visit_name__,
- None,
- ),
- cls,
+ if statement._propagate_attrs:
+ plugin_name = statement._propagate_attrs.get(
+ "compile_state_plugin", "default"
)
else:
- constructor = cls
+ plugin_name = "default"
+
+ klass = cls.plugins[(plugin_name, statement.__visit_name__)]
- return constructor(statement, compiler, **kw)
+ if klass is cls:
+ return cls(statement, compiler, **kw)
+ else:
+ return klass.create_for_statement(statement, compiler, **kw)
def __init__(self, statement, compiler, **kw):
self.statement = statement
@classmethod
- def get_plugin_classmethod(cls, statement, name):
- if statement._compile_state_plugin is not None:
- fn = cls.plugins.get(
- (
- statement._compile_state_plugin,
- statement.__visit_name__,
- name,
- ),
- None,
- )
- if fn is not None:
- return fn
- return getattr(cls, name)
+ def get_plugin_class(cls, statement):
+ plugin_name = statement._propagate_attrs.get(
+ "compile_state_plugin", "default"
+ )
+ try:
+ return cls.plugins[(plugin_name, statement.__visit_name__)]
+ except KeyError:
+ return None
@classmethod
- def plugin_for(cls, plugin_name, visit_name, method_name=None):
- def decorate(fn):
- cls.plugins[(plugin_name, visit_name, method_name)] = fn
- return fn
+ def _get_plugin_compile_state_cls(cls, statement, plugin_name):
+ statement_plugin_name = statement._propagate_attrs.get(
+ "compile_state_plugin", "default"
+ )
+ if statement_plugin_name != plugin_name:
+ return None
+ try:
+ return cls.plugins[(plugin_name, statement.__visit_name__)]
+ except KeyError:
+ return None
+
+ @classmethod
+ def plugin_for(cls, plugin_name, visit_name):
+ def decorate(cls_to_decorate):
+ cls.plugins[(plugin_name, visit_name)] = cls_to_decorate
+ return cls_to_decorate
return decorate
@@ -508,12 +515,12 @@ class InPlaceGenerative(HasMemoized):
class HasCompileState(Generative):
"""A class that has a :class:`.CompileState` associated with it."""
- _compile_state_factory = CompileState._create
-
_compile_state_plugin = None
_attributes = util.immutabledict()
+ _compile_state_factory = CompileState.create_for_statement
+
class _MetaOptions(type):
"""metaclass for the Options class."""
@@ -549,6 +556,16 @@ class Options(util.with_metaclass(_MetaOptions)):
def add_to_element(self, name, value):
return self + {name: getattr(self, name) + value}
+ @hybridmethod
+ def _state_dict(self):
+ return self.__dict__
+
+ _state_dict_const = util.immutabledict()
+
+ @_state_dict.classlevel
+ def _state_dict(cls):
+ return cls._state_dict_const
+
class CacheableOptions(Options, HasCacheKey):
@hybridmethod
@@ -590,6 +607,9 @@ class Executable(Generative):
def _disable_caching(self):
self._cache_enable = HasCacheKey()
+ def _get_plugin_compile_state_cls(self, plugin_name):
+ return CompileState._get_plugin_compile_state_cls(self, plugin_name)
+
@_generative
def options(self, *options):
"""Apply options to this statement.