Skip to content

Commit

Permalink
Databases: Support postgres schema in production environment.
Browse files Browse the repository at this point in the history
- Unlike dev environment, schema will not be created if it does not
exist and instead will throw an error. The dev should also make sure
that they have sufficient usage and create priviliges on the schema.
- The env variables in .env file will not be picked up by the migration
script. Please export them explicitly.
- The migration script inside migration/sql was copied to the postgres
directory to accomodate the postgres schema. That migration will now
not run for both mssql and postgres.
- You might notice that we set the schema in the dataSource from the
env variable and we still modify the SQL strings in migrations file to
include schema name. This is because queryRunner when running
raw sql commands runs the commands directly without modification.
But we still need to set the schema because TypeORM does a select
operation on `_jackson_migrations` table and the schema name is
needed in the dataSource for that.
  • Loading branch information
shubham-padia committed Apr 6, 2024
1 parent 68d44ba commit 3aac072
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 26 deletions.
34 changes: 19 additions & 15 deletions npm/migration/postgres/1640877103193-Initial.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
import {MigrationInterface, QueryRunner} from "typeorm";

const schema = process.env.POSTGRES_SCHEMA || "public";
const jacksonStoreTableName = `${schema}.jackson_store`;
const jacksonIndexTableName = `${schema}.jackson_index`;
const jacksonTTLTableName = `${schema}.hackson_ttl`;

