sbf-dm-migrations 1.3.0.beta

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.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +38 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +468 -0
  5. data/.travis.yml +52 -0
  6. data/Gemfile +61 -0
  7. data/LICENSE +20 -0
  8. data/README.rdoc +39 -0
  9. data/Rakefile +4 -0
  10. data/db/migrations/1_create_people_table.rb +12 -0
  11. data/db/migrations/2_add_dob_to_people.rb +13 -0
  12. data/db/migrations/config.rb +4 -0
  13. data/dm-migrations.gemspec +20 -0
  14. data/examples/Rakefile +149 -0
  15. data/examples/sample_migration.rb +58 -0
  16. data/examples/sample_migration_spec.rb +46 -0
  17. data/lib/dm-migrations/adapters/dm-do-adapter.rb +304 -0
  18. data/lib/dm-migrations/adapters/dm-mysql-adapter.rb +306 -0
  19. data/lib/dm-migrations/adapters/dm-oracle-adapter.rb +339 -0
  20. data/lib/dm-migrations/adapters/dm-postgres-adapter.rb +152 -0
  21. data/lib/dm-migrations/adapters/dm-sqlite-adapter.rb +88 -0
  22. data/lib/dm-migrations/adapters/dm-sqlserver-adapter.rb +184 -0
  23. data/lib/dm-migrations/adapters/dm-yaml-adapter.rb +21 -0
  24. data/lib/dm-migrations/auto_migration.rb +227 -0
  25. data/lib/dm-migrations/exceptions/duplicate_migration.rb +6 -0
  26. data/lib/dm-migrations/migration.rb +323 -0
  27. data/lib/dm-migrations/migration_runner.rb +76 -0
  28. data/lib/dm-migrations/sql/column.rb +5 -0
  29. data/lib/dm-migrations/sql/mysql.rb +84 -0
  30. data/lib/dm-migrations/sql/oracle.rb +9 -0
  31. data/lib/dm-migrations/sql/postgres.rb +89 -0
  32. data/lib/dm-migrations/sql/sqlite.rb +59 -0
  33. data/lib/dm-migrations/sql/sqlserver.rb +9 -0
  34. data/lib/dm-migrations/sql/table.rb +15 -0
  35. data/lib/dm-migrations/sql/table_creator.rb +105 -0
  36. data/lib/dm-migrations/sql/table_modifier.rb +57 -0
  37. data/lib/dm-migrations/sql.rb +7 -0
  38. data/lib/dm-migrations/version.rb +5 -0
  39. data/lib/dm-migrations.rb +3 -0
  40. data/lib/spec/example/migration_example_group.rb +69 -0
  41. data/lib/spec/matchers/migration_matchers.rb +96 -0
  42. data/spec/integration/auto_migration_spec.rb +590 -0
  43. data/spec/integration/auto_upgrade_spec.rb +41 -0
  44. data/spec/integration/migration_runner_spec.rb +84 -0
  45. data/spec/integration/migration_spec.rb +156 -0
  46. data/spec/integration/sql_spec.rb +290 -0
  47. data/spec/isolated/require_after_setup_spec.rb +24 -0
  48. data/spec/isolated/require_before_setup_spec.rb +24 -0
  49. data/spec/isolated/require_spec.rb +23 -0
  50. data/spec/spec_helper.rb +16 -0
  51. data/spec/unit/migration_spec.rb +501 -0
  52. data/spec/unit/sql/column_spec.rb +14 -0
  53. data/spec/unit/sql/postgres_spec.rb +90 -0
  54. data/spec/unit/sql/sqlite_extensions_spec.rb +103 -0
  55. data/spec/unit/sql/table_creator_spec.rb +91 -0
  56. data/spec/unit/sql/table_modifier_spec.rb +47 -0
  57. data/spec/unit/sql/table_spec.rb +26 -0
  58. data/spec/unit/sql_spec.rb +7 -0
  59. data/tasks/spec.rake +21 -0
  60. data/tasks/yard.rake +9 -0
  61. data/tasks/yardstick.rake +19 -0
  62. metadata +120 -0
