Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

10391 expand contract #10551

Draft
wants to merge 5 commits into
base: 10391-dynamo-migrations-kysely-aurora-rds-tokens
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -235,11 +235,11 @@ jobs:
npm run start:migration -- $ENV
fi
- run:
name: Run Postgres Migration
name: Run Migration Postgres Expand
command: |
OUTPUT_ONLY=true npm run deploy:allColors $ENV
POSTGRES_HOST=$(cat ./web-api/terraform/applyables/allColors/output.json | jq -r '.rds_host_name.value')
POSTGRES_HOST=$POSTGRES_HOST POSTGRES_USER=$POSTGRES_USER NODE_ENV=production npm run migration:postgres
POSTGRES_HOST=$POSTGRES_HOST POSTGRES_USER=$POSTGRES_USER NODE_ENV=production npm run migration:postgres:expand
- run:
name: Enable Check Migration Status Cron
command: |
Expand Down Expand Up @@ -555,6 +555,12 @@ jobs:
if [ $MIGRATE_FLAG == true ]; then
npm run migration:cleanup -- $ENV
fi
- run:
name: Run Migration Postgres Contract
command: |
OUTPUT_ONLY=true npm run deploy:allColors $ENV
POSTGRES_HOST=$(cat ./web-api/terraform/applyables/allColors/output.json | jq -r '.rds_host_name.value')
POSTGRES_HOST=$POSTGRES_HOST POSTGRES_USER=$POSTGRES_USER NODE_ENV=production npm run migration:postgres:contract

######################## GLUE JOB: Jobs that run in a lower environment ########################

Expand Down
59 changes: 59 additions & 0 deletions docs/postgres/Expand and Contract Migrations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Expand and Contract Migrations

https://www.tim-wellhausen.de/papers/ExpandAndContract/ExpandAndContract.html

Hard rules:
- Always Expand & Contract
- Up, should do what you want aka changes
- Down, always revert back to previous working state

## Circle Flow (need to implement)

- Deploy
- Migrate
- Expand Migration
- Switch colors
- Cleanup
- Contract Migration

## Renaming field that is partially in Postgres (case.caption)
- DynamoDB Migration
- Expand & Contract
- Add an expand migration that adds a new field called body
- Add a contract migration that removes message field
- In database-types.ts, change MessageTable.message to be MessageTable.body
- Update seed data (fixtures) so that message.message is now message.body in
- Update the mapper so that Message.message = message.body from DB
- (OPTIONAL) Update business entity Message.ts to have Message.body instead of Messge.message
- Deploy changes

## Renaming field that is fully in Postgres (message.message -> message.body)
- Expand & Contract
- Add an expand migration that adds a new field called body
- Add a contract migration that removes message field
- In database-types.ts, change MessageTable.message to be MessageTable.body
- Update seed data (fixtures) so that message.message is now message.body in
- Update the mapper so that Message.message = message.body from DB
- (OPTIONAL) Update business entity Message.ts to have Message.body instead of Messge.message
- Deploy changes

## Dropping a field that is fully in Postgres
- Contract migration

## Dropping a field that is partially in Postgres
- DynamoDB Migration
- Contract migration

## Adding a field that is fully in Postgres
- Expand migration

## Adding a field that is partially in Postgres
- DynamoDB Migration
- Expand migration

## Modifying Validation Rules (default values) is partially in Postgres
- TBD


