sequel-rails 0.1.8 → 0.4.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. data/.gitignore +1 -0
  2. data/.rspec +3 -0
  3. data/.travis.yml +12 -0
  4. data/Gemfile +13 -16
  5. data/History.md +142 -0
  6. data/README.md +124 -0
  7. data/Rakefile +6 -30
  8. data/config.ru +7 -0
  9. data/lib/generators/sequel.rb +11 -8
  10. data/lib/generators/sequel/migration/migration_generator.rb +36 -11
  11. data/lib/generators/sequel/migration/templates/migration.rb.erb +48 -0
  12. data/lib/generators/sequel/model/model_generator.rb +8 -2
  13. data/lib/generators/sequel/model/templates/migration.rb.erb +16 -0
  14. data/lib/generators/sequel/model/templates/{model.rb → model.rb.erb} +4 -1
  15. data/lib/generators/sequel/observer/observer_generator.rb +2 -2
  16. data/lib/generators/sequel/observer/templates/{observer.rb → observer.rb.erb} +0 -0
  17. data/lib/sequel-rails.rb +1 -1
  18. data/lib/sequel_rails.rb +2 -0
  19. data/lib/sequel_rails/configuration.rb +64 -0
  20. data/lib/sequel_rails/migrations.rb +22 -0
  21. data/lib/sequel_rails/railtie.rb +94 -0
  22. data/lib/sequel_rails/railties/controller_runtime.rb +40 -0
  23. data/lib/sequel_rails/railties/database.rake +175 -0
  24. data/lib/sequel_rails/railties/i18n_support.rb +10 -0
  25. data/lib/sequel_rails/railties/log_subscriber.rb +56 -0
  26. data/lib/sequel_rails/sequel/database/active_support_notification.rb +28 -0
  27. data/lib/sequel_rails/sequel/plugins/rails_extensions.rb +35 -0
  28. data/lib/sequel_rails/session_store.rb +80 -0
  29. data/lib/sequel_rails/storage.rb +58 -0
  30. data/lib/sequel_rails/storage/abstract.rb +52 -0
  31. data/lib/sequel_rails/storage/jdbc.rb +45 -0
  32. data/lib/sequel_rails/storage/mysql.rb +31 -0
  33. data/lib/sequel_rails/storage/mysql2.rb +6 -0
  34. data/lib/sequel_rails/storage/postgres.rb +22 -0
  35. data/lib/sequel_rails/storage/sqlite.rb +26 -0
  36. data/lib/sequel_rails/version.rb +3 -0
  37. data/sequel-rails.gemspec +22 -86
  38. data/spec/internal/app/models/user.rb +2 -0
  39. data/spec/internal/config/database.yml +7 -0
  40. data/spec/internal/config/routes.rb +3 -0
  41. data/spec/internal/db/schema.rb +8 -0
  42. data/spec/internal/public/favicon.ico +0 -0
  43. data/spec/lib/generators/sequel/migration_spec.rb +256 -0
  44. data/spec/lib/sequel_rails/railtie_spec.rb +85 -0
  45. data/spec/lib/sequel_rails/railties/log_subscriber_spec.rb +29 -0
  46. data/spec/lib/sequel_rails/storage_spec.rb +108 -0
  47. data/spec/spec_helper.rb +30 -16
  48. data/tasks/spec.rake +63 -29
  49. metadata +194 -142
  50. data/CHANGELOG +0 -15
  51. data/README.rdoc +0 -86
  52. data/VERSION +0 -1
  53. data/autotest/discover.rb +0 -1
  54. data/lib/generators/sequel/migration/templates/migration.rb +0 -16
  55. data/lib/sequel-rails/configuration.rb +0 -61
  56. data/lib/sequel-rails/migrations.rb +0 -30
  57. data/lib/sequel-rails/railtie.rb +0 -90
  58. data/lib/sequel-rails/railties/benchmarking_mixin.rb +0 -23
  59. data/lib/sequel-rails/railties/controller_runtime.rb +0 -43
  60. data/lib/sequel-rails/railties/database.rake +0 -148
  61. data/lib/sequel-rails/railties/i18n_support.rb +0 -12
  62. data/lib/sequel-rails/railties/log_subscriber.rb +0 -31
  63. data/lib/sequel-rails/runtime.rb +0 -14
  64. data/lib/sequel-rails/session_store.rb +0 -82
  65. data/lib/sequel-rails/setup.rb +0 -19
  66. data/lib/sequel-rails/storage.rb +0 -210
  67. data/spec/rcov.opts +0 -6
  68. data/spec/setup_spec.rb +0 -7
  69. data/spec/spec.opts +0 -4
  70. data/tasks/ci.rake +0 -1
  71. data/tasks/clean.rake +0 -6
  72. data/tasks/metrics.rake +0 -37
  73. data/tasks/yard.rake +0 -9
  74. data/tasks/yardstick.rake +0 -20
