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,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