dm-rails 1.0.0.rc1
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/.gitignore +36 -0
- data/Gemfile +37 -0
- data/LICENSE +20 -0
- data/README.rdoc +506 -0
- data/Rakefile +33 -0
- data/VERSION +1 -0
- data/dm-rails.gemspec +85 -0
- data/lib/dm-rails.rb +1 -0
- data/lib/dm-rails/configuration.rb +70 -0
- data/lib/dm-rails/middleware/identity_map.rb +19 -0
- data/lib/dm-rails/railtie.rb +103 -0
- data/lib/dm-rails/railties/benchmarking_mixin.rb +23 -0
- data/lib/dm-rails/railties/controller_runtime.rb +45 -0
- data/lib/dm-rails/railties/database.rake +124 -0
- data/lib/dm-rails/railties/i18n_support.rb +12 -0
- data/lib/dm-rails/railties/log_subscriber.rb +31 -0
- data/lib/dm-rails/session_store.rb +61 -0
- data/lib/dm-rails/setup.rb +41 -0
- data/lib/dm-rails/storage.rb +165 -0
- data/lib/generators/data_mapper.rb +82 -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/tasks/ci.rake +1 -0
- data/tasks/clean.rake +6 -0
- data/tasks/local_gemfile.rake +18 -0
- data/tasks/metrics.rake +37 -0
- data/tasks/yard.rake +9 -0
- data/tasks/yardstick.rake +20 -0
- metadata +171 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Railties
|
3
|
+
|
4
|
+
class LogSubscriber < Rails::LogSubscriber
|
5
|
+
|
6
|
+
def sql(event)
|
7
|
+
name = '%s (%.1fms)' % [event.payload[:name], event.duration]
|
8
|
+
sql = event.payload[:sql].squeeze(' ')
|
9
|
+
|
10
|
+
if odd?
|
11
|
+
name = color(name, :cyan, true)
|
12
|
+
sql = color(sql, nil, true)
|
13
|
+
else
|
14
|
+
name = color(name, :magenta, true)
|
15
|
+
end
|
16
|
+
|
17
|
+
debug " #{name} #{sql}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def odd?
|
21
|
+
@odd_or_even = !@odd_or_even
|
22
|
+
end
|
23
|
+
|
24
|
+
def logger
|
25
|
+
::DataMapper.logger
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'dm-core'
|
2
|
+
|
3
|
+
# Implements DataMapper-specific session store.
|
4
|
+
|
5
|
+
module Rails
|
6
|
+
module DataMapper
|
7
|
+
|
8
|
+
class SessionStore < ActionDispatch::Session::AbstractStore
|
9
|
+
|
10
|
+
class Session
|
11
|
+
|
12
|
+
include ::DataMapper::Resource
|
13
|
+
|
14
|
+
property :id, Serial
|
15
|
+
property :session_id, String, :required => true, :unique => true, :unique_index => true
|
16
|
+
property :data, Object, :required => true, :default => ActiveSupport::Base64.encode64(Marshal.dump({}))
|
17
|
+
property :updated_at, DateTime, :required => false, :index => true
|
18
|
+
|
19
|
+
def self.name
|
20
|
+
'session'
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
SESSION_RECORD_KEY = 'rack.session.record'.freeze
|
26
|
+
|
27
|
+
cattr_accessor :session_class
|
28
|
+
self.session_class = Session
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def get_session(env, sid)
|
33
|
+
sid ||= generate_sid
|
34
|
+
session = find_session(sid)
|
35
|
+
env[SESSION_RECORD_KEY] = session
|
36
|
+
[ sid, session.data ]
|
37
|
+
end
|
38
|
+
|
39
|
+
def set_session(env, sid, session_data)
|
40
|
+
session = get_session_resource(env, sid)
|
41
|
+
session.data = session_data
|
42
|
+
session.updated_at = Time.now if session.dirty?
|
43
|
+
session.save ? sid : false
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_session_resource(env, sid)
|
47
|
+
if env[ENV_SESSION_OPTIONS_KEY][:id].nil?
|
48
|
+
env[SESSION_RECORD_KEY] = find_session(sid)
|
49
|
+
else
|
50
|
+
env[SESSION_RECORD_KEY] ||= find_session(sid)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def find_session(sid)
|
55
|
+
self.class.session_class.first_or_new(:session_id => sid)
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'active_support/core_ext/hash/except'
|
2
|
+
|
3
|
+
require 'dm-rails/configuration'
|
4
|
+
require 'dm-rails/railties/benchmarking_mixin'
|
5
|
+
|
6
|
+
module Rails
|
7
|
+
module DataMapper
|
8
|
+
|
9
|
+
def self.setup(environment)
|
10
|
+
puts "[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
|
+
initialize_foreign_keys
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.setup_logger(logger)
|
18
|
+
::DataMapper.logger = logger
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.setup_with_instrumentation(name, options)
|
22
|
+
puts "[datamapper] Setting up #{name.inspect} repository: '#{options['database']}' on #{options['adapter']}"
|
23
|
+
adapter = ::DataMapper.setup(name, options)
|
24
|
+
adapter.extend ::DataMapper::Adapters::Benchmarking
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.initialize_foreign_keys
|
28
|
+
::DataMapper::Model.descendants.each do |model|
|
29
|
+
model.relationships.each_value { |r| r.child_key }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.preload_models(app)
|
34
|
+
app.config.paths.app.models.each do |path|
|
35
|
+
Dir.glob("#{path}/**/*.rb").sort.each { |file| require_dependency file }
|
36
|
+
end
|
37
|
+
initialize_foreign_keys
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,165 @@
|
|
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 = 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
|
+
end
|
60
|
+
|
61
|
+
def initialize(name, config)
|
62
|
+
@name, @config = name.to_sym, config
|
63
|
+
end
|
64
|
+
|
65
|
+
def create
|
66
|
+
_create
|
67
|
+
puts "[datamapper] Created database '#{database}'"
|
68
|
+
end
|
69
|
+
|
70
|
+
def drop
|
71
|
+
_drop
|
72
|
+
puts "[datamapper] Dropped database '#{database}'"
|
73
|
+
end
|
74
|
+
|
75
|
+
def database
|
76
|
+
@database ||= config['database'] || config['path']
|
77
|
+
end
|
78
|
+
|
79
|
+
def username
|
80
|
+
@username ||= config['username'] || ''
|
81
|
+
end
|
82
|
+
|
83
|
+
def password
|
84
|
+
@password ||= config['password'] || ''
|
85
|
+
end
|
86
|
+
|
87
|
+
def charset
|
88
|
+
@charset ||= config['charset'] || ENV['CHARSET'] || 'utf8'
|
89
|
+
end
|
90
|
+
|
91
|
+
class Sqlite3 < Storage
|
92
|
+
def _create
|
93
|
+
return if in_memory?
|
94
|
+
::DataMapper.setup(name, config.merge('database' => path))
|
95
|
+
end
|
96
|
+
|
97
|
+
def _drop
|
98
|
+
return if in_memory?
|
99
|
+
path.unlink if path.file?
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def in_memory?
|
105
|
+
database == ':memory:'
|
106
|
+
end
|
107
|
+
|
108
|
+
def path
|
109
|
+
@path ||= Pathname(File.expand_path(database, Rails.root))
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
class Mysql < Storage
|
115
|
+
def _create
|
116
|
+
execute("CREATE DATABASE `#{database}` DEFAULT CHARACTER SET #{charset} DEFAULT COLLATE #{collation}")
|
117
|
+
end
|
118
|
+
|
119
|
+
def _drop
|
120
|
+
execute("DROP DATABASE IF EXISTS `#{database}`")
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
def execute(statement)
|
126
|
+
system(
|
127
|
+
'mysql',
|
128
|
+
(username.blank? ? '' : "--user=#{username}"),
|
129
|
+
(password.blank? ? '' : "--password=#{password}"),
|
130
|
+
'-e',
|
131
|
+
statement
|
132
|
+
)
|
133
|
+
end
|
134
|
+
|
135
|
+
def collation
|
136
|
+
@collation ||= config['collation'] || ENV['COLLATION'] || 'utf8_unicode_ci'
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
class Postgres < Storage
|
142
|
+
def _create
|
143
|
+
system(
|
144
|
+
'createdb',
|
145
|
+
'-E',
|
146
|
+
charset,
|
147
|
+
'-U',
|
148
|
+
username,
|
149
|
+
database
|
150
|
+
)
|
151
|
+
end
|
152
|
+
|
153
|
+
def _drop
|
154
|
+
system(
|
155
|
+
'dropdb',
|
156
|
+
'-U',
|
157
|
+
username,
|
158
|
+
database
|
159
|
+
)
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'rails/generators/named_base'
|
2
|
+
require 'rails/generators/migration'
|
3
|
+
require 'rails/generators/active_model'
|
4
|
+
|
5
|
+
module DataMapper
|
6
|
+
module Generators
|
7
|
+
|
8
|
+
class Base < ::Rails::Generators::NamedBase #:nodoc:
|
9
|
+
|
10
|
+
include ::Rails::Generators::Migration
|
11
|
+
|
12
|
+
def self.source_root
|
13
|
+
@_datamapper_source_root ||=
|
14
|
+
File.expand_path("../#{base_name}/#{generator_name}/templates", __FILE__)
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
# Datamapper does not care if migrations have the same name as long as
|
20
|
+
# they have different ids.
|
21
|
+
#
|
22
|
+
def migration_exists?(dirname, file_name) #:nodoc:
|
23
|
+
false
|
24
|
+
end
|
25
|
+
|
26
|
+
# Implement the required interface for Rails::Generators::Migration.
|
27
|
+
#
|
28
|
+
def self.next_migration_number(dirname) #:nodoc:
|
29
|
+
"%.3d" % (current_migration_number(dirname) + 1)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
class ActiveModel < ::Rails::Generators::ActiveModel #:nodoc:
|
35
|
+
def self.all(klass)
|
36
|
+
"#{klass}.all"
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.find(klass, params=nil)
|
40
|
+
"#{klass}.get(#{params})"
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.build(klass, params=nil)
|
44
|
+
if params
|
45
|
+
"#{klass}.new(#{params})"
|
46
|
+
else
|
47
|
+
"#{klass}.new"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def save
|
52
|
+
"#{name}.save"
|
53
|
+
end
|
54
|
+
|
55
|
+
def update_attributes(params=nil)
|
56
|
+
"#{name}.update(#{params})"
|
57
|
+
end
|
58
|
+
|
59
|
+
def errors
|
60
|
+
"#{name}.errors"
|
61
|
+
end
|
62
|
+
|
63
|
+
def destroy
|
64
|
+
"#{name}.destroy"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
module Rails
|
72
|
+
|
73
|
+
module Generators
|
74
|
+
class GeneratedAttribute #:nodoc:
|
75
|
+
def type_class
|
76
|
+
return 'DateTime' if type.to_s == 'datetime'
|
77
|
+
return type.to_s.camelcase
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
@@ -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
|