-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Default to SQLite Database & Better Migrations (#166)
- Loading branch information
1 parent
b981748
commit 3fec8e9
Showing
28 changed files
with
381 additions
and
235 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,27 @@ | ||
import { Pool } from 'pg' | ||
import { SQLDatabase, SQLQueryResult } from '../db' | ||
import { ApiDatabaseConfig } from '@best/types'; | ||
import { migrate } from './migrate'; | ||
|
||
export default class PostgresDatabase extends SQLDatabase { | ||
pool: Pool | ||
migrated = false; | ||
|
||
constructor(config: ApiDatabaseConfig) { | ||
super() | ||
this.pool = new Pool({ | ||
connectionString: config.path | ||
connectionString: config.uri | ||
}) | ||
} | ||
|
||
query(text: string, params: any[]): Promise<SQLQueryResult> { | ||
if (! this.migrated) { throw new Error('Database migrations have not been ensured.') } | ||
|
||
return this.pool.query(text, params) | ||
} | ||
|
||
async performMigrations() { | ||
await migrate(this.pool) | ||
this.migrated = true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import path from 'path' | ||
import fs from 'fs'; | ||
import { promisify } from 'util'; | ||
import { Pool } from 'pg'; | ||
|
||
const asyncReadDir = promisify(fs.readdir); | ||
|
||
interface MigrationContent { | ||
up: string; | ||
down: string; | ||
} | ||
|
||
interface PartialMigration { | ||
id: number; | ||
name: string; | ||
filename: string; | ||
} | ||
|
||
type Migration = PartialMigration & MigrationContent | ||
|
||
const buildMigrations = async (location: string): Promise<Migration[]> => { | ||
const migrationsPath = path.resolve(__dirname, location); | ||
|
||
const files = await asyncReadDir(migrationsPath); | ||
|
||
// we look for .js files since these will be pre-compiled by js | ||
const partialMigrations: PartialMigration[] = files.map(f => f.match(/^((\d+).(.*?))\.js$/)).reduce((migrations, match): PartialMigration[] => { | ||
if (! match) { | ||
return migrations; | ||
} | ||
|
||
const migration = { id: Number(match[2]), name: match[3], filename: match[1] } | ||
|
||
return [...migrations, migration]; | ||
}, <PartialMigration[]>[]).sort((a, b) => Math.sign(a.id - b.id)); | ||
|
||
const migrations: Migration[] = await Promise.all(partialMigrations.map(async (partial): Promise<Migration> => { | ||
const filename = path.resolve(migrationsPath, partial.filename); | ||
const content: MigrationContent = await import(filename); | ||
|
||
return { | ||
...partial, | ||
...content | ||
} | ||
})) | ||
|
||
return migrations | ||
} | ||
|
||
export const migrate = async (db: Pool, redoLast: boolean = false, location: string = 'migrations/', table = 'migrations'): Promise<boolean> => { | ||
const migrations = await buildMigrations(location); | ||
|
||
const client = await db.connect(); | ||
|
||
await client.query(`CREATE TABLE IF NOT EXISTS "${table}" (id INTEGER PRIMARY KEY, name TEXT NOT NULL, up TEXT NOT NULL, down TEXT NOT NULL)`); | ||
|
||
const previous = await client.query(`SELECT * FROM ${table} ORDER BY id ASC`); | ||
let lastMigration = previous.rows[previous.rows.length - 1]; | ||
|
||
if (redoLast && previous.rows.length > 0) { | ||
await client.query('BEGIN'); | ||
try { | ||
await client.query(lastMigration.down); | ||
await client.query(`DELETE FROM "${table}" WHERE id = ?`, lastMigration.id); | ||
await client.query('COMMIT'); | ||
lastMigration = null; | ||
} catch (err) { | ||
await client.query('ROLLBACK'); | ||
client.release(); | ||
throw err; | ||
} | ||
} | ||
|
||
const lastMigrationId = lastMigration ? lastMigration.id : 0; | ||
await Promise.all(migrations.map(async migration => { | ||
if (migration.id > lastMigrationId) { | ||
await client.query('BEGIN'); | ||
try { | ||
await client.query(migration.up); | ||
await client.query(`INSERT INTO "${table}" (id, name, up, down) VALUES ($1, $2, $3, $4)`, [migration.id, migration.name, migration.up, migration.down]); | ||
await client.query('COMMIT'); | ||
} catch (err) { | ||
await client.query('ROLLBACK'); | ||
client.release(); | ||
throw err; | ||
} | ||
} | ||
})) | ||
|
||
client.release(); | ||
|
||
return true; | ||
} |
12 changes: 12 additions & 0 deletions
12
packages/@best/api-db/src/sql/postgres/migrations/001-projects.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
export const up = ` | ||
CREATE TABLE projects ( | ||
id SERIAL PRIMARY KEY, | ||
name character varying(100) NOT NULL, | ||
created_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
last_release_date timestamp without time zone | ||
); | ||
CREATE UNIQUE INDEX projects_unique_name ON projects(name text_ops); | ||
` | ||
|
||
export const down = `DROP TABLE projects;` |
20 changes: 20 additions & 0 deletions
20
packages/@best/api-db/src/sql/postgres/migrations/002-snapshots.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
export const up = ` | ||
CREATE TABLE snapshots ( | ||
id SERIAL PRIMARY KEY, | ||
project_id integer NOT NULL REFERENCES projects(id) ON DELETE CASCADE, | ||
name character varying(200) NOT NULL, | ||
metrics character varying(2000) NOT NULL, | ||
environment_hash character varying(100) NOT NULL, | ||
similarity_hash character varying(100) NOT NULL, | ||
commit character varying(100) NOT NULL, | ||
commit_date timestamp without time zone NOT NULL, | ||
created_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
temporary boolean NOT NULL, | ||
updated_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP | ||
); | ||
CREATE INDEX snapshots_project_id_index ON snapshots(project_id int4_ops); | ||
CREATE UNIQUE INDEX best_snapshot_unqiue_index ON snapshots(project_id int4_ops,commit text_ops,name text_ops) WHERE temporary = false; | ||
` | ||
|
||
export const down = `DROP TABLE snapshots;` |
17 changes: 0 additions & 17 deletions
17
packages/@best/api-db/src/sql/postgres/migrations/1559599488979_setup-projects.js
This file was deleted.
Oops, something went wrong.
34 changes: 0 additions & 34 deletions
34
packages/@best/api-db/src/sql/postgres/migrations/1559600258932_benchmark-snapshot.js
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.