sbf-dm-migrations 1.3.0.beta

Sign up to get free protection for your applications and to get access to all the features.
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,105 @@
1
+ require 'dm-core'
2
+
3
+ module SQL
4
+ class TableCreator
5
+ extend DataMapper::Property::Lookup
6
+
7
+ attr_accessor :table_name, :opts
8
+
9
+ def initialize(adapter, table_name, opts = {}, &block)
10
+ @adapter = adapter
11
+ @table_name = table_name.to_s
12
+ @opts = opts
13
+
14
+ @columns = []
15
+
16
+ instance_eval(&block)
17
+ end
18
+
19
+ def quoted_table_name
20
+ @adapter.send(:quote_name, table_name)
21
+ end
22
+
23
+ def column(name, type, opts = {})
24
+ @columns << Column.new(@adapter, name, type, opts)
25
+ end
26
+
27
+ def to_sql
28
+ "CREATE TABLE #{quoted_table_name} (#{@columns.map(&:to_sql).join(', ')})#{@adapter.table_options(@opts)}"
29
+ end
30
+
31
+ # A helper for using the native NOW() SQL function in a default
32
+ def now
33
+ SqlExpr.new('NOW()')
34
+ end
35
+
36
+ # A helper for using the native UUID() SQL function in a default
37
+ def uuid
38
+ SqlExpr.new('UUID()')
39
+ end
40
+
41
+ class SqlExpr
42
+ attr_accessor :sql
43
+
44
+ def initialize(sql)
45
+ @sql = sql
46
+ end
47
+
48
+ def to_s
49
+ @sql.to_s
50
+ end
51
+ end
52
+
53
+ class Column
54
+ attr_accessor :name, :type
55
+
56
+ def initialize(adapter, name, type, opts = {})
57
+ @adapter = adapter
58
+ @name = name.to_s
59
+ @opts = opts
60
+ @type = build_type(type)
61
+ end
62
+
63
+ def to_sql
64
+ type
65
+ end
66
+
67
+ private def build_type(type_class)
68
+ schema = {name: @name, quote_column_name: quoted_name}
69
+
70
+ %i(nullable nullable?).each do |option|
71
+ next if (value = schema.delete(option)).nil?
72
+
73
+ warn "#{option.inspect} is deprecated, use :allow_nil instead"
74
+ schema[:allow_nil] = value unless schema.key?(:allow_nil)
75
+ end
76
+
77
+ schema[:allow_nil] = !schema[:not_null] unless schema.key?(:allow_nil)
78
+
79
+ if type_class.is_a?(String)
80
+ schema[:primitive] = type_class
81
+ else
82
+ primitive = type_class.respond_to?(:dump_as) ? type_class.dump_as : type_class
83
+ options = @adapter.class.type_by_property_class(type_class) || @adapter.class.type_map[primitive]
84
+
85
+ schema.update(type_class.options) if type_class.respond_to?(:options)
86
+ schema.update(options)
87
+
88
+ schema.delete(:length) if type_class <= DataMapper::Property::Text
89
+ end
90
+
91
+ schema.update(@opts)
92
+
93
+ schema[:length] = schema.delete(:size) if schema.key?(:size)
94
+
95
+ @adapter.send(:with_connection) do |connection|
96
+ @adapter.property_schema_statement(connection, schema)
97
+ end
98
+ end
99
+
100
+ private def quoted_name
101
+ @adapter.send(:quote_name, name)
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,57 @@
1
+ module SQL
2
+ class TableModifier
3
+ extend DataMapper::Property::Lookup
4
+
5
+ attr_accessor :table_name, :opts, :statements, :adapter
6
+
7
+ def initialize(adapter, table_name, opts = {}, &block)
8
+ @adapter = adapter
9
+ @table_name = table_name.to_s
10
+ @opts = opts
11
+
12
+ @statements = []
13
+
14
+ instance_eval(&block)
15
+ end
16
+
17
+ def add_column(name, type, opts = {})
18
+ column = SQL::TableCreator::Column.new(@adapter, name, type, opts)
19
+ @statements << "ALTER TABLE #{quoted_table_name} ADD COLUMN #{column.to_sql}"
20
+ end
21
+
22
+ def drop_column(name)
23
+ # raise NotImplemented for SQLite3. Can't ALTER TABLE, need to copy table.
24
+ # We'd have to inspect it, and we can't, since we aren't executing any queries yet.
25
+ # TODO instead of building the SQL queries when executing the block, create AddColumn,
26
+ # AlterColumn and DropColumn objects that get #to_sql'd
27
+ if name.is_a?(Array)
28
+ name.each { |n| drop_column(n) }
29
+ else
30
+ @statements << "ALTER TABLE #{quoted_table_name} DROP COLUMN #{quote_column_name(name)}"
31
+ end
32
+ end
33
+ alias_method :drop_columns, :drop_column
34
+
35
+ def rename_column(name, new_name, _opts = {})
36
+ # raise NotImplemented for SQLite3
37
+ @statements << @adapter.rename_column_type_statement(table_name, name, new_name)
38
+ end
39
+
40
+ def change_column(name, type, opts = {})
41
+ column = SQL::TableCreator::Column.new(@adapter, name, type, opts)
42
+ @statements << @adapter.change_column_type_statement(table_name, column)
43
+ end
44
+
45
+ def quote_column_name(name)
46
+ @adapter.send(:quote_name, name.to_s)
47
+ end
48
+
49
+ def quoted_table_name
50
+ @adapter.send(:quote_name, table_name)
51
+ end
52
+
53
+ def to_sql
54
+ @statements.join(';')
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,7 @@
1
+ require 'dm-migrations/sql/table_creator'
2
+ require 'dm-migrations/sql/table_modifier'
3
+ require 'dm-migrations/sql/sqlite'
4
+ require 'dm-migrations/sql/mysql'
5
+ require 'dm-migrations/sql/postgres'
6
+ require 'dm-migrations/sql/sqlserver'
7
+ require 'dm-migrations/sql/oracle'
@@ -0,0 +1,5 @@
1
+ module DataMapper
2
+ module Migrations
3
+ VERSION = '1.3.0.beta'.freeze
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ require 'dm-core'
2
+ require 'dm-migrations/migration'
3
+ require 'dm-migrations/auto_migration'
@@ -0,0 +1,69 @@
1
+ require_relative '../matchers/migration_matchers'
2
+
3
+ require 'rspec'
4
+
5
+ module Spec
6
+ module Example
7
+ class MigrationExampleGroup < RSpec::Core::ExampleGroup
8
+ include Spec::Matchers::Migration
9
+
10
+ before(:all) do
11
+ run_prereq_migrations if this_migration.adapter.supports_schema_transactions?
12
+ end
13
+
14
+ before(:each) do
15
+ if this_migration.adapter.supports_schema_transactions?
16
+ this_migration.adapter.begin_transaction
17
+ else
18
+ run_prereq_migrations
19
+ end
20
+ end
21
+
22
+ after(:each) do
23
+ this_migration.adapter.rollback_transaction if this_migration.adapter.supports_schema_transactions?
24
+ end
25
+
26
+ after(:all) do
27
+ this_migration.adapter.recreate_database
28
+ end
29
+
30
+ def run_prereq_migrations
31
+ # 'running n-1 migrations'
32
+ all_databases.each do |db|
33
+ db.adapter.recreate_database
34
+ end
35
+ @@migrations.sort.each do |migration|
36
+ break if migration.name.to_s == migration_name.to_s
37
+
38
+ migration.perform_up
39
+ end
40
+ end
41
+
42
+ def run_migration
43
+ this_migration.perform_up
44
+ end
45
+
46
+ def migration_name
47
+ @migration_name ||= self.class.instance_variable_get('@description_text').to_s
48
+ end
49
+
50
+ def all_databases
51
+ @@migrations.map(&:database).uniq
52
+ end
53
+
54
+ def this_migration
55
+ @@migrations.select { |m| m.name.to_s == migration_name }.first
56
+ end
57
+
58
+ def select(sql)
59
+ this_migration.adapter.select(sql)
60
+ end
61
+
62
+ def table(table_name)
63
+ this_migration.adapter.table(table_name)
64
+ end
65
+
66
+ Spec::Example::MigrationExampleGroup.register
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,96 @@
1
+ module Spec
2
+ module Matchers
3
+ module Migration
4
+ def have_table(table_name)
5
+ HaveTableMatcher.new(table_name)
6
+ end
7
+
8
+ def have_column(column_name)
9
+ HaveColumnMatcher.new(column_name)
10
+ end
11
+
12
+ def permit_null
13
+ NullableColumnMatcher.new
14
+ end
15
+
16
+ def be_primary_key
17
+ PrimaryKeyMatcher.new
18
+ end
19
+
20
+ class HaveTableMatcher
21
+ attr_accessor :table_name, :repository
22
+
23
+ def initialize(table_name)
24
+ @table_name = table_name
25
+ end
26
+
27
+ def matches?(repository)
28
+ repository.adapter.storage_exists?(table_name)
29
+ end
30
+
31
+ def failure_message
32
+ %(expected #{repository} to have table '#{table_name}')
33
+ end
34
+
35
+ def negative_failure_message
36
+ %(expected #{repository} to not have table '#{table_name}')
37
+ end
38
+ end
39
+
40
+ class HaveColumnMatcher
41
+ attr_accessor :table, :column_name
42
+
43
+ def initialize(column_name)
44
+ @column_name = column_name
45
+ end
46
+
47
+ def matches?(table)
48
+ @table = table
49
+ table.columns.map(&:name).include?(column_name.to_s)
50
+ end
51
+
52
+ def failure_message
53
+ %(expected #{table} to have column '#{column_name}')
54
+ end
55
+
56
+ def negative_failure_message
57
+ %(expected #{table} to not have column '#{column_name}')
58
+ end
59
+ end
60
+
61
+ class NullableColumnMatcher
62
+ attr_accessor :column
63
+
64
+ def matches?(column)
65
+ @column = column
66
+ !column.not_null
67
+ end
68
+
69
+ def failure_message
70
+ %(expected #{column.name} to permit NULL)
71
+ end
72
+
73
+ def negative_failure_message
74
+ %(expected #{column.name} to be NOT NULL)
75
+ end
76
+ end
77
+
78
+ class PrimaryKeyMatcher
79
+ attr_accessor :column
80
+
81
+ def matches?(column)
82
+ @column = column
83
+ column.primary_key
84
+ end
85
+
86
+ def failure_message
87
+ %(expected #{column.name} to be PRIMARY KEY)
88
+ end
89
+
90
+ def negative_failure_message
91
+ %(expected #{column.name} to not be PRIMARY KEY)
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end