Skip to content

Commit

Permalink
tree view optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
daimor committed Jul 7, 2020
1 parent c4b72ef commit 44e16d9
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 58 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.DS_Store
node_modules/
out/
out/
*.vsix
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sqltools-intersystems-driver",
"displayName": "InterSystems IRIS Driver",
"displayName": "SQLTools InterSystems IRIS",
"description": "SQLTools Driver for InterSystems IRIS",
"version": "0.0.1",
"engines": {
Expand Down
2 changes: 1 addition & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import { IDriverAlias } from '@sqltools/types';
* Aliases for yout driver. EG: PostgreSQL, PG, postgres can all resolve to your driver
*/
export const DRIVER_ALIASES: IDriverAlias[] = [
{ displayName: 'InterSystems IRIS Driver', value: 'InterSystems IRIS Driver'},
{ displayName: 'InterSystems IRIS', value: 'InterSystems IRIS'},
];
49 changes: 27 additions & 22 deletions src/ls/driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@ import AbstractDriver from '@sqltools/base-driver';
import queries from './queries';
import { IConnectionDriver, MConnectionExplorer, NSDatabase, ContextValue, Arg0 } from '@sqltools/types';
import { v4 as generateId } from 'uuid';
import IRISdb, { IRISDirect } from './irisdb';
import IRISdb, { IRISDirect, IQueries } from './irisdb';
import keywordsCompletion from './keywords';
// import { workspace } from "vscode";

type DriverOptions = any;

export default class IRISDriver extends AbstractDriver<IRISdb, DriverOptions> implements IConnectionDriver {

queries = queries;
queries: IQueries = queries;

public async open() {
if (this.connection) {
Expand Down Expand Up @@ -67,7 +66,7 @@ export default class IRISDriver extends AbstractDriver<IRISdb, DriverOptions> im
const resultsAgg: NSDatabase.IResult[] = [];
queriesResults.forEach(queryResult => {
resultsAgg.push({
cols: Object.keys(queryResult[0]),
cols: queryResult.length ? Object.keys(queryResult[0]) : [],
connId: this.getId(),
messages: [{ date: new Date(), message: `Query ok with ${queryResult.length} results` }],
results: queryResult,
Expand Down Expand Up @@ -96,36 +95,42 @@ export default class IRISDriver extends AbstractDriver<IRISdb, DriverOptions> im
switch (item.type) {
case ContextValue.CONNECTION:
case ContextValue.CONNECTED_CONNECTION:
return <MConnectionExplorer.IChildItem[]>[
{ label: 'Schemas', type: ContextValue.RESOURCE_GROUP, iconId: 'folder', childType: ContextValue.SCHEMA },
];
case ContextValue.TABLE:
case ContextValue.VIEW:
return this.getColumns(item as NSDatabase.ITable);
case ContextValue.SCHEMA:
return <MConnectionExplorer.IChildItem[]>[
{ label: 'Tables', type: ContextValue.RESOURCE_GROUP, iconId: 'folder', childType: ContextValue.TABLE },
{ label: 'Views', type: ContextValue.RESOURCE_GROUP, iconId: 'folder', childType: ContextValue.VIEW },
{ label: 'Procedures', type: ContextValue.RESOURCE_GROUP, iconId: 'folder', childType: ContextValue.FUNCTION },
];
case ContextValue.RESOURCE_GROUP:
return this.getChildrenForGroup({ item, parent });
return this.getSchemas({ item, parent });
case ContextValue.SCHEMA:
return this.getChildrenForSchema({ item, parent });
case ContextValue.TABLE:
case ContextValue.VIEW:
return this.getColumns(item as NSDatabase.ITable);
}
return [];
}

/**
* This method is a helper to generate the connection explorer tree.
* It gets the child based on child types
*/
private async getChildrenForGroup({ parent, item }: Arg0<IConnectionDriver['getChildrenForItem']>) {
console.log("getChildrenForGroup", parent, item);
private async getSchemas({ item }: Arg0<IConnectionDriver['getChildrenForItem']>) {
switch (item.childType) {
case ContextValue.TABLE:
return this.queryResults(this.queries.fetchTableSchemas());
case ContextValue.VIEW:
return this.queryResults(this.queries.fetchViewSchemas());
case ContextValue.FUNCTION:
return this.queryResults(this.queries.fetchFunctionSchemas());
}
return [];
}

private async getChildrenForSchema({ item }: Arg0<IConnectionDriver['getChildrenForItem']>) {
switch (item.childType) {
case ContextValue.SCHEMA:
return this.queryResults(this.queries.fetchSchemas(parent as NSDatabase.IDatabase));
case ContextValue.TABLE:
return this.queryResults(this.queries.fetchTables(parent as NSDatabase.ISchema));
return this.queryResults(this.queries.fetchTables(item as NSDatabase.ISchema));
case ContextValue.VIEW:
return this.queryResults(this.queries.fetchViews(parent as NSDatabase.ISchema));
return this.queryResults(this.queries.fetchViews(item as NSDatabase.ISchema));
case ContextValue.FUNCTION:
return this.queryResults(this.queries.fetchFunctions(item as NSDatabase.ISchema));
}
return [];
}
Expand Down
9 changes: 9 additions & 0 deletions src/ls/irisdb.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as httpModule from "http";
import * as httpsModule from "https";
import requestPromise from "request-promise";
import { QueryBuilder, NSDatabase, IBaseQueries } from "@sqltools/types";

export class IRISDirect {
https?: boolean;
Expand All @@ -12,6 +13,14 @@ export class IRISDirect {
password?: string;
}

export interface IQueries extends IBaseQueries {
fetchTableSchemas?: QueryBuilder<NSDatabase.IDatabase, NSDatabase.ISchema>;
fetchViewSchemas?: QueryBuilder<NSDatabase.IDatabase, NSDatabase.ISchema>;
fetchFunctionSchemas?: QueryBuilder<NSDatabase.IDatabase, NSDatabase.ISchema>;

fetchViews: QueryBuilder<NSDatabase.ISchema, NSDatabase.ITable>;
}

export default class IRISdb {

private config: IRISDirect;
Expand Down
74 changes: 41 additions & 33 deletions src/ls/queries.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { IBaseQueries, ContextValue } from '@sqltools/types';
import { ContextValue, NSDatabase, QueryBuilder } from '@sqltools/types';
import queryFactory from '@sqltools/base-driver/dist/lib/factory';
import { IQueries } from './irisdb';

/** write your queries here go fetch desired data. This queries are just examples copied from SQLite driver */

const describeTable: IBaseQueries['describeTable'] = queryFactory`
const describeTable: IQueries['describeTable'] = queryFactory`
SELECT C.*
FROM pragma_table_info('${p => p.label}') AS C
ORDER BY C.cid ASC
`;

const fetchColumns: IBaseQueries['fetchColumns'] = queryFactory`
const fetchColumns: IQueries['fetchColumns'] = queryFactory`
SELECT
C.COLUMN_NAME AS label,
'${ContextValue.COLUMN}' as type,
Expand All @@ -34,41 +35,40 @@ ORDER BY
C.ORDINAL_POSITION
`;

const fetchRecords: IBaseQueries['fetchRecords'] = queryFactory`
const fetchRecords: IQueries['fetchRecords'] = queryFactory`
SELECT TOP ${p => p.limit || 50} *
FROM ${p => p.table.schema}.${p => (p.table.label || p.table)}
`;

const countRecords: IBaseQueries['countRecords'] = queryFactory`
const countRecords: IQueries['countRecords'] = queryFactory`
SELECT count(1) AS total
FROM ${p => p.table.schema}.${p => (p.table.label || p.table)}
`;

const fetchTablesAndViews = (type: ContextValue, tableType = 'BASE TABLE'): IBaseQueries['fetchTables'] => queryFactory`
SELECT
T.TABLE_NAME AS label,
'${type}' as type,
T.TABLE_SCHEMA AS "schema",
'${type === ContextValue.VIEW ? 'TRUE' : 'FALSE'}' AS isView
FROM INFORMATION_SCHEMA.${type === ContextValue.VIEW ? 'VIEWS' : 'TABLES'} AS T
WHERE
T.TABLE_SCHEMA = '${p => p.schema}'
AND T.TABLE_TYPE = '${tableType}'
const fetchAnyItems = <T>(type: ContextValue, isView: boolean, name: string, func: string): QueryBuilder<NSDatabase.ISchema, T> => queryFactory`
SELECT
${name} AS label,
SCHEMA_NAME AS "schema",
'${type}' as "type",
'${isView ? 'TRUE' : 'FALSE'}' as isView
FROM %SQL_MANAGER.${func}()
WHERE SCHEMA_NAME = '${p => p.schema}'
ORDER BY
T.TABLE_NAME
${name}
`;

const fetchTables: IBaseQueries['fetchTables'] = fetchTablesAndViews(ContextValue.TABLE);
const fetchViews: IBaseQueries['fetchTables'] = fetchTablesAndViews(ContextValue.VIEW , 'view');
const fetchTables = fetchAnyItems<NSDatabase.ITable>(ContextValue.TABLE, false, 'TABLE_NAME', 'TablesTree');
const fetchViews = fetchAnyItems<NSDatabase.ITable>(ContextValue.TABLE, true, 'VIEW_NAME', 'ViewsTree');
const fetchFunctions = fetchAnyItems<NSDatabase.IProcedure>(ContextValue.FUNCTION, false, 'PROCEDURE_NAME', 'ProceduresTree');

const searchTables: IBaseQueries['searchTables'] = queryFactory`
const searchTables: IQueries['searchTables'] = queryFactory`
SELECT name AS label,
type
FROM sqlite_master
${p => p.search ? `WHERE LOWER(name) LIKE '%${p.search.toLowerCase()}%'` : ''}
ORDER BY name
`;
const searchColumns: IBaseQueries['searchColumns'] = queryFactory`
const searchColumns: IQueries['searchColumns'] = queryFactory`
SELECT C.name AS label,
T.name AS "table",
C.type AS dataType,
Expand All @@ -79,39 +79,47 @@ FROM sqlite_master AS T
LEFT OUTER JOIN pragma_table_info((T.name)) AS C ON 1 = 1
WHERE 1 = 1
${p => p.tables.filter(t => !!t.label).length
? `AND LOWER(T.name) IN (${p.tables.filter(t => !!t.label).map(t => `'${t.label}'`.toLowerCase()).join(', ')})`
: ''
}
? `AND LOWER(T.name) IN (${p.tables.filter(t => !!t.label).map(t => `'${t.label}'`.toLowerCase()).join(', ')})`
: ''
}
${p => p.search
? `AND (
? `AND (
LOWER(T.name || '.' || C.name) LIKE '%${p.search.toLowerCase()}%'
OR LOWER(C.name) LIKE '%${p.search.toLowerCase()}%'
)`
: ''
}
: ''
}
ORDER BY C.name ASC,
C.cid ASC
LIMIT ${p => p.limit || 100}
`;

const fetchSchemas: IBaseQueries['fetchSchemas'] = queryFactory`
SELECT
schema_name AS label,
schema_name AS "schema",
const fetchTypedSchemas = (type: ContextValue, func: string): IQueries['fetchSchemas'] => queryFactory`
SELECT
DISTINCT BY (SCHEMA_NAME)
%EXACT(SCHEMA_NAME) AS label,
%EXACT(SCHEMA_NAME) AS "schema",
'${ContextValue.SCHEMA}' as "type",
'${type}' as "childType",
'folder' as iconId
FROM information_schema.schemata
WHERE schema_name <> 'information_schema'
FROM %SQL_MANAGER.${func}()
`;

const fetchTableSchemas = fetchTypedSchemas(ContextValue.TABLE, 'TablesTree');
const fetchViewSchemas = fetchTypedSchemas(ContextValue.VIEW, 'ViewsTree');
const fetchFunctionSchemas = fetchTypedSchemas(ContextValue.FUNCTION, 'ProceduresTree');

export default {
describeTable,
countRecords,
fetchColumns,
fetchRecords,
fetchTables,
fetchFunctions,
fetchViews,
searchTables,
searchColumns,
fetchSchemas,
fetchTableSchemas,
fetchViewSchemas,
fetchFunctionSchemas,
}

0 comments on commit 44e16d9

Please sign in to comment.