Skip to content

Commit 491b5ca

Browse files
committed
WIP: allow users to reference tables with schema.table
1 parent 9637530 commit 491b5ca

File tree

2 files changed

+59
-24
lines changed

2 files changed

+59
-24
lines changed

src/chat/chat.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export function activateChat(context: vscode.ExtensionContext) {
6565
`Getting information from ${Statement.prettyName(usingSchema)}...`
6666
);
6767
let refs = await findPossibleTables(
68+
stream,
6869
usingSchema,
6970
request.prompt.split(` `)
7071
);
@@ -77,17 +78,17 @@ export function activateChat(context: vscode.ExtensionContext) {
7778

7879
if (Object.keys(refs).length === 0) {
7980
stream.progress(`No references found. Doing bigger lookup...`);
80-
refs = await findPossibleTables(usingSchema, []);
81+
refs = await findPossibleTables(stream, usingSchema, []);
8182
}
8283

8384
if (Object.keys(refs).length > 0) {
8485
stream.progress(`Building response...`);
8586
messages.push(
8687
vscode.LanguageModelChatMessage.User(
87-
`Give the developer an SQL statement or information based on the prompt and following table references. Always include code examples where is makes sense. Do not make suggestions for reference you do not have.`
88+
`Provide the developer with SQL statements or relevant information based on the user's prompt and referenced table structures. Always include practical code examples where applicable. Ensure all suggestions are directly applicable to the structures and data provided and avoid making suggestions outside the scope of the available information.`
8889
),
8990
vscode.LanguageModelChatMessage.User(
90-
`Here are the table references for current schema ${usingSchema}\n${refsToMarkdown(
91+
`Here are the table references ${refsToMarkdown(
9192
refs
9293
)}`
9394
),

src/chat/context.ts

Lines changed: 55 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { JobManager } from "../config";
2+
import * as vscode from "vscode";
23
import Statement from "../database/statement";
34

45
export function canTalkToDb() {
@@ -14,21 +15,60 @@ export function getDefaultSchema(): string {
1415

1516
export type TableRefs = { [key: string]: TableColumn[] };
1617

17-
export async function findPossibleTables(schema: string, words: string[]) {
18-
words = words.map((word) =>
19-
word.replace(/[.,\/#!?$%\^&\*;:{}=\-_`~()]/g, "")
20-
);
18+
export async function getTableMetaData(schema: string, tableName: string): Promise<TableColumn[]> {
19+
const objectFindStatement = [
20+
`SELECT `,
21+
` column.TABLE_NAME,`,
22+
` column.COLUMN_NAME,`,
23+
` key.CONSTRAINT_NAME,`,
24+
` column.DATA_TYPE, `,
25+
` column.CHARACTER_MAXIMUM_LENGTH,`,
26+
` column.NUMERIC_SCALE, `,
27+
` column.NUMERIC_PRECISION,`,
28+
` column.IS_NULLABLE, `,
29+
// ` column.HAS_DEFAULT, `,
30+
// ` column.COLUMN_DEFAULT, `,
31+
` column.COLUMN_TEXT, `,
32+
` column.IS_IDENTITY`,
33+
`FROM QSYS2.SYSCOLUMNS2 as column`,
34+
`LEFT JOIN QSYS2.syskeycst as key`,
35+
` on `,
36+
` column.table_schema = key.table_schema and`,
37+
` column.table_name = key.table_name and`,
38+
` column.column_name = key.column_name`,
39+
`WHERE column.TABLE_SCHEMA = '${Statement.delimName(schema, true)}'`,
40+
`AND column.TABLE_NAME = '${Statement.delimName(tableName, true)}'`,
41+
`ORDER BY column.ORDINAL_POSITION`,
42+
].join(` `);
2143

22-
// Add extra words for words with S at the end, to ignore possible plurals
23-
words.forEach((item) => {
24-
if (item.endsWith(`s`)) {
25-
words.push(item.slice(0, -1));
44+
return await JobManager.runSQL(objectFindStatement);
45+
}
46+
47+
export async function parsePromptForRefs(stream: vscode.ChatResponseStream, prompt: string[]): Promise<TableRefs> {
48+
const tables: TableRefs = {};
49+
for (const word of prompt) {
50+
const [schema, table] = word.split(`.`);
51+
if (schema && table) {
52+
stream.progress(`looking up information for ${schema}.${table}`)
53+
const data = await getTableMetaData(schema, table);
54+
tables[table] = tables[table] || [];
55+
tables[table].push(...data);
2656
}
27-
});
57+
}
58+
return tables;
59+
}
60+
61+
export async function findPossibleTables(stream: vscode.ChatResponseStream, schema: string, words: string[]) {
2862

29-
const validWords = words
30-
.filter((item) => item.length > 2 && !item.includes(`'`))
31-
.map((item) => `'${Statement.delimName(item, true)}'`);
63+
let tables: TableRefs = {}
64+
65+
// parse all SCHEMA.TABLE references first
66+
tables = await parsePromptForRefs(stream, words.filter(word => word.includes('.')));
67+
68+
// filter prompt for possible refs to tables
69+
const validWords = words.map(word => word.replace(/[.,\/#!?$%\^&\*;:{}=\-_`~()]/g, ""))
70+
.filter(word => word.length > 2 && !word.endsWith('s') && !word.includes(`'`))
71+
.map(word => `'${Statement.delimName(word, true)}'`);
3272

3373
const objectFindStatement = [
3474
`SELECT `,
@@ -62,16 +102,10 @@ export async function findPossibleTables(schema: string, words: string[]) {
62102
// TODO
63103
const result: TableColumn[] = await JobManager.runSQL(objectFindStatement);
64104

65-
const tables: TableRefs = {};
66-
67-
for (const row of result) {
68-
if (!tables[row.TABLE_NAME]) {
69-
tables[row.TABLE_NAME] = [];
70-
}
71-
105+
result.forEach(row => {
106+
if (!tables[row.TABLE_NAME]) tables[row.TABLE_NAME] = [];
72107
tables[row.TABLE_NAME].push(row);
73-
}
74-
108+
});
75109
return tables;
76110
}
77111

0 commit comments

Comments
 (0)