tpitale-dm-rails 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/Gemfile +63 -0
- data/LICENSE +20 -0
- data/README.rdoc +595 -0
- data/Rakefile +27 -0
- data/VERSION +1 -0
- data/dm-rails.gemspec +94 -0
- data/lib/dm-rails/configuration.rb +76 -0
- data/lib/dm-rails/mass_assignment_security.rb +89 -0
- data/lib/dm-rails/middleware/identity_map.rb +20 -0
- data/lib/dm-rails/multiparameter_attributes.rb +167 -0
- data/lib/dm-rails/railtie.rb +100 -0
- data/lib/dm-rails/railties/controller_runtime.rb +45 -0
- data/lib/dm-rails/railties/database.rake +106 -0
- data/lib/dm-rails/railties/i18n_support.rb +12 -0
- data/lib/dm-rails/railties/log_listener.rb +39 -0
- data/lib/dm-rails/railties/log_subscriber.rb +54 -0
- data/lib/dm-rails/session_store.rb +77 -0
- data/lib/dm-rails/setup.rb +84 -0
- data/lib/dm-rails/storage.rb +209 -0
- data/lib/dm-rails.rb +1 -0
- data/lib/generators/data_mapper/migration/migration_generator.rb +30 -0
- data/lib/generators/data_mapper/migration/templates/migration.rb +23 -0
- data/lib/generators/data_mapper/model/model_generator.rb +23 -0
- data/lib/generators/data_mapper/model/templates/model.rb +11 -0
- data/lib/generators/data_mapper/observer/observer_generator.rb +19 -0
- data/lib/generators/data_mapper/observer/templates/observer.rb +7 -0
- data/lib/generators/data_mapper.rb +82 -0
- data/spec/models/fake.rb +31 -0
- data/spec/models/topic.rb +11 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/unit/mass_assignment_security_spec.rb +43 -0
- data/spec/unit/multiparameter_attributes_spec.rb +168 -0
- data/tasks/clean.rake +6 -0
- data/tasks/yard.rake +9 -0
- data/tasks/yardstick.rake +20 -0
- metadata +161 -0
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'dm-rails/setup'
|
2
|
+
require 'dm-rails/storage'
|
3
|
+
|
4
|
+
namespace :db do
|
5
|
+
|
6
|
+
desc 'Create the database, load the schema, and initialize with the seed data'
|
7
|
+
task :setup => [ 'db:create', 'db:automigrate', 'db:seed' ]
|
8
|
+
|
9
|
+
namespace :create do
|
10
|
+
desc 'Create all the local databases defined in config/database.yml'
|
11
|
+
task :all => :environment do
|
12
|
+
Rails::DataMapper.storage.create_all
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "Create all local databases defined for the current Rails.env"
|
17
|
+
task :create => :environment do
|
18
|
+
Rails::DataMapper.storage.create_environment(Rails::DataMapper.configuration.repositories[Rails.env])
|
19
|
+
end
|
20
|
+
|
21
|
+
namespace :drop do
|
22
|
+
desc 'Drop all the local databases defined in config/database.yml'
|
23
|
+
task :all => :environment do
|
24
|
+
Rails::DataMapper.storage.drop_all
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "Drop all local databases defined for the current Rails.env"
|
29
|
+
task :drop => :environment do
|
30
|
+
Rails::DataMapper.storage.drop_environment(Rails::DataMapper.configuration.repositories[Rails.env])
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
desc 'Perform destructive automigration of all repositories in the current Rails.env'
|
35
|
+
task :automigrate => :environment do
|
36
|
+
require 'dm-migrations'
|
37
|
+
Rails::DataMapper.configuration.repositories[Rails.env].each do |repository, config|
|
38
|
+
::DataMapper.auto_migrate!(repository.to_sym)
|
39
|
+
puts "[datamapper] Finished auto_migrate! for :#{repository} repository '#{config['database']}'"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
desc 'Perform non destructive automigration of all repositories in the current Rails.env'
|
44
|
+
task :autoupgrade => :environment do
|
45
|
+
require 'dm-migrations'
|
46
|
+
Rails::DataMapper.configuration.repositories[Rails.env].each do |repository, config|
|
47
|
+
::DataMapper.auto_upgrade!(repository.to_sym)
|
48
|
+
puts "[datamapper] Finished auto_upgrade! for :#{repository} repository '#{config['database']}'"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
desc 'Load the seed data from db/seeds.rb'
|
53
|
+
task :seed => :environment do
|
54
|
+
seed_file = File.join(Rails.root, 'db', 'seeds.rb')
|
55
|
+
load(seed_file) if File.exist?(seed_file)
|
56
|
+
end
|
57
|
+
|
58
|
+
namespace :migrate do
|
59
|
+
task :load => :environment do
|
60
|
+
require 'dm-migrations/migration_runner'
|
61
|
+
FileList['db/migrate/*.rb'].each do |migration|
|
62
|
+
load migration
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
desc 'Migrate up using migrations'
|
67
|
+
task :up, [:version] => [:load] do |t, args|
|
68
|
+
::DataMapper::MigrationRunner.migrate_up!(args[:version])
|
69
|
+
end
|
70
|
+
|
71
|
+
desc 'Migrate down using migrations'
|
72
|
+
task :down, [:version] => [:load] do |t, args|
|
73
|
+
::DataMapper::MigrationRunner.migrate_down!(args[:version])
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
desc 'Migrate the database to the latest version'
|
78
|
+
task :migrate do
|
79
|
+
migrate_task = if Dir['db/migrate/*.rb'].empty?
|
80
|
+
'db:autoupgrade'
|
81
|
+
else
|
82
|
+
'db:migrate:up'
|
83
|
+
end
|
84
|
+
|
85
|
+
Rake::Task[migrate_task].invoke
|
86
|
+
end
|
87
|
+
|
88
|
+
namespace :sessions do
|
89
|
+
desc "Creates the sessions table for DataMapperStore"
|
90
|
+
task :create => :environment do
|
91
|
+
require 'dm-rails/session_store'
|
92
|
+
Rails::DataMapper::SessionStore::Session.auto_migrate!
|
93
|
+
database = Rails::DataMapper.configuration.repositories[Rails.env]['database']
|
94
|
+
puts "Created '#{database}.sessions'"
|
95
|
+
end
|
96
|
+
|
97
|
+
desc "Clear the sessions table for DataMapperStore"
|
98
|
+
task :clear => :environment do
|
99
|
+
require 'dm-rails/session_store'
|
100
|
+
Rails::DataMapper::SessionStore::Session.destroy!
|
101
|
+
database = Rails::DataMapper.configuration.repositories[Rails.env]['database']
|
102
|
+
puts "Deleted entries from '#{database}.sessions'"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'active_support/notifications'
|
2
|
+
|
3
|
+
# TODO This needs to be fixed upstream in active_support/notifications/instrumenter.rb
|
4
|
+
#
|
5
|
+
# We need to monkeypatch this for now, because the original implementation hardcodes the
|
6
|
+
# duration to the time elapsed between start and end of the event. The current upstream
|
7
|
+
# implementation is included here for reference:
|
8
|
+
#
|
9
|
+
# def duration
|
10
|
+
# @duration ||= 1000.0 * (@end - @time)
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# It should be safe to assume that explicitly provided duration information should be at
|
14
|
+
# least as precise as the current generic solution, if not more (as in our specific case).
|
15
|
+
#
|
16
|
+
module ActiveSupport
|
17
|
+
module Notifications
|
18
|
+
class Event
|
19
|
+
def duration
|
20
|
+
payload[:duration] ? (payload[:duration] / 1000.0) : 1000.0 * (self.end - self.time)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module LogListener
|
27
|
+
def log(message)
|
28
|
+
ActiveSupport::Notifications.instrument('sql.data_mapper',
|
29
|
+
:name => 'SQL',
|
30
|
+
:sql => message.query, # TODO think about changing the key to :query
|
31
|
+
:start => message.start,
|
32
|
+
:duration => message.duration,
|
33
|
+
:connection_id => self.object_id
|
34
|
+
)
|
35
|
+
super
|
36
|
+
rescue Exception => e
|
37
|
+
::DataMapper.logger.error "[datamapper] #{e.class.name}: #{e.message}: #{message.inspect}}"
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Railties
|
3
|
+
|
4
|
+
class LogSubscriber < ActiveSupport::LogSubscriber
|
5
|
+
|
6
|
+
def self.runtime=(value)
|
7
|
+
Thread.current["data_mapper_sql_runtime"] = value
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.runtime
|
11
|
+
Thread.current["data_mapper_sql_runtime"] ||= 0
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.reset_runtime
|
15
|
+
rt, self.runtime = runtime, 0
|
16
|
+
rt
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
super
|
21
|
+
@odd_or_even = false
|
22
|
+
end
|
23
|
+
|
24
|
+
def sql(event)
|
25
|
+
self.class.runtime += event.duration
|
26
|
+
return unless logger.debug?
|
27
|
+
|
28
|
+
name = '%s (%.3fms)' % [event.payload[:name], event.duration]
|
29
|
+
sql = event.payload[:sql].squeeze(' ')
|
30
|
+
|
31
|
+
if odd?
|
32
|
+
name = color(name, CYAN, true)
|
33
|
+
sql = color(sql, nil, true)
|
34
|
+
else
|
35
|
+
name = color(name, MAGENTA, true)
|
36
|
+
end
|
37
|
+
|
38
|
+
debug " #{name} #{sql}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def odd?
|
42
|
+
@odd_or_even = !@odd_or_even
|
43
|
+
end
|
44
|
+
|
45
|
+
def logger
|
46
|
+
::DataMapper.logger
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
DataMapper::Railties::LogSubscriber.attach_to :data_mapper
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'dm-core'
|
2
|
+
require 'active_support/core_ext/class/attribute'
|
3
|
+
|
4
|
+
# Implements DataMapper-specific session store.
|
5
|
+
|
6
|
+
module Rails
|
7
|
+
module DataMapper
|
8
|
+
|
9
|
+
class SessionStore < ActionDispatch::Session::AbstractStore
|
10
|
+
|
11
|
+
class Session
|
12
|
+
|
13
|
+
include ::DataMapper::Resource
|
14
|
+
|
15
|
+
property :id, Serial
|
16
|
+
property :session_id, String, :required => true, :unique => true, :length => 0..150
|
17
|
+
property :data, Object, :required => false
|
18
|
+
property :updated_at, DateTime, :index => true
|
19
|
+
|
20
|
+
def self.name
|
21
|
+
'session'
|
22
|
+
end
|
23
|
+
|
24
|
+
def data
|
25
|
+
attribute_get(:data) || {}
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
# for backward compatibility with Rails 3.0
|
31
|
+
ENV_SESSION_OPTIONS_KEY = ::Rack::Session::Abstract::ENV_SESSION_OPTIONS_KEY unless const_defined?("ENV_SESSION_OPTIONS_KEY")
|
32
|
+
SESSION_RECORD_KEY = 'rack.session.record'.freeze
|
33
|
+
|
34
|
+
class_attribute :session_class
|
35
|
+
self.session_class = Session
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def get_session(env, sid)
|
40
|
+
sid ||= generate_sid
|
41
|
+
session = find_session(sid)
|
42
|
+
env[SESSION_RECORD_KEY] = session
|
43
|
+
[ sid, session.data ]
|
44
|
+
end
|
45
|
+
|
46
|
+
def set_session(env, sid, session_data, options = {})
|
47
|
+
session = get_session_resource(env, sid)
|
48
|
+
session.data = session_data
|
49
|
+
session.updated_at = DateTime.now if session.dirty?
|
50
|
+
session.save ? sid : false
|
51
|
+
end
|
52
|
+
|
53
|
+
def get_session_resource(env, sid)
|
54
|
+
if env[ENV_SESSION_OPTIONS_KEY][:id].nil?
|
55
|
+
env[SESSION_RECORD_KEY] = find_session(sid)
|
56
|
+
else
|
57
|
+
env[SESSION_RECORD_KEY] ||= find_session(sid)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def find_session(sid)
|
62
|
+
self.class.session_class.first_or_new(:session_id => sid)
|
63
|
+
end
|
64
|
+
|
65
|
+
def destroy_session(env, sid = nil, options = {})
|
66
|
+
sid ||= current_session_id(env)
|
67
|
+
find_session(sid).destroy
|
68
|
+
end
|
69
|
+
|
70
|
+
def destroy(env)
|
71
|
+
destroy_session(env)
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'active_support/core_ext/hash/except'
|
2
|
+
|
3
|
+
require 'dm-rails/configuration'
|
4
|
+
require 'dm-rails/railties/log_listener'
|
5
|
+
|
6
|
+
module Rails
|
7
|
+
module DataMapper
|
8
|
+
|
9
|
+
def self.setup(environment)
|
10
|
+
::DataMapper.logger.info "[datamapper] Setting up the #{environment.inspect} environment:"
|
11
|
+
configuration.repositories[environment].each do |name, config|
|
12
|
+
setup_with_instrumentation(name.to_sym, config)
|
13
|
+
end
|
14
|
+
finalize
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.setup_with_instrumentation(name, options)
|
18
|
+
|
19
|
+
adapter = if options['uri']
|
20
|
+
database_uri = ::Addressable::URI.parse(options['uri'])
|
21
|
+
::DataMapper.logger.info "[datamapper] Setting up #{name.inspect} repository: '#{database_uri.path}' on #{database_uri.scheme}"
|
22
|
+
::DataMapper.setup(name, database_uri)
|
23
|
+
else
|
24
|
+
::DataMapper.logger.info "[datamapper] Setting up #{name.inspect} repository: '#{options['database']}' on #{options['adapter']}"
|
25
|
+
::DataMapper.setup(name, options)
|
26
|
+
end
|
27
|
+
|
28
|
+
if convention = configuration.resource_naming_convention[name]
|
29
|
+
adapter.resource_naming_convention = convention
|
30
|
+
end
|
31
|
+
if convention = configuration.field_naming_convention[name]
|
32
|
+
adapter.field_naming_convention = convention
|
33
|
+
end
|
34
|
+
setup_log_listener(adapter.options['adapter'])
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.setup_logger(logger)
|
38
|
+
::DataMapper.logger = logger
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.setup_log_listener(adapter_name)
|
42
|
+
adapter_name = 'sqlite3' if adapter_name == 'sqlite'
|
43
|
+
driver_name = ActiveSupport::Inflector.camelize(adapter_name)
|
44
|
+
|
45
|
+
setup_do_driver(driver_name) do |driver|
|
46
|
+
DataObjects::Connection.send(:include, LogListener)
|
47
|
+
# FIXME Setting DataMapper::Logger.new($stdout, :off) alone won't work because the #log
|
48
|
+
# method is currently only available in DO and needs an explicit DO Logger instantiated.
|
49
|
+
# We turn the logger :off because ActiveSupport::Notifications handles displaying log messages
|
50
|
+
driver.logger = DataObjects::Logger.new($stdout, :off)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.finalize
|
55
|
+
::DataMapper.finalize
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.preload_models(app)
|
59
|
+
app.config.paths['app/models'].each do |path|
|
60
|
+
Dir.glob("#{path}/**/*.rb").sort.each { |file| require_dependency file[path.length..-1] }
|
61
|
+
end
|
62
|
+
finalize
|
63
|
+
end
|
64
|
+
|
65
|
+
class << self
|
66
|
+
private
|
67
|
+
|
68
|
+
if RUBY_VERSION < '1.9'
|
69
|
+
def setup_do_driver(driver_name)
|
70
|
+
if Object.const_defined?('DataObjects') && DataObjects.const_defined?(driver_name)
|
71
|
+
yield DataObjects.const_get(driver_name)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
else
|
75
|
+
def setup_do_driver(driver_name)
|
76
|
+
if Object.const_defined?('DataObjects', false) && DataObjects.const_defined?(driver_name, false)
|
77
|
+
yield DataObjects.const_get(driver_name, false)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
module Rails
|
2
|
+
module DataMapper
|
3
|
+
|
4
|
+
def self.storage
|
5
|
+
Storage
|
6
|
+
end
|
7
|
+
|
8
|
+
class Storage
|
9
|
+
attr_reader :name, :config
|
10
|
+
|
11
|
+
def self.create_all
|
12
|
+
with_local_repositories { |config| create_environment(config) }
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.drop_all
|
16
|
+
with_local_repositories { |config| drop_environment(config) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.create_environment(config)
|
20
|
+
config.each { |repo_name, repo_config| new(repo_name, repo_config).create }
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.drop_environment(config)
|
24
|
+
config.each { |repo_name, repo_config| new(repo_name, repo_config).drop }
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.new(name, config)
|
28
|
+
klass = lookup_class(config['adapter'])
|
29
|
+
if klass.equal?(self)
|
30
|
+
super(name, config)
|
31
|
+
else
|
32
|
+
klass.new(name, config)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class << self
|
37
|
+
private
|
38
|
+
|
39
|
+
def with_local_repositories
|
40
|
+
Rails::DataMapper.configuration.repositories.each_value do |config|
|
41
|
+
if config['host'].blank? || %w[ 127.0.0.1 localhost ].include?(config['host'])
|
42
|
+
yield(config)
|
43
|
+
else
|
44
|
+
puts "This task only modifies local databases. #{config['database']} is on a remote host."
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def lookup_class(adapter)
|
50
|
+
klass_name = normalized_adapter_name(adapter).camelize.to_sym
|
51
|
+
|
52
|
+
unless Storage.const_defined?(klass_name)
|
53
|
+
raise "Adapter #{adapter} not supported (#{klass_name.inspect})"
|
54
|
+
end
|
55
|
+
|
56
|
+
const_get(klass_name)
|
57
|
+
end
|
58
|
+
|
59
|
+
def normalized_adapter_name(adapter_name)
|
60
|
+
adapter_name.to_s == 'sqlite3' ? 'sqlite' : adapter_name
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
def initialize(name, config)
|
66
|
+
@name, @config = name.to_sym, config
|
67
|
+
end
|
68
|
+
|
69
|
+
def create
|
70
|
+
puts create_message if _create
|
71
|
+
end
|
72
|
+
|
73
|
+
def drop
|
74
|
+
puts drop_message if _drop
|
75
|
+
end
|
76
|
+
|
77
|
+
def database
|
78
|
+
@database ||= config['database'] || config['path']
|
79
|
+
end
|
80
|
+
|
81
|
+
def username
|
82
|
+
@username ||= config['username'] || ''
|
83
|
+
end
|
84
|
+
|
85
|
+
def password
|
86
|
+
@password ||= config['password'] || ''
|
87
|
+
end
|
88
|
+
|
89
|
+
def charset
|
90
|
+
@charset ||= config['charset'] || ENV['CHARSET'] || 'utf8'
|
91
|
+
end
|
92
|
+
|
93
|
+
def create_message
|
94
|
+
"[datamapper] Created database '#{database}'"
|
95
|
+
end
|
96
|
+
|
97
|
+
def drop_message
|
98
|
+
"[datamapper] Dropped database '#{database}'"
|
99
|
+
end
|
100
|
+
|
101
|
+
# Create the configured database
|
102
|
+
#
|
103
|
+
# This is a noop so that calling this method
|
104
|
+
# won't explode on people who use adapters that
|
105
|
+
# don't support creating a storage recepticle
|
106
|
+
def _create
|
107
|
+
true
|
108
|
+
end
|
109
|
+
|
110
|
+
# Drop the configured database
|
111
|
+
#
|
112
|
+
# This is a noop so that calling this method
|
113
|
+
# won't explode on people who use adapters that
|
114
|
+
# don't support dropping a storage recepticle
|
115
|
+
def _drop
|
116
|
+
true
|
117
|
+
end
|
118
|
+
|
119
|
+
class Sqlite < Storage
|
120
|
+
|
121
|
+
# This is a noop for sqlite
|
122
|
+
#
|
123
|
+
# Overwritten solely for documentation purposes
|
124
|
+
#
|
125
|
+
# Both auto_migrate!/auto_upgrade! will create the actual database
|
126
|
+
# if the connection has been setup properly and there actually
|
127
|
+
# are statements to execute (i.e. at least one model is declared)
|
128
|
+
#
|
129
|
+
# DataMapper.setup alone won't create the actual database so there
|
130
|
+
# really is no API to simply create an empty database for sqlite3.
|
131
|
+
#
|
132
|
+
# we return true to indicate success nevertheless
|
133
|
+
def _create
|
134
|
+
true
|
135
|
+
end
|
136
|
+
|
137
|
+
def _drop
|
138
|
+
return if in_memory?
|
139
|
+
path.unlink if path.file?
|
140
|
+
end
|
141
|
+
|
142
|
+
def create_message
|
143
|
+
"[datamapper] db:create is a noop for sqlite3, use db:automigrate instead (#{database})"
|
144
|
+
end
|
145
|
+
|
146
|
+
private
|
147
|
+
|
148
|
+
def in_memory?
|
149
|
+
database == ':memory:'
|
150
|
+
end
|
151
|
+
|
152
|
+
def path
|
153
|
+
@path ||= Pathname(File.expand_path(database, Rails.root))
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
class Mysql < Storage
|
159
|
+
def _create
|
160
|
+
execute("CREATE DATABASE `#{database}` DEFAULT CHARACTER SET #{charset} DEFAULT COLLATE #{collation}")
|
161
|
+
end
|
162
|
+
|
163
|
+
def _drop
|
164
|
+
execute("DROP DATABASE IF EXISTS `#{database}`")
|
165
|
+
end
|
166
|
+
|
167
|
+
private
|
168
|
+
|
169
|
+
def execute(statement)
|
170
|
+
system(
|
171
|
+
'mysql',
|
172
|
+
(username.blank? ? '' : "--user=#{username}"),
|
173
|
+
(password.blank? ? '' : "--password=#{password}"),
|
174
|
+
'-e',
|
175
|
+
statement
|
176
|
+
)
|
177
|
+
end
|
178
|
+
|
179
|
+
def collation
|
180
|
+
@collation ||= config['collation'] || ENV['COLLATION'] || 'utf8_unicode_ci'
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
class Postgres < Storage
|
186
|
+
def _create
|
187
|
+
system(
|
188
|
+
'createdb',
|
189
|
+
'-E',
|
190
|
+
charset,
|
191
|
+
'-U',
|
192
|
+
username,
|
193
|
+
database
|
194
|
+
)
|
195
|
+
end
|
196
|
+
|
197
|
+
def _drop
|
198
|
+
system(
|
199
|
+
'dropdb',
|
200
|
+
'-U',
|
201
|
+
username,
|
202
|
+
database
|
203
|
+
)
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
data/lib/dm-rails.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'dm-rails/railtie'
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'generators/data_mapper'
|
2
|
+
|
3
|
+
module DataMapper
|
4
|
+
module Generators
|
5
|
+
|
6
|
+
class MigrationGenerator < Base
|
7
|
+
|
8
|
+
argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"
|
9
|
+
class_option :id, :type => :numeric, :desc => "The id to be used in this migration"
|
10
|
+
|
11
|
+
def create_migration_file
|
12
|
+
set_local_assigns!
|
13
|
+
migration_template "migration.rb", "db/migrate/#{file_name}.rb"
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
attr_reader :migration_action
|
19
|
+
|
20
|
+
def set_local_assigns!
|
21
|
+
if file_name =~ /^(add|remove|drop)_.*_(?:to|from)_(.*)/
|
22
|
+
@migration_action = $1 == 'add' ? 'add' : 'drop'
|
23
|
+
@table_name = $2.pluralize
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
migration <%= migration_number.to_i %>, :<%= migration_file_name %> do
|
2
|
+
|
3
|
+
up do
|
4
|
+
<% unless attributes.empty? -%>
|
5
|
+
modify_table :<%= table_name %> do
|
6
|
+
<% attributes.each do |attribute| -%>
|
7
|
+
<%= migration_action %>_column :<%= attribute.name %><% if migration_action == 'add' %>, :<%= attribute.type_class %><% end -%>
|
8
|
+
<% end -%>
|
9
|
+
end
|
10
|
+
<% end -%>
|
11
|
+
end
|
12
|
+
|
13
|
+
down do
|
14
|
+
<% unless attributes.empty? -%>
|
15
|
+
modify_table :<%= table_name %> do
|
16
|
+
<% attributes.reverse.each do |attribute| -%>
|
17
|
+
<%= migration_action == 'add' ? 'drop' : 'add' %>_column :<%= attribute.name %><% if migration_action == 'drop' %>, :<%= attribute.type_class %><% end -%>
|
18
|
+
<% end -%>
|
19
|
+
end
|
20
|
+
<% end -%>
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'generators/data_mapper'
|
2
|
+
|
3
|
+
module DataMapper
|
4
|
+
module Generators
|
5
|
+
|
6
|
+
class ModelGenerator < Base
|
7
|
+
argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"
|
8
|
+
|
9
|
+
check_class_collision
|
10
|
+
|
11
|
+
class_option :timestamps, :type => :boolean
|
12
|
+
class_option :parent, :type => :string, :desc => "The parent class for the generated model"
|
13
|
+
|
14
|
+
def create_model_file
|
15
|
+
template 'model.rb', File.join('app/models', class_path, "#{file_name}.rb")
|
16
|
+
end
|
17
|
+
|
18
|
+
hook_for :test_framework
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class <%= class_name %><%= "< #{options[:parent].classify}" if options[:parent] %>
|
2
|
+
|
3
|
+
<% unless options[:parent] -%>
|
4
|
+
include DataMapper::Resource
|
5
|
+
|
6
|
+
property :id, Serial
|
7
|
+
<% end %>
|
8
|
+
<% attributes.each do |attribute| -%>
|
9
|
+
property :<%= attribute.name -%>, <%= attribute.type_class %>
|
10
|
+
<% end %>
|
11
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'generators/data_mapper'
|
2
|
+
|
3
|
+
module DataMapper
|
4
|
+
module Generators
|
5
|
+
|
6
|
+
class ObserverGenerator < Base
|
7
|
+
|
8
|
+
check_class_collision :suffix => "Observer"
|
9
|
+
|
10
|
+
def create_observer_file
|
11
|
+
template 'observer.rb', File.join('app/models', class_path, "#{file_name}_observer.rb")
|
12
|
+
end
|
13
|
+
|
14
|
+
hook_for :test_framework
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|