export class Initial1640877103193 implements MigrationInterface {
name = 'Initial1640877103193'

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE "jackson_store" ("key" character varying(1500) NOT NULL, "value" text NOT NULL, "iv" character varying(64), "tag" character varying(64), CONSTRAINT "PK_87b6fc1475fbd1228d2f53c6f4a" PRIMARY KEY ("key"))`);
await queryRunner.query(`CREATE TABLE "jackson_index" ("id" SERIAL NOT NULL, "key" character varying(1500) NOT NULL, "storeKey" character varying(1500) NOT NULL, CONSTRAINT "PK_a95aa83f01e3c73e126856b7820" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "_jackson_index_key" ON "jackson_index" ("key") `);
await queryRunner.query(`CREATE INDEX "_jackson_index_key_store" ON "jackson_index" ("key", "storeKey") `);
await queryRunner.query(`CREATE TABLE "jackson_ttl" ("key" character varying(1500) NOT NULL, "expiresAt" bigint NOT NULL, CONSTRAINT "PK_7c9bcdfb4d82e873e19935ec806" PRIMARY KEY ("key"))`);
await queryRunner.query(`CREATE INDEX "_jackson_ttl_expires_at" ON "jackson_ttl" ("expiresAt") `);
await queryRunner.query(`ALTER TABLE "jackson_index" ADD CONSTRAINT "FK_937b040fb2592b4671cbde09e83" FOREIGN KEY ("storeKey") REFERENCES "jackson_store"("key") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`CREATE TABLE ${jacksonStoreTableName} ("key" character varying(1500) NOT NULL, "value" text NOT NULL, "iv" character varying(64), "tag" character varying(64), CONSTRAINT "PK_87b6fc1475fbd1228d2f53c6f4a" PRIMARY KEY ("key"))`);
await queryRunner.query(`CREATE TABLE ${jacksonIndexTableName} ("id" SERIAL NOT NULL, "key" character varying(1500) NOT NULL, "storeKey" character varying(1500) NOT NULL, CONSTRAINT "PK_a95aa83f01e3c73e126856b7820" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "_jackson_index_key" ON ${jacksonIndexTableName} ("key") `);
await queryRunner.query(`CREATE INDEX "_jackson_index_key_store" ON ${jacksonIndexTableName} ("key", "storeKey") `);
await queryRunner.query(`CREATE TABLE ${jacksonTTLTableName} ("key" character varying(1500) NOT NULL, "expiresAt" bigint NOT NULL, CONSTRAINT "PK_7c9bcdfb4d82e873e19935ec806" PRIMARY KEY ("key"))`);
await queryRunner.query(`CREATE INDEX "_jackson_ttl_expires_at" ON ${jacksonTTLTableName} ("expiresAt") `);
await queryRunner.query(`ALTER TABLE ${jacksonIndexTableName} ADD CONSTRAINT "FK_937b040fb2592b4671cbde09e83" FOREIGN KEY ("storeKey") REFERENCES ${jacksonStoreTableName}("key") ON DELETE CASCADE ON UPDATE NO ACTION`);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "jackson_index" DROP CONSTRAINT "FK_937b040fb2592b4671cbde09e83"`);
await queryRunner.query(`DROP INDEX "public"."_jackson_ttl_expires_at"`);
await queryRunner.query(`DROP TABLE "jackson_ttl"`);
await queryRunner.query(`DROP INDEX "public"."_jackson_index_key_store"`);
await queryRunner.query(`DROP INDEX "public"."_jackson_index_key"`);
await queryRunner.query(`DROP TABLE "jackson_index"`);
await queryRunner.query(`DROP TABLE "jackson_store"`);
await queryRunner.query(`ALTER TABLE ${jacksonIndexTableName} DROP CONSTRAINT "FK_937b040fb2592b4671cbde09e83"`);
await queryRunner.query(`DROP INDEX ${schema}."_jackson_ttl_expires_at"`);
await queryRunner.query(`DROP TABLE ${jacksonTTLTableName}`);
await queryRunner.query(`DROP INDEX ${schema}."_jackson_index_key_store"`);
await queryRunner.query(`DROP INDEX ${schema}."_jackson_index_key"`);
await queryRunner.query(`DROP TABLE ${jacksonIndexTableName}`);
await queryRunner.query(`DROP TABLE ${jacksonStoreTableName}`);
}

}
11 changes: 7 additions & 4 deletions npm/migration/postgres/1644332647279-createdAt.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import {MigrationInterface, QueryRunner} from "typeorm";

const schema = process.env.POSTGRES_SCHEMA || "public";
const jacksonStoreTableName = `${schema}.jackson_store`;

export class createdAt1644332647279 implements MigrationInterface {
name = 'createdAt1644332647279'

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "jackson_store" ADD "createdAt" TIMESTAMP NOT NULL DEFAULT now()`);
await queryRunner.query(`ALTER TABLE "jackson_store" ADD "modifiedAt" TIMESTAMP`);
await queryRunner.query(`ALTER TABLE ${jacksonStoreTableName} ADD "createdAt" TIMESTAMP NOT NULL DEFAULT now()`);
await queryRunner.query(`ALTER TABLE ${jacksonStoreTableName} ADD "modifiedAt" TIMESTAMP`);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "jackson_store" DROP COLUMN "modifiedAt"`);
await queryRunner.query(`ALTER TABLE "jackson_store" DROP COLUMN "createdAt"`);
await queryRunner.query(`ALTER TABLE ${jacksonStoreTableName} DROP COLUMN "modifiedAt"`);
await queryRunner.query(`ALTER TABLE ${jacksonStoreTableName} DROP COLUMN "createdAt"`);
}

}
11 changes: 7 additions & 4 deletions npm/migration/postgres/1692767993709-pg_namespace.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import { MigrationInterface, QueryRunner } from "typeorm";

const schema = process.env.POSTGRES_SCHEMA || "public";
const jacksonStoreTableName = `${schema}.jackson_store`;

export class PgNamespace1692767993709 implements MigrationInterface {
name = 'PgNamespace1692767993709'

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "jackson_store" ADD "namespace" character varying(64)`);
await queryRunner.query(`CREATE INDEX "_jackson_store_namespace" ON "jackson_store" ("namespace") `);
await queryRunner.query(`ALTER TABLE ${jacksonStoreTableName} ADD "namespace" character varying(64)`);
await queryRunner.query(`CREATE INDEX "_jackson_store_namespace" ON ${jacksonStoreTableName} ("namespace") `);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP INDEX "public"."_jackson_store_namespace"`);
await queryRunner.query(`ALTER TABLE "jackson_store" DROP COLUMN "namespace"`);
await queryRunner.query(`DROP INDEX ${schema}."_jackson_store_namespace"`);
await queryRunner.query(`ALTER TABLE ${jacksonStoreTableName} DROP COLUMN "namespace"`);
}

}
31 changes: 31 additions & 0 deletions npm/migration/postgres/1692817789888-namespace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { MigrationInterface, QueryRunner } from "typeorm"

// This file is same as npm/migration/sql/1692817789888-namespace.ts,
// but, with the added postgres schema name.

const schema = process.env.POSTGRES_SCHEMA || "public";
const jacksonStoreTableName = `${schema}.jackson_store`;

export class namespace1692817789888 implements MigrationInterface {
name = 'namespace1692817789888'

public async up(queryRunner: QueryRunner): Promise<void> {
const response = await queryRunner.query(`select jackson.key from ${jacksonStoreTableName} jackson`)
const searchTerm = ':';
for (const k in response) {
const key = response[k].key;
const tokens2 = key.split(searchTerm).slice(0, 2);
const value = tokens2.join(searchTerm);
queryRunner.query(`update ${jacksonStoreTableName} set namespace = '${value}' where ${jacksonStoreTableName}.key = '${key}'`)
}
}

public async down(queryRunner: QueryRunner): Promise<void> {
const response = await queryRunner.query(`select jackson.key from ${jacksonStoreTableName} jackson`)
for (const k in response) {
const key = response[k].key;
queryRunner.query(`update ${jacksonStoreTableName} set namespace = NULL where ${jacksonStoreTableName}.key = '${key}'`)
}
}

}
11 changes: 8 additions & 3 deletions npm/typeorm.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require('reflect-metadata');
import { DataSource, DatabaseType, DataSourceOptions } from 'typeorm';
import * as mssql from './src/db/sql/mssql';
import { DEFAULT_POSTGRES_SCHEMA } from './src/db/constants';

const type =
process.env.DB_ENGINE === 'planetscale'
Expand Down Expand Up @@ -45,7 +46,7 @@ const baseOpts = {
logging: 'all',
entities: [`src/db/${entitiesDir}/entity/**/*.ts`],
migrations:
type === 'mssql'
type === 'mssql' || type === 'postgres'
? [`migration/${migrationsDir}/**/*.ts`]
: [`migration/${migrationsDir}/**/*.ts`, `migration/sql/**/*.ts`],
};
Expand All @@ -62,14 +63,18 @@ if (type === 'mssql') {
...baseOpts,
});
} else {
AppDataSource = new DataSource(<DataSourceOptions>{
const dataSourceOptions = {
url:
process.env.DB_URL ||
process.env.DATABASE_URL ||
'postgresql://postgres:postgres@localhost:5432/postgres',
ssl,
...baseOpts,
});
};
if (type === 'postgres') {
dataSourceOptions['schema'] = process.env.POSTGRES_SCHEMA || DEFAULT_POSTGRES_SCHEMA;
}
AppDataSource = new DataSource(<DataSourceOptions>dataSourceOptions);
}

export default AppDataSource;

0 comments on commit 3aac072

Please sign in to comment.