postgre analyser supports compisite db names

This commit is contained in:
Jan Prochazka 2024-09-19 14:15:22 +02:00
parent f39ec26c29
commit 4ea6595ca7
27 changed files with 72 additions and 18 deletions

View File

@ -1,7 +1,7 @@
const stableStringify = require('json-stable-stringify'); const stableStringify = require('json-stable-stringify');
const _ = require('lodash'); const _ = require('lodash');
const fp = require('lodash/fp'); const fp = require('lodash/fp');
const { testWrapper } = require('../tools'); const { testWrapper, extractConnection } = require('../tools');
const engines = require('../engines'); const engines = require('../engines');
const { runCommandOnDriver } = require('dbgate-tools'); const { runCommandOnDriver } = require('dbgate-tools');
@ -54,6 +54,25 @@ describe('Schema tests', () => {
expect(structure2).toBeNull(); expect(structure2).toBeNull();
}) })
); );
test.each(engines.filter(x => x.supportSchemas).map(engine => [engine.label, engine]))(
'Table inside schema - %s',
testWrapper(async (conn, driver, engine) => {
await baseStructure(conn, driver);
await runCommandOnDriver(conn, driver, dmp => dmp.createSchema('myschema'));
const schemaConnDef = {
...extractConnection(engine),
database: `${conn._database_name}::myschema`,
};
const schemaConn = await driver.connect(schemaConnDef);
await driver.query(schemaConn, `create table myschema.myt1 (id int not null primary key)`);
const structure1 = await driver.analyseFull(schemaConn);
expect(structure1.tables.length).toEqual(1);
expect(structure1.tables[0].tableName).toEqual('myt1');
})
);
}); });
describe('Base analyser test', () => { describe('Base analyser test', () => {

View File

@ -13,3 +13,16 @@ export function findDefaultSchema(schemaList: SchemaInfo[], dialect: SqlDialect)
} }
return schemaList[0]?.schemaName; return schemaList[0]?.schemaName;
} }
export function isCompositeDbName(name: string) {
return name?.includes('::');
}
export function splitCompositeDbName(name: string) {
const [database, schema] = name.split('::');
return { database, schema };
}
export function extractDbNameFromComposite(name: string) {
return isCompositeDbName(name) ? splitCompositeDbName(name).database : name;
}

View File

@ -1,4 +1,4 @@
const { DatabaseAnalyser } = require('dbgate-tools'); const { DatabaseAnalyser } = global.DBGATE_PACKAGES['dbgate-tools'];
const sql = require('./sql'); const sql = require('./sql');
function extractDataType(dataType) { function extractDataType(dataType) {

View File

@ -5,6 +5,7 @@ const Analyser = require('./Analyser');
const { createClient } = require('@clickhouse/client'); const { createClient } = require('@clickhouse/client');
const createBulkInsertStream = require('./createBulkInsertStream'); const createBulkInsertStream = require('./createBulkInsertStream');
/** @type {import('dbgate-types').EngineDriver} */ /** @type {import('dbgate-types').EngineDriver} */
const driver = { const driver = {
...driverBase, ...driverBase,
@ -15,7 +16,7 @@ const driver = {
url: databaseUrl, url: databaseUrl,
username: user, username: user,
password: password, password: password,
database: database, database,
}); });
client._database_name = database; client._database_name = database;

View File

@ -81,7 +81,6 @@ const driver = {
await pool.connect(); await pool.connect();
// const pool = await MongoClient.connect(mongoUrl); // const pool = await MongoClient.connect(mongoUrl);
pool.__getDatabase = database ? () => pool.db(database) : () => pool.db(); pool.__getDatabase = database ? () => pool.db(database) : () => pool.db();
pool.__databaseName = database;
return pool; return pool;
}, },
// @ts-ignore // @ts-ignore

View File

