|
| 1 | +--- |
| 2 | +sidebar_position: 1 |
| 3 | +--- |
| 4 | + |
| 5 | +# MSSQL |
| 6 | + |
| 7 | +:::info |
| 8 | + |
| 9 | +For instructions on how to apply database migrations, please refer to the |
| 10 | +[Getting Started](../../getting-started/server/database/mssql/index.md#updating-the-database) |
| 11 | +documentation. |
| 12 | + |
| 13 | +::: |
| 14 | + |
| 15 | +:::tip |
| 16 | + |
| 17 | +We recommend reading [T-SQL Code Style](../code-style/sql.md) since it has a major impact in how we |
| 18 | +write migrations. |
| 19 | + |
| 20 | +::: |
| 21 | + |
| 22 | +## SQL database project |
| 23 | + |
| 24 | +We use a |
| 25 | +[SDK-style SQL project](https://learn.microsoft.com/en-us/sql/azure-data-studio/extensions/sql-database-project-extension-sdk-style-projects?view=sql-server-ver16) |
| 26 | +(`.sqlproj`) to develop the database locally -- this means we have an up-to-date representation of |
| 27 | +the database in `src/Sql`, and any modifications need to be represented there as well. SDK-style SQL |
| 28 | +projects are available in Visual Studio Code that provides schema comparison and more. You may also |
| 29 | +modify the `.sql` files directly with any text editor. |
| 30 | + |
| 31 | +To make a database change, start by modifying the `.sql` files in `src/Sql/dbo`. These changes will |
| 32 | +also need to be applied in a migration script. Migration scripts are located in |
| 33 | +`util/Migrator/DbScripts`. |
| 34 | + |
| 35 | +You can either generate the migration scripts automatically using the _Schema Comparison_ |
| 36 | +functionality or by manually writing them. Do note that the automatic method will only take you so |
| 37 | +far and it will need to be manually edited to adhere to the code styles. |
| 38 | + |
| 39 | +For added safeguards we have automated linting and validation to ensure the SQL project is always up |
| 40 | +to date with the migrations. |
| 41 | + |
| 42 | +The separate database definitions in `src/Sql/.../dbo` serve as a "master" reference for the |
| 43 | +intended and final state of the database at that time. This is crucial because the state of database |
| 44 | +definitions at the current moment may differ from when a migration was added in the past. These |
| 45 | +definitions act as a lint and validation step to ensure that migrations work as expected, and the |
| 46 | +separation helps maintain clarity and accuracy in database schema management and synchronization |
| 47 | +processes. |
| 48 | + |
| 49 | +## Modifying the database |
| 50 | + |
| 51 | +In accordance with the tenets of [Evolutionary Database Design](./edd.mdx) every change must be |
| 52 | +considered as split into two parts: |
| 53 | + |
| 54 | +1. A backwards-compatible transition migration |
| 55 | +2. A non-backwards-compatible final migration |
| 56 | + |
| 57 | +Most changes are entirely backwards-compatible in their final form. If this is the case, only one |
| 58 | +phase of changes is required. With the use of beta testing, partial roll-outs, |
| 59 | +[feature flags](../feature-flags.md), etc. the often-chosen path is to spread a change across |
| 60 | +several major releases with a calculated future state that can perform a "cleanup" migration that is |
| 61 | +backwards-compatible but still represents an overall-_incompatible_ change beyond the boundaries of |
| 62 | +what we need for individual release safety. |
| 63 | + |
| 64 | +### Backwards compatible migration |
| 65 | + |
| 66 | +1. Modify the source `.sql` files in `src/Sql/dbo`. |
| 67 | +2. Write a migration script, and place it in `util/Migrator/DbScripts`. Each script must be prefixed |
| 68 | + with the current date. |
| 69 | + |
| 70 | +Tips to ensure backwards compatibility: |
| 71 | + |
| 72 | +- any existing stored procedure accepts the same input parameters and that new parameters have |
| 73 | + nullable defaults |
| 74 | +- when a column is renamed the existing stored procedures first check (coalesce) the new location |
| 75 | + before falling back to the old location |
| 76 | +- continued updating of the old data columns since in case of a rollback no data should be lost |
| 77 | + |
| 78 | +### Non-backwards compatible migration |
| 79 | + |
| 80 | +These changes should be written from the perspective of "all data has been migrated" and any old |
| 81 | +stored procedures that were kept around for backwards compatibility should be removed. Any logic for |
| 82 | +syncing old and new data should also be removed in this step. |
| 83 | + |
| 84 | +Since the `dbo` schema represents the current state we need to introduce a "future" state that we |
| 85 | +will call `dbo_finalization`. |
| 86 | + |
| 87 | +1. Copy the relevant `.sql` files from `src/Sql/dbo` to `src/Sql/dbo_finalization`. |
| 88 | +2. Remove the backwards compatibility logic that is no longer needed e.g. dual reads and writes to |
| 89 | + columns. |
| 90 | +3. Write a new Migration and place it in `src/Migrator/DbScripts_finalization`. Name it |
| 91 | + `YYYY-0M-FinalizationMigration.sql`. |
| 92 | + - Typically migrations are designed to be run in sequence. However since the migrations in |
| 93 | + `DbScripts_finalization` can be run out of order, care must be taken to ensure they remain |
| 94 | + compatible with the changes to `DbScripts`. In order to achieve this we only keep a single |
| 95 | + migration, which executes all backwards incompatible schema changes. |
| 96 | + |
| 97 | +Upon execution any finalization scripts will be [automatically moved](./edd.mdx#online-environments) |
| 98 | +for proper history. |
0 commit comments