Skip to content

Instantly share code, notes, and snippets.

@dux
Last active January 6, 2023 18:18
Show Gist options
  • Save dux/3750be692ef9478267377419e1ab563b to your computer and use it in GitHub Desktop.
Save dux/3750be692ef9478267377419e1ab563b to your computer and use it in GitHub Desktop.
Ruby Sequel switch databases on the fly
  1. I wanted to keep global user data in one database and org data in separate database
  2. I want to use Sequel models in the same way as I was using a single databases
  3. I need simple interface to define that model data resides in Organization and not Global DB

Only possible solution I found is by patching Sequel native methods. If anyone knows better way to do it, like injecting DB connection just before dataset executes a query, please comment and explain.

I tried to use "sharding" and "arbitrary_servers", but that is not what I want. I have 1000nds of orgs, and 1000nds of DBs. I need connections to be fuly dynamic and I want to define request context once when request starts in Thread.current.

module Sequel::Plugins::OrgData
module ClassMethods
def __modelize data
new.tap do |model|
model.instance_exec { @values = data }
end
end
def __conn
Thread.current[:org_db]
end
def find id
__modelize __conn[to_s.tableize.to_sym].where(id:id).first
end
end
module DatasetMethods
def count
custom = sql.sub 'SELECT * ', 'select count(id) as cnt '
model.__conn.fetch(custom).first[:cnt]
end
def each &block
model.__conn.fetch(sql).each do |row|
block.call self.model.__modelize(row)
end
end
end
end
###
# User and Invoice data is in org database shards
User.plugin :org_data
Invoice.plugin :org_data
###
org = Org[123] # comes from default DB, "postgres://some_server:5432/app_data"
inv = org.invoices # comes from ORG DB, "postgres://some_server:5432/app_org_data_123"
###
def get_it
puts [
User.find(1).name,
User.where(org_id: 123).count,
User.first(3).map(&:name).join(', ')
].join(' --- ')
end
Thread.current[:org_db] = Sequel.connect('postgres://localhost:5432/app_org_data_1')
get_it
Thread.current[:org_db] = Sequel.connect('postgres://localhost:5432/app_org_data_2')
get_it
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment