Class: XMigra::SchemaUpdater

Inherits:
SchemaManipulator show all
Includes:
ReversionScriptBuilding
Defined in:
lib/xmigra/schema_updater.rb

Constant Summary collapse

DEV_SCRIPT_WARNING =
<<-"END_OF_TEXT"
*********************************************************
***                    WARNING                        ***
*********************************************************

THIS SCRIPT IS FOR USE ONLY ON DEVELOPMENT DATABASES.

IF RUN ON AN EMPTY DATABASE IT WILL CREATE A DEVELOPMENT
DATABASE THAT IS NOT GUARANTEED TO FOLLOW ANY COMMITTED
MIGRATION PATH.

RUNNING THIS SCRIPT ON A PRODUCTION DATABASE WILL FAIL.
END_OF_TEXT

Constants inherited from SchemaManipulator

XMigra::SchemaManipulator::ACCESS_SUBDIR, XMigra::SchemaManipulator::DBINFO_FILE, XMigra::SchemaManipulator::INDEXES_SUBDIR, XMigra::SchemaManipulator::PERMISSIONS_FILE, XMigra::SchemaManipulator::PLUGIN_KEY, XMigra::SchemaManipulator::STRUCTURE_SUBDIR, XMigra::SchemaManipulator::VERINC_FILE

Instance Attribute Summary collapse

Attributes inherited from SchemaManipulator

#path, #plugin

Instance Method Summary collapse

Methods included from ReversionScriptBuilding

#reversion_script, #reversions

Methods inherited from SchemaManipulator

#branch_upgrade_file, #load_plugin!

Constructor Details

#initialize(path) ⇒ SchemaUpdater

Returns a new instance of SchemaUpdater.



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/xmigra/schema_updater.rb', line 24

def initialize(path)
  super(path)
  
  @file_based_groups = []
  
  begin
    @file_based_groups << (@access_artifacts = AccessArtifactCollection.new(
      @path.join(ACCESS_SUBDIR),
      :db_specifics=>@db_specifics,
      :filename_metavariable=>@db_info.fetch('filename metavariable', nil)
    ))
    @file_based_groups << (@indexes = IndexCollection.new(
      @path.join(INDEXES_SUBDIR),
      :db_specifics=>@db_specifics
    ))
    @file_based_groups << (@migrations = MigrationChain.new(
      @path.join(STRUCTURE_SUBDIR),
      :db_specifics=>@db_specifics,
      :vcs_specifics=>@vcs_specifics,
    ))
    
    @branch_upgrade = BranchUpgrade.new(branch_upgrade_file)
    @file_based_groups << [@branch_upgrade] if @branch_upgrade.found?
  rescue Error
    raise
  rescue StandardError
    raise Error, "Error initializing #{self.class} components"
  end
  
  @production = false
  @dry_run = false
  @include_grants = nil
end

Instance Attribute Details

#access_artifactsObject (readonly)

Returns the value of attribute access_artifacts.



59
60
61
# File 'lib/xmigra/schema_updater.rb', line 59

def access_artifacts
  @access_artifacts
end

#branch_upgradeObject (readonly)

Returns the value of attribute branch_upgrade.



59
60
61
# File 'lib/xmigra/schema_updater.rb', line 59

def branch_upgrade
  @branch_upgrade
end

#dry_runObject

Returns the value of attribute dry_run.



58
59
60
# File 'lib/xmigra/schema_updater.rb', line 58

def dry_run
  @dry_run
end

#include_grantsObject

Returns the value of attribute include_grants.



58
59
60
# File 'lib/xmigra/schema_updater.rb', line 58

def include_grants
  @include_grants
end

#indexesObject (readonly)

Returns the value of attribute indexes.



59
60
61
# File 'lib/xmigra/schema_updater.rb', line 59

def indexes
  @indexes
end

#migrationsObject (readonly)

Returns the value of attribute migrations.



59
60
61
# File 'lib/xmigra/schema_updater.rb', line 59

def migrations
  @migrations
end

#productionObject

Returns the value of attribute production.



58
59
60
# File 'lib/xmigra/schema_updater.rb', line 58

def production
  @production
end

Instance Method Details

#amend_script_parts(parts) ⇒ Object



166
167
# File 'lib/xmigra/schema_updater.rb', line 166

def amend_script_parts(parts)
end

#apply_migration_sqlObject



183
184
185
186
187
188
# File 'lib/xmigra/schema_updater.rb', line 183

def apply_migration_sql
  # Apply selected migrations
  @migrations.collect do |m|
    m.migration_application_sql
  end
end

#branch_upgrade_sqlObject



190
191
# File 'lib/xmigra/schema_updater.rb', line 190

def branch_upgrade_sql
end

#check_working_copy!Object



173
174
175
# File 'lib/xmigra/schema_updater.rb', line 173

def check_working_copy!
  raise VersionControlError, "XMigra source not under version control" if production
end

#create_access_artifacts_sqlObject



177
178
179
180
181
# File 'lib/xmigra/schema_updater.rb', line 177

def create_access_artifacts_sql
  scripts = []
  @access_artifacts.each_definition_sql {|s| scripts << s}
  return scripts unless scripts.empty?
end

#ddl_block_separatorObject



73
# File 'lib/xmigra/schema_updater.rb', line 73

def ddl_block_separator; "\n"; end

#each_file_pathObject



210
211
212
213
214
# File 'lib/xmigra/schema_updater.rb', line 210

def each_file_path
  @file_based_groups.each do |group|
    group.each {|item| yield item.file_path}
  end
end

#grant_access_sqlObject



193
194
195
196
197
198
199
200
201
202
# File 'lib/xmigra/schema_updater.rb', line 193

def grant_access_sql
  sql_gen = PermissionScriptWriter.new(path)
  if respond_to?(:warning)
    updater = self
    sql_gen.define_singleton_method(:warning) do |message|
      updater.warning(message)
    end
  end
  return sql_gen.permissions_sql(:transactional => false)
end

#in_ddl_transaction(options = {}) ⇒ Object



65
66
67
68
69
70
71
# File 'lib/xmigra/schema_updater.rb', line 65

def in_ddl_transaction(options = {})
  if options[:dry_run]
    raise(XMigra::Error, 'DDL transaction not supported; dry-run unavailable.')
  end
  
  yield
end

#include_grants_in_upgrade?Boolean

Returns:

  • (Boolean)


216
217
218
219
# File 'lib/xmigra/schema_updater.rb', line 216

def include_grants_in_upgrade?
  return @include_grants unless @include_grants.nil?
  return @db_info.fetch('grants in upgrade', false)
end

#inspectObject



61
62
63
# File 'lib/xmigra/schema_updater.rb', line 61

def inspect
  "<#{self.class.name}: path=#{path.to_s.inspect}, db=#{@db_specifics}, vcs=#{@vcs_specifics}>"
end

#sql_comment_block(text) ⇒ Object



169
170
171
# File 'lib/xmigra/schema_updater.rb', line 169

def sql_comment_block(text)
  text.lines.collect {|l| '-- ' + l.chomp + "\n"}.join('')
end

#update_sqlObject

Raises:



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/xmigra/schema_updater.rb', line 75

def update_sql
  raise XMigra::Error, "Incomplete migration chain" unless @migrations.complete?
  raise XMigra::Error, "Unchained migrations exist" unless @migrations.includes_all?
  if respond_to? :warning
    @branch_upgrade.warnings.each {|w| warning(w)}
    if @branch_upgrade.found? && !@branch_upgrade.applicable?(@migrations)
      warning("#{branch_upgrade.file_path} does not apply to the current migration chain.")
    end
  end
  
  check_working_copy!
  migrations.check_declaratives_current!
  
  intro_comment = @db_info.fetch('script comment', '')
  if Plugin.active
    intro_comment = intro_comment.dup
    Plugin.active.amend_source_sql(intro_comment)
  end
  intro_comment << if production
    sql_comment_block(vcs_information || "")
  else
    sql_comment_block(DEV_SCRIPT_WARNING)
  end
  intro_comment << "\n\n"
  
  # If supported, wrap transactionality around modifications
  intro_comment + in_ddl_transaction(:dry_run => @dry_run) do
    script_parts = [
      # Check for blatantly incorrect application of script, e.g. running
      # on master or template database.
      :check_execution_environment_sql,
      
      # Create schema version control (SVC) tables if they don't exist
      :ensure_version_tables_sql,
      
      # Create and fill a temporary table with migration IDs known by
      # the script with order information
      :create_and_fill_migration_table_sql,
      
      # Create and fill a temporary table with index information known by
      # the script
      :create_and_fill_indexes_table_sql,
      
      # Check that all migrations applied to the database are known to
      # the script (as far back as the most recent "version bridge" record)
      :check_preceding_migrations_sql,
      
      # Check that there are no "gaps" in the chain of migrations
      # that have already been applied
      :check_chain_continuity_sql,
      
      # Mark migrations in the temporary table that should be installed
      :select_for_install_sql,
      
      # Check production configuration of database
      :production_config_check_sql,
      
      # Remove all access artifacts
      :remove_access_artifacts_sql,
      
      # Remove all undesired indexes
      :remove_undesired_indexes_sql,
      
      # Apply a branch upgrade if indicated
      :branch_upgrade_sql,
      
      # Apply selected migrations
      :apply_migration_sql,
      
      # Create all access artifacts
      :create_access_artifacts_sql,
      
      # Create any desired indexes that don't yet exist
      :create_new_indexes_sql,
    ]
    
    if include_grants_in_upgrade?
      script_parts << :grant_access_sql
    end
    
    # Any cleanup needed
    script_parts << :upgrade_cleanup_sql
    
    amend_script_parts(script_parts)
    
    script_parts.map {|mn| self.send(mn)}.flatten.compact.join(ddl_block_separator).tap do |result|
      Plugin.active.amend_composed_sql(result) if Plugin.active
    end
  end
end

#upgrade_cleanup_sqlObject



204
205
# File 'lib/xmigra/schema_updater.rb', line 204

def upgrade_cleanup_sql
end

#vcs_informationObject



207
208
# File 'lib/xmigra/schema_updater.rb', line 207

def vcs_information
end