@@ -0,0 +1,10 @@
1
+ module SequelRails
2
+
3
+ module I18nSupport
4
+ # Set the i18n scope to overwrite ActiveModel.
5
+ def i18n_scope #:nodoc:
6
+ :sequel
7
+ end
8
+ end
9
+
10
+ end
@@ -0,0 +1,56 @@
1
+ module SequelRails
2
+ module Railties
3
+
4
+ class LogSubscriber < ActiveSupport::LogSubscriber
5
+
6
+ def self.runtime=(value)
7
+ Thread.current["sequel_sql_runtime"] = value
8
+ end
9
+
10
+ def self.runtime
11
+ Thread.current["sequel_sql_runtime"] ||= 0
12
+ end
13
+
14
+ def self.reset_runtime
15
+ rt, self.runtime = runtime, 0
16
+ rt
17
+ end
18
+
19
+ def sql(event)
20
+ self.class.runtime += event.duration
21
+ return unless logger.debug?
22
+
23
+ payload = event.payload
24
+
25
+ name = '%s (%.1fms)' % [payload[:name], event.duration]
26
+ sql = payload[:sql].squeeze(' ')
27
+ binds = nil
28
+
29
+ unless (payload[:binds] || []).empty?
30
+ binds = " " + payload[:binds].map { |col,v|
31
+ [col.name, v]
32
+ }.inspect
33
+ end
34
+
35
+ if odd?
36
+ name = color(name, :cyan, true)
37
+ sql = color(sql, nil, true)
38
+ else
39
+ name = color(name, :magenta, true)
40
+ end
41
+
42
+ debug " #{name} #{sql}#{binds}"
43
+ end
44
+
45
+ def odd?
46
+ @odd_or_even = !@odd_or_even
47
+ end
48
+
49
+ def logger
50
+ ::SequelRails.configuration.logger
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,28 @@
1
+ require "sequel/database/logging"
2
+ require "active_support/notifications"
3
+
4
+ module Sequel
5
+ class Database
6
+
7
+ def log_yield(sql, args=nil)
8
+ sql_for_log = args ? "#{sql}; #{args.inspect}" : sql
9
+ start = Time.now
10
+ begin
11
+ ::ActiveSupport::Notifications.instrument(
12
+ "sql.sequel",
13
+ sql: sql,
14
+ name: self.class,
15
+ binds: args,
16
+ ) do
17
+ yield
18
+ end
19
+ rescue => e
20
+ log_exception(e, sql_for_log) unless @loggers.empty?
21
+ raise
22
+ ensure
23
+ log_duration(Time.now - start, sql_for_log) unless e || @loggers.empty?
24
+ end
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,35 @@
1
+ require "sequel"
2
+
3
+ module Sequel
4
+ module Plugins
5
+ # The RailsExtensions plugin adds a single class method to Sequel::Model in
6
+ # order to make its use in controllers a little more like ActiveRecord's.
7
+ # The +find!+ method is added which will raise an exception if no object is
8
+ # found. By adding the following code to a Railtie:
9
+ #
10
+ # config.action_dispatch.rescue_responses.merge!(
11
+ # 'Sequel::Plugins::RailsExtensions::ModelNotFound' => :not_found
12
+ # )
13
+ #
14
+ # Usage:
15
+ #
16
+ # # Apply plugin to all models:
17
+ # Sequel::Model.plugin :rails_extensions
18
+ #
19
+ # # Apply plugin to a single model:
20
+ # Album.plugin :rails_extensions
21
+ module RailsExtensions
22
+ class ModelNotFound < Sequel::Error
23
+ end
24
+
25
+ module ClassMethods
26
+ def find!(args)
27
+ m = self[args]
28
+ raise ModelNotFound, "Couldn't find #{self} matching #{args}." unless m
29
+ m
30
+ end
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,80 @@
1
+ require "sequel"
2
+
3
+ # Implements Sequel-specific session store.
4
+
5
+ module SequelRails
6
+
7
+ class SessionStore < ActionDispatch::Session::AbstractStore
8
+
9
+ class Session < ::Sequel::Model
10
+
11
+ # property :id, Serial
12
+ # property :session_id, String, :required => true, :unique => true, :unique_index => true
13
+ # property :data, Object, :required => true, :default => ActiveSupport::Base64.encode64(Marshal.dump({}))
14
+ # property :updated_at, DateTime, :required => false, :index => true
15
+
16
+ class << self
17
+
18
+ def auto_migrate!
19
+ self.db.create_table :sessions do
20
+ primary_key :id
21
+ column :session_id, String,
22
+ :null => false,
23
+ :unique => true,
24
+ :index => true
25
+
26
+ column :data, :text,
27
+ :null => false
28
+
29
+ column :updated_at, DateTime,
30
+ :null => true,
31
+ :index => true
32
+ end
33
+ end
34
+
35
+ end
36
+
37
+ def self.name
38
+ 'session'
39
+ end
40
+
41
+ end
42
+
43
+ SESSION_RECORD_KEY = 'rack.session.record'.freeze
44
+
45
+ cattr_accessor :session_class
46
+ self.session_class = Session
47
+
48
+ private
49
+
50
+ def get_session(env, sid)
51
+ sid ||= generate_sid
52
+ session = find_session(sid)
53
+ env[SESSION_RECORD_KEY] = session
54
+ [ sid, session.data ]
55
+ end
56
+
57
+ def set_session(env, sid, session_data)
58
+ session = get_session_resource(env, sid)
59
+ session.data = session_data
60
+ session.updated_at = Time.now if session.dirty?
61
+ session.save
62
+ end
63
+
64
+ def get_session_resource(env, sid)
65
+ if env[ENV_SESSION_OPTIONS_KEY][:id].nil?
66
+ env[SESSION_RECORD_KEY] = find_session(sid)
67
+ else
68
+ env[SESSION_RECORD_KEY] ||= find_session(sid)
69
+ end
70
+ end
71
+
72
+ def find_session(sid)
73
+ klass = self.class.session_class
74
+
75
+ klass.where(:session_id => sid).first || klass.new(:session_id => sid)
76
+ end
77
+
78
+ end
79
+
80
+ end
@@ -0,0 +1,58 @@
1
+ require "sequel_rails/storage/abstract"
2
+ require "sequel_rails/storage/sqlite"
3
+ require "sequel_rails/storage/mysql"
4
+ require "sequel_rails/storage/mysql2"
5
+ require "sequel_rails/storage/postgres"
6
+ require "sequel_rails/storage/jdbc"
7
+
8
+ module SequelRails
9
+ module Storage
10
+ def self.create_all
11
+ with_local_repositories { |config| create_environment(config) }
12
+ end
13
+
14
+ def self.drop_all
15
+ with_local_repositories { |config| drop_environment(config) }
16
+ end
17
+
18
+ def self.create_environment(config)
19
+ adapter_for(config).create
20
+ end
21
+
22
+ def self.drop_environment(config)
23
+ adapter_for(config).drop
24
+ end
25
+
26
+ def self.adapter_for(config_or_env)
27
+ config = if config_or_env.kind_of? Hash
28
+ config_or_env
29
+ else
30
+ ::SequelRails.configuration.environments[config_or_env.to_s]
31
+ end
32
+ lookup_class(config['adapter']).new config
33
+ end
34
+
35
+ private
36
+
37
+ def self.with_local_repositories
38
+ ::SequelRails.configuration.environments.each_value do |config|
39
+ next if config['database'].blank?
40
+ if config['host'].blank? || %w[ 127.0.0.1 localhost ].include?(config['host'])
41
+ yield config
42
+ else
43
+ puts "This task only modifies local databases. #{config['database']} is on a remote host."
44
+ end
45
+ end
46
+ end
47
+
48
+ def self.lookup_class(adapter)
49
+ klass_name = adapter.camelize.to_sym
50
+
51
+ unless self.const_defined?(klass_name)
52
+ raise "Adapter #{adapter} not supported (#{klass_name.inspect})"
53
+ end
54
+
55
+ const_get klass_name
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,52 @@
1
+ module SequelRails
2
+ module Storage
3
+ class Abstract
4
+
5
+ attr_reader :config
6
+
7
+ def initialize(config)
8
+ @config = config
9
+ end
10
+
11
+ def create
12
+ _create
13
+ puts "[sequel] Created database '#{database}'"
14
+ end
15
+
16
+ def drop
17
+ ::Sequel::Model.db.disconnect
18
+ _drop
19
+ puts "[sequel] Dropped database '#{database}'"
20
+ end
21
+
22
+ def database
23
+ @database ||= config['database'] || config['path']
24
+ end
25
+
26
+ def username
27
+ @username ||= config['username'] || config['user'] || ''
28
+ end
29
+
30
+ def password
31
+ @password ||= config['password'] || ''
32
+ end
33
+
34
+ def host
35
+ @host ||= config['host'] || ''
36
+ end
37
+
38
+ def port
39
+ @port ||= config['port'] || ''
40
+ end
41
+
42
+ def owner
43
+ @owner ||= config['owner'] || ''
44
+ end
45
+
46
+ def charset
47
+ @charset ||= config['charset'] || ENV['CHARSET'] || 'utf8'
48
+ end
49
+
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,45 @@
1
+ module SequelRails
2
+ module Storage
3
+ class Jdbc < Abstract
4
+
5
+ def _is_mysql?
6
+ database.match(/^jdbc:mysql/)
7
+ end
8
+
9
+ def _root_url
10
+ database.scan(/^jdbc:mysql:\/\/\w*:?\d*/)
11
+ end
12
+
13
+ def db_name
14
+ database.scan(/^jdbc:mysql:\/\/\w+:?\d*\/(\w+)/).flatten.first
15
+ end
16
+
17
+ def _params
18
+ database.scan(/\?.*$/)
19
+ end
20
+
21
+ def _create
22
+ if _is_mysql?
23
+ ::Sequel.connect("#{_root_url}#{_params}") do |db|
24
+ db.execute("CREATE DATABASE IF NOT EXISTS `#{db_name}` DEFAULT CHARACTER SET #{charset} DEFAULT COLLATE #{collation}")
25
+ end
26
+ end
27
+ end
28
+
29
+ def _drop
30
+ if _is_mysql?
31
+ ::Sequel.connect("#{_root_url}#{_params}") do |db|
32
+ db.execute("DROP DATABASE IF EXISTS `#{db_name}`")
33
+ end
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def collation
40
+ @collation ||= config['collation'] || ENV['COLLATION'] || 'utf8_unicode_ci'
41
+ end
42
+
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,31 @@
1
+ require 'shellwords'
2
+
3
+ module SequelRails
4
+ module Storage
5
+ class Mysql < Abstract
6
+ def _create
7
+ execute("CREATE DATABASE IF NOT EXISTS `#{database}` DEFAULT CHARACTER SET #{charset} DEFAULT COLLATE #{collation}")
8
+ end
9
+
10
+ def _drop
11
+ execute("DROP DATABASE IF EXISTS `#{database}`")
12
+ end
13
+
14
+ private
15
+
16
+ def execute(statement)
17
+ commands = ["mysql"]
18
+ commands << "--user=#{Shellwords.escape(username)}" unless username.blank?
19
+ commands << "--password=#{Shellwords.escape(password)}" unless password.blank?
20
+ commands << "--host=#{host}" unless host.blank?
21
+ commands << "-e" << statement
22
+ system(*commands)
23
+ end
24
+
25
+ def collation
26
+ @collation ||= config['collation'] || ENV['COLLATION'] || 'utf8_unicode_ci'
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,6 @@
1
+ module SequelRails
2
+ module Storage
3
+ class Mysql2 < Mysql
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,22 @@
1
+ module SequelRails
2
+ module Storage
3
+ class Postgres < Abstract
4
+ def _create
5
+ ENV["PGPASSWORD"] = password unless password.blank?
6
+ commands = ["createdb", "--encoding", charset]
7
+ commands << "--username" << username unless username.blank?
8
+ commands << "--owner" << owner unless owner.blank?
9
+ commands << "--port" << port unless port.blank?
10
+ commands << "--host" << host unless host.blank?
11
+ commands << database
12
+ res = system(*commands)
13
+ ENV["PGPASSWORD"] = nil
14
+ res
15
+ end
16
+
17
+ def _drop
18
+ system("dropdb", "-U", username, database)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,26 @@
1
+ module SequelRails
2
+ module Storage
3
+ class Sqlite < Abstract
4
+ def _create
5
+ return if in_memory?
6
+ ::Sequel.connect(config.merge('database' => path))
7
+ end
8
+
9
+ def _drop
10
+ return if in_memory?
11
+ path.unlink if path.file?
12
+ end
13
+
14
+ private
15
+
16
+ def in_memory?
17
+ database == ':memory:'
18
+ end
19
+
20
+ def path
21
+ @path ||= Pathname(File.expand_path(database, Rails.root))
22
+ end
23
+
24
+ end
25
+ end
26
+ end