mirror of https://github.com/nocodb/nocodb
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
322 lines
9.1 KiB
322 lines
9.1 KiB
import fs from 'fs'; |
|
import process from 'process'; |
|
import { knex } from 'knex'; |
|
import SqlMgrv2 from '../../src/db/sql-mgr/v2/SqlMgrv2'; |
|
import type { Knex } from 'knex'; |
|
import type { DbConfig } from '../../src/interface/config'; |
|
import NcConfigFactory from '../../src/utils/NcConfigFactory' |
|
|
|
export default class TestDbMngr { |
|
public static readonly dbName = 'test_meta'; |
|
public static readonly sakilaDbName = 'test_sakila'; |
|
public static metaKnex: Knex; |
|
public static sakilaKnex: Knex; |
|
|
|
public static defaultConnection = { |
|
user: 'root', |
|
password: 'password', |
|
host: 'localhost', |
|
port: 3306, |
|
client: 'mysql2', |
|
}; |
|
|
|
public static pgConnection = { |
|
user: 'postgres', |
|
password: 'password', |
|
host: 'localhost', |
|
port: 5432, |
|
client: 'pg', |
|
}; |
|
|
|
public static connection: { |
|
user: string; |
|
password: string; |
|
host: string; |
|
port: number; |
|
client: string; |
|
} = TestDbMngr.defaultConnection; |
|
|
|
public static dbConfig: DbConfig; |
|
|
|
static populateConnectionConfig() { |
|
const { user, password, host, port, client } = TestDbMngr.defaultConnection; |
|
TestDbMngr.connection = { |
|
user: process.env['DB_USER'] || user, |
|
password: process.env['DB_PASSWORD'] || password, |
|
host: process.env['DB_HOST'] || host, |
|
port: Number(process.env['DB_PORT']) || port, |
|
client: process.env['DB_CLIENT'] || client, |
|
}; |
|
|
|
console.log(TestDbMngr.connection); |
|
} |
|
|
|
static async testConnection(config: DbConfig) { |
|
try { |
|
console.log('Testing connection', TestDbMngr.connection); |
|
return await SqlMgrv2.testConnection(config); |
|
} catch (e) { |
|
console.log(e); |
|
return { code: -1, message: 'Connection invalid' }; |
|
} |
|
} |
|
|
|
static async init() { |
|
TestDbMngr.populateConnectionConfig(); |
|
|
|
// common for both pg and mysql |
|
if (await TestDbMngr.isDbConfigured()) { |
|
await TestDbMngr.connectDb(); |
|
} else { |
|
console.log('Mysql is not configured. Switching to sqlite'); |
|
await TestDbMngr.switchToSqlite(); |
|
} |
|
} |
|
|
|
private static async isDbConfigured() { |
|
const { user, password, host, port, client } = TestDbMngr.connection; |
|
const config = NcConfigFactory.urlToDbConfig( |
|
`${client}://${user}:${password}@${host}:${port}`, |
|
); |
|
config.connection = { |
|
user, |
|
password, |
|
host, |
|
port, |
|
}; |
|
const result = await TestDbMngr.testConnection(config); |
|
return result.code !== -1; |
|
} |
|
static async connectDb() { |
|
const { user, password, host, port, client } = TestDbMngr.connection; |
|
if (!process.env[`DATABASE_URL`]) { |
|
process.env[ |
|
`DATABASE_URL` |
|
] = `${client}://${user}:${password}@${host}:${port}/${TestDbMngr.dbName}`; |
|
} |
|
|
|
TestDbMngr.dbConfig = NcConfigFactory.urlToDbConfig( |
|
NcConfigFactory.extractXcUrlFromJdbc(process.env[`DATABASE_URL`]), |
|
); |
|
this.dbConfig.meta = { |
|
tn: 'nc_evolutions', |
|
dbAlias: 'db', |
|
api: { |
|
type: 'rest', |
|
prefix: '', |
|
graphqlDepthLimit: 10, |
|
}, |
|
inflection: { |
|
tn: 'camelize', |
|
cn: 'camelize', |
|
}, |
|
}; |
|
|
|
await TestDbMngr.setupMeta(); |
|
await TestDbMngr.setupSakila(); |
|
} |
|
|
|
static async setupMeta() { |
|
if (TestDbMngr.metaKnex) { |
|
await TestDbMngr.metaKnex.destroy(); |
|
} |
|
|
|
if (TestDbMngr.isSqlite()) { |
|
await TestDbMngr.resetMetaSqlite(); |
|
TestDbMngr.metaKnex = knex(TestDbMngr.getMetaDbConfig()); |
|
return; |
|
} |
|
|
|
TestDbMngr.metaKnex = knex(TestDbMngr.getDbConfigWithNoDb()); |
|
await TestDbMngr.resetDatabase(TestDbMngr.metaKnex, TestDbMngr.dbName); |
|
await TestDbMngr.metaKnex.destroy(); |
|
|
|
TestDbMngr.metaKnex = knex(TestDbMngr.getMetaDbConfig()); |
|
await TestDbMngr.useDatabase(TestDbMngr.metaKnex, TestDbMngr.dbName); |
|
} |
|
|
|
static async setupSakila() { |
|
if (TestDbMngr.sakilaKnex) { |
|
await TestDbMngr.sakilaKnex.destroy(); |
|
} |
|
|
|
if (TestDbMngr.isSqlite()) { |
|
await TestDbMngr.seedSakila(); |
|
TestDbMngr.sakilaKnex = knex(TestDbMngr.getSakilaDbConfig()); |
|
return; |
|
} |
|
|
|
TestDbMngr.sakilaKnex = knex(TestDbMngr.getDbConfigWithNoDb()); |
|
await TestDbMngr.resetDatabase( |
|
TestDbMngr.sakilaKnex, |
|
TestDbMngr.sakilaDbName, |
|
); |
|
await TestDbMngr.sakilaKnex.destroy(); |
|
|
|
TestDbMngr.sakilaKnex = knex(TestDbMngr.getSakilaDbConfig()); |
|
await TestDbMngr.useDatabase( |
|
TestDbMngr.sakilaKnex, |
|
TestDbMngr.sakilaDbName, |
|
); |
|
} |
|
|
|
static async switchToSqlite() { |
|
// process.env[`DATABASE_URL`] = `sqlite3:///?database=${__dirname}/${TestDbMngr.dbName}.sqlite`; |
|
TestDbMngr.dbConfig = { |
|
client: 'sqlite3', |
|
connection: { |
|
filename: `${__dirname}/${TestDbMngr.dbName}.db`, |
|
database: TestDbMngr.dbName, |
|
}, |
|
useNullAsDefault: true, |
|
meta: { |
|
tn: 'nc_evolutions', |
|
dbAlias: 'db', |
|
api: { |
|
type: 'rest', |
|
prefix: '', |
|
graphqlDepthLimit: 10, |
|
}, |
|
inflection: { |
|
tn: 'camelize', |
|
cn: 'camelize', |
|
}, |
|
}, |
|
}; |
|
|
|
process.env[ |
|
`NC_DB` |
|
] = `sqlite3:///?database=${__dirname}/${TestDbMngr.dbName}.db`; |
|
await TestDbMngr.setupMeta(); |
|
await TestDbMngr.setupSakila(); |
|
} |
|
|
|
private static async resetDatabase(knexClient, dbName) { |
|
if (TestDbMngr.isSqlite()) { |
|
// return knexClient.raw(`DELETE FROM sqlite_sequence`); |
|
} else { |
|
try { |
|
await knexClient.raw(`DROP DATABASE ${dbName}`); |
|
} catch (e) {} |
|
await knexClient.raw(`CREATE DATABASE ${dbName}`); |
|
console.log(`Database ${dbName} created`); |
|
|
|
if (!TestDbMngr.isPg()) { |
|
await knexClient.raw(`USE ${dbName}`); |
|
} |
|
} |
|
} |
|
|
|
static isSqlite() { |
|
return TestDbMngr.dbConfig.client === 'sqlite3'; |
|
} |
|
|
|
static isPg() { |
|
return TestDbMngr.dbConfig.client === 'pg'; |
|
} |
|
|
|
private static async useDatabase(knexClient, dbName) { |
|
if (!TestDbMngr.isSqlite() && !TestDbMngr.isPg()) { |
|
await knexClient.raw(`USE ${dbName}`); |
|
} |
|
} |
|
|
|
static getDbConfigWithNoDb() { |
|
const dbConfig = JSON.parse(JSON.stringify(TestDbMngr.dbConfig)); |
|
delete dbConfig.connection.database; |
|
return dbConfig; |
|
} |
|
|
|
static getMetaDbConfig() { |
|
return TestDbMngr.dbConfig; |
|
} |
|
|
|
private static resetMetaSqlite() { |
|
if (fs.existsSync(`${__dirname}/test_meta.db`)) { |
|
fs.unlinkSync(`${__dirname}/test_meta.db`); |
|
} |
|
} |
|
|
|
static getSakilaDbConfig() { |
|
const sakilaDbConfig = JSON.parse(JSON.stringify(TestDbMngr.dbConfig)); |
|
sakilaDbConfig.connection.database = TestDbMngr.sakilaDbName; |
|
sakilaDbConfig.connection.multipleStatements = true; |
|
if (TestDbMngr.isSqlite()) { |
|
sakilaDbConfig.connection.filename = `${__dirname}/test_sakila.db`; |
|
} |
|
return sakilaDbConfig; |
|
} |
|
|
|
static async seedSakila() { |
|
const testsDir = __dirname.replace('tests/unit', 'tests'); |
|
|
|
if (TestDbMngr.isSqlite()) { |
|
if (fs.existsSync(`${__dirname}/test_sakila.db`)) { |
|
fs.unlinkSync(`${__dirname}/test_sakila.db`); |
|
} |
|
fs.copyFileSync( |
|
`${testsDir}/sqlite-sakila-db/sakila.db`, |
|
`${__dirname}/test_sakila.db`, |
|
); |
|
} else if (TestDbMngr.isPg()) { |
|
const schemaFile = fs |
|
.readFileSync(`${testsDir}/pg-sakila-db/01-postgres-sakila-schema.sql`) |
|
.toString(); |
|
const dataFile = fs |
|
.readFileSync( |
|
`${testsDir}/pg-sakila-db/02-postgres-sakila-insert-data.sql`, |
|
) |
|
.toString(); |
|
await TestDbMngr.sakilaKnex.raw(schemaFile); |
|
await TestDbMngr.sakilaKnex.raw(dataFile); |
|
} else { |
|
const schemaFile = fs |
|
.readFileSync(`${testsDir}/mysql-sakila-db/03-test-sakila-schema.sql`) |
|
.toString(); |
|
const dataFile = fs |
|
.readFileSync(`${testsDir}/mysql-sakila-db/04-test-sakila-data.sql`) |
|
.toString(); |
|
await TestDbMngr.sakilaKnex.raw(schemaFile); |
|
await TestDbMngr.sakilaKnex.raw(dataFile); |
|
} |
|
} |
|
|
|
static async disableForeignKeyChecks(knexClient) { |
|
if (TestDbMngr.isSqlite()) { |
|
await knexClient.raw('PRAGMA foreign_keys = OFF'); |
|
} else if (TestDbMngr.isPg()) { |
|
await knexClient.raw(`SET session_replication_role = 'replica'`); |
|
} else { |
|
await knexClient.raw(`SET FOREIGN_KEY_CHECKS = 0`); |
|
} |
|
} |
|
|
|
static async enableForeignKeyChecks(knexClient) { |
|
if (TestDbMngr.isSqlite()) { |
|
await knexClient.raw(`PRAGMA foreign_keys = ON;`); |
|
} else if (TestDbMngr.isPg()) { |
|
await knexClient.raw(`SET session_replication_role = 'origin'`); |
|
} else { |
|
await knexClient.raw(`SET FOREIGN_KEY_CHECKS = 1`); |
|
} |
|
} |
|
|
|
static async showAllTables(knexClient) { |
|
if (TestDbMngr.isSqlite()) { |
|
const tables = await knexClient.raw( |
|
`SELECT name FROM sqlite_master WHERE type='table'`, |
|
); |
|
return tables |
|
.filter((t) => t.name !== 'sqlite_sequence' && t.name !== '_evolutions') |
|
.map((t) => t.name); |
|
} else if (TestDbMngr.isPg()) { |
|
const tables = await knexClient.raw( |
|
`SELECT tablename FROM pg_catalog.pg_tables WHERE schemaname != 'pg_catalog' AND schemaname != 'information_schema';`, |
|
); |
|
return tables.rows.map((t) => t.tablename); |
|
} else { |
|
const response = await knexClient.raw(`SHOW TABLES`); |
|
return response[0].map((table) => Object.values(table)[0]); |
|
} |
|
} |
|
}
|
|
|