lib/arel/middleware/chain.rb in arel_toolkit-0.4.2 vs lib/arel/middleware/chain.rb in arel_toolkit-0.4.3
- old
+ new
@@ -1,93 +1,102 @@
+require_relative './no_op_cache'
+require_relative './cache_accessor'
+
module Arel
module Middleware
class Chain
- attr_reader :executing_middleware
+ attr_reader :executing_middleware_depth
attr_reader :executor
+ attr_reader :cache
+ MAX_RECURSION_DEPTH = 10
+
def initialize(
internal_middleware = [],
internal_context = {},
- executor_class = Arel::Middleware::DatabaseExecutor
+ executor_class = Arel::Middleware::DatabaseExecutor,
+ cache: nil
)
@internal_middleware = internal_middleware
@internal_context = internal_context
@executor = executor_class.new(internal_middleware)
- @executing_middleware = false
+ @executing_middleware_depth = 0
+ @cache = cache || NoOpCache
end
+ def cache_accessor
+ @cache_accessor ||= CacheAccessor.new @cache
+ end
+
def execute(sql, binds = [], &execute_sql)
return execute_sql.call(sql, binds).to_casted_result if internal_middleware.length.zero?
- check_middleware_recursion(sql)
+ if (cached_sql = cache_accessor.read(sql))
+ return execute_sql.call(cached_sql, binds).to_casted_result
+ end
- updated_context = context.merge(original_sql: sql)
- enhanced_arel = Arel.enhance(Arel.sql_to_arel(sql, binds: binds))
-
- result = executor.run(enhanced_arel, updated_context, execute_sql)
-
- result.to_casted_result
+ execute_with_middleware(sql, binds, execute_sql).to_casted_result
rescue ::PgQuery::ParseError
execute_sql.call(sql, binds)
ensure
- @executing_middleware = false
+ @executing_middleware_depth -= 1
end
def current
internal_middleware.dup
end
- def apply(middleware, &block)
+ def apply(middleware, cache: @cache, &block)
new_middleware = Array.wrap(middleware)
- continue_chain(new_middleware, internal_context, &block)
+ continue_chain(new_middleware, internal_context, cache: cache, &block)
end
alias only apply
def none(&block)
- continue_chain([], internal_context, &block)
+ continue_chain([], internal_context, cache: cache, &block)
end
- def except(without_middleware, &block)
+ def except(without_middleware, cache: @cache, &block)
without_middleware = Array.wrap(without_middleware)
new_middleware = internal_middleware - without_middleware
- continue_chain(new_middleware, internal_context, &block)
+ continue_chain(new_middleware, internal_context, cache: cache, &block)
end
- def insert_before(new_middleware, existing_middleware, &block)
+ def insert_before(new_middleware, existing_middleware, cache: @cache, &block)
new_middleware = Array.wrap(new_middleware)
index = internal_middleware.index(existing_middleware)
updated_middleware = internal_middleware.insert(index, *new_middleware)
- continue_chain(updated_middleware, internal_context, &block)
+ continue_chain(updated_middleware, internal_context, cache: cache, &block)
end
- def prepend(new_middleware, &block)
+ def prepend(new_middleware, cache: @cache, &block)
new_middleware = Array.wrap(new_middleware)
updated_middleware = new_middleware + internal_middleware
- continue_chain(updated_middleware, internal_context, &block)
+ continue_chain(updated_middleware, internal_context, cache: cache, &block)
end
- def insert_after(new_middleware, existing_middleware, &block)
+ def insert_after(new_middleware, existing_middleware, cache: @cache, &block)
new_middleware = Array.wrap(new_middleware)
index = internal_middleware.index(existing_middleware)
updated_middleware = internal_middleware.insert(index + 1, *new_middleware)
- continue_chain(updated_middleware, internal_context, &block)
+ continue_chain(updated_middleware, internal_context, cache: cache, &block)
end
- def append(new_middleware, &block)
+ def append(new_middleware, cache: @cache, &block)
new_middleware = Array.wrap(new_middleware)
updated_middleware = internal_middleware + new_middleware
- continue_chain(updated_middleware, internal_context, &block)
+ continue_chain(updated_middleware, internal_context, cache: cache, &block)
end
def context(new_context = nil, &block)
if new_context.nil? && !block.nil?
raise 'You cannot do a block statement while calling context without arguments'
end
return internal_context if new_context.nil?
- continue_chain(internal_middleware, new_context, &block)
+ continue_chain(internal_middleware, new_context, cache: @cache, &block)
end
def to_sql(type, &block)
middleware = Arel::Middleware::ToSqlMiddleware.new(type)
@@ -107,12 +116,27 @@
attr_reader :internal_middleware
attr_reader :internal_context
private
- def continue_chain(middleware, context, &block)
- new_chain = Arel::Middleware::Chain.new(middleware, context)
+ def execute_with_middleware(sql, binds, execute_sql)
+ check_middleware_recursion(sql)
+
+ updated_context = context.merge(
+ original_sql: sql,
+ original_binds: binds,
+ cache_accessor: cache_accessor,
+ )
+
+ arel = Arel.sql_to_arel(sql, binds: binds)
+ enhanced_arel = Arel.enhance(arel)
+
+ executor.run(enhanced_arel, updated_context, execute_sql)
+ end
+
+ def continue_chain(middleware, context, cache:, &block)
+ new_chain = Arel::Middleware::Chain.new(middleware, context, cache: cache)
maybe_execute_block(new_chain, &block)
end
def maybe_execute_block(new_chain, &block)
return new_chain if block.nil?
@@ -123,11 +147,11 @@
ensure
Arel::Middleware.current_chain = previous_chain
end
def check_middleware_recursion(sql)
- if executing_middleware
+ if executing_middleware_depth > MAX_RECURSION_DEPTH
message = <<~ERROR
Middleware is being called from within middleware, aborting execution
to prevent endless recursion. You can do the following if you want to execute SQL
inside middleware:
@@ -138,10 +162,10 @@
#{sql}
ERROR
raise message
else
- @executing_middleware = true
+ @executing_middleware_depth += 1
end
end
end
end
end