import type { Adapter } from "../adapters/adapter.ts" ; import { CreateTableOptions , TableBuilder } from "./tablebuilder.ts" ; import type { ColumnBuilder } from "./columnbuilder.ts" ; /**
 * Database schema migration helper
 */ export class Schema { constructor ( /** The database adapter */ private adapter ) { } param name public async createTable ( name , fn , options ? ) { const builder = new TableBuilder ( name , this . adapter , options ) ; fn ( builder ) ; await builder . execute ( ) ; } param name param newName public async renameTable ( name , newName ) { await this . adapter . query ( `ALTER TABLE ${ name } RENAME TO ${ newName }` ) ; } param tableName param options public dropTable ( tableName , options ? ) ; param tableNames param options public dropTable ( tableNames , options ? ) ; /** Drop table from the database */ public async dropTable ( tableName , options ? ) { options = Object . assign ( { } , { ifExists : false } , options ) ; const query = [ `DROP TABLE` ] ; if ( options . ifExists ) query . push ( `IF EXISTS` ) ; if ( Array . isArray ( tableName ) ) { if ( this . adapter . dialect === "sqlite" ) { for ( const table of tableName ) { const tableQuery = query . join ( " " ) + ` ${ table }` ; await this . adapter . query ( tableQuery ) ; } } else { query . push ( tableName . join ( ", " ) ) ; await this . adapter . query ( query . join ( " " ) ) ; } } else { query . push ( tableName ) ; await this . adapter . query ( query . join ( " " ) ) ; } } param tableName public async hasTable ( tableName ) { let query ; switch ( this . adapter . dialect ) { case "sqlite" : query = `SELECT EXISTS (SELECT name FROM sqlite_master WHERE type='table' AND name='${ tableName }')` ; break ; case "postgres" : query = `SELECT EXISTS (SELECT FROM pg_tables WHERE tablename = '${ tableName }')` ; break ; case "mysql" : query = `SELECT EXISTS (SELECT * FROM information_schema.tables WHERE table_name = '${ tableName }' LIMIT 1)` ; break ; default : return false ; } const result = await this . adapter . query ( query ) ; switch ( this . adapter . dialect ) { case "postgres" : return result [ 0 ] && result [ 0 ] . exists ? true : false ; case "mysql" : case "sqlite" : default : return ! ! result [ 0 ] [ Object . keys ( result [ 0 ] ) [ 0 ] ] ; } } param tableName param columnName public async hasColumn ( tableName , columnName ) { let query ; switch ( this . adapter . dialect ) { case "sqlite" : query = `PRAGMA table_info(${ tableName });` ; break ; case "mysql" : case "postgres" : default : query = `SELECT EXISTS (SELECT column_name FROM information_schema.columns WHERE table_name='${ tableName }' and column_name='${ columnName }');` ; break ; } const result = await this . adapter . query ( query ) ; switch ( this . adapter . dialect ) { case "sqlite" : return ! ! result . find ( ( item ) => item . name === columnName ) ; case "postgres" : return result [ 0 ] && result [ 0 ] . exists ? true : false ; case "mysql" : return ! ! result [ 0 ] [ Object . keys ( result [ 0 ] ) [ 0 ] ] ; default : throw new Error ( "Database dialect not implemented!" ) ; } } /** Create an index */ public addIndex ( index ) { throw new Error ( "Not implemented yet!" ) ; } /** Remove an index */ public removeIndex ( index ) { throw new Error ( "Not implemented yet!" ) ; } param tableName param columnName param newColumnName public async renameColumn ( tableName , columnName , newColumnName ) { await this . adapter . query ( `ALTER TABLE ${ tableName } RENAME ${ columnName } TO ${ newColumnName }` ) ; } param tableName param column public async addColumn ( tableName , column ) { await this . adapter . query ( `ALTER TABLE ${ tableName } ADD ${ column . toSQL ( this . adapter . dialect ) }` ) ; } /** Update a column's datatype */ public alterColumn ( column , newColumn ) { throw new Error ( "Not implemented yet!" ) ; } param tableName param columnName public async dropColumn ( tableName , columnName ) { switch ( this . adapter . dialect ) { case "sqlite" : throw new Error ( "SQLite doesn't support DROP COLUMN at the moment!" ) ; case "mysql" : case "postgres" : default : await this . adapter . query ( `ALTER TABLE ${ tableName } DROP COLUMN ${ columnName }` ) ; break ; } } /** Execute SQL query */ public query ( query ) { return this . adapter . query ( query ) ; } }