diff --git a/public/app/plugins/datasource/mssql/datasource.ts b/public/app/plugins/datasource/mssql/datasource.ts index 8de1d6f0aa7..1b7c2adbe9c 100644 --- a/public/app/plugins/datasource/mssql/datasource.ts +++ b/public/app/plugins/datasource/mssql/datasource.ts @@ -8,7 +8,7 @@ import { getSchema, showDatabases, showTables } from './MSSqlMetaQuery'; import { MSSqlQueryModel } from './MSSqlQueryModel'; import { MSSqlResponseParser } from './response_parser'; import { fetchColumns, fetchTables, getSqlCompletionProvider } from './sqlCompletionProvider'; -import { getIcon, getRAQBType, toRawSql } from './sqlUtil'; +import { getIcon, getRAQBType, SCHEMA_NAME, toRawSql } from './sqlUtil'; export class MssqlDatasource extends SqlDatasource { completionProvider: LanguageCompletionProvider | undefined = undefined; @@ -72,7 +72,7 @@ export class MssqlDatasource extends SqlDatasource { lookup: async (path?: string) => { if (!path) { const datasets = await this.fetchDatasets(); - return datasets.map((d) => ({ name: d, completion: `${d}.` })); + return datasets.map((d) => ({ name: d, completion: `${d}.${SCHEMA_NAME}.` })); } else { const parts = path.split('.').filter((s: string) => s); if (parts.length > 2) { @@ -80,7 +80,7 @@ export class MssqlDatasource extends SqlDatasource { } if (parts.length === 1) { const tables = await this.fetchTables(parts[0]); - return tables.map((t) => ({ name: t, completion: `${t}\`` })); + return tables.map((t) => ({ name: t, completion: `${t}` })); } else { return []; } diff --git a/public/app/plugins/datasource/mssql/sqlCompletionProvider.ts b/public/app/plugins/datasource/mssql/sqlCompletionProvider.ts index 9b4b9fd0392..0343fdf6005 100644 --- a/public/app/plugins/datasource/mssql/sqlCompletionProvider.ts +++ b/public/app/plugins/datasource/mssql/sqlCompletionProvider.ts @@ -7,7 +7,6 @@ import { LanguageCompletionProvider, LinkedToken, StatementPlacementProvider, - // StatementPosition, SuggestionKindProvider, TableDefinition, TokenType, @@ -15,10 +14,11 @@ import { import { AGGREGATE_FNS, OPERATORS } from 'app/features/plugins/sql/constants'; import { DB, SQLQuery } from 'app/features/plugins/sql/types'; +import { SCHEMA_NAME } from './sqlUtil'; + interface CompletionProviderGetterArgs { getColumns: React.MutableRefObject<(t: SQLQuery) => Promise>; getTables: React.MutableRefObject<(d?: string) => Promise>; - // getTableSchema: React.MutableRefObject<(p: string, d: string, t: string) => Promise>; } export const getSqlCompletionProvider: (args: CompletionProviderGetterArgs) => LanguageCompletionProvider = @@ -33,20 +33,19 @@ export const getSqlCompletionProvider: (args: CompletionProviderGetterArgs) => L let processedToken = token; let tablePath = processedToken.value; - while (processedToken.next) { + while (processedToken.next && processedToken.next.type !== TokenType.Whitespace) { tablePath += processedToken.next.value; processedToken = processedToken.next; } - return tablePath; + const tableName = tablePath.split('.').pop(); + + return tableName || tablePath; }, }, columns: { resolve: async (t: string) => { - // TODO - seems like a limitation in experimental since we may need database and table to get columns - // use . as delimiter? - // const cols = await getColumns({ table: t } as SQLQuery); return await getColumns.current({ table: t, refId: 'A' }); }, }, @@ -57,58 +56,36 @@ export const getSqlCompletionProvider: (args: CompletionProviderGetterArgs) => L }); export enum CustomStatementPlacement { - AfterDataset = 'afterDataset', + AfterDatabase = 'afterDatabase', } export enum CustomSuggestionKind { - TablesWithinDataset = 'tablesWithinDataset', - Partition = 'partition', + TablesWithinDatabase = 'tablesWithinDatabase', } export const customStatementPlacement: StatementPlacementProvider = () => [ { - id: CustomStatementPlacement.AfterDataset, + id: CustomStatementPlacement.AfterDatabase, resolve: (currentToken, previousKeyword) => { return Boolean( currentToken?.is(TokenType.Delimiter, '.') || (currentToken?.is(TokenType.Whitespace) && currentToken?.previous?.is(TokenType.Delimiter, '.')) || - // (currentToken?.value === '`' && currentToken?.previous?.is(TokenType.Delimiter, '.')) || - (currentToken?.isNumber() && currentToken.value.endsWith('.')) // number with dot at the end like "projectname-21342." - // (currentToken?.value === '`' && isTypingTableIn(currentToken)) + (currentToken?.isNumber() && currentToken.value.endsWith('.')) ); }, }, - // TODO - remove - frin big query - // Overriding default behaviour of AfterFrom resolver - // { - // id: StatementPosition.AfterFrom, - // overrideDefault: true, - // resolve: (currentToken) => { - // const untilFrom = currentToken?.getPreviousUntil(TokenType.Keyword, [], 'from'); - // if (!untilFrom) { - // return false; - // } - // let q = ''; - // for (let i = untilFrom?.length - 1; i >= 0; i--) { - // q += untilFrom[i].value; - // } - - // return q.startsWith('`') && q.endsWith('`'); - // }, - // }, ]; export const customSuggestionKinds: ( getTables: CompletionProviderGetterArgs['getTables'], getFields: CompletionProviderGetterArgs['getColumns'] - // getTableSchema: CompletionProviderGetterArgs['getTableSchema'] ) => SuggestionKindProvider = (getTables) => () => [ { - id: CustomSuggestionKind.TablesWithinDataset, - applyTo: [CustomStatementPlacement.AfterDataset], + id: CustomSuggestionKind.TablesWithinDatabase, + applyTo: [CustomStatementPlacement.AfterDatabase], suggestionsResolver: async (ctx) => { - const tablePath = ctx.currentToken ? getTablePath(ctx.currentToken) : ''; + const tablePath = ctx.currentToken ? getDatabaseName(ctx.currentToken) : ''; const t = await getTables.current(tablePath); return t.map((table) => ({ @@ -125,76 +102,25 @@ export const customSuggestionKinds: ( })); }, }, - // { - // id: CustomSuggestionKind.TablesWithinDataset, - // applyTo: [StatementPosition.AfterFrom], - // suggestionsResolver: async (ctx) => { - // console.log('after from'); - // const tablePath = ctx.currentToken ? getTablePath(ctx.currentToken) : ''; - // const t = await getTables.current(tablePath); - - // return t.map((table) => ({ - // label: table.name, - // insertText: table.completion ?? table.name, - // command: { id: 'editor.action.triggerSuggest', title: '' }, - // kind: CompletionItemKind.Field, - // sortText: CompletionItemPriority.High, - // range: { - // ...ctx.range, - // startColumn: ctx.range.endColumn, - // endColumn: ctx.range.endColumn, - // }, - // })); - // } - // } ]; -export function getTablePath(token: LinkedToken) { +export function getDatabaseName(token: LinkedToken) { let processedToken = token; - let tablePath = ''; + let database = ''; while (processedToken?.previous && !processedToken.previous.isWhiteSpace()) { processedToken = processedToken.previous; - tablePath = processedToken.value + tablePath; + database = processedToken.value + database; } - tablePath = tablePath.trim(); + if (database.includes(SCHEMA_NAME)) { + database = database.replace(SCHEMA_NAME, ''); + } - // TODO - remove - frin big query + database = database.trim(); - // if (tablePath.startsWith('`')) { - // tablePath = tablePath.slice(1); - // } - - // if (tablePath.endsWith('`')) { - // tablePath = tablePath.slice(0, -1); - // } - - return tablePath; + return database; } -// TODO - not sure if we need this -// function isTypingTableIn(token: LinkedToken | null, l?: boolean) { -// if (!token) { -// return false; -// } -// const tokens = token.getPreviousUntil(TokenType.Keyword, [], 'from'); -// if (!tokens) { -// return false; -// } - -// let path = ''; -// for (let i = tokens.length - 1; i >= 0; i--) { -// path += tokens[i].value; -// } - -// // TODO - remove - frin big query -// // if (path.startsWith('`')) { -// // path = path.slice(1); -// // } - -// return path.split('.').length === 2; -// } - export async function fetchColumns(db: DB, q: SQLQuery) { const cols = await db.fields(q); if (cols.length > 0) { diff --git a/public/app/plugins/datasource/mssql/sqlUtil.ts b/public/app/plugins/datasource/mssql/sqlUtil.ts index 3aaff45f41a..2aa41cb3213 100644 --- a/public/app/plugins/datasource/mssql/sqlUtil.ts +++ b/public/app/plugins/datasource/mssql/sqlUtil.ts @@ -79,6 +79,8 @@ export function getRAQBType(type: string): RAQBFieldTypes { } } +export const SCHEMA_NAME = 'dbo'; + export function toRawSql({ sql, dataset, table }: SQLQuery): string { let rawQuery = ''; @@ -90,7 +92,7 @@ export function toRawSql({ sql, dataset, table }: SQLQuery): string { rawQuery += createSelectClause(sql.columns, sql.limit); if (dataset && table) { - rawQuery += `FROM ${dataset}.dbo.${table} `; + rawQuery += `FROM ${dataset}.${SCHEMA_NAME}.${table} `; } if (sql.whereString) {