@@ -3,7 +3,8 @@ import * as vscode from "vscode";
3
3
import { JobManager } from "../config" ;
4
4
import Schemas , { AllSQLTypes , SQLType } from "../database/schemas" ;
5
5
import Statement from "../database/statement" ;
6
- import { DB2_SYSTEM_PROMPT } from "./continue/prompts" ;
6
+ import { DB2_SYSTEM_PROMPT } from "./prompts" ;
7
+ import { Db2ContextItems } from "./prompt" ;
7
8
8
9
export function canTalkToDb ( ) {
9
10
return JobManager . getSelection ( ) !== undefined ;
@@ -23,12 +24,6 @@ interface MarkdownRef {
23
24
SCHMEA ?: string ;
24
25
}
25
26
26
- interface ContextDefinition {
27
- id : string ;
28
- type : SQLType ;
29
- content : any ;
30
- }
31
-
32
27
/**
33
28
* Builds a semantic representation of a database schema by fetching all objects
34
29
* associated with the schema, cleaning them, and filtering out unnecessary properties.
@@ -112,165 +107,135 @@ export async function buildSchemaDefinition(schema: string): Promise<Partial<Bas
112
107
return compressedData ;
113
108
}
114
109
110
+ // hello my.world how/are you? -> [hello, my, ., world, how, /, are, you]
111
+ function splitUpUserInput ( input : string ) : string [ ] {
112
+ input = input . replace ( / [ , ! ? $ % \^ & \* ; : { } = \- ` ~ ( ) ] / g, "" )
113
+
114
+ let parts : string [ ] = [ ] ;
115
+
116
+ // Split the input string by spaces, dots and forward slash
117
+
118
+ let cPart = `` ;
119
+ let char : string ;
120
+
121
+ const addPart = ( ) => {
122
+ if ( cPart ) {
123
+ parts . push ( cPart ) ;
124
+ cPart = `` ;
125
+ }
126
+ }
127
+
128
+ for ( let i = 0 ; i < input . length ; i ++ ) {
129
+ char = input [ i ] ;
130
+
131
+ switch ( char ) {
132
+ case ` ` :
133
+ addPart ( ) ;
134
+ break ;
135
+
136
+ case `/` :
137
+ case `.` :
138
+ addPart ( ) ;
139
+ parts . push ( char ) ;
140
+ break ;
141
+
142
+ default :
143
+ if ( [ `/` , `.` ] . includes ( cPart ) ) {
144
+ addPart ( ) ;
145
+ }
146
+
147
+ cPart += char ;
148
+ break ;
149
+ }
150
+ }
151
+
152
+ addPart ( ) ;
153
+
154
+ return parts ;
155
+ }
156
+
115
157
/**
116
- * Generates the SQL table definitions for the given schema and input words .
158
+ * Generates the SQL object definitions for the given input string .
117
159
*
118
- * This function parses the input words to identify potential table references,
119
- * filters them based on the schema's available tables, and generates the SQL
120
- * definitions for the identified tables.
160
+ * This function parses the input words to identify potential SQL object references,
161
+ * and generates the SQL definitions for the identified objects based on the library list.
121
162
*
122
- * @param {string } schema - The schema name to search for tables.
123
- * @param {string[] } input - An array of words that may contain table references.
124
- * @returns {Promise<{[key: string]: string | undefined}> } A promise that resolves to an object
125
- * where the keys are table names and the values are their corresponding SQL definitions.
163
+ * @param {string } input - A string that may contain table references.
126
164
*/
127
- export async function generateTableDefinition ( schema : string , input : string [ ] ) {
128
- let tables : ContextDefinition [ ] = [ ] ;
165
+ export async function getSqlContextItems ( input : string ) : Promise < { items : Db2ContextItems [ ] , refs : ResolvedSqlObject [ ] } > {
129
166
// Parse all SCHEMA.TABLE references first
130
- const schemaTableRefs = input . filter ( ( word ) => word . includes ( "." ) ) ;
131
- const justWords = input . map ( ( word ) =>
132
- word . replace ( / [ , \/ # ! ? $ % \^ & \* ; : { } = \- _ ` ~ ( ) ] / g, "" )
133
- ) ;
167
+ const tokens = splitUpUserInput ( input ) ;
134
168
135
169
// Remove plurals from words
136
- justWords . push (
137
- ...justWords
170
+ tokens . push (
171
+ ...tokens
138
172
. filter ( ( word ) => word . endsWith ( "s" ) )
139
173
. map ( ( word ) => word . slice ( 0 , - 1 ) )
140
174
) ;
141
175
142
- // Filter prompt for possible refs to tables
143
- const validWords = justWords
144
- . filter (
145
- ( word ) => word . length > 2 && ! word . endsWith ( "s" ) && ! word . includes ( `'` )
146
- )
147
- . map ( ( word ) => `${ Statement . delimName ( word , true ) } ` ) ;
148
-
149
- const allTables : BasicSQLObject [ ] = await Schemas . getObjects ( schema , [
150
- `tables` ,
151
- ] ) ;
152
-
153
- const filteredTables = Array . from (
154
- new Set (
155
- validWords . filter ( ( word ) => allTables . some ( ( table ) => table . name == word ) )
156
- )
157
- ) ;
176
+ let possibleRefs : { name : string , schema ?: string } [ ] = [ ] ;
177
+ for ( let i = 0 ; i < tokens . length ; i ++ ) {
178
+ const token = tokens [ i ] ;
179
+
180
+ if ( token [ i + 1 ] && [ `.` , `/` ] . includes ( token [ i + 1 ] ) && tokens [ i + 2 ] ) {
181
+ const nextToken = tokens [ i + 2 ] ;
158
182
159
- await Promise . all (
160
- filteredTables . map ( async ( token ) => {
161
- try {
162
- const content = await Schemas . generateSQL ( schema , token , `TABLE` ) ;
163
- if ( content ) {
164
- tables . push ( {
165
- id : token ,
166
- type : `tables` ,
167
- content : content ,
168
- } ) ;
169
- }
170
- } catch ( e ) {
171
- // ignore
172
- }
173
- } )
174
- ) ;
183
+ possibleRefs . push ( {
184
+ name : Statement . delimName ( nextToken , true ) ,
185
+ schema : Statement . delimName ( token , true ) ,
186
+ } ) ;
187
+
188
+ i += 2 ; // Skip the next token as it's already processed
189
+
190
+ } else {
191
+ possibleRefs . push ( {
192
+ name : Statement . delimName ( token , true ) ,
193
+ } ) ;
194
+ }
195
+ }
175
196
176
- // check for QSYS2
177
- // for (const item of schemaTableRefs) {
178
- // const [curSchema, table] = item.split(`.`);
179
- // if (curSchema.toUpperCase() === `QSYS2`) {
180
- // try {
181
- // const content = await Schemas.getObjects
182
- // } catch (e) {
183
- // continue
184
- // }
185
- // }
186
- // }
187
-
188
- return tables ;
197
+ const allObjects = await Schemas . resolveObjects ( possibleRefs ) ;
198
+ const contextItems = await getContentItemsForRefs ( allObjects ) ;
199
+
200
+ return {
201
+ items : contextItems ,
202
+ refs : allObjects ,
203
+ } ;
189
204
}
190
205
191
- // depreciated
192
- export async function findPossibleTables (
193
- stream : vscode . ChatResponseStream ,
194
- schema : string ,
195
- words : string [ ]
196
- ) {
197
- let tables : TableRefs = { } ;
206
+ export async function getContentItemsForRefs ( allObjects : ResolvedSqlObject [ ] ) : Promise < Db2ContextItems [ ] > {
207
+ const items : ( Db2ContextItems | undefined ) [ ] = await Promise . all (
208
+ allObjects . map ( async ( o ) => {
209
+ try {
210
+ if ( o . sqlType === `SCHEMA` ) {
211
+ const schemaSemantic = await buildSchemaDefinition ( o . name ) ;
212
+ if ( schemaSemantic ) {
213
+ return {
214
+ name : `SCHEMA Definition` ,
215
+ description : `${ o . name } definition` ,
216
+ content : JSON . stringify ( schemaSemantic )
217
+ } ;
218
+ }
219
+
220
+ return undefined ;
198
221
199
- // Parse all SCHEMA.TABLE references first
200
- const schemaTableRefs = words . filter ( ( word ) => word . includes ( "." ) ) ;
201
- const justWords = words . map ( ( word ) =>
202
- word . replace ( / [ , \/ # ! ? $ % \^ & \* ; : { } = \- _ ` ~ ( ) ] / g, "" )
203
- ) ;
222
+ } else {
223
+ const content = await Schemas . generateSQL ( o . schema , o . name , o . sqlType ) ;
204
224
205
- // Remove plurals from words
206
- justWords . push (
207
- ...justWords
208
- . filter ( ( word ) => word . endsWith ( "s" ) )
209
- . map ( ( word ) => word . slice ( 0 , - 1 ) )
225
+ return {
226
+ name : `${ o . sqlType . toLowerCase ( ) } definition for ${ o . name } ` ,
227
+ description : `${ o . sqlType } definition` ,
228
+ content : content
229
+ } ;
230
+ }
231
+
232
+ } catch ( e ) {
233
+ return undefined ;
234
+ }
235
+ } )
210
236
) ;
211
237
212
- // Filter prompt for possible refs to tables
213
- const validWords = justWords
214
- . filter (
215
- ( word ) => word . length > 2 && ! word . endsWith ( "s" ) && ! word . includes ( `'` )
216
- )
217
- . map ( ( word ) => `'${ Statement . delimName ( word , true ) } '` ) ;
218
-
219
- const objectFindStatement = [
220
- `SELECT ` ,
221
- ` column.TABLE_SCHEMA,` ,
222
- ` column.TABLE_NAME,` ,
223
- ` column.COLUMN_NAME,` ,
224
- ` key.CONSTRAINT_NAME,` ,
225
- ` column.DATA_TYPE, ` ,
226
- ` column.CHARACTER_MAXIMUM_LENGTH,` ,
227
- ` column.NUMERIC_SCALE, ` ,
228
- ` column.NUMERIC_PRECISION,` ,
229
- ` column.IS_NULLABLE, ` ,
230
- // ` column.HAS_DEFAULT, `,
231
- // ` column.COLUMN_DEFAULT, `,
232
- ` column.COLUMN_TEXT, ` ,
233
- ` column.IS_IDENTITY` ,
234
- `FROM QSYS2.SYSCOLUMNS2 as column` ,
235
- `LEFT JOIN QSYS2.syskeycst as key` ,
236
- ` on ` ,
237
- ` column.table_schema = key.table_schema and` ,
238
- ` column.table_name = key.table_name and` ,
239
- ` column.column_name = key.column_name` ,
240
- `WHERE column.TABLE_SCHEMA = '${ Statement . delimName ( schema , true ) } '` ,
241
- ...[
242
- schemaTableRefs . length > 0
243
- ? `AND (column.TABLE_NAME in (${ validWords . join (
244
- `, `
245
- ) } ) OR (${ schemaTableRefs
246
- . map ( ( ref ) => {
247
- const [ schema , table ] = ref . split ( "." ) ;
248
- const cleanedTable = table . replace (
249
- / [ , \/ # ! ? $ % \^ & \* ; : { } = \- _ ` ~ ( ) ] / g,
250
- ""
251
- ) ;
252
- return `(column.TABLE_SCHEMA = '${ Statement . delimName (
253
- schema ,
254
- true
255
- ) } ' AND column.TABLE_NAME = '${ Statement . delimName (
256
- cleanedTable ,
257
- true
258
- ) } ')`;
259
- } )
260
- . join ( " OR " ) } ))`
261
- : `AND column.TABLE_NAME in (${ validWords . join ( `, ` ) } )` ,
262
- ] ,
263
- `ORDER BY column.ORDINAL_POSITION` ,
264
- ] . join ( ` ` ) ;
265
- // TODO
266
- const result : TableColumn [ ] = await JobManager . runSQL ( objectFindStatement ) ;
267
-
268
- result . forEach ( ( row ) => {
269
- const tableName = row . TABLE_NAME . toLowerCase ( ) ;
270
- if ( ! tables [ tableName ] ) tables [ tableName ] = [ ] ;
271
- tables [ tableName ] . push ( row ) ;
272
- } ) ;
273
- return tables ;
238
+ return items . filter ( ( item ) => item !== undefined ) ;
274
239
}
275
240
276
241
/**
0 commit comments