@ -79,11 +79,16 @@ const driver = {
async connect(conn) { async connect(conn) {
const { authType } = conn; const { authType } = conn;
if (requireMsnodesqlv8 && (authType == 'sspi' || authType == 'sql')) { const result =
return nativeConnect(conn); requireMsnodesqlv8 && (authType == 'sspi' || authType == 'sql')
? await nativeConnect(conn)
: await tediousConnect(conn);
if (result) {
result._database_name = conn.database;
} }
return tediousConnect(conn); return result;
}, },
async close(pool) { async close(pool) {
return pool.close(); return pool.close();

View File

@ -2,7 +2,8 @@ const fp = require('lodash/fp');
const _ = require('lodash'); const _ = require('lodash');
const sql = require('./sql'); const sql = require('./sql');
const { DatabaseAnalyser, isTypeString, isTypeNumeric } = global.DBGATE_PACKAGES['dbgate-tools']; const { DatabaseAnalyser, isTypeString, isTypeNumeric, isCompositeDbName, splitCompositeDbName } =
global.DBGATE_PACKAGES['dbgate-tools'];
function normalizeTypeName(dataType) { function normalizeTypeName(dataType) {
if (dataType == 'character varying') return 'varchar'; if (dataType == 'character varying') return 'varchar';
@ -56,7 +57,12 @@ class Analyser extends DatabaseAnalyser {
createQuery(resFileName, typeFields, replacements = {}) { createQuery(resFileName, typeFields, replacements = {}) {
const query = super.createQuery(sql[resFileName], typeFields, replacements); const query = super.createQuery(sql[resFileName], typeFields, replacements);
return query; const dbname = this.pool._database_name;
const schemaCondition = isCompositeDbName(dbname)
? `= '${splitCompositeDbName(dbname).schema}' `
: ' IS NOT NULL ';
return query.replace(/=SCHEMA_NAME_CONDITION/g, schemaCondition);
} }
async _computeSingleObjectId() { async _computeSingleObjectId() {

View File

@ -89,6 +89,7 @@ const drivers = driverBases.map(driverBase => ({
await this.query(client, 'SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY'); await this.query(client, 'SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY');
} }
client._database_name = database;
return client; return client;
}, },
async close(pool) { async close(pool) {

View File

@ -20,5 +20,6 @@ where
or or
('views:' || table_schema || '.' || table_name) =OBJECT_ID_CONDITION ('views:' || table_schema || '.' || table_name) =OBJECT_ID_CONDITION
) )
and table_schema =SCHEMA_NAME_CONDITION
order by ordinal_position order by ordinal_position
`; `;

View File

@ -7,5 +7,5 @@ select
basecol.table_name, basecol.table_name,
basecol.ordinal_position basecol.ordinal_position
from information_schema.key_column_usage basecol from information_schema.key_column_usage basecol
where ('tables:' || basecol.table_schema || '.' || basecol.table_name) =OBJECT_ID_CONDITION where ('tables:' || basecol.table_schema || '.' || basecol.table_name) =OBJECT_ID_CONDITION and basecol.table_schema =SCHEMA_NAME_CONDITION
`; `;

View File

@ -7,4 +7,5 @@ select
fk.unique_constraint_name as "unique_constraint_name", fk.unique_constraint_name as "unique_constraint_name",
fk.unique_constraint_schema as "unique_constraint_schema" fk.unique_constraint_schema as "unique_constraint_schema"
from information_schema.referential_constraints fk from information_schema.referential_constraints fk
where fk.constraint_schema =SCHEMA_NAME_CONDITION
`; `;

View File

@ -5,5 +5,5 @@ select
base.constraint_name as "constraint_name", base.constraint_name as "constraint_name",
base.constraint_schema as "constraint_schema" base.constraint_schema as "constraint_schema"
from information_schema.table_constraints base from information_schema.table_constraints base
where ('tables:' || base.table_schema || '.' || base.table_name) =OBJECT_ID_CONDITION where ('tables:' || base.table_schema || '.' || base.table_name) =OBJECT_ID_CONDITION and base.table_schema =SCHEMA_NAME_CONDITION
`; `;

View File

@ -4,5 +4,5 @@ select
f_table_name as "pure_name", f_table_name as "pure_name",
f_geography_column as "column_name" f_geography_column as "column_name"
from public.geography_columns from public.geography_columns
where ('tables:' || f_table_schema || '.' || f_table_name) =OBJECT_ID_CONDITION where ('tables:' || f_table_schema || '.' || f_table_name) =OBJECT_ID_CONDITION and f_table_schema =SCHEMA_NAME_CONDITION
`; `;

View File

@ -4,5 +4,5 @@ select
f_table_name as "pure_name", f_table_name as "pure_name",
f_geometry_column as "column_name" f_geometry_column as "column_name"
from public.geometry_columns from public.geometry_columns
where ('tables:' || f_table_schema || '.' || f_table_name) =OBJECT_ID_CONDITION where ('tables:' || f_table_schema || '.' || f_table_name) =OBJECT_ID_CONDITION and f_table_schema =SCHEMA_NAME_CONDITION
`; `;

View File

@ -19,6 +19,7 @@ module.exports = `
and t.relnamespace = c.oid and t.relnamespace = c.oid
and c.nspname != 'pg_catalog' and c.nspname != 'pg_catalog'
and ('tables:' || c.nspname || '.' || t.relname) =OBJECT_ID_CONDITION and ('tables:' || c.nspname || '.' || t.relname) =OBJECT_ID_CONDITION
and c.nspname =SCHEMA_NAME_CONDITION
order by order by
t.relname t.relname
`; `;

View File

@ -21,6 +21,7 @@ module.exports = `
and t.relnamespace = c.oid and t.relnamespace = c.oid
and c.nspname != 'pg_catalog' and c.nspname != 'pg_catalog'
and ('tables:' || c.nspname || '.' || t.relname) =OBJECT_ID_CONDITION and ('tables:' || c.nspname || '.' || t.relname) =OBJECT_ID_CONDITION
and c.nspname =SCHEMA_NAME_CONDITION
order by order by
t.relname t.relname
`; `;

View File

@ -12,6 +12,7 @@ FROM pg_catalog.pg_class
WHERE pg_class.relkind = 'm' WHERE pg_class.relkind = 'm'
AND pg_attribute.attnum >= 1 AND pg_attribute.attnum >= 1
AND ('matviews:' || pg_namespace.nspname || '.' || pg_class.relname) =OBJECT_ID_CONDITION AND ('matviews:' || pg_namespace.nspname || '.' || pg_class.relname) =OBJECT_ID_CONDITION
AND pg_namespace.nspname =SCHEMA_NAME_CONDITION
ORDER BY pg_attribute.attnum ORDER BY pg_attribute.attnum
`; `;

View File

@ -4,5 +4,5 @@ select
schemaname as "schema_name", schemaname as "schema_name",
md5(definition) as "hash_code" md5(definition) as "hash_code"
from from
pg_catalog.pg_matviews WHERE schemaname NOT LIKE 'pg_%' pg_catalog.pg_matviews WHERE schemaname NOT LIKE 'pg_%' AND schemaname =SCHEMA_NAME_CONDITION
`; `;

View File

@ -7,4 +7,5 @@ select
from from
pg_catalog.pg_matviews WHERE schemaname NOT LIKE 'pg_%' pg_catalog.pg_matviews WHERE schemaname NOT LIKE 'pg_%'
and ('matviews:' || schemaname || '.' || matviewname) =OBJECT_ID_CONDITION and ('matviews:' || schemaname || '.' || matviewname) =OBJECT_ID_CONDITION
and schemaname =SCHEMA_NAME_CONDITION
`; `;

View File

@ -14,5 +14,6 @@ where
and table_constraints.table_schema !~ '^_timescaledb_' and table_constraints.table_schema !~ '^_timescaledb_'
and table_constraints.constraint_type = 'PRIMARY KEY' and table_constraints.constraint_type = 'PRIMARY KEY'
and ('tables:' || table_constraints.table_schema || '.' || table_constraints.table_name) =OBJECT_ID_CONDITION and ('tables:' || table_constraints.table_schema || '.' || table_constraints.table_name) =OBJECT_ID_CONDITION
and table_constraints.table_schema =SCHEMA_NAME_CONDITION
order by key_column_usage.ordinal_position order by key_column_usage.ordinal_position
`; `;

View File

@ -6,5 +6,5 @@ select
routine_type as "object_type" routine_type as "object_type"
from from
information_schema.routines where routine_schema != 'information_schema' and routine_schema != 'pg_catalog' and routine_schema !~ '^_timescaledb_' information_schema.routines where routine_schema != 'information_schema' and routine_schema != 'pg_catalog' and routine_schema !~ '^_timescaledb_'
and routine_type in ('PROCEDURE', 'FUNCTION') and routine_type in ('PROCEDURE', 'FUNCTION') and routine_schema =SCHEMA_NAME_CONDITION
`; `;

View File

@ -9,6 +9,7 @@ select
max(external_language) as "language" max(external_language) as "language"
from from
information_schema.routines where routine_schema != 'information_schema' and routine_schema != 'pg_catalog' and routine_schema !~ '^_timescaledb_' information_schema.routines where routine_schema != 'information_schema' and routine_schema != 'pg_catalog' and routine_schema !~ '^_timescaledb_'
and routine_schema =SCHEMA_NAME_CONDITION
and ( and (
(routine_type = 'PROCEDURE' and ('procedures:' || routine_schema || '.' || routine_name) =OBJECT_ID_CONDITION) (routine_type = 'PROCEDURE' and ('procedures:' || routine_schema || '.' || routine_name) =OBJECT_ID_CONDITION)
or or

View File

@ -8,4 +8,5 @@ and infoTables.table_schema <> 'information_schema'
and infoTables.table_schema <> 'pg_internal' and infoTables.table_schema <> 'pg_internal'
and infoTables.table_schema !~ '^pg_toast' and infoTables.table_schema !~ '^pg_toast'
and infoTables.table_schema !~ '^_timescaledb_' and infoTables.table_schema !~ '^_timescaledb_'
and infoTables.table_schema =SCHEMA_NAME_CONDITION
`; `;

View File

@ -26,4 +26,5 @@ and infoTables.table_schema <> 'information_schema'
and infoTables.table_schema <> 'pg_internal' and infoTables.table_schema <> 'pg_internal'
and infoTables.table_schema !~ '^pg_toast' and infoTables.table_schema !~ '^pg_toast'
and infoTables.table_schema !~ '^_timescaledb_' and infoTables.table_schema !~ '^_timescaledb_'
and infoTables.table_schema =SCHEMA_NAME_CONDITION
`; `;

View File

@ -1,3 +1,3 @@
module.exports = ` module.exports = `
select conname as "constraint_name" from pg_constraint where contype = 'u' select conname as "constraint_name" from pg_constraint where contype = 'u' and connamespace = SCHEMA_ID_CONDITION
`; `;

View File

@ -4,5 +4,5 @@ select
table_schema as "schema_name", table_schema as "schema_name",
md5(view_definition) as "hash_code" md5(view_definition) as "hash_code"
from from
information_schema.views where table_schema != 'information_schema' and table_schema != 'pg_catalog' and table_schema !~ '^_timescaledb_' information_schema.views where table_schema != 'information_schema' and table_schema != 'pg_catalog' and table_schema !~ '^_timescaledb_' and table_schema =SCHEMA_NAME_CONDITION
`; `;

View File

@ -6,6 +6,6 @@ select
md5(view_definition) as "hash_code" md5(view_definition) as "hash_code"
from from
information_schema.views information_schema.views
where table_schema != 'information_schema' and table_schema != 'pg_catalog' and table_schema !~ '^_timescaledb_' where table_schema != 'information_schema' and table_schema != 'pg_catalog' and table_schema !~ '^_timescaledb_' and table_schema =SCHEMA_NAME_CONDITION
and ('views:' || table_schema || '.' || table_name) =OBJECT_ID_CONDITION and ('views:' || table_schema || '.' || table_name) =OBJECT_ID_CONDITION
`; `;