From a561383f6ac23ce38a5f8586eafb3a19694ac05e Mon Sep 17 00:00:00 2001 From: Zack Moore <1731364+ormico@users.noreply.github.com> Date: Sun, 14 Mar 2021 21:27:44 -0400 Subject: [PATCH 1/3] adding first patch section --- docs/tutorial.md | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/docs/tutorial.md b/docs/tutorial.md index 02218fe..cbb1d7b 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -151,7 +151,50 @@ git commit -m "init dbpatch project" ## Creating the first Patches -```dbpatch addpatch -n first-patch``` +Before allowing the other developers to begin working on the database, Casey wants to add a patch setting up all the database properties and settings. + +```dbpatch addpatch -n config-database``` + +This will add the first patch to `patches.json` and creates a new folder under the `Patches` folder. The patch id is based on the local date and time, a random number, and the patch name pased on the command line. In our example, the patch id is `202103141849-3260-config-database`. + +To find the new patch id list the contents of the `Patches` director and find the newly created patch folder. + +In the new patch folder which is named `Patches/202103141849-3260-config-database` create a new SQL file named `config-db.sql`. In this file, enter any `ALTER DATABASE` commands along with any other initial database setup. + +Here is a sample of what the file may look like: +``` +ALTER DATABASE CURRENT SET COMPATIBILITY_LEVEL = 150 +GO +ALTER DATABASE CURRENT SET ANSI_NULL_DEFAULT OFF +GO +ALTER DATABASE CURRENT SET ANSI_NULLS OFF +GO +ALTER DATABASE CURRENT SET ANSI_PADDING OFF +GO +ALTER DATABASE CURRENT SET ANSI_WARNINGS OFF +GO +ALTER DATABASE CURRENT SET ARITHABORT OFF +GO +ALTER DATABASE CURRENT SET AUTO_CLOSE OFF +GO +ALTER DATABASE CURRENT SET AUTO_SHRINK OFF +GO +declare @dbname nvarchar(128) = db_name() +EXEC sys.sp_db_vardecimal_storage_format @dbname, N'ON' +GO +... +``` + +### Note about Patch folders +In patch folders, developers can create any number of database script files. These files will be sorted alphabetically and executed in order against the database. It is a good practice to use just one script file per patch when your database supports this, but if you need to create multiple files another best practice is to name the files in such a way as to both ensure the order and make it obvious to all developers what order the files will execute in. For example, numbering the files ensures the sort order and is obvious to other developers. + +An example of this patter might look like: +``` +1-create-table.sql +2-add-indexes.sql +``` + + ```202103082324-1408-first-patch``` ``` From 5231a7814160c88cfefec312bb2beb1fa5258610 Mon Sep 17 00:00:00 2001 From: Zack Moore <1731364+ormico@users.noreply.github.com> Date: Sun, 14 Mar 2021 21:32:37 -0400 Subject: [PATCH 2/3] set language on code blocks --- docs/tutorial.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/tutorial.md b/docs/tutorial.md index cbb1d7b..27544f5 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -32,11 +32,11 @@ dbpatch doesn't yet have working distribution packages but can be installed usin #### Steps Using `wget`, the install shell script can be downloaded and piped to bash to perform the install. This is the quickest way to get dbpatch installed, but it requires trusting the install script. -``` +```bash wget -qO- https://github.com/ormico/dbpatchmanager/releases/latest/download/install-dbpatch.sh | sudo bash ``` Or, you can download the install script and review it's contents before running. -``` +```bash #download install-dbpatch.sh wget -q https://github.com/ormico/dbpatchmanager/releases/latest/download/install-dbpatch.sh -O install-dbpatch.sh #review install-dbpatch.sh code before executing @@ -67,7 +67,7 @@ Our Imaginary Team: ## Creating a new Project (SQL Server) To get started, create a folder for the the database project. In that folder run `dbpatch init` and specify the `--dbtype` parameter. For this example, specify a MS SQL Server database by using `sqlserver` as the dbtype value. -``` +```bash mkdir mydb cd mydb git init @@ -83,7 +83,7 @@ dbpatch requires that a database exists for it to connect to. dbpatch will not c In our example, we are using `sqlcmd` from the command line to create our example database but any SQL Server tool that can execute scripts will do. Execute the following from the command line. -``` +```bash sqlcmd -S . -Q "create database [dbpatch-example-ann]" sqlcmd -S . -Q "create database [dbpatch-example-bettie]" sqlcmd -S . -Q "create database [dbpatch-example-casey]" @@ -98,7 +98,7 @@ In this step, we are going to create the second file `patches.local.json`. Where Create a file in the database project folder named `patches.local.json`. The contents of the file should look like the following, but in place of this connection string specify the connection string to your development database. This is usually a database and server running on your local workstation. -``` +```json { "ConnectionString": "Server=.;Database=dbpatch-example-casey;Trusted_Connection=True;" } @@ -107,21 +107,21 @@ Create a file in the database project folder named `patches.local.json`. The con For our imaginary team, lets create a separate local file for each developer. We can swap this file in and out as we simulate commands for each individual. Create the following three files using the correct connection strings for your workstation. `patches.ann-local.json` -``` +```json { "ConnectionString": "Server=.;Database=dbpatch-example-ann;Trusted_Connection=True;" } ``` `patches.bettie-local.json` -``` +```json { "ConnectionString": "Server=.;Database=dbpatch-example-bettie;Trusted_Connection=True;" } ``` `patches.casey-local.json` -``` +```json { "ConnectionString": "Server=.;Database=dbpatch-example-casey;Trusted_Connection=True;" } @@ -135,7 +135,7 @@ For this example we also want to ignore the other patches local files we created Create a `.gitignore` file that contains the following entries. `.gitignore` -``` +```bash patches.local.json patches.ann-local.json patches.bettie-local.json @@ -144,7 +144,7 @@ patches.casey-local.json Check in the files we have created so far (except for the ones that are ignored). -``` +```bash git stage * git commit -m "init dbpatch project" ``` @@ -162,7 +162,7 @@ To find the new patch id list the contents of the `Patches` director and find th In the new patch folder which is named `Patches/202103141849-3260-config-database` create a new SQL file named `config-db.sql`. In this file, enter any `ALTER DATABASE` commands along with any other initial database setup. Here is a sample of what the file may look like: -``` +```sql ALTER DATABASE CURRENT SET COMPATIBILITY_LEVEL = 150 GO ALTER DATABASE CURRENT SET ANSI_NULL_DEFAULT OFF @@ -189,7 +189,7 @@ GO In patch folders, developers can create any number of database script files. These files will be sorted alphabetically and executed in order against the database. It is a good practice to use just one script file per patch when your database supports this, but if you need to create multiple files another best practice is to name the files in such a way as to both ensure the order and make it obvious to all developers what order the files will execute in. For example, numbering the files ensures the sort order and is obvious to other developers. An example of this patter might look like: -``` +```bash 1-create-table.sql 2-add-indexes.sql ``` @@ -197,7 +197,7 @@ An example of this patter might look like: ```202103082324-1408-first-patch``` -``` +```bash git branch casey/db-initial-setup git checkout casey/db-initial-setup git stage * From 171989b6de17b2aac5861dd86eba61d40cae5f75 Mon Sep 17 00:00:00 2001 From: Zack Moore <1731364+ormico@users.noreply.github.com> Date: Mon, 15 Mar 2021 00:18:23 -0400 Subject: [PATCH 3/3] second patch --- docs/tutorial-db-hunt-diagram1.png | Bin 0 -> 24638 bytes docs/tutorial.md | 147 +++++++++++++++++++++++++++-- 2 files changed, 139 insertions(+), 8 deletions(-) create mode 100644 docs/tutorial-db-hunt-diagram1.png diff --git a/docs/tutorial-db-hunt-diagram1.png b/docs/tutorial-db-hunt-diagram1.png new file mode 100644 index 0000000000000000000000000000000000000000..daba4ae64134664782e2d3064312063c69e12978 GIT binary patch literal 24638 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 dbpatch build + +202103141849-3260-config-database +Patches\202103141849-3260-config-database\config-db.sql +``` + +If there are no errors and the schema in the database has the correct changes, the patch should now be checked in. + +``` git stage * -git commit -m "first patch" +git commit -m "Casey's initial db patch" ``` +## Taking a look at the InstalledPatches table +Before moving to the next step let's take a look at the `InstalledPatches` table. -//todo: decide what kind of db we are building and create the final whole project in an example repo or folder. make a schema diagram and post it in this example +`dbo.InstalledPatches` was not included in the patch sql that Casey created. `InstalledPatches` is an artifact created by dbpatch and the SQL Server module to track which patches have already been installed in a particular instance of the database. -### Building the Database after Schema additions +Each database module written for dbpatch can implement this tracking in it's own way that is most appropriate for that database type. The SQL Server module does this by creating a table and keeping a record for each patch that is installed. This can be overridden by providing an alternative SQL Script for reading and writing this information. -//todo: make sure dbpatch doesn't do anything if patches.json is not in current folder -```dbpatch build``` +----> STOPED HERE +//todo: add to intro a description of the example db project we are creating 'scavenger hunt' ## Merging schema changes from another user +Casey now has the database project and repository ready for other developers to start contributing. + +Ann is working on the tables for tracking each Scavenger Hunt, the Teams participating, and each Treasure that can be found. Her design looks like this. + +![db diagram showing Hunt Treasure and Team tables](tutorial-db-hunt-diagram1.png) + +Ann begins by creating a branch from main and switching to that new branch. +``` +git checkout -b feature/ann-create-hunt-tables +``` +The next step is for Ann to create a new Patch and add her schema change file. Because Ann branched from main, she already has the initial patch that Casey made. +```bash +dbpatch addpatch -n create-hunt-tables +``` +Listing the contents of `Patches` shows our new Patch folder +``` +> ls Patches + Directory: C:\Users\ormico\Projects\dbpatch-example\Patches + +Mode LastWriteTime Length Name +---- ------------- ------ ---- +d---- 3/14/2021 6:53 PM 202103141849-3260-config-database +d---- 3/14/2021 11:47 PM 202103142347-5594-create-hunt-tables +``` + +Ann's schema changes +``` +CREATE TABLE [dbo].[Hunt] +( + [HuntId] [int] NOT NULL, + [HuntName] [nvarchar](100) NOT NULL, + [StartDate] [datetime] NOT NULL, + [EndDate] [datetime] NOT NULL, + CONSTRAINT [PK_Hunt] PRIMARY KEY CLUSTERED([HuntId] ASC) +) +GO + +CREATE UNIQUE NONCLUSTERED INDEX [UX_Hunt] ON [dbo].[Hunt] +( + [HuntName] ASC +) +GO + +CREATE TABLE [dbo].[Team] +( + [TeamId] [int] NOT NULL, + [TeamName] [nvarchar](50) NOT NULL, + [HuntId] [int] NOT NULL, + [SignupDate] [date] NOT NULL, + CONSTRAINT [PK_Team] PRIMARY KEY CLUSTERED([TeamId] ASC) +) +GO + +CREATE UNIQUE NONCLUSTERED INDEX [UX_Team] ON [dbo].[Team] +( + [HuntId] ASC, + [TeamName] ASC +) +GO + +ALTER TABLE [dbo].[Team] WITH CHECK ADD CONSTRAINT [FK_Team_Hunt] FOREIGN KEY([HuntId]) +REFERENCES [dbo].[Hunt] ([HuntId]) +GO + +ALTER TABLE [dbo].[Team] CHECK CONSTRAINT [FK_Team_Hunt] +GO + +CREATE TABLE [dbo].[Treasure] +( + [TreasureId] [int] NOT NULL, + [TrasureName] [nvarchar](100) NOT NULL, + [Description] [nvarchar](500) NULL, + [Clue] [nvarchar](max) NOT NULL, + [HuntId] [int] NOT NULL, + [LocationStreetAddress] [nvarchar](200) NULL, + [LocationLatitudeLongitude] [nvarchar](200) NULL, + CONSTRAINT [PK_Treasure] PRIMARY KEY CLUSTERED([TreasureId] ASC) +) +GO + +CREATE UNIQUE NONCLUSTERED INDEX [UX_Treasure] ON [dbo].[Treasure] +( + [HuntId] ASC, + [TrasureName] ASC +) +GO + +ALTER TABLE [dbo].[Treasure] WITH CHECK ADD CONSTRAINT [FK_Treasure_Hunt] FOREIGN KEY([HuntId]) +REFERENCES [dbo].[Hunt]([HuntId]) +GO + +ALTER TABLE [dbo].[Treasure] CHECK CONSTRAINT [FK_Treasure_Hunt] +GO +``` + + +Ann build +``` +cp patches.ann-local.json patches.local.json +dbpatch build + +202103141849-3260-config-database +Patches\202103141849-3260-config-database\config-db.sql +202103142347-5594-create-hunt-tables +Patches\202103142347-5594-create-hunt-tables\hunt-team-treasure-tables.sql +``` + + ### Building the Database after Schema merge ## Examining InstalledPatches table