## Modifying Validation Rules (default values) is fully in Postgres
- TBD
55 changes: 55 additions & 0 deletions docs/postgres/expand-contract.drawio
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<mxfile host="65bd71144e">
<diagram id="Lxun0BaanxL01t6XbsJt" name="Page-1">
<mxGraphModel dx="1244" dy="666" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="6" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#008a00;fontColor=#ffffff;strokeColor=#005700;" parent="1" vertex="1">
<mxGeometry x="130" y="300" width="150" height="360" as="geometry"/>
</mxCell>
<mxCell id="7" value="passive" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="175" y="320" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="8" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#0050ef;fontColor=#ffffff;strokeColor=#001DBC;" parent="1" vertex="1">
<mxGeometry x="655" y="290" width="150" height="360" as="geometry"/>
</mxCell>
<mxCell id="9" value="active" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="700" y="310" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="10" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;" parent="1" vertex="1">
<mxGeometry x="340" y="300" width="155" height="180" as="geometry"/>
</mxCell>
<mxCell id="11" value="{&lt;br&gt;body: &quot;hell&quot;,&lt;br&gt;message: &quot;hello&quot;&lt;br&gt;}" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="355" y="340" width="125" height="120" as="geometry"/>
</mxCell>
<mxCell id="12" value="You are here" style="shape=flexArrow;endArrow=classic;html=1;width=11;endSize=5.85;fillColor=#a20025;strokeColor=#6F0000;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="380" y="90" as="sourcePoint"/>
<mxPoint x="379.5" y="190" as="targetPoint"/>
<Array as="points">
<mxPoint x="379.5" y="150"/>
</Array>
</mxGeometry>
</mxCell>
<mxCell id="14" value=".message" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="667.5" y="390" width="125" height="120" as="geometry"/>
</mxCell>
<mxCell id="15" value=".body" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="130" y="370" width="125" height="120" as="geometry"/>
</mxCell>
<mxCell id="20" value="Deploy" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="320" y="210" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="21" value="Switch Colors" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="470" y="210" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="22" value="Contract" style="rounded=1;whiteSpace=wrap;html=1;fontStyle=1" parent="1" vertex="1">
<mxGeometry x="640" y="210" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="23" value="Expand" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="145" y="210" width="120" height="60" as="geometry"/>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,9 @@
"maintenance:engage:local": ". ./setup-local-env.sh && npx ts-node --transpile-only scripts/set-maintenance-mode-locally.ts true",
"migrate:local": "AWS_ACCESS_KEY_ID=S3RVER AWS_SECRET_ACCESS_KEY=S3RVER SOURCE_TABLE=efcms-local DESTINATION_TABLE=efcms-local-1 ts-node --transpile-only ./web-api/run-local-migration.ts",
"migration:cleanup": "./scripts/migration/update-deploy-table-after-migration.sh",
"migration:postgres": "npx ts-node --transpile-only ./web-api/src/persistence/postgres/utils/migrate/migrate.ts",
"migration:rollback:postgres": "npx ts-node --transpile-only ./web-api/src/persistence/postgres/utils//rollback.ts",
"migration:postgres:expand": "npx ts-node --transpile-only ./web-api/src/persistence/postgres/utils/migrate/migrate.ts expand",
"migration:postgres:contract": "npx ts-node --transpile-only ./web-api/src/persistence/postgres/utils/migrate/migrate.ts contract",
"migration:rollback:postgres": "npx ts-node --transpile-only ./web-api/src/persistence/postgres/utils/migrate/rollback.ts",
"pending-color-switch": "./web-client/pending-color-switch.sh",
"postinstall": "husky install",
"print:success": "echo 'Build successful. You can access the site at http://localhost:1234'",
Expand Down
3 changes: 2 additions & 1 deletion run-local.sh
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ else
fi
fi

npm run migration:postgres
npm run migration:postgres:expand
npm run migration:postgres:contract
npm run seed:postgres

