Created
June 23, 2010 23:36
-
-
Save tmm1/450736 to your computer and use it in GitHub Desktop.
patch to add sequel support to a new rails3 app
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/app/models/model.rb b/app/models/model.rb | |
new file mode 100644 | |
index 0000000..14c4620 | |
--- /dev/null | |
+++ b/app/models/model.rb | |
@@ -0,0 +1,2 @@ | |
+class Model < Sequel::Model | |
+end | |
\ No newline at end of file | |
diff --git a/config/application.rb b/config/application.rb | |
index 43d772f..6bc5bf0 100644 | |
--- a/config/application.rb | |
+++ b/config/application.rb | |
@@ -1,6 +1,11 @@ | |
require File.expand_path('../boot', __FILE__) | |
-require 'rails/all' | |
+# Since we don't need ActiveRecord or ActiveResource we'll just pick | |
+# which frameworks to include in our app | |
+# require 'rails/all' | |
+require 'active_support/all' | |
+require 'action_controller/railtie' | |
+require 'action_mailer/railtie' | |
# If you have a Gemfile, require the gems listed there, including any gems | |
# you've limited to :test, :development, or :production. | |
diff --git a/config/initializers/sequel.rb b/config/initializers/sequel.rb | |
new file mode 100644 | |
index 0000000..231a6f9 | |
--- /dev/null | |
+++ b/config/initializers/sequel.rb | |
@@ -0,0 +1,45 @@ | |
+# TODO modify sequel serialization plugin to use yajl as a backend | |
+require 'yajl/json_gem' | |
+JSON.default_options.merge! :symbolize_keys=>true | |
+ | |
+module Kernel | |
+ if defined? id | |
+ undef :id | |
+ undef :type | |
+ end | |
+end | |
+ | |
+module Sequel | |
+ class Dataset | |
+ def size | |
+ count | |
+ end | |
+ end | |
+end | |
+ | |
+# Setup plugins and extensions we're using | |
+Sequel.extension :pagination | |
+Sequel.extension :pretty_table | |
+ | |
+Sequel::Model.unrestrict_primary_key | |
+Sequel::Model.plugin :hook_class_methods | |
+Sequel::Model.plugin :active_model | |
+Sequel::Model.plugin :validation_helpers | |
+Sequel::Model.plugin :timestamps | |
+Sequel::Plugins::ValidationHelpers::DEFAULT_OPTIONS[:presence].update( | |
+ :message => lambda{"is missing"} | |
+) | |
+ | |
+# this lives in /lib | |
+require File.expand_path('../../../lib/sequel_extensions', __FILE__) | |
+ | |
+Sequel.default_timezone = :utc | |
+ | |
+# clear out any existing connections | |
+Sequel::DATABASES.clear | |
+Sequel::Model.db = nil | |
+ | |
+# connect to the db configured for the current Rails.env | |
+DB = Sequel.connect(Rails.configuration.database_configuration[Rails.env]) | |
+ | |
+DB.loggers << Rails.logger | |
\ No newline at end of file | |
diff --git a/db/migrate/20100623000000_model.rb b/db/migrate/20100623000000_model.rb | |
new file mode 100644 | |
index 0000000..1dca971 | |
--- /dev/null | |
+++ b/db/migrate/20100623000000_model.rb | |
@@ -0,0 +1,22 @@ | |
+Class.new(Sequel::Migration) do | |
+ def up | |
+ create_table :models do | |
+ primary_key :id | |
+ varchar :name, :null => false | |
+ int :size | |
+ blob :data | |
+ datetime :created_at | |
+ | |
+ index :created_at | |
+ end | |
+ alter_table :models do | |
+ drop_column :name | |
+ add_column :description, :blob | |
+ set_column_type :description, :text | |
+ end | |
+ end | |
+ | |
+ def down | |
+ drop_table :models | |
+ end | |
+end | |
\ No newline at end of file | |
diff --git a/lib/sequel_extensions.rb b/lib/sequel_extensions.rb | |
new file mode 100644 | |
index 0000000..4a47b63 | |
--- /dev/null | |
+++ b/lib/sequel_extensions.rb | |
@@ -0,0 +1,49 @@ | |
+require 'securerandom' | |
+ | |
+class Sequel::Model | |
+ def type | |
+ self[:type] | |
+ end | |
+ | |
+ def_dataset_method :on_duplicate_key_update, :insert_ignore | |
+ | |
+ def set_columns(params, *fields) | |
+ fields = fields.flatten | |
+ params = params.reject{ |k,v| !fields.include?(k.to_sym) } | |
+ set_only(params, fields) | |
+ end | |
+ | |
+ def save! | |
+ save(:validate=>false) | |
+ end | |
+ | |
+ def full_messages(options = {}) | |
+ full_messages = [] | |
+ | |
+ @errors.each_key do |attr| | |
+ @errors[attr].each do |message| | |
+ next unless message | |
+ | |
+ if attr == "base" | |
+ full_messages << message | |
+ else | |
+ attr_name = @base.class.human_attribute_name(attr) | |
+ full_messages << attr_name + I18n.t('activerecord.errors.format.separator', :default => ' ') + message | |
+ end | |
+ end | |
+ end | |
+ full_messages | |
+ end | |
+ | |
+ alias :attributes :values | |
+end | |
+ | |
+class Sequel::Dataset | |
+ def keyed_hash(key) | |
+ inject({}){|h,v| h.update v[key] => v } | |
+ end | |
+ | |
+ def keyed_arr_hash(key) | |
+ inject(Hash.new{|ho,k| ho[k] = []}){|h,v| h[v[key]] << v; h} | |
+ end | |
+end | |
\ No newline at end of file | |
diff --git a/lib/sequel_migration.rb b/lib/sequel_migration.rb | |
new file mode 100644 | |
index 0000000..233b9eb | |
--- /dev/null | |
+++ b/lib/sequel_migration.rb | |
@@ -0,0 +1,159 @@ | |
+require File.expand_path('../config/application', __FILE__) | |
+require 'active_record/errors' | |
+require 'active_record/migration' | |
+ | |
+DB = Sequel.connect(Rails.configuration.database_configuration[Rails.env]) | |
+DB.loggers << Logger.new(STDOUT) | |
+ | |
+if defined? ActiveRecord::Base | |
+ raise "cannot use the migration hack if ActiveRecord::Base exists" | |
+else | |
+ module ActiveRecord::Base | |
+ class << self | |
+ def connection | |
+ unless DB.respond_to?(:initialize_schema_migrations_table) | |
+ def DB.initialize_schema_migrations_table | |
+ unless table_exists?(:schema_migrations) | |
+ create_table(:schema_migrations) do | |
+ varchar :version, :null => false, :unique => true | |
+ end | |
+ | |
+ if table_exists?(:schema_info) | |
+ version = DB[:schema_info].get(:version) | |
+ migrated = DB[:schema_migrations].select(:version).map(:version).map(&:to_i) | |
+ | |
+ migrations_path = ActiveRecord::Migrator.migrations_path | |
+ versions = Dir["#{migrations_path}/[0-9]*_*.rb"].map do |filename| | |
+ filename.split('/').last.split('_').first.to_i | |
+ end | |
+ | |
+ DB[:schema_migrations].insert_ignore.insert(:version => version) | |
+ | |
+ inserted = Set.new | |
+ (versions - migrated).each do |v| | |
+ if inserted.include?(v) | |
+ raise "Duplicate migration #{v}. Please renumber your migrations to resolve the conflict." | |
+ elsif v < version | |
+ DB[:schema_migrations].insert(:version => v) | |
+ inserted << v | |
+ end | |
+ end | |
+ | |
+ DB.drop_table(:schema_info) | |
+ end | |
+ end | |
+ end | |
+ def DB.supports_migrations? | |
+ true | |
+ end | |
+ def DB.supports_ddl_transactions? | |
+ false | |
+ end | |
+ end | |
+ | |
+ DB | |
+ end | |
+ def logger | |
+ DB.loggers.first | |
+ end | |
+ def transaction(&blk) | |
+ DB.transaction(&blk) | |
+ end | |
+ end | |
+ end | |
+end | |
+ | |
+module Sequel | |
+ extension :migration | |
+ remove_const :Migrator | |
+ class Migration | |
+ class << self | |
+ def migrate(direction) | |
+ case direction | |
+ when :up then announce "migrating" | |
+ when :down then announce "reverting" | |
+ end | |
+ | |
+ result = nil | |
+ time = Benchmark.measure { result = new(DB).send(direction) } | |
+ | |
+ case direction | |
+ when :up then announce "migrated (%.4fs)" % time.real; write | |
+ when :down then announce "reverted (%.4fs)" % time.real; write | |
+ end | |
+ | |
+ result | |
+ end | |
+ | |
+ def write(text="") | |
+ puts(text) | |
+ end | |
+ | |
+ def announce(message) | |
+ version = defined?(@version) ? @version : nil | |
+ | |
+ text = "#{version} #{name}: #{message}" | |
+ length = [0, 75 - text.length].max | |
+ write "== %s %s" % [text, "=" * length] | |
+ end | |
+ end | |
+ end | |
+ class MigrationProxy < ActiveRecord::MigrationProxy | |
+ def load_migration | |
+ Migration.descendants.clear | |
+ load(File.expand_path(filename)) | |
+ klass = Migration.descendants.last | |
+ klass | |
+ end | |
+ end | |
+ class Migrator < ActiveRecord::Migrator | |
+ class << self | |
+ def schema_migrations_table_name | |
+ :schema_migrations | |
+ end | |
+ def migrations_table | |
+ DB[schema_migrations_table_name] | |
+ end | |
+ def get_all_versions | |
+ migrations_table.select(:version).map(:version).map(&:to_i).sort | |
+ end | |
+ def current_version | |
+ if DB.table_exists?(schema_migrations_table_name) | |
+ migrations_table.order(:version.desc).limit(1).get(:version) || 0 | |
+ else | |
+ 0 | |
+ end | |
+ end | |
+ def proper_table_name(name) | |
+ name | |
+ end | |
+ end | |
+ | |
+ def migrations | |
+ unless @migrations | |
+ super | |
+ @migrations.map!{ |m| | |
+ o = MigrationProxy.new | |
+ o.name, o.version, o.filename = m.name, m.version, m.filename | |
+ o | |
+ } | |
+ end | |
+ @migrations | |
+ end | |
+ | |
+ def record_version_state_after_migrating(version) | |
+ @migrated_versions ||= [] | |
+ if down? | |
+ @migrated_versions.delete(version) | |
+ self.class.migrations_table.where(:version => version).delete | |
+ else | |
+ @migrated_versions.push(version).sort! | |
+ self.class.migrations_table.insert(:version => version) | |
+ end | |
+ end | |
+ | |
+ def ddl_transaction | |
+ yield # assume no transactions for ddl (mysql) | |
+ end | |
+ end | |
+end | |
\ No newline at end of file | |
diff --git a/lib/tasks/sequel.rake b/lib/tasks/sequel.rake | |
new file mode 100644 | |
index 0000000..2f20b78 | |
--- /dev/null | |
+++ b/lib/tasks/sequel.rake | |
@@ -0,0 +1,147 @@ | |
+# TODO: DRY these up | |
+namespace :db do | |
+ namespace :schema do | |
+ desc "Create a db/schema.rb file that can be portably used against any DB supported by Sequel" | |
+ task :dump do | |
+ Sequel.extension :schema_dumper | |
+ db = Sequel.connect(Rails.configuration.database_configuration[Rails.env]) | |
+ File.open(ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb", "w") do |file| | |
+ file.write(db.dump_schema_migration) | |
+ end | |
+ Rake::Task["db:schema:dump"].reenable | |
+ end | |
+ | |
+ desc "Load a schema.rb file into the database" | |
+ task :load do | |
+ file = ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb" | |
+ if File.exists?(file) | |
+ load(file) | |
+ else | |
+ abort %{#{file} doesn't exist yet. Run "rake db:migrate" to create it then try again. If you do not intend to use a database, you should instead alter #{Rails.root}/config/boot.rb to limit the frameworks that will be loaded} | |
+ end | |
+ end | |
+ end | |
+ | |
+ namespace :create do | |
+ desc 'Create all the local databases defined in config/database.yml' | |
+ task :all do | |
+ Rails.configuration.database_configuration.each_value do |config| | |
+ next unless config['database'] | |
+ database = config.delete('database') | |
+ DB = Sequel.connect(config) | |
+ default_options = "DEFAULT CHARSET utf8 COLLATE utf8_unicode_ci" | |
+ puts "Creating database \"#{config['database']}\" if it doesn't already exist" | |
+ DB.run "CREATE DATABASE IF NOT EXISTS `#{config['database']}` /*!40100 #{default_options} */" | |
+ end | |
+ end | |
+ end | |
+ | |
+ desc "Create the database defined in config/database.yml for the current Rails.env - also creates the test database if Rails.env.development?" | |
+ task :create do | |
+ connect_options = Rails.configuration.database_configuration[Rails.env] | |
+ connect_options.delete('database') | |
+ DB = Sequel.connect(connect_options) | |
+ default_options = "DEFAULT CHARSET utf8 COLLATE utf8_unicode_ci" | |
+ puts "Creating database \"#{Rails.configuration.database_configuration[Rails.env]['database']}\" if it doesn't already exist" | |
+ DB.run "CREATE DATABASE IF NOT EXISTS `#{Rails.configuration.database_configuration[Rails.env]['database']}` /*!40100 #{default_options} */" | |
+ if Rails.env.development? && Rails.configuration.database_configuration['test'] | |
+ puts "Creating database \"#{Rails.configuration.database_configuration['test']['database']}\" if it doesn't already exist" | |
+ DB.run "CREATE DATABASE IF NOT EXISTS `#{Rails.configuration.database_configuration['test']['database']}` /*!40100 #{default_options} */" | |
+ end | |
+ end | |
+ | |
+ namespace :drop do | |
+ desc 'Drops all the local databases defined in config/database.yml' | |
+ task :all do | |
+ Rails.configuration.database_configuration.each_value do |config| | |
+ next unless config['database'] | |
+ database = config.delete('database') | |
+ DB = Sequel.connect(config) | |
+ puts "Dropping database #{database} if it exists" | |
+ DB.run "DROP DATABASE IF EXISTS `#{database}`" | |
+ end | |
+ end | |
+ end | |
+ | |
+ desc "Create the database defined in config/database.yml for the current Rails.env - also creates the test database if Rails.env.development?" | |
+ task :drop do | |
+ connect_options = Rails.configuration.database_configuration[Rails.env] | |
+ connect_options.delete('database') | |
+ DB = Sequel.connect(connect_options) | |
+ | |
+ puts "Dropping database #{Rails.configuration.database_configuration[Rails.env]['database']} if it exists" | |
+ DB.run "DROP DATABASE IF EXISTS `#{Rails.configuration.database_configuration[Rails.env]['database']}`" | |
+ end | |
+ | |
+ namespace :migrate do | |
+ task :load do | |
+ require File.expand_path('../../sequel_migration', __FILE__) | |
+ end | |
+ | |
+ desc 'Rollbacks the database one migration and re migrate up. If you want to rollback more than one step, define STEP=x. Target specific version with VERSION=x.' | |
+ task :redo => :load do | |
+ if ENV["VERSION"] | |
+ Rake::Task["db:migrate:down"].invoke | |
+ Rake::Task["db:migrate:up"].invoke | |
+ else | |
+ Rake::Task["db:rollback"].invoke | |
+ Rake::Task["db:migrate"].invoke | |
+ end | |
+ end | |
+ | |
+ desc 'Resets your database using your migrations for the current environment' | |
+ task :reset => ["db:drop", "db:create", "db:migrate"] | |
+ | |
+ desc 'Runs the "up" for a given migration VERSION.' | |
+ task :up => :load do | |
+ version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil | |
+ raise "VERSION is required" unless version | |
+ Sequel::Migrator.run(:up, "db/migrate/", version) | |
+ Rake::Task["db:schema:dump"].invoke | |
+ end | |
+ | |
+ desc 'Runs the "down" for a given migration VERSION.' | |
+ task :down => :load do | |
+ version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil | |
+ raise "VERSION is required" unless version | |
+ Sequel::Migrator.run(:down, "db/migrate/", version) | |
+ Rake::Task["db:schema:dump"].invoke | |
+ end | |
+ end | |
+ | |
+ desc 'Migrate the database to the latest version' | |
+ task :migrate => :'migrate:load' do | |
+ Sequel::Migrator.migrate("db/migrate/", ENV["VERSION"] ? ENV["VERSION"].to_i : nil) | |
+ Rake::Task["db:schema:dump"].invoke | |
+ end | |
+ | |
+ desc 'Rolls the schema back to the previous version. Specify the number of steps with STEP=n' | |
+ task :rollback => :'migrate:load' do | |
+ step = ENV['STEP'] ? ENV['STEP'].to_i : 1 | |
+ Sequel::Migrator.rollback('db/migrate/', step) | |
+ Rake::Task["db:schema:dump"].invoke | |
+ end | |
+ | |
+ desc 'Pushes the schema to the next version. Specify the number of steps with STEP=n' | |
+ task :forward => :'migrate:load' do | |
+ step = ENV['STEP'] ? ENV['STEP'].to_i : 1 | |
+ Sequel::Migrator.forward('db/migrate/', step) | |
+ Rake::Task["db:schema:dump"].invoke | |
+ end | |
+ | |
+ desc 'Load the seed data from db/seeds.rb' | |
+ task :seed => :environment do | |
+ seed_file = File.join(Rails.root, 'db', 'seeds.rb') | |
+ load(seed_file) if File.exist?(seed_file) | |
+ end | |
+ | |
+ desc 'Create the database, load the schema, and initialize with the seed data' | |
+ task :setup => [ 'db:create', 'db:migrate', 'db:seed' ] | |
+ | |
+ desc 'Drops and recreates the database from db/schema.rb for the current environment and loads the seeds.' | |
+ task :reset => [ 'db:drop', 'db:setup' ] | |
+ | |
+ namespace :test do | |
+ task :prepare => ['db:reset'] | |
+ end | |
+end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment