require 'sequel'
require 'logger'
require 'sinatra/base'
DB = Sequel.sqlite("test.db")
DB.sql_log_level = :debug
DB.loggers << Logger.new($stdout)
DB.extension :async_thread_pool
Sequel::Model.plugin :concurrent_eager_loading
# create/recreate tables. DESTROYS ALL DATA.
DB.create_table! :foos do
primary_key :id
String :name
end
DB.create_table! :bars do
primary_key :id
foreign_key :foo_id, :foos, on_delete: :cascade
String :description
end
DB.create_table! :fizzes do
primary_key :id
foreign_key :foo_id, :foos, on_delete: :cascade
Integer :counter
end
DB.create_table! :buzzes do
primary_key :id
foreign_key :fizz_id, :fizzes, on_delete: :cascade
TrueClass :match
end
# Model definitions
class Foo < Sequel::Model (:foos)
one_to_many :bars, class: "Bar"
one_to_many :fizzes, class: "Fizz"
end
class Bar < Sequel::Model (:bars)
many_to_one :foo, class: "Foo"
end
class Fizz < Sequel::Model (:fizzes)
many_to_one :foo, class: "Foo"
one_to_many :buzzes, class: "Buzz"
end
class Buzz < Sequel::Model (:buzzes)
many_to_one :fizz, class: "Fizz"
end
# plug in some data.
foos = ['Andy', 'Jim', 'Tony'].map{|name|
Foo.new(name: name).save
}
bars = [['T1', 'T2'], ['E1', 'E2', 'E3'], ['A', 'B']].each_with_index.map{|for_foo, idx|
for_foo.map{|desc|
Bar.new(description: desc, foo_id: foos[idx].id).save
}
}
fizzes = [
[11, 12],
[21, 22, 23],
[31]
].each_with_index.map{|for_foo, idx|
foo_id = foos[idx].id
for_foo.map{|count|
Fizz.new(counter: count, foo_id: foo_id).save
}
}
buzzes = [
[[true, false], [true]],
[[], [true], [false]],
[[false, false]]
].each_with_index.map{|for_foo, idx|
for_foo.each_with_index{|for_fizz, jdx|
fizz_id = fizzes[idx][jdx].id
for_fizz.map{|matchval|
Buzz.new(match: matchval, fizz_id: fizz_id).save
}
}
}
# create some sinatra endpoints for testing
class ConcApp < Sinatra::Base
# this will succeed, and print out data.
get '/eager' do
foo = Foo.eager(:bars, fizzes: :buzzes).all.first
p_foo = CGI.escapeHTML(foo.inspect)
p_bars = CGI.escapeHTML(foo.bars.inspect)
p_fizzes = CGI.escapeHTML(foo.fizzes.inspect)
p_buzzes = CGI.escapeHTML(foo.fizzes.map{|f| f.buzzes}.inspect)
"Hello world
#{p_foo}
#{p_bars}
#{p_fizzes}
#{p_buzzes}"
end
# this will hang after fetching from the :foos table.
get '/eager-concurrent' do
foo = Foo.eager_load_concurrently.eager(:bars, fizzes: :buzzes).all.first
p_foo = CGI.escapeHTML(foo.inspect)
p_bars = CGI.escapeHTML(foo.bars.inspect)
p_fizzes = CGI.escapeHTML(foo.fizzes.inspect)
p_buzzes = CGI.escapeHTML(foo.fizzes.map{|f| f.buzzes}.inspect)
"Hello world
#{p_foo}
#{p_bars}
#{p_fizzes}
#{p_buzzes}"
end
get '/' do
foo = Foo.first
p_foo = CGI.escapeHTML(foo.inspect)
"Hello world\n#{p_foo}"
end
end
run Rack::Cascade.new [ConcApp]
if defined?(PhusionPassenger)
PhusionPassenger.on_event(:starting_worker_process) do |forked|
if forked
# We're in smart spawning mode; behave nice.
puts "DEBUG: Passenger forked spawning"
DB.disconnect
else
# We're in conservative spawning mode. We don't need to do anything.
end
end
end