RivetSamples/Convert-Migration.ps1
<#
.SYNOPSIS Demonstrates how to use the Rivet object model to convert migrations to standalone SQL scripts. .DESCRIPTION Sometimes you can't run your migration scripts directly against a database. In these situations, it is useful to be able to grab the SQL from your migrations and convert them into a different form. This script demonstates how to do that by outputing your migrations into four different files per database: one for schema changes, one for code object changes, one for data, and one for unknown kinds of changes. .LINK Merge-Migration .EXAMPLE Convert-Migration.ps1 -OutputPath 'F:\BuildOutput\DBScripts' Demonstrates how to run `Convert-Migration.ps1`. #> [CmdletBinding()] param( [Parameter(Mandatory)] # The directory where the scripts should be output. [String]$OutputPath, # The path to the rivet.json file to use. By default, it will look in the current directory. [String]$ConfigFilePath, # Mapping of migration base name (e.g. `20130115142433_CreateTable`) to the person's name who created it. [hashtable]$Author = @{ }, # A list of migrations to include. Only migrations that match are returned. Wildcards permitted. [String[]]$Include, # Any migrations/files to exclude. Wildcards accepted. [String[]]$Exclude, # Only get migrations before this date/time. [DateTime]$Before, # Only get migrations after this date/time. [DateTime]$After ) $timer = New-Object 'Diagnostics.Stopwatch' $timerForWrites = New-Object 'Diagnostics.Stopwatch' function Write-Timing { [CmdletBinding()] param( [Parameter(Mandatory)] [string] $Message ) if( -not $timer.IsRunning ) { $timer.Start() } if( -not $timerForWrites.IsRunning ) { $timerForWrites.Start() } Write-Debug -Message ('Convert-Migration {0} {1} {2}' -f $timer.Elapsed,$timerForWrites.Elapsed,$Message) $timerForWrites.Restart() } #Requires -Version 5.1 Set-StrictMode -Version 'Latest' Write-Timing -Message ('BEGIN') & (Join-Path -Path $PSScriptRoot -ChildPath '..\Import-Rivet.ps1' -Resolve) Write-Timing -Message (' Import-Rivet.ps1') if( -not (Test-Path -Path $OutputPath -PathType Container) ) { $null = New-Item -ItemType 'Directory' -Path $OutputPath -Force } else { Get-ChildItem -Path $OutputPath -File | Remove-Item } $getMigrationParams = @{ } @( 'ConfigFilePath', 'Exclude', 'Include', 'Before', 'After' ) | Where-Object { $PSBoundParameters.ContainsKey( $_ ) } | ForEach-Object { $getMigrationParams.$_ = Get-Variable -Name $_ -ValueOnly } $newTables = New-Object 'Collections.Generic.HashSet[string]' $migrations = Get-Migration @getMigrationParams $mergedMigrations = $migrations | Merge-Migration foreach( $migration in $mergedMigrations ) { Write-Timing -Message (' {0}' -f $migration.FullName) $name = $migration.Path | Split-Path -Leaf $name = [IO.Path]::GetFileNameWithoutExtension($name) $header = '' if( $Author -and $Author.ContainsKey($name) ) { $header = ': {0}' -f $Author[$name] } $header = '-- {0}{1}' -f $name,$header foreach( $op in $migration.PushOperations ) { if( -not $op ) { continue } Write-Timing -Message (' {0}' -f $op.GetType().FullName) $schemasScriptPath = Join-Path -Path $OutputPath -ChildPath ('{0}.Schemas.sql' -f $migration.Database) $schemaScriptPath = Join-Path -Path $OutputPath -ChildPath ('{0}.Schema.sql' -f $migration.Database) $dependentObjectScriptPath = Join-Path -Path $OutputPath -ChildPath ('{0}.DependentObject.sql' -f $migration.Database) $extendedPropertyScriptPath = Join-Path -Path $OutputPath -ChildPath ('{0}.ExtendedProperty.sql' -f $migration.Database) $codeObjectScriptPath = Join-Path -Path $OutputPath -ChildPath ('{0}.CodeObject.sql' -f $migration.Database) $dataScriptPath = Join-Path -Path $OutputPath -ChildPath ('{0}.Data.sql' -f $migration.Database) $unknownScriptPath = Join-Path -Path $OutputPath -ChildPath ('{0}.Unknown.sql' -f $migration.Database) $triggerScriptPath = Join-Path -Path $OutputPath -ChildPath ('{0}.Trigger.sql' -f $migration.Database) $constraintScriptPath = Join-Path -Path $OutputPath -ChildPath ('{0}.Constraint.sql' -f $migration.Database) $foreignKeyScriptPath = Join-Path -Path $OutputPath -ChildPath ('{0}.ForeignKey.sql' -f $migration.Database) $typeScriptPath = Join-Path -Path $OutputPath -ChildPath ('{0}.Type.sql' -f $migration.Database) if( $op -is [Rivet.Operations.AddTableOperation] ) { $newTables.Add( $op.ObjectName ) | Out-Null } $path = switch -Regex ( $op.GetType() ) { '(Add|Remove|Update)ExtendedProperty' { $extendedPropertyScriptPath break } '(Add|Remove|Update)Schema' { $schemasScriptPath break } '(Add|Remove|Update)(Table|RowGuidCol)' { $schemaScriptPath break } '(Add|Remove|Update)Trigger' { $triggerScriptPath break } '(Add|Remove|Update)(Index|PrimaryKey|UniqueKey)' { $tableName = '{0}.{1}' -f $op.SchemaName,$op.TableName if( $newTables.Contains( $tableName ) ) { $schemaScriptPath } else { $dependentObjectScriptPath } break } '(Add|Remove)(CheckConstraint|DefaultConstraint)' { $constraintScriptPath break } '(Enable|Disable)Constraint' { $constraintScriptPath break } '(Add|Remove|Disable|Enable)ForeignKey' { $foreignKeyScriptPath break } '(Add|Remove|Update)(DataType|Synonym)' { $typeScriptPath break } 'Rename(Column|Constraint|DataType|Index|Object)?Operation' { $schemaScriptPath } '(Add|Remove|Update)(CodeObjectMetadata|StoredProcedure|UserDefinedFunction|View)' { $codeObjectScriptPath break } '(Add|Remove|Update)Row' { $dataScriptPath break } 'RawDdl|ScriptFile' { Write-Warning ('Generic migration operation found in ''{0}''.' -f $migration.Path) $unknownScriptPath break } default { Write-Error ('Unknown migration operation ''{0}'' in ''{1}''.' -f $op.GetType(),$migration.Path) return } } if( -not (Test-Path -Path $path -PathType Leaf) ) { $null = New-Item -Path $path -ItemType 'File' -Force } $header | Add-Content -Path $path $op.ToIdempotentQuery() | Add-Content -Path $path ("GO{0}" -f [Environment]::NewLine) | Add-Content -Path $path } } Write-Timing -Message ('END') |