echo "Seeding cognito-local users"
Expand Down
2 changes: 1 addition & 1 deletion web-api/src/database-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export interface MessageTable {
isRead: boolean;
isRepliedTo: boolean;
leadDocketNumber?: string;
message: string;
body: string;
messageId: string;
parentMessageId: string;
subject: string;
Expand Down
5 changes: 3 additions & 2 deletions web-api/src/persistence/postgres/messages/mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import { NewMessageKysely, UpdateMessageKysely } from '@web-api/database-types';
import { RawMessage } from '@shared/business/entities/Message';
import { transformNullToUndefined } from '@web-api/persistence/postgres/utils/transformNullToUndefined';

function pickFields(message) {
function pickFields(message): NewMessageKysely {
return {
attachments: JSON.stringify(message.attachments),
body: message.message,
completedAt: message.completedAt,
completedBy: message.completedBy,
completedBySection: message.completedBySection,
Expand All @@ -20,7 +21,6 @@ function pickFields(message) {
isCompleted: message.isCompleted,
isRead: message.isRead,
isRepliedTo: message.isRepliedTo,
message: message.message,
messageId: message.messageId,
parentMessageId: message.parentMessageId,
subject: message.subject,
Expand Down Expand Up @@ -60,6 +60,7 @@ export function messageResultEntity(message) {
caseTitle: Case.getCaseTitle(message.caption || ''),
completedAt: message.completedAt?.toISOString(),
createdAt: message.createdAt.toISOString(),
message: message.body,
trialDate: message.trialDate?.toISOString(),
}),
);
Expand Down
75 changes: 59 additions & 16 deletions web-api/src/persistence/postgres/utils/migrate/migrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import { FileMigrationProvider, Migrator } from 'kysely';
import { promises as fs } from 'fs';
import { getDbWriter } from '../../../../database';

async function migrateToLatest() {
async function migrateToLatest(migrationType: string) {
if (migrationType !== 'expand' && migrationType !== 'contract') {
throw new Error(`Unable to run unknown migration type: ${migrationType}`);
}

await getDbWriter(async writer => {
const migrator = new Migrator({
db: writer,
Expand All @@ -14,26 +18,65 @@ async function migrateToLatest() {
}),
});

const { error, results } = await migrator.migrateToLatest();
const migrations = await migrator.getMigrations();

results?.forEach(it => {
if (it.status === 'Success') {
console.log(
`migration "${it.migrationName}" was executed successfully`,
);
} else if (it.status === 'Error') {
console.error(`failed to execute migration "${it.migrationName}"`);
}
});
for (const migration of migrations) {
if (
migration.name.includes(`.${migrationType}`) &&
migration.executedAt === undefined
) {
const { error, results } = await migrator.migrateTo(migration.name);
results?.forEach(it => {
if (it.status === 'Success') {
console.log(
`migration "${it.migrationName}" was executed successfully`,
);
} else if (it.status === 'Error') {
console.error(`failed to execute migration "${it.migrationName}"`);
}
});

if (error) {
console.error('failed to migrate');
console.error(error);
process.exit(1);
if (error) {
console.error('failed to migrate');
console.error(error);
process.exit(1);
}
}
}

await writer.destroy();
});
}

migrateToLatest().catch;
migrateToLatest(process.argv[2]).catch;

// eslint-disable-next-line spellcheck/spell-checker
/*
DB Now
0001-init 1st
0002-init-indexes 2nd
293474924-init-indexes 3rd
nov5-init-indexes 4th
nov3-init-indexes 5th

0003-add-message-body.expand.ts
0004-add-something.expand.ts
0003-add-message-body.contract.ts
0004-add-something.contract.ts

0001-init.expand
0002-init-indexes.expand
0003-add-message-body.expand.ts
0004-add-something.expand.ts
0003-add-message-body.contract.ts
0004-add-something.contract.ts

In Repo
0001-init.expand
0002-init-indexes.exapand
0003-add-message-body.expand.ts
0003-remove-message-message.contract.ts
0004-add-something.expand.ts
0004-remove-something.contract.ts

*/
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Kysely, sql } from 'kysely';

export async function up(db: Kysely<any>): Promise<void> {
await db.schema.alterTable('dwMessage').addColumn('body', 'text').execute();
await db
.updateTable('dwMessage')
.set({
body: sql`message`,
})
.execute();
}

export async function down(db: Kysely<any>): Promise<void> {
await db.schema.alterTable('dwMessage').dropColumn('body').execute();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Kysely, sql } from 'kysely';

export async function up(db: Kysely<any>): Promise<void> {
await db.schema.alterTable('dwMessage').dropColumn('message').execute();
}

export async function down(db: Kysely<any>): Promise<void> {
await db.schema
.alterTable('dwMessage')
.addColumn('message', 'varchar')
.execute();
await db
.updateTable('dwMessage')
.set({
message: sql`body`,
})
.execute();
}
14 changes: 7 additions & 7 deletions web-api/src/persistence/postgres/utils/seed/fixtures/messages.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { NewMessageKysely } from '@web-api/database-types';
import { calculateDate } from '@shared/business/utilities/DateHandler';

/* eslint-disable @miovision/disallow-date/no-new-date */
export const messages: NewMessageKysely[] = [
{
attachments: JSON.stringify([]),
createdAt: new Date('2020-06-05T18:02:25.280Z'),
body: 'hello!',
createdAt: calculateDate({ dateString: '2020-06-05T18:02:25.280Z' }),
docketNumber: '105-20',
from: 'Test Petitionsclerk',
fromSection: 'petitions',
fromUserId: '3805d1ab-18d0-43ec-bafb-654e83405416',
isCompleted: false,
isRead: false,
isRepliedTo: false,
message: 'hello!',
messageId: 'eb0a139a-8951-4de1-8b83-f02a27504105',
parentMessageId: 'eb0a139a-8951-4de1-8b83-f02a27504105',
subject: 'message to myself',
Expand All @@ -26,15 +26,15 @@ export const messages: NewMessageKysely[] = [
documentId: '4796a931-14fb-43e6-948f-d2b67ce4c1cb',
},
]),
createdAt: new Date('2023-06-02T21:15:50.105Z'),
body: 'Could you please review this?',
createdAt: calculateDate({ dateString: '2023-06-02T21:15:50.105Z' }),
docketNumber: '103-20',
from: 'Test Admissions Clerk',
fromSection: 'admissions',
fromUserId: '9d7d63b7-d7a5-4905-ba89-ef71bf30057f',
isCompleted: false,
isRead: false,
isRepliedTo: false,
message: 'Could you please review this?',
messageId: '1d4c1fd9-5265-4e46-894f-b8426d3a6836',
parentMessageId: '1d4c1fd9-5265-4e46-894f-b8426d3a6836',
subject: 'Administrative Record',
Expand All @@ -48,15 +48,15 @@ export const messages: NewMessageKysely[] = [
documentId: '8ed9bad9-db58-43c8-b03f-c2e3ad92995f',
},
]),
createdAt: new Date('2020-08-18T18:07:36.333Z'),
body: 'Test message with deleted document.',
createdAt: calculateDate({ dateString: '2020-08-18T18:07:36.333Z' }),
docketNumber: '104-19',
from: 'Test Docketclerk',
fromSection: 'docket',
fromUserId: '1805d1ab-18d0-43ec-bafb-654e83405416',
isCompleted: false,
isRead: false,
isRepliedTo: false,
message: 'Test message with deleted document.',
messageId: '2d1191d3-4597-454a-a2b2-84e267ccf01e',
parentMessageId: '2d1191d3-4597-454a-a2b2-84e267ccf01e',
subject: 'Order',
Expand Down