public
Last active — forked from nkallen/MODULARITY_OLYMPICS.markdown

  • Download Gist
_README.txt
1 2 3 4 5 6 7 8 9 10
I want to turn this into a programming contest. Everyone should do this using their favorite technique and language. But, I want to add three more challenges (that admittedly stack the deck in my favor).
 
1. create a stats collecting query decorate that measures the time it takes to execute the query
(assume you have a stats object that responds to #measure and takes a block: stats.measure { sleep 1.second }
2. read "configuration" from a hash like:
{ :timeout => 1.second, :stats => true }
that adds the timeout and stats decorators to the factory if present in the hash, otherwise not.
3. at the end write a program that REVERSES the order of the decorators. So if you did Timeout(Stats(Query)) make it Stats(Timeout(Query)). Note that you must do this programmatically so write a generic decorator reversing function. You may expand the proxy interface to have a method called "underlying", "delegate" or some such.
 
The contest is: do this in your language in as "elegant" a way as you like. The goal is clarity and modularity.
a_program.rb
Ruby
1 2 3 4 5 6 7
query_factory = MemoizingQueryFactory.new(TimingOutQueryFactory.new(Query, 1.second))
query_evaluator = QueryEvaluator.new(ConnectionPool.new(20), query_factory)
 
query_evaluator.transaction do |t|
t.select("SELECT ... FOR UPDATE FROM ...")
t.execute("INSERT ...")
end
memoizing_query_factory.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11
class MemoizingQueryFactory
def initialize(query_factory)
@memo = Hash.new do |h, k|
h = query_factory.new(*k)
end
end
 
def new(connection, query_string, *args)
@memo[[connection, query_string, args]]
end
end
query_evaluator.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
class QueryEvaluator
def initialize(connection_pool, query_factory = Query)
@query_factory = query_factory
@connection_pool = connection_pool
end
 
def select(query_string, *args)
@connection_pool.with_connection do |connection|
@query_factory.new(connection, query_string, *args).select
end
end
 
def execute(query_string, *args)
@connection_pool.with_connection do |connection|
@query_factory.new(connection, query_string, *args).execute
end
end
 
def transaction
@connection_pool.with_connection do |connection|
yield TransactionalQueryEvaluator.new(connection, @query_factory)
end
end
end
 
class TransactionalQueryEvaluator
def initialize(connection, query_factory)
@connection = connection
@query_factory = query_factory
end
 
def select(query_string, *args)
@query_factory.new(@connection, query_string, *args).select
end
 
def execute(query_string, *args)
@query_factory.new(@connection, query_string, *args).select
end
 
def transaction
yield self
end
end
timing_out_query_proxy.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
class TimingOutQueryProxyFactory
def initialize(query_factory, timeout)
@query_factory = query_factory
@timeout = timeout
end
 
def new(connection, query_string, *args)
@query_factory.new(connection, query_string, *args)
end
end
 
class TimingOutQueryProxy
def initialize(query, timeout)
@query = query
@timeout = timeout
end
 
def select
Timeout.timeout(@timeout) do
@query.select
end
end
 
# ...
end

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.