Extras/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=$true)] [string] # The directory where the scripts should be output. $OutputPath, [Parameter()] [string] # The path to the rivet.json file to use. By default, it will look in the current directory. $ConfigFilePath, [Parameter()] [Hashtable] # Mapping of migration base name (e.g. `20130115142433_CreateTable`) to the person's name who created it. $Author = @{ }, [string[]] # A list of migrations to include. Only migrations that match are returned. Wildcards permitted. $Include, [string[]] # Any migrations/files to exclude. Wildcards accepted. $Exclude, [DateTime] # Only get migrations before this date/time. $Before, [DateTime] # Only get migrations after this date/time. $After ) Set-StrictMode -Version 'Latest' & (Join-Path -Path $PSScriptRoot -ChildPath '..\Import-Rivet.ps1' -Resolve) 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 } $operations = New-Object 'Collections.ArrayList' $newTables = New-Object 'Collections.Generic.HashSet[string]' $opIdx = @{ } Get-Migration @getMigrationParams | Merge-Migration | ForEach-Object { $migration = $_ $migration.PushOperations | Where-Object { $_ } | ForEach-Object { $op = $_ $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) $header = $op.Source | ForEach-Object { $name = $_.FullName $by = '' if( $Author -and $Author.ContainsKey( $name ) ) { $by = ': {0}' -f $Author[$name] } '-- {0}{1}' -f $name,$by } $header = $header -join ([Environment]::NewLine) if( $op -is [Rivet.Operations.AddTableOperation] ) { $newTables.Add( $op.ObjectName ) | Out-Null } $op = $_ $path = switch -Regex ( $op.GetType() ) { '(Add|Remove|Update)ExtendedProperty' { $extendedPropertyScriptPath break } '(Add|Remove|Update)Schema' { $schemasScriptPath break } '(Add|Remove|Update)Table' { $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|Index)?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 } } |