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
57
# 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 => e
    XMigra.log_error(e)
    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.



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

def access_artifacts
  @access_artifacts
end

#branch_upgradeObject (readonly)

Returns the value of attribute branch_upgrade.



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

def branch_upgrade
  @branch_upgrade
end

#dry_runObject

Returns the value of attribute dry_run.



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

def dry_run
  @dry_run
end

#include_grantsObject

Returns the value of attribute include_grants.



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

def include_grants
  @include_grants
end

#indexesObject (readonly)

Returns the value of attribute indexes.



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

def indexes
  @indexes
end

#migrationsObject (readonly)

Returns the value of attribute migrations.



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

def migrations
  @migrations
end

#productionObject

Returns the value of attribute production.



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

def production
  @production
end

Instance Method Details

#amend_script_parts(parts) ⇒ Object



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

def amend_script_parts(parts)
end

#apply_migration_sqlObject



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

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

#branch_upgrade_sqlObject



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

def branch_upgrade_sql
end

#check_working_copy!Object



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

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

#create_access_artifacts_sqlObject



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

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

#ddl_block_separatorObject



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

def ddl_block_separator; "\n"; end

#each_file_pathObject



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

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

#grant_access_sqlObject



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

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



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

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)


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

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

#inspectObject



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

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

#sql_comment_block(text) ⇒ Object



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

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

#update_sqlObject

Raises:



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
165
# File 'lib/xmigra/schema_updater.rb', line 76

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



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

def upgrade_cleanup_sql
end

#vcs_informationObject



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

def vcs_information
end