From 67895f5c13703c9fb6c35aaed3c16db334eba034 Mon Sep 17 00:00:00 2001 From: mertmit Date: Tue, 26 Mar 2024 11:42:42 +0300 Subject: [PATCH] fix: type issues with SqlClient Signed-off-by: mertmit --- .../settings/data-sources/EditBase.vue | 52 +- .../nc-gui/components/dlg/TableCreate.vue | 7 +- packages/nc-gui/composables/useTableNew.ts | 3 +- packages/nc-gui/store/base.ts | 5 + packages/nc-gui/utils/baseCreateUtils.ts | 12 +- packages/nocodb-sdk/src/lib/Api.ts | 4 +- packages/nocodb/.gitignore | 1 + packages/nocodb/src/db/CustomKnex.ts | 3 - .../nocodb/src/db/sql-client/lib/SqlClient.ts | 6 +- .../src/db/sql-client/lib/SqlClientFactory.ts | 5 - .../db/sql-client/lib/mysql/MysqlClient.ts | 2 - .../src/db/sql-client/lib/pg/PgClient.ts | 2 - .../lib/snowflake/SnowflakeClient.ts | 2621 ----------------- .../lib/snowflake/snowflake.queries.ts | 5 - .../db/sql-client/lib/sqlite/SqliteClient.ts | 3 - packages/nocodb/src/db/sql-mgr/SqlMgr.ts | 8 +- packages/nocodb/src/db/sql-mgr/v2/SqlMgrv2.ts | 6 +- .../src/db/sql-migrator/lib/KnexMigrator.ts | 12 +- .../db/sql-migrator/lib/KnexMigratorv2Tans.ts | 8 +- .../nocodb/src/services/columns.service.ts | 4 +- 20 files changed, 91 insertions(+), 2678 deletions(-) delete mode 100644 packages/nocodb/src/db/sql-client/lib/snowflake/SnowflakeClient.ts delete mode 100644 packages/nocodb/src/db/sql-client/lib/snowflake/snowflake.queries.ts diff --git a/packages/nc-gui/components/dashboard/settings/data-sources/EditBase.vue b/packages/nc-gui/components/dashboard/settings/data-sources/EditBase.vue index 7bc88241c7..0798a35964 100644 --- a/packages/nc-gui/components/dashboard/settings/data-sources/EditBase.vue +++ b/packages/nc-gui/components/dashboard/settings/data-sources/EditBase.vue @@ -2,7 +2,7 @@ import type { SourceType } from 'nocodb-sdk' import { Form, message } from 'ant-design-vue' import type { SelectHandler } from 'ant-design-vue/es/vc-select/Select' -import type { DefaultConnection, ProjectCreateForm, SQLiteConnection } from '#imports' +import type { DefaultConnection, ProjectCreateForm, SQLiteConnection, SnowflakeConnection } from '#imports' import { CertTypes, ClientType, @@ -387,6 +387,56 @@ onMounted(async () => { + +
- + { :placeholder="$t('msg.info.enterTableName')" /> +
diff --git a/packages/nc-gui/composables/useTableNew.ts b/packages/nc-gui/composables/useTableNew.ts index d51e3dd67a..01c74800d5 100644 --- a/packages/nc-gui/composables/useTableNew.ts +++ b/packages/nc-gui/composables/useTableNew.ts @@ -23,10 +23,11 @@ import { } from '#imports' export function useTableNew(param: { onTableCreate?: (tableMeta: TableType) => void; baseId: string; sourceId?: string }) { - const table = reactive<{ title: string; table_name: string; columns: string[] }>({ + const table = reactive<{ title: string; table_name: string; columns: string[]; is_hybrid: boolean }>({ title: '', table_name: '', columns: SYSTEM_COLUMNS, + is_hybrid: true, }) const { t } = useI18n() diff --git a/packages/nc-gui/store/base.ts b/packages/nc-gui/store/base.ts index 1e6913dad0..e2190709ec 100644 --- a/packages/nc-gui/store/base.ts +++ b/packages/nc-gui/store/base.ts @@ -104,6 +104,10 @@ export const useBase = defineStore('baseStore', () => { return getBaseType(sourceId) === 'pg' } + function isSnowflake(sourceId?: string) { + return getBaseType(sourceId) === 'snowflake' + } + function isXcdbBase(sourceId?: string) { const source = sources.value.find((source) => source.id === sourceId) return (source?.is_meta as boolean) || (source?.is_local as boolean) || false @@ -284,6 +288,7 @@ export const useBase = defineStore('baseStore', () => { isMssql, isPg, isSqlite, + isSnowflake, sqlUis, isSharedBase, isSharedErd, diff --git a/packages/nc-gui/utils/baseCreateUtils.ts b/packages/nc-gui/utils/baseCreateUtils.ts index 6c6f39af21..cf324a2e38 100644 --- a/packages/nc-gui/utils/baseCreateUtils.ts +++ b/packages/nc-gui/utils/baseCreateUtils.ts @@ -137,12 +137,12 @@ const sampleConnectionData: { [key in ConnectionClientType]: DefaultConnection } useNullAsDefault: true, }, [ClientType.SNOWFLAKE]: { - account: 'account', - username: 'username', - password: 'password', - warehouse: 'warehouse', - database: 'database', - schema: 'schema', + account: 'LOCATOR.REGION', + username: 'USERNAME', + password: 'PASSWORD', + warehouse: 'COMPUTE_WH', + database: 'DATABASE', + schema: 'PUBLIC', }, tidb: { host: defaultHost, diff --git a/packages/nocodb-sdk/src/lib/Api.ts b/packages/nocodb-sdk/src/lib/Api.ts index 8197a6b44c..189ffded61 100644 --- a/packages/nocodb-sdk/src/lib/Api.ts +++ b/packages/nocodb-sdk/src/lib/Api.ts @@ -11100,7 +11100,7 @@ export class Api< * @tags DB Data Table Row * @name Update * @summary Update Table Rows - * @request PUT:/api/v2/tables/{tableId}/records + * @request PATCH:/api/v2/tables/{tableId}/records * @response `200` `any` OK * @response `400` `{ \** @example BadRequest [Error]: *\ @@ -11125,7 +11125,7 @@ export class Api< } >({ path: `/api/v2/tables/${tableId}/records`, - method: 'PUT', + method: 'PATCH', query: query, body: data, type: ContentType.Json, diff --git a/packages/nocodb/.gitignore b/packages/nocodb/.gitignore index 2cb3a719d6..ccece4a5b0 100644 --- a/packages/nocodb/.gitignore +++ b/packages/nocodb/.gitignore @@ -45,5 +45,6 @@ test_sakila_?.db # nc-gui dir is copied for building local docker. /docker/main.js /docker/nc-gui/ +/docker/public/ /tests/unit/.env \ No newline at end of file diff --git a/packages/nocodb/src/db/CustomKnex.ts b/packages/nocodb/src/db/CustomKnex.ts index 077d158c1a..cda64ad395 100644 --- a/packages/nocodb/src/db/CustomKnex.ts +++ b/packages/nocodb/src/db/CustomKnex.ts @@ -1,5 +1,4 @@ import { Knex, knex } from 'knex'; -import { SnowflakeClient } from 'nc-help'; import { defaults, types } from 'pg'; import dayjs from 'dayjs'; import type { FilterType } from 'nocodb-sdk'; @@ -1029,8 +1028,6 @@ function CustomKnex( arg.useNullAsDefault = true; } - if (arg?.client === 'snowflake') arg.client = SnowflakeClient; - const kn: any = knex(arg); const knexRaw = kn.raw; diff --git a/packages/nocodb/src/db/sql-client/lib/SqlClient.ts b/packages/nocodb/src/db/sql-client/lib/SqlClient.ts index b716b3c508..1ee9106ae9 100644 --- a/packages/nocodb/src/db/sql-client/lib/SqlClient.ts +++ b/packages/nocodb/src/db/sql-client/lib/SqlClient.ts @@ -1,6 +1,8 @@ class SqlClient { protected connectionConfig: any; protected sqlClient: any; + protected queries: any; + protected _version: any; constructor(connectionConfig) { this.connectionConfig = connectionConfig; @@ -108,7 +110,9 @@ class SqlClient { async tableSelectStatement(_args): Promise {} - async totalRecords(_args): Promise {} + async totalRecords(_args?): Promise {} + + async getDefaultByteaOutputFormat(_args = {}): Promise {} } export default SqlClient; diff --git a/packages/nocodb/src/db/sql-client/lib/SqlClientFactory.ts b/packages/nocodb/src/db/sql-client/lib/SqlClientFactory.ts index d90555c7e9..f63310236e 100644 --- a/packages/nocodb/src/db/sql-client/lib/SqlClientFactory.ts +++ b/packages/nocodb/src/db/sql-client/lib/SqlClientFactory.ts @@ -71,11 +71,6 @@ export default class { } } - // todo: tobe done - // if (Noco.isEE()) { - // return SqlClientFactoryEE.create(connectionConfig); - // } - return SqlClientFactory.create(connectionConfig); } } diff --git a/packages/nocodb/src/db/sql-client/lib/mysql/MysqlClient.ts b/packages/nocodb/src/db/sql-client/lib/mysql/MysqlClient.ts index e651d1cc30..1d6f9c5b3b 100644 --- a/packages/nocodb/src/db/sql-client/lib/mysql/MysqlClient.ts +++ b/packages/nocodb/src/db/sql-client/lib/mysql/MysqlClient.ts @@ -20,8 +20,6 @@ const log = new Debug('MysqlClient'); const evt = new Emit(); class MysqlClient extends KnexClient { - protected queries: any; - protected _version: any; protected types: any; constructor(connectionConfig) { diff --git a/packages/nocodb/src/db/sql-client/lib/pg/PgClient.ts b/packages/nocodb/src/db/sql-client/lib/pg/PgClient.ts index ebde137d51..6abc62e369 100644 --- a/packages/nocodb/src/db/sql-client/lib/pg/PgClient.ts +++ b/packages/nocodb/src/db/sql-client/lib/pg/PgClient.ts @@ -11,8 +11,6 @@ import queries from '~/db/sql-client/lib/pg/pg.queries'; const log = new Debug('PGClient'); class PGClient extends KnexClient { - protected queries: any; - protected _version: any; constructor(connectionConfig) { super(connectionConfig); // this.sqlClient = null; diff --git a/packages/nocodb/src/db/sql-client/lib/snowflake/SnowflakeClient.ts b/packages/nocodb/src/db/sql-client/lib/snowflake/SnowflakeClient.ts deleted file mode 100644 index 6660988d3f..0000000000 --- a/packages/nocodb/src/db/sql-client/lib/snowflake/SnowflakeClient.ts +++ /dev/null @@ -1,2621 +0,0 @@ -import { nanoid } from 'nanoid'; -import find from 'lodash/find'; -import isEmpty from 'lodash/isEmpty'; -import KnexClient from '../KnexClient'; -import Debug from '../../../util/Debug'; -import Result from '../../../util/Result'; -import queries from './snowflake.queries'; - -const log = new Debug('SnowflakeClient'); - -const rowsToLower = (arr) => { - for (const a of arr) { - for (const [k, v] of Object.entries(a)) { - delete a[k]; - a[k.toLowerCase()] = v; - } - } - return arr; -}; - -class SnowflakeClient extends KnexClient { - private queries: any; - private _version: any; - constructor(connectionConfig) { - super(connectionConfig); - // this.sqlClient = null; - this.queries = queries; - this._version = {}; - } - - /** - * - * - * @param {Object} args - * @returns {Object} result - * @returns {Number} code - * @returns {String} message - */ - async schemaCreateWithCredentials(args) { - const func = this.schemaCreateWithCredentials.name; - const result = new Result(); - log.api(`${func}:args:`, args); - - try { - if (!args.schema) { - args.schema = `nc${nanoid(8)}`; - } - - // const connectionParamsWithoutDb = JSON.parse( - // JSON.stringify(this.connectionConfig) - // ); - // - // delete connectionParamsWithoutDb.connection.database; - // - // const tempSqlClient = knex(connectionParamsWithoutDb); - - const data = await this.sqlClient.raw('create schema ?', [args.schema]); - - // postgres=# create database mydb; - // postgres=# create user myuser with encrypted password 'mypass'; - // postgres=# grant all privileges on database mydb to myuser; - - log.debug('Create database if not exists', data); - - // create new knex client - // this.sqlClient = knex(this.connectionConfig); - // tempSqlClient.destroy(); - result.object = args; - } catch (e) { - // log.ppe(e); - result.code = -1; - result.message = e.message; - result.object = e; - } - return result; - } - - /** - * - * @param {Object} - args - * @param args.sequence_name - * @returns {Promise<{upStatement, downStatement}>} - */ - async sequenceDelete(args: any = {}) { - const _func = this.sequenceDelete.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - - try { - const query = `${this.querySeparator()}DROP SEQUENCE ${ - args.sequence_name - }`; - await this.sqlClient.raw(query); - result.data.object = { - upStatement: [{ sql: query }], - downStatement: [ - { - sql: `${this.querySeparator()}CREATE SEQUENCE ${ - args.sequence_name - }`, - }, - ], - }; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - /** - * - * @param {Object} - args - Input arguments - * @returns {Object[]} - sequences - * @property {String} - sequences[].sequence_name - * @property {String} - sequences[].type - * @property {String} - sequences[].definer - * @property {String} - sequences[].modified - * @property {String} - sequences[].created - * @property {String} - sequences[].security_type - * @property {String} - sequences[].comment - * @property {String} - sequences[].character_set_client - * @property {String} - sequences[].collation_connection - * @property {String} - sequences[].database collation - */ - async sequenceList(args: any = {}) { - const _func = this.sequenceList.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - try { - args.databaseName = this.database; - const { rows } = await this.raw(`select * - from "${this.database}".information_schema.sequences;`); - - result.data.list = rowsToLower(rows).map((seq) => { - return { - ...seq, - original_sequence_name: seq.sequence_name, - }; - }); - } catch (e) { - log.ppe(e, _func); - throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - /** - * - * @param {Object} - args - Input arguments - * @param {String} - args.sequence_name - * @param {String} - args.start_value - * @param {String} - args.min_value - * @param {String} - args.max_value - * @param {String} - args.increment_by - * @returns {Object} - result - */ - async sequenceCreate(args: any = {}) { - const func = this.sequenceCreate.name; - const result = new Result(); - log.api(`${func}:args:`, args); - try { - const query = - this.querySeparator() + `CREATE SEQUENCE ${args.sequence_name}`; - await this.sqlClient.raw(query); - result.data.object = { - upStatement: [{ sql: query }], - downStatement: [ - { - sql: this.querySeparator() + `DROP SEQUENCE ${args.sequence_name}`, - }, - ], - }; - } catch (e) { - log.ppe(e, func); - throw e; - } - - log.api(`${func}: result`, result); - return result; - } - - /** - * - * @param {Object} - args - Input arguments - * @param {String} - args.sequence_name - * @param {String} - args.start_value - * @param {String} - args.min_value - * @param {String} - args.max_value - * @param {String} - args.increment_by - * @returns {Object} - result - */ - async sequenceUpdate(args: any = {}) { - const func = this.sequenceUpdate.name; - const result = new Result(); - log.api(`${func}:args:`, args); - try { - const upQuery = - this.querySeparator() + - `ALTER SEQUENCE ${args.original_sequence_name} RENAME TO ${args.sequence_name};`; - const downQuery = - this.querySeparator() + - `ALTER SEQUENCE ${args.sequence_name} RENAME TO ${args.original_sequence_name};`; - - await this.sqlClient.raw(upQuery); - result.data.object = { - upStatement: [{ sql: upQuery }], - downStatement: [{ sql: downQuery }], - }; - } catch (e) { - log.ppe(e, func); - throw e; - } - - log.api(`${func}: result`, result); - return result; - } - - /** - * @param {Object} args - * @returns {Object} result - * @returns {Number} code - * @returns {String} message - */ - async testConnection(args: any = {}) { - const func = this.testConnection.name; - const result = new Result(); - log.api(`${func}:args:`, args); - - try { - await this.sqlClient.raw('SELECT 1+1 as data'); - } catch (e) { - // log.ppe(e); - result.code = -1; - result.message = e.message; - result.object = e; - } finally { - if (result.code) { - this.emitE(`TestConnection result: ${result.message}`); - } else { - this.emit(`TestConnection result: ${result.code}`); - } - } - return result; - } - - getKnexDataTypes() { - const result = new Result(); - - result.data.list = [ - 'NUMBER', - 'DECIMAL', - 'NUMERIC', - 'INT', - 'INTEGER', - 'BIGINT', - 'SMALLINT', - 'TINYINT', - 'BYTEINT', - 'FLOAT', - 'FLOAT4', - 'FLOAT8', - 'DOUBLE', - 'DOUBLE PRECISION', - 'REAL', - 'VARCHAR', - 'CHAR', - 'CHARACTER', - 'STRING', - 'TEXT', - 'BINARY', - 'VARBINARY', - 'BOOLEAN', - 'DATE', - 'DATETIME', - 'TIME', - 'TIMESTAMP', - 'TIMESTAMP_LTZ', - 'TIMESTAMP_NTZ', - 'TIMESTAMP_TZ', - 'VARIANT', - 'OBJECT', - 'ARRAY', - 'GEOGRAPHY', - ]; - - return result; - } - - /** - * - * - * @param {Object} args - * @returns {Object} result - * @returns {Number} code - * @returns {String} message - * @returns {Object} object - {version, primary, major, minor} - */ - async version(args: any = {}) { - const _func = this.version.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - - try { - result.data.object = {}; - const data = await this.sqlClient.raw( - 'SELECT CURRENT_VERSION() as "server_version"', - ); - log.debug(data.rows[0]); - result.data.object.version = data.rows[0].server_version; - const versions = data.rows[0].server_version.split('.'); - - if (versions.length && (versions.length === 3 || versions.length === 2)) { - result.data.object.primary = versions[0]; - result.data.object.major = versions[1]; - result.data.object.minor = - versions.length > 2 ? versions[2] : versions[1]; - result.data.object.key = versions[0] + versions[1]; - } else { - result.code = -1; - result.message = `Invalid version : ${data.rows[0].server_version}`; - } - } catch (e) { - log.ppe(e); - result.code = -1; - result.message = e.message; - } finally { - log.api(`${_func} :result: %o`, result); - } - return result; - } - - /** - * - * @param {Object} args - * @param {String} args.database - * @returns {Result} - */ - async createDatabaseIfNotExists(args: any = {}) { - const _func = this.createDatabaseIfNotExists.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - let tempSqlClient; - - try { - let rows = []; - try { - log.debug('checking if db exists'); - rows = ( - await this.sqlClient.raw( - `SELECT DATABASE_NAME as database FROM SNOWFLAKE.information_schema.DATABASES WHERE DATABASE_NAME = ??`, - [args.database], - ) - ).rows; - } catch (e) { - log.debug('db does not exist'); - } - if (rows.length === 0) { - log.debug('creating database:', args); - await this.sqlClient.raw(`CREATE DATABASE ??`, [args.database]); - } - - await this.sqlClient.raw(`CREATE SCHEMA IF NOT EXISTS ??.??`, [ - args.database, - this.schema, - ]); - } catch (e) { - log.ppe(e, _func); - throw e; - } finally { - if (tempSqlClient) { - await tempSqlClient.destroy(); - } - } - - log.api(`${_func}: result`, result); - return result; - } - - async dropDatabase(args) { - const _func = this.dropDatabase.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - - try { - await this.sqlClient.raw(`DROP DATABASE ${args.database};`); - } catch (e) { - log.ppe(e, _func); - // throw e; - } - - log.api(`${_func}: result`, result); - return result; - } - - /** - * - * @param args {tn} - * @returns - */ - async createTableIfNotExists(args) { - const _func = this.createTableIfNotExists.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - - try { - /** ************** START : create _evolution table if not exists *************** */ - const exists = await this.sqlClient.raw( - `SELECT table_schema,table_name as "tn", table_catalog - FROM "${this.database}".information_schema.tables - where table_schema=? and table_name = ?`, - [this.schema, args.tn], - ); - - if (exists.rows.length === 0) { - const data = await this.sqlClient.schema.createTable( - args.tn, - function (table) { - table.increments(); - table.string('title').notNullable(); - table.string('titleDown').nullable(); - table.string('description').nullable(); - table.integer('batch').nullable(); - table.string('checksum').nullable(); - table.integer('status').nullable(); - table.dateTime('created'); - table.timestamps(); - }, - ); - log.debug('Table created:', `${args.tn}`, data); - } else { - log.debug(`${args.tn} tables exists`); - } - /** ************** END : create _evolution table if not exists *************** */ - } catch (e) { - log.ppe(e, _func); - throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - async hasTable(args: any = {}) { - const _func = this.hasTable.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - - try { - const { rows } = await this.sqlClient.raw( - `SELECT table_schema,table_name as "tn", table_catalog FROM "${this.database}".information_schema.tables where table_schema = ? and table_name = ? and table_catalog = ?`, - [this.schema, args.tn, this.database], - ); - result.data.value = rows.length > 0; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - async hasDatabase(args: any = {}) { - const _func = this.hasDatabase.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - - try { - const { rows } = await this.sqlClient.raw( - `SELECT DATABASE_NAME as database FROM SNOWFLAKE.information_schema.DATABASES WHERE DATABASE_NAME = ?`, - [args.databaseName], - ); - result.data.value = rows.length > 0; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - /** - * - * @param {Object} - args - for future reasons - * @returns {Object[]} - databases - * @property {String} - databases[].database_name - */ - async databaseList(args: any = {}) { - const _func = this.databaseList.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - - try { - const { rows } = await this.sqlClient.raw( - `SELECT DATABASE_NAME as database_name FROM SNOWFLAKE.information_schema.DATABASES;`, - ); - result.data.list = rows; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - /** - * - * @param {Object} - args - for future reasons - * @returns {Object[]} - tables - * @property {String} - tables[].tn - */ - async tableList(args: any = {}) { - const _func = this.tableList.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - try { - const { rows } = await this.raw( - `SELECT table_schema as "ts", table_name as "tn", table_type as "table_type" - FROM "${this.database}".information_schema.tables - where table_schema = ? - ORDER BY table_schema, table_name`, - [this.schema], - ); - - result.data.list = rows.filter( - ({ table_type }) => table_type.toLowerCase() === 'base table', - ); - } catch (e) { - log.ppe(e, _func); - throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - async schemaList(args: any = {}) { - const _func = this.schemaList.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - - try { - const { rows } = await this.raw( - `SELECT SCHEMA_NAME as "schema_name" FROM "${this.database}".information_schema.SCHEMATA order by schema_name;`, - ); - - result.data.list = rows; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - /** - * - * @param {Object} - args - Input arguments - * @param {Object} - args.tn - - * @returns {Object[]} - columns - * @property {String} - columns[].tn - * @property {String} - columns[].cn - * @property {String} - columns[].dt - * @property {String} - columns[].dtx - * @property {String} - columns[].np - * @property {String} - columns[].ns - - * @property {String} - columns[].clen - - * @property {String} - columns[].dp - - * @property {String} - columns[].cop - - * @property {String} - columns[].pk - - * @property {String} - columns[].nrqd - - * @property {String} - columns[].not_nullable - - * @property {String} - columns[].ct - - * @property {String} - columns[].un - - * @property {String} - columns[].ai - - * @property {String} - columns[].unique - - * @property {String} - columns[].cdf - - * @property {String} - columns[].cc - - * @property {String} - columns[].csn - - */ - - async columnList(args: any = {}) { - const _func = this.columnList.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - try { - args.databaseName = this.database; - await this.sqlClient.raw( - `SHOW PRIMARY KEYS IN SCHEMA "${this.database}"."${this.schema}";`, - ); - await this.sqlClient.raw( - `SHOW UNIQUE KEYS IN SCHEMA "${this.database}"."${this.schema}";`, - ); - - const lastQueries = await this.sqlClient.raw(` - select * from table("${this.database}".information_schema.query_history()) - WHERE query_text like 'SHOW%' - ORDER BY start_time DESC - LIMIT 30;`); - - let pk_query_id, uq_query_id; - for (const r of lastQueries.rows) { - if ( - r.QUERY_TEXT === - `SHOW PRIMARY KEYS IN SCHEMA "${this.database}"."${this.schema}";` - ) { - pk_query_id = r.QUERY_ID; - } else if ( - r.QUERY_TEXT === - `SHOW UNIQUE KEYS IN SCHEMA "${this.database}"."${this.schema}";` - ) { - uq_query_id = r.QUERY_ID; - } - if (pk_query_id && uq_query_id) { - break; - } - } - - const response = await this.sqlClient.raw( - `SELECT - cl.table_name as "tn", - column_name as "cn", - data_type as "dt", - is_identity as "au", - tc.constraint_type as "ck", - character_maximum_length as "clen", - numeric_precision as "np", - numeric_scale as "ns", - ordinal_position as "cop", - is_nullable as "nrqd", - column_default as "cdf", - identity_generation as "generation_expression", - character_octet_length as "character_octet_length", - character_set_name as "csn", - "PK"."key_sequence" as "pk_ordinal_position", - "PK"."constraint_name" as "pk_constraint_name", - udt_name - FROM "${this.database}".information_schema.COLUMNS cl - LEFT JOIN (select * from table(result_scan('${pk_query_id}')) UNION select * from table(result_scan('${uq_query_id}'))) pk - LEFT JOIN "${this.database}".information_schema.table_constraints tc ON tc.constraint_name = "PK"."constraint_name" - ON "PK"."schema_name" = cl.table_schema and "PK"."table_name" = cl.table_name and pk."column_name" = cl.column_name - WHERE cl.table_catalog = ? and cl.table_schema = ? and cl.table_name = ?;`, - [this.database, this.schema, args.tn], - ); - - const columns = []; - - for (let i = 0; i < response.rows.length; ++i) { - const column: any = {}; - - column.tn = response.rows[i].tn; - column.cn = response.rows[i].cn; - column.cno = response.rows[i].cn; - column.dt = response.rows[i].dt; - column.np = response.rows[i].np; - column.ns = response.rows[i].ns; - column.clen = response.rows[i].clen; - column.dp = response.rows[i].dp; - column.cop = response.rows[i].cop; - - // todo : there are lot of types in pg - handle them - //column.dtx = this.getKnexDataType(column.dt); - column.dtx = response.rows[i].dt; - column.pk = response.rows[i].pk_constraint_name !== null; - - column.nrqd = response.rows[i].nrqd !== 'NO'; - column.not_nullable = !column.nrqd; - column.rqd = !column.nrqd; - - // todo: there is no type of unsigned in postgres - response.rows[i].ct = response.rows[i].dt || ''; - column.un = response.rows[i].ct.indexOf('unsigned') !== -1; - - column.ai = false; - if (response.rows[i].au) { - column.ai = response.rows[i].au === 'YES'; - } - - // todo : need to find if column is unique or not - // column['unique'] = response.rows[i]['cst'].indexOf('UNIQUE') === -1 ? false : true; - - column.cdf = response.rows[i].cdf; - // ? response.rows[i].cdf.split("::")[0].replace(/'/g, "") - // : response.rows[i].cdf; - - // todo : need to find column comment - column.cc = response.rows[i].cc; - - column.csn = response.rows[i].csn; - column.dtxp = - response.rows[i].clen || response.rows[i].np || response.rows[i].dp; - column.dtxs = response.rows[i].ns; - column.au = response.rows[i].au; - column.data_type_custom = response.rows[i].udt_name; - if (column.dt === 'USER-DEFINED') { - column.dtxp = response.rows[i].enum_values; - } - - columns.push(column); - } - - result.data.list = columns; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - /** - * - * @param {Object} - args - Input arguments - * @param {Object} - args.tn - - * @returns {Object[]} - indexes - * @property {String} - indexes[].table - - * @property {String} - indexes[].cn - - * @property {String} - indexes[].key_name - - * @property {String} - indexes[].non_unique - - * @property {String} - indexes[].seq_in_index - - * @property {String} - indexes[].collation - - * @property {String} - indexes[].cardinality - - * @property {String} - indexes[].sub_part - - * @property {String} - indexes[].packed - - * @property {String} - indexes[].null - - * @property {String} - indexes[].index_type - - * @property {String} - indexes[].comment - - * @property {String} - indexes[].index_comment - - * @property {String} - indexes[].cstn - - * @property {String} - indexes[].cst - c = check constraint, f = foreign key constraint, p = primary key constraint, u = unique constraint, t = constraint trigger, x = exclusion constraint - */ - async indexList(args: any = {}) { - const _func = this.indexList.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - try { - // TODO indexList - result.data.list = []; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - /** - * - * @param {Object} - args - Input arguments - * @param {Object} - args.tn - - * @returns {Object[]} - indexes - * @property {String} - indexes[].cstn - - * @property {String} - indexes[].cn - - * @property {String} - indexes[].op - - * @property {String} - indexes[].puc - - * @property {String} - indexes[].cst - - */ - async constraintList(args: any = {}) { - const _func = this.constraintList.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - try { - await this.sqlClient.raw( - `SHOW PRIMARY KEYS IN SCHEMA "${this.database}"."${this.schema}";`, - ); - await this.sqlClient.raw( - `SHOW UNIQUE KEYS IN SCHEMA "${this.database}"."${this.schema}";`, - ); - - const lastQueries = await this.sqlClient.raw(` - select * from table("${this.database}".INFORMATION_SCHEMA.query_history()) - WHERE query_text like 'SHOW%' - ORDER BY start_time DESC - LIMIT 30;`); - - let pk_query_id, uq_query_id; - for (const r of lastQueries.rows) { - if ( - r.QUERY_TEXT === - `SHOW PRIMARY KEYS IN SCHEMA "${this.database}"."${this.schema}";` - ) { - pk_query_id = r.QUERY_ID; - } else if ( - r.QUERY_TEXT === - `SHOW UNIQUE KEYS IN SCHEMA "${this.database}"."${this.schema}";` - ) { - uq_query_id = r.QUERY_ID; - } - if (pk_query_id && uq_query_id) { - break; - } - } - - const { rows } = await this.sqlClient.raw( - `SELECT - constraint_name as "cstn", - "PK"."column_name" as "cn", - constraint_type as "cst" - FROM "${this.database}".information_schema.table_constraints tc - LEFT JOIN (select * from table(result_scan('${pk_query_id}')) UNION select * from table(result_scan('${uq_query_id}'))) pk - ON "PK"."constraint_name" = tc.constraint_name - WHERE tc.table_catalog = ? and tc.table_schema = ? and tc.table_name = ?;`, - [this.database, this.schema, args.tn], - ); - - result.data.list = rows; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - /** - * - * @param {Object} - args - Input arguments - * @param {Object} - args.tn - - * @returns {Object[]} - relations - * @property {String} - relations[].tn - * @property {String} - relations[].cstn - - * @property {String} - relations[].tn - - * @property {String} - relations[].cn - - * @property {String} - relations[].rtn - - * @property {String} - relations[].rcn - - * @property {String} - relations[].puc - - * @property {String} - relations[].ur - - * @property {String} - relations[].dr - - * @property {String} - relations[].mo - - */ - async relationList(args: any = {}) { - const _func = this.relationList.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - try { - await this.sqlClient.raw( - `SHOW IMPORTED KEYS IN SCHEMA "${this.database}"."${this.schema}";`, - ); - - const lastQueries = await this.sqlClient.raw(` - select * from table("${this.database}".information_schema.query_history()) - WHERE query_text like 'SHOW%' - ORDER BY start_time DESC - LIMIT 30;`); - - let ik_query_id; - for (const r of lastQueries.rows) { - if ( - r.QUERY_TEXT === - `SHOW IMPORTED KEYS IN SCHEMA "${this.database}"."${this.schema}";` - ) { - ik_query_id = r.QUERY_ID; - break; - } - } - - const { rows } = await this.sqlClient.raw( - `SELECT - constraint_name as "cstn", - "PK"."fk_table_name" as "tn", - "PK"."fk_column_name" as "cn", - "PK"."pk_schema_name" as "foreign_table_schema", - "PK"."pk_table_name" as "rtn", - "PK"."pk_column_name" as "rcn", - "PK"."update_rule" as "ur", - "PK"."delete_rule" as "dr" - FROM "${this.database}".information_schema.table_constraints tc - LEFT JOIN (select * from table(result_scan('${ik_query_id}'))) pk - ON "PK"."fk_name" = tc.constraint_name - WHERE tc.constraint_type = 'FOREIGN KEY' and tc.table_catalog = ? and tc.table_schema = ? and tc.table_name = ?;`, - [this.database, this.schema, args.tn], - ); - - result.data.list = rows; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - /** - * - * @param {Object} - args - Input arguments - * @param {Object} - args.tn - - * @returns {Object[]} - relations - * @property {String} - relations[].tn - * @property {String} - relations[].cstn - - * @property {String} - relations[].tn - - * @property {String} - relations[].cn - - * @property {String} - relations[].rtn - - * @property {String} - relations[].rcn - - * @property {String} - relations[].puc - - * @property {String} - relations[].ur - - * @property {String} - relations[].dr - - * @property {String} - relations[].mo - - */ - async relationListAll(args: any = {}) { - const _func = this.relationListAll.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - try { - await this.sqlClient.raw( - `SHOW IMPORTED KEYS IN SCHEMA "${this.database}"."${this.schema}";`, - ); - - const lastQueries = await this.sqlClient.raw(` - select * from table("${this.database}".information_schema.query_history()) - WHERE query_text like 'SHOW%' - ORDER BY start_time DESC - LIMIT 30;`); - - let ik_query_id; - for (const r of lastQueries.rows) { - if ( - r.QUERY_TEXT === - `SHOW IMPORTED KEYS IN SCHEMA "${this.database}"."${this.schema}";` - ) { - ik_query_id = r.QUERY_ID; - break; - } - } - - const { rows } = await this.sqlClient.raw( - `SELECT - constraint_name as "cstn", - "PK"."fk_table_name" as "tn", - "PK"."fk_column_name" as "cn", - "PK"."pk_schema_name" as "foreign_table_schema", - "PK"."pk_table_name" as "rtn", - "PK"."pk_column_name" as "rcn", - "PK"."update_rule" as "ur", - "PK"."delete_rule" as "dr" - FROM "${this.database}".information_schema.table_constraints tc - LEFT JOIN (select * from table(result_scan('${ik_query_id}'))) pk - ON "PK"."fk_name" = tc.constraint_name - WHERE tc.constraint_type = 'FOREIGN KEY' and tc.table_catalog = ? and tc.table_schema = ?;`, - [this.database, this.schema], - ); - - result.data.list = rows; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - /** - * - * @param {Object} - args - Input arguments - * @param {Object} - args.tn - - * @returns {Object[]} - triggers - * @property {String} - triggers[].trigger - * @property {String} - triggers[].event - * @property {String} - triggers[].table - * @property {String} - triggers[].statement - * @property {String} - triggers[].timing - * @property {String} - triggers[].created - * @property {String} - triggers[].sql_mode - * @property {String} - triggers[].definer - * @property {String} - triggers[].character_set_client - * @property {String} - triggers[].collation_connection - * @property {String} - triggers[].database collation - */ - async triggerList(args: any = {}) { - const _func = this.triggerList.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - try { - result.data.list = []; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - /** - * - * @param {Object} - args - Input arguments - * @returns {Object[]} - functions - * @property {String} - functions[].function_name - * @property {String} - functions[].type - * @property {String} - functions[].definer - * @property {String} - functions[].modified - * @property {String} - functions[].created - * @property {String} - functions[].security_type - * @property {String} - functions[].comment - * @property {String} - functions[].character_set_client - * @property {String} - functions[].collation_connection - * @property {String} - functions[].database collation - */ - async functionList(args: any = {}) { - const _func = this.functionList.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - try { - result.data.list = []; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - /** - * @todo Remove the function - pg doesn't support procedure - * - * @param {Object} - args - For future reasons - * @returns {Object[]} - procedures - * @property {String} - procedures[].procedure_name - * @property {String} - procedures[].type - * @property {String} - procedures[].definer - * @property {String} - procedures[].modified - * @property {String} - procedures[].created - * @property {String} - procedures[].security_type - * @property {String} - procedures[].comment - * @property {String} - procedures[].definer - * @property {String} - procedures[].character_set_client - * @property {String} - procedures[].collation_connection - * @property {String} - procedures[].database collation - */ - async procedureList(args: any = {}) { - const _func = this.procedureList.name; - const result = new Result(); - result.data.list = []; - log.api(`${_func}:args:`, args); - - // todo: update query - https://dataedo.com/kb/query/postgresql/list-stored-procedures - try { - result.data.list = []; - } catch (e) { - // todo: enable log - // log.ppe(e, _func); - // throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - /** - * - * @param {Object} - args - Input arguments - * @returns {Object[]} - views - * @property {String} - views[].sql_mode - * @property {String} - views[].create_function - * @property {String} - views[].database collation - * @property {String} - views[].collation_connection - * @property {String} - views[].character_set_client - */ - async viewList(args: any = {}) { - const _func = this.viewList.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - try { - const { rows } = await this.sqlClient.raw( - `select * from "${this.database}".INFORMATION_SCHEMA.views WHERE table_schema = ?;`, - [this.schema], - ); - - for (let i = 0; i < rows.length; ++i) { - rows[i].view_name = rows[i].TABLE_NAME; - } - - result.data.list = rows; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - /** - * - * @param {Object} - args - Input arguments - * @param {Object} - args.function_name - - * @returns {Object[]} - functions - * @property {String} - create_function - * @property {String} - function_declaration - */ - async functionRead(args: any = {}) { - const _func = this.functionRead.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - try { - result.data.list = []; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - /** - * @todo Remove the function - pg doesn't support procedure - * - * @param {Object} - args - Input arguments - * @param {Object} - args.procedure_name - - * @returns {Object[]} - functions - * @property {String} - sql_mode - * @property {String} - create_function - * @property {String} - database collation - * @property {String} - collation_connection - * @property {String} - character_set_client - */ - async procedureRead(args: any = {}) { - const _func = this.procedureRead.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - try { - result.data.list = []; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - /** - * - * @param {Object} - args - Input arguments - * @param {Object} - args.view_name - - * @returns {Object[]} - views - * @property {String} - views[].tn - */ - async viewRead(args: any = {}) { - const _func = this.viewRead.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - try { - args.databaseName = this.database; - - const { rows } = await this.sqlClient.raw( - `select * from "${this.database}".INFORMATION_SCHEMA.views WHERE table_name='${args.view_name}' and table_schema = '${this.schema}';`, - ); - - for (let i = 0; i < rows.length; ++i) { - rows[i].view_name = rows[i].TABLE_NAME; - // rows[i].view_definition = rows[i].view_definition; - } - - result.data.list = rows; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - async triggerRead(args: any = {}) { - const _func = this.triggerRead.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - try { - result.data.list = []; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - async schemaCreate(args: any = {}) { - const _func = this.schemaCreate.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - - try { - await this.sqlClient.raw(`create schema ${args.database_name}`); - } catch (e) { - log.ppe(e, _func); - throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - async schemaDelete(args: any = {}) { - const _func = this.schemaDelete.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - - try { - await this.sqlClient.raw(`drop schema ${args.database_name}`); - } catch (e) { - log.ppe(e, _func); - throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - async triggerDelete(args: any = {}) { - const _func = this.triggerDelete.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - try { - throw new Error('Function not supported for Snowflake yet'); - const upQuery = this.genQuery(`DROP TRIGGER IF EXISTS ?? ON ??`, [ - args.trigger_name, - args.tn, - ]); - await this.sqlClient.raw(upQuery); - result.data.object = { - upStatement: [{ sql: this.querySeparator() + upQuery }], - downStatement: [ - { - sql: - this.querySeparator() + - this.genQuery( - `CREATE TRIGGER ?? \n${args.timing} ${args.event}\nON ?? FOR EACH ROW\n${args.statement}`, - [args.trigger_name, args.tn], - ), - }, - ], - }; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - /** - * - * @param {Object} - args - Input arguments - * @param {String} - args.function_name - * @param {String} - args.function_declaration - * @param {String} - args.create_function - * @returns {Object[]} - result rows - */ - async functionDelete(args: any = {}) { - const _func = this.functionDelete.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - const upQuery = - this.querySeparator() + - `DROP FUNCTION IF EXISTS ${args.function_declaration}`; - const downQuery = this.querySeparator() + args.create_function; - try { - throw new Error('Function not supported for Snowflake yet'); - await this.sqlClient.raw(upQuery); - result.data.object = { - upStatement: [{ sql: upQuery }], - downStatement: [{ sql: downQuery }], - }; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - log.api(`${_func}: result`, result); - - return result; - } - - // @todo Remove the function - pg doesn't support procedure - async procedureDelete(args: any = {}) { - const _func = this.procedureDelete.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - try { - throw new Error('Function not supported for Snowflake yet'); - await this.sqlClient.raw( - `DROP PROCEDURE IF EXISTS ${args.procedure_name}`, - ); - } catch (e) { - log.ppe(e, _func); - throw e; - } - log.api(`${_func}: result`, result); - - return result; - } - - /** - * - * @param {Object} args - * @param {String} func : function name - * @returns {Result} - * @returns {Object} - Result.data - * @returns {String} - Result.data.value - sql query - */ - async _getQuery(args) { - try { - if (isEmpty(this._version)) { - const result = await this.version(); - this._version = result.data.object; - log.debug( - `Version was empty for ${args.func}: population version for database as`, - this._version, - ); - } - - if (this._version.key in this.queries[args.func]) { - return this.queries[args.func][this._version.key].sql; - } - return this.queries[args.func].default.sql; - } catch (error) { - log.ppe(error, this._getQuery.name); - throw error; - } - } - - /** - * - * @param {Object} - args - Input arguments - * @param {String} - args.function_name - * @param {String} - args.create_function - * @returns {Object[]} - result rows - */ - async functionCreate(args: any = {}) { - const func = this.functionCreate.name; - const result = new Result(); - - log.api(`${func}:args:`, args); - - try { - throw new Error('Function not supported for Snowflake yet'); - const upQuery = this.querySeparator() + args.create_function; - - await this.sqlClient.raw(upQuery); - - const functionCreated = await this.functionRead({ - function_name: args.function_name, - }); - - const downQuery = - this.querySeparator() + - `DROP FUNCTION IF EXISTS ${functionCreated.data.list[0].function_declaration}`; - - result.data.object = { - upStatement: [{ sql: upQuery }], - downStatement: [{ sql: downQuery }], - }; - } catch (e) { - log.ppe(e, func); - throw e; - } - - log.api(`${func}: result`, result); - return result; - } - - /** - * - * @param {Object} - args - Input arguments - * @param {String} - args.tn - * @param {String} - args.function_name - * @param {String} - args.event - * @param {String} - args.timing - * @returns {Object[]} - result rows - */ - async functionUpdate(args: any = {}) { - const func = this.functionUpdate.name; - const result = new Result(); - log.api(`${func}:args:`, args); - try { - throw new Error('Function not supported for Snowflake yet'); - const upQuery = this.querySeparator() + args.create_function; - let downQuery = this.querySeparator() + args.oldCreateFunction; - - await this.sqlClient.raw( - `DROP FUNCTION IF EXISTS ${args.function_declaration};`, - ); - await this.sqlClient.raw(upQuery); - - const functionCreated = await this.functionRead({ - function_name: args.function_name, - }); - - downQuery = - `DROP FUNCTION IF EXISTS ${functionCreated.data.list[0].function_declaration};` + - downQuery; - - result.data.object = { - upStatement: [{ sql: upQuery }], - downStatement: [{ sql: downQuery }], - }; - } catch (e) { - log.ppe(e, func); - throw e; - } - - log.api(`${func}: result`, result); - return result; - } - - /** - * @todo Remove the function - pg doesn't support procedure - * - * @param {Object} - args - Input arguments - * @param {String} - args.tn - * @param {String} - args.procedure_name - * @param {String} - args.event - * @param {String} - args.timing - * @returns {Object[]} - result rows - * - */ - async procedureCreate(args: any = {}) { - const func = this.procedureCreate.name; - const result = new Result(); - log.api(`${func}:args:`, args); - try { - throw new Error('Function not supported for Snowflake yet'); - const upQuery = - this.querySeparator() + - `CREATE TRIGGER \`${args.procedure_name}\` \n${args.timing} ${ - args.event - }\nON ${this.getTnPath(args.tn)} FOR EACH ROW\n${args.statement}`; - await this.sqlClient.raw(upQuery); - const downQuery = - this.querySeparator() + - `DROP PROCEDURE IF EXISTS ${args.procedure_name}`; - result.data.object = { - upStatement: [{ sql: upQuery }], - downStatement: [{ sql: downQuery }], - }; - } catch (e) { - log.ppe(e, func); - throw e; - } - - log.api(`${func}: result`, result); - return result; - } - - /** - * @todo Remove the function - pg doesn't support procedure - * - * @param {Object} - args - Input arguments - * @param {String} - args.tn - * @param {String} - args.procedure_name - * @param {String} - args.event - * @param {String} - args.timing - * @returns {Object[]} - result rows - */ - async procedureUpdate(args: any = {}) { - const func = this.procedureUpdate.name; - const result = new Result(); - log.api(`${func}:args:`, args); - try { - throw new Error('Function not supported for Snowflake yet'); - const query = - this.querySeparator() + `DROP TRIGGER ${args.procedure_name}`; - const upQuery = - this.querySeparator() + - `CREATE TRIGGER \`${args.procedure_name}\` \n${args.timing} ${ - args.event - }\nON ${this.getTnPath(args.tn)} FOR EACH ROW\n${args.statement}`; - - await this.sqlClient.raw(query); - await this.sqlClient.raw(upQuery); - - result.data.object = { - upStatement: [{ sql: upQuery }], - downStatement: [{ sql: ';' }], - }; - } catch (e) { - log.ppe(e, func); - throw e; - } - - log.api(`${func}: result`, result); - return result; - } - - /** - * - * @param {Object} - args - Input arguments - * @param {String} - args.tn - * @param {String} - args.trigger_name - * @param {String} - args.event - * @param {String} - args.timing - * @returns {Object[]} - result rows - */ - async triggerCreate(args: any = {}) { - const func = this.triggerCreate.name; - const result = new Result(); - log.api(`${func}:args:`, args); - try { - throw new Error('Function not supported for Snowflake yet'); - const upQuery = - this.querySeparator() + - `CREATE TRIGGER ${args.trigger_name} \n${args.timing} ${ - args.event - }\nON ${this.getTnPath(args.tn)} FOR EACH ROW\n${args.statement}`; - await this.sqlClient.raw(upQuery); - result.data.object = { - upStatement: [{ sql: upQuery }], - downStatement: [ - { sql: this.querySeparator() + `DROP TRIGGER ${args.trigger_name}` }, - ], - }; - } catch (e) { - log.ppe(e, func); - throw e; - } - - log.api(`${func}: result`, result); - return result; - } - - /** - * - * @param {Object} - args - Input arguments - * @param {String} - args.tn - * @param {String} - args.trigger_name - * @param {String} - args.event - * @param {String} - args.timing - * @param {String} - args.oldStatement - * @returns {Object[]} - result rows - */ - async triggerUpdate(args: any = {}) { - const func = this.triggerUpdate.name; - const result = new Result(); - log.api(`${func}:args:`, args); - try { - throw new Error('Function not supported for Snowflake yet'); - await this.sqlClient.raw( - `DROP TRIGGER ${args.trigger_name} ON ${args.tn}`, - ); - await this.sqlClient.raw( - `CREATE TRIGGER ${args.trigger_name} \n${args.timing} ${ - args.event - }\nON ${this.getTnPath(args.tn)} FOR EACH ROW\n${args.statement}`, - ); - - result.data.object = { - upStatement: - this.querySeparator() + - `DROP TRIGGER ${args.trigger_name} ON ${ - args.tn - };${this.querySeparator()}CREATE TRIGGER ${args.trigger_name} \n${ - args.timing - } ${args.event}\nON ${this.getTnPath(args.tn)} FOR EACH ROW\n${ - args.statement - }`, - downStatement: - this.querySeparator() + - `CREATE TRIGGER ${args.trigger_name} \n${args.timing} ${ - args.event - }\nON ${this.getTnPath(args.tn)} FOR EACH ROW\n${args.oldStatement}`, - }; - } catch (e) { - log.ppe(e, func); - throw e; - } - - log.api(`${func}: result`, result); - return result; - } - - /** - * - * @param {Object} - args - Input arguments - * @param {String} - args.view_name - * @param {String} - args.view_definition - * @returns {Object} - up and down statements - */ - async viewCreate(args: any = {}) { - const func = this.viewCreate.name; - const result = new Result(); - log.api(`${func}:args:`, args); - try { - const query = args.view_definition; - - await this.sqlClient.raw(query); - result.data.object = { - upStatement: [{ sql: this.querySeparator() + query }], - downStatement: [ - { sql: this.querySeparator() + `DROP VIEW "${args.view_name}"` }, - ], - }; - } catch (e) { - log.ppe(e, func); - throw e; - } - - log.api(`${func}: result`, result); - return result; - } - - /** - * - * @param {Object} - args - Input arguments - * @param {String} - args.view_name - * @param {String} - args.view_definition - * @param {String} - args.oldViewDefination - * @returns {Object} - up and down statements - */ - async viewUpdate(args: any = {}) { - const func = this.viewUpdate.name; - const result = new Result(); - log.api(`${func}:args:`, args); - try { - const query = `CREATE OR REPLACE VIEW "${args.view_name}" AS \n${args.view_definition}`; - - await this.sqlClient.raw(query); - result.data.object = { - upStatement: this.querySeparator() + query, - downStatement: - this.querySeparator() + - `CREATE VIEW "${args.view_name}" AS \n${args.oldViewDefination}`, - }; - } catch (e) { - log.ppe(e, func); - throw e; - } - - log.api(`${func}: result`, result); - return result; - } - - /** - * - * @param {Object} - args - Input arguments - * @param {String} - args.view_name - * @param {String} - args.view_definition - * @param {String} - args.oldViewDefination - * @returns {Object} - up and down statements - */ - async viewDelete(args: any = {}) { - const func = this.viewDelete.name; - const result = new Result(); - log.api(`${func}:args:`, args); - // `DROP TRIGGER ${args.view_name}` - try { - const query = `DROP VIEW ${args.view_name}`; - - await this.sqlClient.raw(query); - - result.data.object = { - upStatement: [{ sql: this.querySeparator() + query }], - downStatement: [ - { - sql: - this.querySeparator() + - `CREATE VIEW "${args.view_name}" AS \n${args.oldViewDefination}`, - }, - ], - }; - } catch (e) { - log.ppe(e, func); - throw e; - } - - log.api(`${func}: result`, result); - return result; - } - - /** - * - * @param {Object} - args - * @param {String} - args.tn - * @param {Object[]} - args.columns - * @param {String} - args.columns[].tn - * @param {String} - args.columns[].cn - * @param {String} - args.columns[].dt - * @param {String} - args.columns[].np - * @param {String} - args.columns[].ns - - * @param {String} - args.columns[].clen - - * @param {String} - args.columns[].dp - - * @param {String} - args.columns[].cop - - * @param {String} - args.columns[].pk - - * @param {String} - args.columns[].nrqd - - * @param {String} - args.columns[].not_nullable - - * @param {String} - args.columns[].ct - - * @param {String} - args.columns[].un - - * @param {String} - args.columns[].ai - - * @param {String} - args.columns[].unique - - * @param {String} - args.columns[].cdf - - * @param {String} - args.columns[].cc - - * @param {String} - args.columns[].csn - - * @param {String} - args.columns[].dtx - * - value will be 'specificType' for all cols except ai - * - for ai it will be integer, bigInteger - * - tiny, small and medium Int auto increement is not supported - * @param {String} - args.columns[].dtxp - to use in UI - * @param {String} - args.columns[].dtxs - to use in UI - * @returns {Promise<{upStatement, downStatement}>} - */ - async tableCreate(args) { - const _func = this.tableCreate.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - - try { - args.table = args.tn; - args.sqlClient = this.sqlClient; - - /**************** create table ****************/ - const upQuery = this.querySeparator() + this.createTable(args.tn, args); - await this.sqlClient.schema.raw(upQuery); - - const downStatement = - this.querySeparator() + - this.sqlClient - .raw(`DROP TABLE ??`, [this.getTnPath(args.table)]) - .toString(); - - this.emit(`Success : ${upQuery}`); - - const triggerStatements = await this.afterTableCreate(args); - - /**************** return files *************** */ - result.data.object = { - upStatement: [{ sql: upQuery }, ...triggerStatements.upStatement], - downStatement: [ - ...triggerStatements.downStatement, - { sql: downStatement }, - ], - }; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - return result; - } - - async afterTableCreate(_args) { - const result = { upStatement: [], downStatement: [] }; - return result; - } - - async afterTableUpdate(_args) { - const result = { upStatement: [], downStatement: [] }; - return result; - } - - /** - * - * @param {Object} - args - * @param {String} - args.table - * @param {String} - args.table - * @param {Object[]} - args.columns - * @param {String} - args.columns[].tn - * @param {String} - args.columns[].cn - * @param {String} - args.columns[].dt - * @param {String} - args.columns[].np - * @param {String} - args.columns[].ns - - * @param {String} - args.columns[].clen - - * @param {String} - args.columns[].dp - - * @param {String} - args.columns[].cop - - * @param {String} - args.columns[].pk - - * @param {String} - args.columns[].nrqd - - * @param {String} - args.columns[].not_nullable - - * @param {String} - args.columns[].ct - - * @param {String} - args.columns[].un - - * @param {String} - args.columns[].ai - - * @param {String} - args.columns[].unique - - * @param {String} - args.columns[].cdf - - * @param {String} - args.columns[].cc - - * @param {String} - args.columns[].csn - - * @param {Number} - args.columns[].altered - 1,2,4 = addition,edited,deleted - * @returns {Promise<{upStatement, downStatement}>} - */ - async tableUpdate(args) { - const _func = this.tableUpdate.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - - try { - args.table = args.tn; - const originalColumns = args.originalColumns; - args.connectionConfig = this._connectionConfig; - args.sqlClient = this.sqlClient; - - let upQuery = ''; - let downQuery = ''; - - for (let i = 0; i < args.columns.length; ++i) { - const oldColumn = find(originalColumns, { - cn: args.columns[i].cno, - }); - - if (args.columns[i].altered & 4) { - // col remove - upQuery += this.alterTableRemoveColumn( - args.table, - args.columns[i], - oldColumn, - upQuery, - ); - downQuery += this.alterTableAddColumn( - args.table, - oldColumn, - args.columns[i], - downQuery, - ); - } else if (args.columns[i].altered & 2 || args.columns[i].altered & 8) { - // col edit - upQuery += this.alterTableChangeColumn( - args.table, - args.columns[i], - oldColumn, - upQuery, - ); - downQuery += this.alterTableChangeColumn( - args.table, - oldColumn, - args.columns[i], - downQuery, - ); - } else if (args.columns[i].altered & 1) { - // col addition - upQuery += this.alterTableAddColumn( - args.table, - args.columns[i], - oldColumn, - upQuery, - ); - downQuery += this.alterTableRemoveColumn( - args.table, - args.columns[i], - oldColumn, - downQuery, - ); - } - } - - upQuery += - (upQuery ? ';' : '') + - this.alterTablePK( - args.table, - args.columns, - args.originalColumns, - upQuery, - ); - downQuery += - (downQuery ? ';' : '') + - this.alterTablePK( - args.table, - args.originalColumns, - args.columns, - downQuery, - ); - - if (upQuery) { - //upQuery = `ALTER TABLE "${args.columns[0].tn}" ${upQuery};`; - //downQuery = `ALTER TABLE "${args.columns[0].tn}" ${downQuery};`; - } - - for (const q of upQuery.split(';')) { - if (q && q.trim() !== '') { - await this.sqlClient.raw(q); - } - } - - // console.log(upQuery); - - const afterUpdate = await this.afterTableUpdate(args); - - result.data.object = { - upStatement: [ - { sql: this.querySeparator() + upQuery }, - ...afterUpdate.upStatement, - ], - downStatement: [ - ...afterUpdate.downStatement, - { sql: this.querySeparator() + downQuery }, - ], - }; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - return result; - } - - /** - * - * @param {Object} - args - * @param args.tn - * @returns {Promise<{upStatement, downStatement}>} - */ - async tableDelete(args) { - const _func = this.tableDelete.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - try { - // const { columns } = args; - args.sqlClient = this.sqlClient; - - /** ************** create up & down statements *************** */ - const upStatement = - this.querySeparator() + - this.sqlClient - .raw(`DROP TABLE ??`, [this.getTnPath(args.tn)]) - .toString(); - let downQuery = this.createTable(args.tn, args); - - /** - - columnList - relationList - indexesList - createAggregatedIndexes - filterOutPkAndFk - - downQuery - create table - via columnList - we are doing this - + create fks - via relationList - + create indexes - slightly tricky - - */ - - let relationsList: any = await this.relationList(args); - - relationsList = relationsList.data.list; - - for (const relation of relationsList) { - const downQb = this.sqlClient.schema.table( - relation.tn, - function (table) { - table = table - .foreign(relation.cn, null) - .references(relation.rcn) - .on(relation.rtn); - - if (relation.ur) { - table = table.onUpdate(relation.ur); - } - if (relation.dr) { - table.onDelete(relation.dr); - } - }, - ); - await downQb; - downQuery += this.querySeparator() + downQb.toQuery(); - } - - let indexList: any = await this.indexList(args); - - indexList = indexList.data.list.filter( - ({ cst }) => cst !== 'p' && cst !== 'f', - ); - - const indexesMap: { [key: string]: any } = {}; - - for (const { key_name, non_unique, cn } of indexList) { - if (!(key_name in indexesMap)) { - indexesMap[key_name] = { - tn: args.tn, - indexName: key_name, - non_unique, - columns: [], - }; - } - indexesMap[key_name].columns.push(cn); - } - - for (const { non_unique, tn, columns, indexName } of Object.values( - indexesMap, - )) { - downQuery += - this.querySeparator() + - this.sqlClient.schema - .table(tn, function (table) { - if (non_unique) { - table.index(columns, indexName); - } else { - table.unique(columns, indexName); - } - }) - .toQuery(); - } - - this.emit(`Success : ${upStatement}`); - - /** ************** drop tn *************** */ - await this.sqlClient.raw(`DROP TABLE ??`, [this.getTnPath(args.tn)]); - - /** ************** return files *************** */ - result.data.object = { - upStatement: [{ sql: upStatement }], - downStatement: [{ sql: this.querySeparator() + downQuery }], - }; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - return result; - } - - /** - * - * @param {Object} - args - * @param {String} - args.parentTable - * @param {String} - args.parentColumn - * @param {String} - args.childColumn - * @param {String} - args.childTable - * @returns {Promise<{upStatement, downStatement}>} - */ - async relationCreate(args) { - const _func = this.relationCreate.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - - const foreignKeyName = args.foreignKeyName || null; - - try { - await this.sqlClient.schema.table(args.childTable, (table) => { - table = table - .foreign(args.childColumn, foreignKeyName) - .references(args.parentColumn) - .on(this.getTnPath(args.parentTable)); - - if (args.onUpdate) { - table = table.onUpdate(args.onUpdate); - } - if (args.onDelete) { - table.onDelete(args.onDelete); - } - }); - - const upQb = this.sqlClient.schema.table(args.childTable, (table) => { - table = table - .foreign(args.childColumn, foreignKeyName) - .references(args.parentColumn) - .on(this.getTnPath(args.parentTable)); - - if (args.onUpdate) { - table = table.onUpdate(args.onUpdate); - } - if (args.onDelete) { - table.onDelete(args.onDelete); - } - }); - - await upQb; - - const upStatement = this.querySeparator() + upQb.toQuery(); - - this.emit(`Success : ${upStatement}`); - - const downStatement = - this.querySeparator() + - this.sqlClient.schema - .table(args.childTable, (table) => { - table.dropForeign(args.childColumn, foreignKeyName); - }) - .toQuery(); - - // let files = this.evolutionFilesCreate(args, upStatement, downStatement); - // - // // create a migration file - // //let files = this.evolutionForCreateRel(args); - // - // await this.sqlClient('xc_evolutions').insert({ - // title: files.up, - // titleDown: files.down, - // description: '', - // status: 0 - // //created: Date.now() - // }) - - result.data.object = { - upStatement: [{ sql: upStatement }], - downStatement: [{ sql: downStatement }], - }; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - return result; - } - - /** - * - * @param {Object} - args - * @param {String} - args.parentTable - * @param {String} - args.parentColumn - * @param {String} - args.childColumn - * @param {String} - args.childTable - * @param {String} - args.foreignKeyName - * @returns {Promise<{upStatement, downStatement}>} - */ - async relationDelete(args) { - const _func = this.relationDelete.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - - const foreignKeyName = args.foreignKeyName || null; - - try { - // const self = this; - - await this.sqlClient.schema.table(args.childTable, function (table) { - table.dropForeign(args.childColumn, foreignKeyName); - }); - - const upStatement = - this.querySeparator() + - this.sqlClient.schema - .table(args.childTable, function (table) { - table.dropForeign(args.childColumn, foreignKeyName); - }) - .toQuery(); - - const downStatement = - this.querySeparator() + - (await this.sqlClient.schema - .table(args.childTable, (table) => { - table - .foreign(args.childColumn, foreignKeyName) - .references(args.parentColumn) - .on(this.getTnPath(args.parentTable)); - }) - .toQuery()); - - // let files = this.evolutionFilesCreate(args, upStatement, downStatement); - // - // // create a migration file - // //let files = this.evolutionForCreateRel(args); - // - // await this.sqlClient('xc_evolutions').insert({ - // title: files.up, - // titleDown: files.down, - // description: '', - // status: 0 - // //created: Date.now() - // }) - - result.data.object = { - upStatement: [{ sql: upStatement }], - downStatement: [{ sql: downStatement }], - }; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - return result; - } - - /** - * - * @param args - * @param args.tn - * @returns {Object} Result - * @returns {String} result.data - */ - async tableCreateStatement(args) { - const _func = this.tableCreateStatement.name; - let result = new Result(); - log.api(`${_func}:args:`, args); - try { - result = await this.columnList(args); - const upQuery = this.createTable(args.tn, { - tn: args.tn, - columns: result.data.list, - }); - result.data = upQuery; - } catch (e) { - log.ppe(e, _func); - throw e; - } - - return result; - } - - /** - * - * @param args - * @param args.tn - * @returns {Object} Result - * @returns {String} result.data - */ - async tableInsertStatement(args) { - const _func = this.tableInsertStatement.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - try { - result.data = `INSERT INTO ?? (`; - let values = ' VALUES ('; - const response = await this.columnList(args); - if (response.data && response.data.list) { - for (let i = 0; i < response.data.list.length; ++i) { - if (!i) { - result.data += `\n"${response.data.list[i].cn}"\n\t`; - values += `\n<${response.data.list[i].cn}>\n\t`; - } else { - result.data += `, \`"${response.data.list[i].cn}"\`\n\t`; - values += `, <${response.data.list[i].cn}>\n\t`; - } - } - } - - result.data += `)`; - values += `);`; - result.data += values; - result.data = this.genQuery(result.data, [this.getTnPath(args.tn)]); - } catch (e) { - log.ppe(e, _func); - throw e; - } - - return result; - } - - /** - * - * @param args - * @param args.tn - * @returns {Object} Result - * @returns {String} result.data - */ - async tableUpdateStatement(args) { - const _func = this.tableUpdateStatement.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - - try { - result.data = `UPDATE ?? \nSET\n`; - const response = await this.columnList(args); - if (response.data && response.data.list) { - for (let i = 0; i < response.data.list.length; ++i) { - if (!i) { - result.data += `"${response.data.list[i].cn}" = <\`${response.data.list[i].cn}\`>\n\t`; - } else { - result.data += `,"${response.data.list[i].cn}" = <\`${response.data.list[i].cn}\`>\n\t`; - } - } - } - - result.data += ';'; - result.data = this.genQuery(result.data, [this.getTnPath(args.tn)]); - } catch (e) { - log.ppe(e, _func); - throw e; - } - - return result; - } - - /** - * - * @param args - * @param args.tn - * @returns {Object} Result - * @returns {String} result.data - */ - async tableDeleteStatement(args) { - const _func = this.tableDeleteStatement.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - try { - result.data = `DELETE FROM ?? where ;`; - result.data = this.genQuery(result.data, [this.getTnPath(args.tn)]); - } catch (e) { - log.ppe(e, _func); - throw e; - } - - return result; - } - - /** - * - * @param args - * @param args.tn - * @returns {Object} Result - * @returns {String} result.data - */ - async tableTruncateStatement(args) { - const _func = this.tableTruncateStatement.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - try { - result.data = `TRUNCATE TABLE ??`; - result.data = this.genQuery(result.data, [this.getTnPath(args.tn)]); - } catch (e) { - log.ppe(e, _func); - throw e; - } - - return result; - } - - /** - * - * @param args - * @param args.tn - * @returns {Object} Result - * @returns {String} result.data - */ - async tableSelectStatement(args) { - const _func = this.tableSelectStatement.name; - const result = new Result(); - log.api(`${_func}:args:`, args); - - try { - result.data = `SELECT `; - const response = await this.columnList(args); - if (response.data && response.data.list) { - for (let i = 0; i < response.data.list.length; ++i) { - if (!i) { - result.data += `"${response.data.list[i].cn}"\n\t`; - } else { - result.data += `, "${response.data.list[i].cn}"\n\t`; - } - } - } - - result.data += ` FROM ??;`; - result.data = this.genQuery(result.data, [this.getTnPath(args.tn)]); - } catch (e) { - log.ppe(e, _func); - throw e; - } - - return result; - } - - alterTablePK(t, n, o, _existingQuery, createTable = false) { - const numOfPksInOriginal = []; - const numOfPksInNew = []; - let pksChanged = 0; - - for (let i = 0; i < n.length; ++i) { - if (n[i].pk) { - if (n[i].altered !== 4) numOfPksInNew.push(n[i].cn); - } - } - - for (let i = 0; i < o.length; ++i) { - if (o[i].pk) { - numOfPksInOriginal.push(o[i].cn); - } - } - - if (numOfPksInNew.length === numOfPksInOriginal.length) { - for (let i = 0; i < numOfPksInNew.length; ++i) { - if (numOfPksInOriginal[i] !== numOfPksInNew[i]) { - pksChanged = 1; - break; - } - } - } else { - pksChanged = numOfPksInNew.length - numOfPksInOriginal.length; - } - - let query = ''; - if (!numOfPksInNew.length && !numOfPksInOriginal.length) { - // do nothing - } else if (pksChanged) { - query += numOfPksInOriginal.length - ? this.genQuery(`alter TABLE ?? drop constraint IF EXISTS ??;`, [ - t, - `${t}_pkey`, - ]) - : ''; - if (numOfPksInNew.length) { - if (createTable) { - query += this.genQuery(`, constraint ?? PRIMARY KEY (??)`, [ - `${t}_pkey`, - numOfPksInNew, - ]); - } else { - query += this.genQuery( - `alter TABLE ?? add constraint ?? PRIMARY KEY(??);`, - [t, `${t}_pkey`, numOfPksInNew], - ); - } - } - } - - return query; - } - - alterTableRemoveColumn(t, n, _o, existingQuery) { - const shouldSanitize = true; - let query = existingQuery ? ',' : ''; - query += this.genQuery( - `ALTER TABLE ?? DROP COLUMN ??`, - [this.getTnPath(t), n.cn], - shouldSanitize, - ); - return query; - } - - createTableColumn(t, n, o, existingQuery) { - return this.alterTableColumn(t, n, o, existingQuery, 0); - } - - alterTableAddColumn(t, n, o, existingQuery) { - return this.alterTableColumn(t, n, o, existingQuery, 1); - } - - alterTableChangeColumn(t, n, o, existingQuery) { - return this.alterTableColumn(t, n, o, existingQuery, 2); - } - - createTable(table, args) { - let query = ''; - - for (let i = 0; i < args.columns.length; ++i) { - query += this.createTableColumn(table, args.columns[i], null, query); - } - - query += this.alterTablePK(table, args.columns, [], query, true); - - query = this.genQuery(`CREATE TABLE ?? (${query});`, [ - this.getTnPath(args.tn), - ]); - - return query; - } - - alterTableColumn(t, n, o, existingQuery, change = 2) { - let query = ''; - - const defaultValue = this.sanitiseDefaultValue(n); - const shouldSanitize = true; - - if (change === 0) { - query = existingQuery ? ',' : ''; - if (n.ai) { - query += this.genQuery( - ` ?? NUMBER(38,0) NOT NULL autoincrement UNIQUE`, - [n.cn], - shouldSanitize, - ); - } else { - query += this.genQuery( - ` ?? ${this.sanitiseDataType(n.dt)}`, - [n.cn], - shouldSanitize, - ); - query += n.dtxp && n.dt !== 'text' ? `(${n.dtxp})` : ''; - query += n.rqd ? ' NOT NULL' : ' NULL'; - query += defaultValue ? ` DEFAULT ${defaultValue}` : ''; - } - } else if (change === 1) { - query += this.genQuery( - ` ADD ?? ${this.sanitiseDataType(n.dt)}`, - [n.cn], - shouldSanitize, - ); - query += n.dtxp && n.dt !== 'text' ? `(${n.dtxp})` : ''; - query += n.rqd ? ' NOT NULL' : ' NULL'; - query += defaultValue ? ` DEFAULT ${defaultValue}` : ''; - query = this.genQuery( - `ALTER TABLE ?? ${query};`, - [this.getTnPath(t)], - shouldSanitize, - ); - } else { - if (n.cn !== o.cn) { - query += this.genQuery( - `\nALTER TABLE ?? RENAME COLUMN ?? TO ?? ;\n`, - [this.getTnPath(t), o.cn, n.cn], - shouldSanitize, - ); - } - - if (n.dt !== o.dt) { - query += this.genQuery( - `\nALTER TABLE ?? ALTER COLUMN ?? SET DATA TYPE ${this.sanitiseDataType( - n.dt, - )}`, - [this.getTnPath(t), n.cn], - shouldSanitize, - ); - query += n.dtxp && n.dt !== 'text' ? `(${n.dtxp});\n` : ';\n'; - } - - if (n.rqd !== o.rqd) { - query += this.genQuery( - `\nALTER TABLE ?? ALTER COLUMN ?? `, - [this.getTnPath(t), n.cn], - shouldSanitize, - ); - query += n.rqd ? ` SET NOT NULL;\n` : ` DROP NOT NULL;\n`; - } - - if (n.cdf !== o.cdf) { - query += this.genQuery( - `\nALTER TABLE ?? ALTER COLUMN ?? `, - [this.getTnPath(t), n.cn], - shouldSanitize, - ); - query += n.cdf - ? ` SET DEFAULT ${this.sanitiseDefaultValue(n.cdf)};\n` - : ` DROP DEFAULT;\n`; - } - } - return query; - } - - get schema() { - return this.connectionConfig && this.connectionConfig.connection.schema; - } - - get database() { - return this.connectionConfig && this.connectionConfig.connection.database; - } - - getTnPath(t) { - return `${this.database}.${this.schema}.${t}`; - } - - /** - * - * @param {Object} args - * @returns {Object} result - * @returns {Number} code - * @returns {String} message - */ - async totalRecords(args: any = {}) { - const func = this.totalRecords.name; - const result = new Result(); - log.api(`${func}:args:`, args); - - try { - const data = await this.sqlClient.raw( - `SELECT SUM(record_count) as "TotalRecords" FROM - (SELECT t.table_schema || '.' || t.table_name as "table_name",t.row_count as record_count - FROM "${this.database}".information_schema.tables t - WHERE t.table_type = 'BASE TABLE and table_schema = ?' - )`, - [this.schema], - ); - result.data = data.rows[0]; - } catch (e) { - result.code = -1; - result.message = e.message; - result.object = e; - } finally { - log.api(`${func} :result: ${result}`); - } - return result; - } - - // Todo: error handling - async insert(args) { - const { tn, data } = args; - const res = await this.sqlClient(tn).insert(data); - log.debug(res); - return res; - } - - async update(args) { - const { tn, data, whereConditions } = args; - const res = await this.sqlClient(tn).where(whereConditions).update(data); - return res; - } - - async delete(args) { - const { tn, whereConditions } = args; - const res = await this.sqlClient(tn).where(whereConditions).del(); - log.debug(res); - return res; - } -} - -export default SnowflakeClient; diff --git a/packages/nocodb/src/db/sql-client/lib/snowflake/snowflake.queries.ts b/packages/nocodb/src/db/sql-client/lib/snowflake/snowflake.queries.ts deleted file mode 100644 index 0cf8d6a46e..0000000000 --- a/packages/nocodb/src/db/sql-client/lib/snowflake/snowflake.queries.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Snowflake queries - -const sfQueries = {}; - -export default sfQueries; diff --git a/packages/nocodb/src/db/sql-client/lib/sqlite/SqliteClient.ts b/packages/nocodb/src/db/sql-client/lib/sqlite/SqliteClient.ts index d2c2bf2341..ccbdca0c90 100644 --- a/packages/nocodb/src/db/sql-client/lib/sqlite/SqliteClient.ts +++ b/packages/nocodb/src/db/sql-client/lib/sqlite/SqliteClient.ts @@ -15,9 +15,6 @@ const nanoid = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz_', 6); const log = new Debug('SqliteClient'); class SqliteClient extends KnexClient { - private queries: any; - private _version: any; - constructor(connectionConfig) { // sqlite does not support inserting default values and knex fires a warning without this flag connectionConfig.connection.useNullAsDefault = true; diff --git a/packages/nocodb/src/db/sql-mgr/SqlMgr.ts b/packages/nocodb/src/db/sql-mgr/SqlMgr.ts index bd0365b840..f3c3a5b6d3 100644 --- a/packages/nocodb/src/db/sql-mgr/SqlMgr.ts +++ b/packages/nocodb/src/db/sql-mgr/SqlMgr.ts @@ -12,7 +12,6 @@ import type MssqlClient from '~/db/sql-client/lib/mssql/MssqlClient'; import type MysqlClient from '~/db/sql-client/lib/mysql/MysqlClient'; import type OracleClient from '~/db/sql-client/lib/oracle/OracleClient'; import type PGClient from '~/db/sql-client/lib/pg/PgClient'; -import type SnowflakeClient from '~/db/sql-client/lib/snowflake/SnowflakeClient'; import type SqliteClient from '~/db/sql-client/lib/sqlite/SqliteClient'; import Result from '~/db/util/Result'; import Debug from '~/db/util/Debug'; @@ -344,12 +343,7 @@ export default class SqlMgr { public async baseGetSqlClient( args, ): Promise< - | SnowflakeClient - | MysqlClient - | SqliteClient - | MssqlClient - | OracleClient - | PGClient + MysqlClient | SqliteClient | MssqlClient | OracleClient | PGClient > { const func = this.baseGetSqlClient.name; log.api(`${func}:args:`, args); diff --git a/packages/nocodb/src/db/sql-mgr/v2/SqlMgrv2.ts b/packages/nocodb/src/db/sql-mgr/v2/SqlMgrv2.ts index 3125c0e1ac..9c0232c275 100644 --- a/packages/nocodb/src/db/sql-mgr/v2/SqlMgrv2.ts +++ b/packages/nocodb/src/db/sql-mgr/v2/SqlMgrv2.ts @@ -1,11 +1,11 @@ // import debug from 'debug'; // import {XKnex} from "../sql-data-mapper"; -import SqlClientFactory from '../../sql-client/lib/SqlClientFactory'; -import KnexMigratorv2 from '../../sql-migrator/lib/KnexMigratorv2'; -import Debug from '../../util/Debug'; import type { MetaService } from '~/meta/meta.service'; import type Source from '~/models/Source'; +import SqlClientFactory from '~/db/sql-client/lib/SqlClientFactory'; +import KnexMigratorv2 from '~/db/sql-migrator/lib/KnexMigratorv2'; +import Debug from '~/db/util/Debug'; import NcConnectionMgrv2 from '~/utils/common/NcConnectionMgrv2'; const log = new Debug('SqlMgr'); diff --git a/packages/nocodb/src/db/sql-migrator/lib/KnexMigrator.ts b/packages/nocodb/src/db/sql-migrator/lib/KnexMigrator.ts index c3ed970503..2e9eb477d6 100644 --- a/packages/nocodb/src/db/sql-migrator/lib/KnexMigrator.ts +++ b/packages/nocodb/src/db/sql-migrator/lib/KnexMigrator.ts @@ -5,12 +5,12 @@ import glob from 'glob'; import Handlebars from 'handlebars'; import mkdirp from 'mkdirp'; import rmdir from 'rmdir'; -import SqlClientFactory from '../../sql-client/lib/SqlClientFactory'; -import Debug from '../../util/Debug'; -import Emit from '../../util/emit'; -import Result from '../../util/Result'; -import * as fileHelp from '../../util/file.help'; -import SqlMigrator from './SqlMigrator'; +import SqlClientFactory from '~/db/sql-client/lib/SqlClientFactory'; +import Debug from '~/db/util/Debug'; +import Emit from '~/db/util/emit'; +import Result from '~/db/util/Result'; +import * as fileHelp from '~/db/util/file.help'; +import SqlMigrator from '~/db/sql-migrator/lib/SqlMigrator'; import { getToolDir, NcConfig } from '~/utils/nc-config'; const evt = new Emit(); diff --git a/packages/nocodb/src/db/sql-migrator/lib/KnexMigratorv2Tans.ts b/packages/nocodb/src/db/sql-migrator/lib/KnexMigratorv2Tans.ts index 32e4592317..6e62bfea00 100644 --- a/packages/nocodb/src/db/sql-migrator/lib/KnexMigratorv2Tans.ts +++ b/packages/nocodb/src/db/sql-migrator/lib/KnexMigratorv2Tans.ts @@ -11,7 +11,6 @@ import type MssqlClient from '~/db/sql-client/lib/mssql/MssqlClient'; import type MysqlClient from '~/db/sql-client/lib/mysql/MysqlClient'; import type OracleClient from '~/db/sql-client/lib/oracle/OracleClient'; import type PGClient from '~/db/sql-client/lib/pg/PgClient'; -import type SnowflakeClient from '~/db/sql-client/lib/snowflake/SnowflakeClient'; import type SqliteClient from '~/db/sql-client/lib/sqlite/SqliteClient'; import Noco from '~/Noco'; import NcConnectionMgrv2 from '~/utils/common/NcConnectionMgrv2'; @@ -33,12 +32,7 @@ export default class KnexMigratorv2Tans extends KnexMigratorv2 { protected async getSqlClient( source: Source, ): Promise< - | SnowflakeClient - | MysqlClient - | SqliteClient - | MssqlClient - | OracleClient - | PGClient + MysqlClient | SqliteClient | MssqlClient | OracleClient | PGClient > { return this.sqlClient || NcConnectionMgrv2.getSqlClient(source); } diff --git a/packages/nocodb/src/services/columns.service.ts b/packages/nocodb/src/services/columns.service.ts index f6b1762503..b896d90904 100644 --- a/packages/nocodb/src/services/columns.service.ts +++ b/packages/nocodb/src/services/columns.service.ts @@ -2592,7 +2592,7 @@ export class ColumnsService { (param.column as LinkToAnotherColumnReqType).type === 'bt'; // if xcdb base then treat as virtual relation to avoid creating foreign key - if (param.source.isMeta()) { + if (param.source.isMeta() || param.source.type === 'snowflake') { (param.column as LinkToAnotherColumnReqType).virtual = true; } @@ -3004,6 +3004,8 @@ export class ColumnsService { indexName?: string; nonUnique?: boolean; }) { + // TODO: implement for snowflake (right now create index does not work with identifier quoting in snowflake - bug?) + if (source.type === 'snowflake') return; const model = await column.getModel(); const indexArgs = { columns: [column.column_name],