@@ -0,0 +1,13 @@
1
+ migration 2, :add_dob_to_people do
2
+ up do
3
+ modify_table :people do
4
+ add_column :dob, DateTime, allow_nil: true
5
+ end
6
+ end
7
+
8
+ down do
9
+ modify_table :people do
10
+ drop_column :dob
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,4 @@
1
+ DataMapper::Logger.new($stdout, :debug)
2
+ DataMapper.logger.debug('Starting Migration')
3
+
4
+ DataMapper.setup(:default, 'postgres://postgres@localhost/dm_core_test')
@@ -0,0 +1,20 @@
1
+ require File.expand_path('../lib/dm-migrations/version', __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.authors = ['Dan Kubb']
5
+ gem.email = ['dan.kubb@gmail.com']
6
+ gem.summary = 'DataMapper plugin for writing and spec-ing migrations'
7
+ gem.description = 'DataMapper plugin for modifying and maintaining database structure, triggers, stored procedures, and data'
8
+ gem.homepage = 'https://datamapper.org'
9
+ gem.license = 'Nonstandard'
10
+
11
+ gem.files = `git ls-files`.split("\n")
12
+ gem.extra_rdoc_files = %w(LICENSE README.rdoc)
13
+
14
+ gem.name = 'sbf-dm-migrations'
15
+ gem.require_paths = ['lib']
16
+ gem.version = DataMapper::Migrations::VERSION
17
+ gem.required_ruby_version = '>= 2.7.8'
18
+
19
+ gem.add_runtime_dependency('sbf-dm-core', '~> 1.3.0.beta')
20
+ end
data/examples/Rakefile ADDED
@@ -0,0 +1,149 @@
1
+ # Sample tasks using dm-migrations
2
+ # Roughly following Rails conventions, and mostly based on Padrino's dm:* tasks
3
+ #
4
+ # Cf. https://github.com/padrino/padrino-framework/blob/master/padrino-gen/lib/padrino-gen/padrino-tasks/datamapper.rb
5
+ # https://github.com/firespring/dm-rails/blob/master/lib/dm-rails/railties/database.rake
6
+ #
7
+
8
+ require 'rake'
9
+
10
+ # replace this with however your app configures DataMapper repositor(ies)
11
+ task :environment do
12
+ require File.expand_path('boot', File.dirname(__FILE__))
13
+ end
14
+
15
+ namespace :db do
16
+
17
+ namespace :auto do
18
+
19
+ desc 'Perform auto-migration (reset your db data)'
20
+ task migrate: :environment do |t, _|
21
+ puts '=> Auto-migrating'
22
+ DataMapper.auto_migrate!
23
+ puts "<= #{t.name} done"
24
+ end
25
+
26
+ desc 'Perform non destructive auto-migration'
27
+ task upgrade: :environment do |t, _|
28
+ puts '=> Auto-upgrading'
29
+ DataMapper.auto_upgrade!
30
+ puts "<= #{t.name} done"
31
+ end
32
+
33
+ end
34
+
35
+ desc 'Run all pending migrations, or up to specified migration'
36
+ task :migrate, [:version] => :load_migrations do |t, args|
37
+ if (vers = args[:version] || ENV.fetch('VERSION', nil))
38
+ puts "=> Migrating up to version #{vers}"
39
+ migrate_up!(vers)
40
+ else
41
+ puts '=> Migrating up'
42
+ migrate_up!
43
+ end
44
+ puts "<= #{t.name} done"
45
+ end
46
+
47
+ desc 'Rollback down to specified migration, or rollback last STEP=x migrations (default 1)'
48
+ task :rollback, [:version] => :load_migrations do |t, args|
49
+ if (vers = args[:version] || ENV.fetch('VERSION', nil))
50
+ puts "=> Rolling back down to migration #{vers}"
51
+ migrate_down!(vers)
52
+ else
53
+ step = ENV['STEP'].to_i || 1
54
+ applied = migrations.delete_if(&:needs_up?).sort # NOTE: this is N queries as currently implemented
55
+ target = applied[-1 * step] || applied[0]
56
+ if target
57
+ puts "=> Rolling back #{step} step(s)"
58
+ migrate_down!(target.position - 1)
59
+ else
60
+ warn "No migrations to rollback: #{step} step(s)"
61
+ end
62
+ end
63
+ puts "<= #{t.name} done"
64
+ end
65
+
66
+ desc 'List migrations descending, showing which have been applied'
67
+ task migrations: :load_migrations do
68
+ puts(migrations.sort.reverse.map { |m| "#{m.position} #{m.name} #{m.needs_up? ? '' : 'APPLIED'}" })
69
+ end
70
+
71
+ task load_migrations: :environment do
72
+ require 'dm-migrations/migration_runner'
73
+ FileList['db/migrate/*.rb'].each do |migration|
74
+ load migration
75
+ end
76
+ end
77
+
78
+
79
+ desc 'Create the database'
80
+ task :create, [:repository] => :environment do |t, args|
81
+ repo = args[:repository] || ENV['REPOSITORY'] || :default
82
+ config = DataMapper.repository(repo)&.adapter&.options&.symbolize_keys
83
+ user = config[:user]
84
+ password = config[:password]
85
+ host = config[:host]
86
+ database = config[:database] || config[:path].sub('/', '')
87
+ charset = config[:charset] || ENV['CHARSET'] || 'utf8'
88
+ collation = config[:collation] || ENV['COLLATION'] || 'utf8_unicode_ci'
89
+ puts "=> Creating database '#{database}'"
90
+
91
+ case config[:adapter]
92
+ when 'postgres'
93
+ system('createdb', '-E', charset, '-h', host, '-U', user, database)
94
+ when 'mysql'
95
+ query = [
96
+ 'mysql', "--user=#{user}", (password.blank? ? '' : "--password=#{password}"), (%w(127.0.0.1 localhost).include?(host) ? '-e' : "--host=#{host} -e"),
97
+ "CREATE DATABASE #{database} DEFAULT CHARACTER SET #{charset} DEFAULT COLLATE #{collation}".inspect
98
+ ]
99
+ system(query.compact.join(' '))
100
+ when 'sqlite3'
101
+ DataMapper.setup(DataMapper.repository&.name, config)
102
+ else
103
+ raise "Adapter #{config[:adapter]} not supported for creating databases yet."
104
+ end
105
+ puts "<= #{t.name} done"
106
+ end
107
+
108
+ desc 'Drop the database'
109
+ task :drop, [:repository] => :environment do |t, args|
110
+ repo = args[:repository] || ENV['REPOSITORY'] || :default
111
+ config = DataMapper.repository(repo)&.adapter&.options&.symbolize_keys
112
+ user = config[:user]
113
+ password = config[:password]
114
+ host = config[:host]
115
+ database = config[:database] || config[:path].sub('/', '')
116
+ puts "=> Dropping database '#{database}'"
117
+ case config[:adapter]
118
+ when 'postgres'
119
+ system('dropdb', '-h', host, '-U', user, database)
120
+ when 'mysql'
121
+ query = [
122
+ 'mysql', "--user=#{user}",
123
+ (password.blank? ? '' : "--password=#{password}"),
124
+ (%w(127.0.0.1 localhost).include?(host) ? '-e' : "--host=#{host} -e"),
125
+ "DROP DATABASE IF EXISTS #{database}".inspect
126
+ ]
127
+ system(query.compact.join(' '))
128
+ when 'sqlite3'
129
+ FileUtils.rm_f(config[:path])
130
+ else
131
+ raise "Adapter #{config[:adapter]} not supported for dropping databases yet."
132
+ end
133
+ puts "<= #{t.name} done"
134
+ end
135
+
136
+ desc 'Load the seed data from db/seeds.rb'
137
+ task seed: :environment do |t, _|
138
+ puts '=> Loading seed data'
139
+ seed_file = File.expand_path('db/seeds.rb', File.dirname(__FILE__))
140
+ load(seed_file) if File.exist?(seed_file)
141
+ puts "<= #{t.name} done"
142
+ end
143
+
144
+ desc 'Drop the database, migrate from scratch and initialize with the seed data'
145
+ task reset: %i(drop setup)
146
+
147
+ desc 'Create the database, migrate and initialize with the seed data'
148
+ task setup: %i(create migrate seed)
149
+ end
@@ -0,0 +1,58 @@
1
+ require 'dm-migrations/migration_runner'
2
+
3
+ DataMapper.setup(:default, 'sqlite3::memory')
4
+
5
+ DataMapper::Logger.new(STDOUT, :debug)
6
+ DataMapper.logger.debug( 'Starting Migration' )
7
+
8
+ migration 1, :create_people_table do
9
+ up do
10
+ create_table :people do
11
+ column :id, Integer, serial: true
12
+ column :name, String, size: 50
13
+ column :age, Integer
14
+ end
15
+ end
16
+ down do
17
+ drop_table :people
18
+ end
19
+ end
20
+
21
+ migration 2, :add_dob_to_people do
22
+ up do
23
+ modify_table :people do
24
+ add_column :dob, DateTime, allow_nil: true
25
+ end
26
+ end
27
+
28
+ down do
29
+ modify_table :people do
30
+ drop_column :dob
31
+ end
32
+ end
33
+ end
34
+
35
+ # migrate_down!
36
+ # migrate_up!
37
+ #
38
+ # class Person
39
+ # include DataMapper::Resource
40
+ #
41
+ # property :id, Serial
42
+ # property :name, String, :size => 50
43
+ # property :age, Integer
44
+ # property :dob, DateTime, :default => proc { Time.now }
45
+ #
46
+ # end
47
+ #
48
+ # Person.create(:name => "Mark Bates", :age => 31)
49
+ # puts Person.first.inspect
50
+ # puts Person.all.inspect
51
+
52
+ if $0 == __FILE__
53
+ if $*.first == 'down'
54
+ migrate_down!
55
+ else
56
+ migrate_up!
57
+ end
58
+ end
@@ -0,0 +1,46 @@
1
+ require 'pathname'
2
+
3
+ dir = Pathname(__FILE__).dirname.expand_path
4
+
5
+ require "#{dir}sample_migration"
6
+ require "#{dir}../lib/spec/example/migration_example_group"
7
+
8
+ describe :create_people_table, type: :migration do
9
+ before do
10
+ run_migration
11
+ end
12
+
13
+ it 'creates a people table' do
14
+ expect(repository(:default)).to have_table(:people)
15
+ end
16
+
17
+ it 'has an id column as the primary key' do
18
+ expect(table(:people)).to have_column(:id)
19
+ expect(table(:people).column(:id).type).to eq 'integer'
20
+ # expect(table(:people).column(:id)).to be_primary_key
21
+ end
22
+
23
+ it 'has a name column as a string' do
24
+ expect(table(:people)).to have_column(:name)
25
+ expect(table(:people).column(:name).type).to eq 'character varying'
26
+ expect(table(:people).column(:name)).to permit_null
27
+ end
28
+
29
+ it 'has a nullable age column as a int' do
30
+ expect(table(:people)).to have_column(:age)
31
+ expect(table(:people).column(:age).type).to eq 'integer'
32
+ expect(table(:people).column(:age)).to permit_null
33
+ end
34
+ end
35
+
36
+ describe :add_dob_to_people, type: :migration do
37
+ before do
38
+ run_migration
39
+ end
40
+
41
+ it 'adds a dob column as a timestamp' do
42
+ expect(table(:people)).to have_column(:dob)
43
+ expect(table(:people).column(:dob).type).to eq 'timestamp without time zone'
44
+ expect(table(:people).column(:dob)).to permit_null
45
+ end
46
+ end
@@ -0,0 +1,304 @@
1
+ require 'dm-migrations/auto_migration'
2
+
3
+ module DataMapper
4
+ module Migrations
5
+ module DataObjectsAdapter
6
+ # Returns whether the storage_name exists.
7
+ #
8
+ # @param [String] storage_name
9
+ # a String defining the name of a storage, for example a table name.
10
+ #
11
+ # @return [Boolean]
12
+ # true if the storage exists
13
+ #
14
+ # @api semipublic
15
+ def storage_exists?(storage_name)
16
+ statement = DataMapper::Ext::String.compress_lines(<<-SQL)
17
+ SELECT COUNT(*)
18
+ FROM "information_schema"."tables"
19
+ WHERE "table_type" = 'BASE TABLE'
20
+ AND "table_schema" = ?
21
+ AND "table_name" = ?
22
+ SQL
23
+
24
+ select(statement, schema_name, storage_name).first > 0
25
+ end
26
+
27
+ # Returns whether the field exists.
28
+ #
29
+ # @param [String] storage_name
30
+ # a String defining the name of a storage, for example a table name.
31
+ # @param [String] column_name
32
+ # a String defining the name of a field, for example a column name.
33
+ #
34
+ # @return [Boolean]
35
+ # true if the field exists.
36
+ #
37
+ # @api semipublic
38
+ def field_exists?(storage_name, column_name)
39
+ statement = DataMapper::Ext::String.compress_lines(<<-SQL)
40
+ SELECT COUNT(*)
41
+ FROM "information_schema"."columns"
42
+ WHERE "table_schema" = ?
43
+ AND "table_name" = ?
44
+ AND "column_name" = ?
45
+ SQL
46
+
47
+ select(statement, schema_name, storage_name, column_name).first > 0
48
+ end
49
+
50
+ # @api semipublic
51
+ def upgrade_model_storage(model)
52
+ name = self.name
53
+ properties = model.properties_with_subclasses(name)
54
+
55
+ return properties if create_model_storage(model)
56
+
57
+ table_name = model.storage_name(name)
58
+
59
+ with_connection do |connection|
60
+ properties.map do |property|
61
+ schema_hash = property_schema_hash(property)
62
+ next if field_exists?(table_name, schema_hash[:name])
63
+
64
+ statement = alter_table_add_column_statement(connection, table_name, schema_hash)
65
+ command = connection.create_command(statement)
66
+ command.execute_non_query
67
+
68
+ # For simple :index => true columns, add an appropriate index.
69
+ # Upgrading doesn't know how to deal with complex indexes yet.
70
+ if property.options[:index] === true
71
+ statement = create_index_statement(model, property.name, [property.field])
72
+ command = connection.create_command(statement)
73
+ command.execute_non_query
74
+ end
75
+
76
+ property
77
+ end.compact
78
+ end
79
+ end
80
+
81
+ # @api semipublic
82
+ def create_model_storage(model)
83
+ name = self.name
84
+ properties = model.properties_with_subclasses(name)
85
+
86
+ return false if storage_exists?(model.storage_name(name))
87
+ return false if properties.empty?
88
+
89
+ with_connection do |connection|
90
+ statements = [create_table_statement(connection, model, properties)]
91
+ statements.concat(create_index_statements(model))
92
+ statements.concat(create_unique_index_statements(model))
93
+
94
+ statements.each do |statement|
95
+ command = connection.create_command(statement)
96
+ command.execute_non_query
97
+ end
98
+ end
99
+
100
+ true
101
+ end
102
+
103
+ # @api semipublic
104
+ def destroy_model_storage(model)
105
+ return true unless supports_drop_table_if_exists? || storage_exists?(model.storage_name(name))
106
+
107
+ execute(drop_table_statement(model))
108
+ true
109
+ end
110
+
111
+ module SQL # :nodoc:
112
+ # private ## This cannot be private for current migrations
113
+
114
+ # Adapters that support AUTO INCREMENT fields for CREATE TABLE
115
+ # statements should overwrite this to return true
116
+ #
117
+ # @api private
118
+ def supports_serial?
119
+ false
120
+ end
121
+
122
+ # @api private
123
+ def supports_drop_table_if_exists?
124
+ false
125
+ end
126
+
127
+ # @api private
128
+ def schema_name
129
+ raise NotImplementedError, "#{self.class}#schema_name not implemented"
130
+ end
131
+
132
+ # @api private
133
+ def alter_table_add_column_statement(connection, table_name, schema_hash)
134
+ "ALTER TABLE #{quote_name(table_name)} #{add_column_statement} #{property_schema_statement(connection, schema_hash)}"
135
+ end
136
+
137
+ # @api private
138
+ def create_table_statement(connection, model, properties)
139
+ DataMapper::Ext::String.compress_lines(<<-SQL)
140
+ CREATE TABLE #{quote_name(model.storage_name(name))}
141
+ (#{properties.map { |property| property_schema_statement(connection, property_schema_hash(property)) }.join(', ')},
142
+ PRIMARY KEY(#{properties.key.map { |property| quote_name(property.field) }.join(', ')}))
143
+ SQL
144
+ end
145
+
146
+ # @api private
147
+ def drop_table_statement(model)
148
+ table_name = quote_name(model.storage_name(name))
149
+ if supports_drop_table_if_exists?
150
+ "DROP TABLE IF EXISTS #{table_name}"
151
+ else
152
+ "DROP TABLE #{table_name}"
153
+ end
154
+ end
155
+
156
+ # @api private
157
+ def create_index_statements(model)
158
+ name = self.name
159
+ model.storage_name(name)
160
+
161
+ indexes(model).map do |index_name, fields|
162
+ create_index_statement(model, index_name, fields)
163
+ end
164
+ end
165
+
166
+ # @api private
167
+ def create_index_statement(model, index_name, fields)
168
+ table_name = model.storage_name(name)
169
+
170
+ DataMapper::Ext::String.compress_lines(<<-SQL)
171
+ CREATE INDEX #{quote_name("index_#{table_name}_#{index_name}")} ON
172
+ #{quote_name(table_name)} (#{fields.map { |field| quote_name(field) }.join(', ')})
173
+ SQL
174
+ end
175
+
176
+ # @api private
177
+ def create_unique_index_statements(model)
178
+ name = self.name
179
+ table_name = model.storage_name(name)
180
+ key = model.key(name).map(&:field)
181
+ unique_indexes = unique_indexes(model).reject { |_index_name, fields| fields == key }
182
+
183
+ unique_indexes.map do |index_name, fields|
184
+ DataMapper::Ext::String.compress_lines(<<-SQL)
185
+ CREATE UNIQUE INDEX #{quote_name("unique_#{table_name}_#{index_name}")} ON
186
+ #{quote_name(table_name)} (#{fields.map { |field| quote_name(field) }.join(', ')})
187
+ SQL
188
+ end
189
+ end
190
+
191
+ # @api private
192
+ def property_schema_hash(property)
193
+ dump_class = property.dump_class
194
+ type_by_property_class = self.class.type_by_property_class(property.class)
195
+
196
+ schema = (type_by_property_class || self.class.type_map[dump_class]).merge(name: property.field)
197
+
198
+ schema_primitive = schema[:primitive]
199
+
200
+ if dump_class.equal?(String) && schema_primitive != 'TEXT' && schema_primitive != 'CLOB' && schema_primitive != 'NVARCHAR' &&
201
+ schema_primitive != 'BYTEA' && schema_primitive != 'VARBINARY'
202
+ schema[:length] = property.length
203
+ elsif dump_class.equal?(BigDecimal) || dump_class.equal?(Float)
204
+ schema[:precision] = property.precision
205
+ schema[:scale] = property.scale
206
+ end
207
+
208
+ schema[:allow_nil] = property.allow_nil?
209
+ schema[:serial] = property.serial?
210
+
211
+ default = property.default
212
+
213
+ if default.nil? || default.respond_to?(:call)
214
+ # remove the default if the property does not allow nil
215
+ schema.delete(:default) unless schema[:allow_nil]
216
+ else
217
+ schema[:default] = property.dump(default)
218
+ end
219
+
220
+ schema
221
+ end
222
+
223
+ # @api private
224
+ def property_schema_statement(connection, schema)
225
+ statement = quote_name(schema[:name])
226
+ statement << " #{schema[:primitive]}"
227
+
228
+ length = schema[:length]
229
+
230
+ if schema[:precision] && schema[:scale]
231
+ statement << "(#{%i(precision scale).map { |key| connection.quote_value(schema[key]) }.join(', ')})"
232
+ elsif length == 'max'
233
+ statement << '(max)'
234
+ elsif length
235
+ statement << "(#{connection.quote_value(length)})"
236
+ end
237
+
238
+ default = schema[:default]
239
+ statement << " DEFAULT #{connection.quote_value(default)}" if default
240
+
241
+ statement << ' NOT NULL' unless schema[:allow_nil]
242
+
243
+ statement
244
+ end
245
+
246
+ # @api private
247
+ def indexes(model)
248
+ model.properties(name).indexes
249
+ end
250
+
251
+ # @api private
252
+ def unique_indexes(model)
253
+ model.properties(name).unique_indexes
254
+ end
255
+
256
+ # @api private
257
+ def add_column_statement
258
+ 'ADD COLUMN'
259
+ end
260
+ end
261
+
262
+ include SQL
263
+
264
+ module ClassMethods
265
+ # Default types for all data object based adapters.
266
+ #
267
+ # @return [Hash] default types for data objects adapters.
268
+ #
269
+ # @api private
270
+ def type_map
271
+ length = Property::String.length
272
+ precision = Property::Numeric.precision
273
+ scale = Property::Decimal.scale
274
+
275
+ {
276
+ Property::Binary => {primitive: 'BLOB'},
277
+ Object => {primitive: 'TEXT'},
278
+ Integer => {primitive: 'INTEGER'},
279
+ String => {primitive: 'VARCHAR', length: length},
280
+ Class => {primitive: 'VARCHAR', length: length},
281
+ BigDecimal => {primitive: 'DECIMAL', precision: precision, scale: scale},
282
+ Float => {primitive: 'FLOAT', precision: precision},
283
+ DateTime => {primitive: 'TIMESTAMP'},
284
+ Date => {primitive: 'DATE'},
285
+ Time => {primitive: 'TIMESTAMP'},
286
+ TrueClass => {primitive: 'BOOLEAN'},
287
+ Property::Text => {primitive: 'TEXT'}
288
+ }.freeze
289
+ end
290
+
291
+ # Finds a type for a given property.
292
+ #
293
+ # @return [Hash | nil] type matching the given property or one of the properties ancestors
294
+ #
295
+ # @api private
296
+ def type_by_property_class(property_class)
297
+ return nil unless property_class < DataMapper::Property
298
+
299
+ type_map[property_class] || type_by_property_class(property_class.superclass)
300
+ end
301
+ end
302
+ end
303
+ end
304
+ end