@@ -260,7 +260,12 @@ suite('Positron DuckDB Extension Test Suite', () => {
260
260
ExportFormat . Html
261
261
]
262
262
} ,
263
- convert_to_code : { support_status : SupportStatus . Unsupported }
263
+ convert_to_code : {
264
+ support_status : SupportStatus . Supported ,
265
+ code_syntaxes : [ {
266
+ code_syntax_name : "SQL"
267
+ } ]
268
+ }
264
269
}
265
270
} satisfies BackendState ) ;
266
271
@@ -2117,4 +2122,255 @@ suite('Positron DuckDB Extension Test Suite', () => {
2117
2122
assert . strictEqual ( numberStats . median , '42' , 'Median should be 42' ) ;
2118
2123
assert . strictEqual ( numberStats . stdev , '0' , 'Standard deviation should be 0 for single value' ) ;
2119
2124
} ) ;
2125
+
2126
+ test ( 'convertToCode - with row filters' , async ( ) => {
2127
+ const tableName = makeTempTableName ( ) ;
2128
+
2129
+ // Create a test table with more diverse data for filtering
2130
+ await createTempTable ( tableName , [
2131
+ {
2132
+ name : 'id' ,
2133
+ type : 'INTEGER' ,
2134
+ values : [ '1' , '2' , '3' , '4' , '5' ]
2135
+ } ,
2136
+ {
2137
+ name : 'name' ,
2138
+ type : 'VARCHAR' ,
2139
+ values : [ "'Alice'" , "'Bob'" , "'Charlie'" , "'David'" , "'Eve'" ]
2140
+ } ,
2141
+ {
2142
+ name : 'age' ,
2143
+ type : 'INTEGER' ,
2144
+ values : [ '25' , '30' , '35' , '40' , '45' ]
2145
+ }
2146
+ ] ) ;
2147
+
2148
+ const uri = vscode . Uri . from ( { scheme : 'duckdb' , path : tableName } ) ;
2149
+
2150
+ // Get full schema to build row filter
2151
+ const fullSchema = await getSchema ( tableName ) ;
2152
+
2153
+ // Create filter: age > 30
2154
+ const rowFilter : RowFilter = {
2155
+ filter_id : 'test-filter' ,
2156
+ condition : RowFilterCondition . And ,
2157
+ column_schema : fullSchema . columns [ 2 ] , // age column
2158
+ filter_type : RowFilterType . Compare ,
2159
+ params : {
2160
+ op : FilterComparisonOp . Gt ,
2161
+ value : '30'
2162
+ }
2163
+ } ;
2164
+
2165
+ // Apply the filter first so it's reflected in the SQL generation
2166
+ await dxExec ( {
2167
+ method : DataExplorerBackendRequest . SetRowFilters ,
2168
+ uri : uri . toString ( ) ,
2169
+ params : {
2170
+ filters : [ rowFilter ]
2171
+ }
2172
+ } ) ;
2173
+
2174
+ // Test convert to code with row filter applied
2175
+ const result = await dxExec ( {
2176
+ method : DataExplorerBackendRequest . ConvertToCode ,
2177
+ uri : uri . toString ( ) ,
2178
+ params : {
2179
+ column_filters : [ ] ,
2180
+ row_filters : [ rowFilter ] ,
2181
+ sort_keys : [ ] ,
2182
+ code_syntax_name : { code_syntax_name : 'SQL' }
2183
+ }
2184
+ } ) ;
2185
+
2186
+ assert . ok ( result , 'Convert to code result should be returned' ) ;
2187
+ assert . ok ( result . converted_code , 'Converted code should be present' ) ;
2188
+ assert . strictEqual ( result . converted_code . length , 3 , 'Should have 3 lines of code' ) ;
2189
+ assert . strictEqual ( result . converted_code [ 0 ] , 'SELECT * ' , 'First line should be SELECT * ' ) ;
2190
+ assert . strictEqual ( result . converted_code [ 1 ] , `FROM "${ tableName } "` , `Second line should reference the table name` ) ;
2191
+ assert . strictEqual ( result . converted_code [ 2 ] , 'WHERE "age" > 30' , 'Third line should have the WHERE clause' ) ;
2192
+ } ) ;
2193
+
2194
+ test ( 'convertToCode - with sort columns' , async ( ) => {
2195
+ const tableName = makeTempTableName ( ) ;
2196
+
2197
+ // Create a test table with more diverse data for sorting
2198
+ await createTempTable ( tableName , [
2199
+ {
2200
+ name : 'id' ,
2201
+ type : 'INTEGER' ,
2202
+ values : [ '1' , '2' , '3' , '4' , '5' ]
2203
+ } ,
2204
+ {
2205
+ name : 'name' ,
2206
+ type : 'VARCHAR' ,
2207
+ values : [ "'Alice'" , "'Bob'" , "'Charlie'" , "'David'" , "'Eve'" ]
2208
+ } ,
2209
+ {
2210
+ name : 'age' ,
2211
+ type : 'INTEGER' ,
2212
+ values : [ '25' , '30' , '35' , '40' , '45' ]
2213
+ }
2214
+ ] ) ;
2215
+
2216
+ const uri = vscode . Uri . from ( { scheme : 'duckdb' , path : tableName } ) ;
2217
+
2218
+ // Create sort key: sort by name descending
2219
+ const sortKey : ColumnSortKey = {
2220
+ column_index : 1 , // name column
2221
+ ascending : false
2222
+ } ;
2223
+
2224
+ // Apply the sort key first so it's reflected in the SQL generation
2225
+ await dxExec ( {
2226
+ method : DataExplorerBackendRequest . SetSortColumns ,
2227
+ uri : uri . toString ( ) ,
2228
+ params : {
2229
+ sort_keys : [ sortKey ]
2230
+ }
2231
+ } ) ;
2232
+
2233
+ // Test convert to code with sort key applied
2234
+ const result = await dxExec ( {
2235
+ method : DataExplorerBackendRequest . ConvertToCode ,
2236
+ uri : uri . toString ( ) ,
2237
+ params : {
2238
+ column_filters : [ ] ,
2239
+ row_filters : [ ] ,
2240
+ sort_keys : [ sortKey ] ,
2241
+ code_syntax_name : { code_syntax_name : 'SQL' }
2242
+ }
2243
+ } ) ;
2244
+
2245
+ assert . ok ( result , 'Convert to code result should be returned' ) ;
2246
+ assert . ok ( result . converted_code , 'Converted code should be present' ) ;
2247
+ assert . strictEqual ( result . converted_code . length , 3 , 'Should have 3 lines of code' ) ;
2248
+ assert . strictEqual ( result . converted_code [ 0 ] , 'SELECT * ' , 'First line should be SELECT * ' ) ;
2249
+ assert . strictEqual ( result . converted_code [ 1 ] , `FROM "${ tableName } "` , `Second line should reference the table name` ) ;
2250
+ assert . strictEqual ( result . converted_code [ 2 ] , 'ORDER BY "name" DESC' , 'Third line should have the ORDER BY clause' ) ;
2251
+ } ) ;
2252
+
2253
+ test ( 'convertToCode - with both row filters and sort columns' , async ( ) => {
2254
+ const tableName = makeTempTableName ( ) ;
2255
+
2256
+ // Create a test table with data for filtering and sorting
2257
+ await createTempTable ( tableName , [
2258
+ {
2259
+ name : 'id' ,
2260
+ type : 'INTEGER' ,
2261
+ values : [ '1' , '2' , '3' , '4' , '5' ]
2262
+ } ,
2263
+ {
2264
+ name : 'name' ,
2265
+ type : 'VARCHAR' ,
2266
+ values : [ "'Alice'" , "'Bob'" , "'Charlie'" , "'David'" , "'Eve'" ]
2267
+ } ,
2268
+ {
2269
+ name : 'age' ,
2270
+ type : 'INTEGER' ,
2271
+ values : [ '25' , '30' , '35' , '40' , '45' ]
2272
+ }
2273
+ ] ) ;
2274
+
2275
+ const uri = vscode . Uri . from ( { scheme : 'duckdb' , path : tableName } ) ;
2276
+
2277
+ // Get full schema to build row filter
2278
+ const fullSchema = await getSchema ( tableName ) ;
2279
+
2280
+ // Create filter: age > 30
2281
+ const rowFilter : RowFilter = {
2282
+ filter_id : 'test-filter' ,
2283
+ condition : RowFilterCondition . And ,
2284
+ column_schema : fullSchema . columns [ 2 ] , // age column
2285
+ filter_type : RowFilterType . Compare ,
2286
+ params : {
2287
+ op : FilterComparisonOp . Gt ,
2288
+ value : '30'
2289
+ }
2290
+ } ;
2291
+
2292
+ // Create sort key: sort by name ascending
2293
+ const sortKey : ColumnSortKey = {
2294
+ column_index : 1 , // name column
2295
+ ascending : true
2296
+ } ;
2297
+
2298
+ // Apply the filter and sort key
2299
+ await dxExec ( {
2300
+ method : DataExplorerBackendRequest . SetRowFilters ,
2301
+ uri : uri . toString ( ) ,
2302
+ params : {
2303
+ filters : [ rowFilter ]
2304
+ }
2305
+ } ) ;
2306
+
2307
+ await dxExec ( {
2308
+ method : DataExplorerBackendRequest . SetSortColumns ,
2309
+ uri : uri . toString ( ) ,
2310
+ params : {
2311
+ sort_keys : [ sortKey ]
2312
+ }
2313
+ } ) ;
2314
+
2315
+ // Test convert to code with both row filter and sort key applied
2316
+ const result = await dxExec ( {
2317
+ method : DataExplorerBackendRequest . ConvertToCode ,
2318
+ uri : uri . toString ( ) ,
2319
+ params : {
2320
+ column_filters : [ ] ,
2321
+ row_filters : [ rowFilter ] ,
2322
+ sort_keys : [ sortKey ] ,
2323
+ code_syntax_name : { code_syntax_name : 'SQL' }
2324
+ }
2325
+ } ) ;
2326
+
2327
+ assert . ok ( result , 'Convert to code result should be returned' ) ;
2328
+ assert . ok ( result . converted_code , 'Converted code should be present' ) ;
2329
+ assert . strictEqual ( result . converted_code . length , 4 , 'Should have 4 lines of code' ) ;
2330
+ assert . strictEqual ( result . converted_code [ 0 ] , 'SELECT * ' , 'First line should be SELECT * ' ) ;
2331
+ assert . strictEqual ( result . converted_code [ 1 ] , `FROM "${ tableName } "` , `Second line should reference the table name` ) ;
2332
+ assert . strictEqual ( result . converted_code [ 2 ] , 'WHERE "age" > 30' , 'Third line should have the WHERE clause' ) ;
2333
+ assert . strictEqual ( result . converted_code [ 3 ] , 'ORDER BY "name"' , 'Fourth line should have the ORDER BY clause' ) ;
2334
+ } ) ;
2335
+
2336
+ test ( 'convertToCode - with long/complex filename/URI' , async ( ) => {
2337
+ // Use a long filename that needs to be quoted in SQL
2338
+ const specialTableName = makeTempTableName ( ) + '_complex_tablename_with_underscores' ;
2339
+
2340
+ // Create a simple test table
2341
+ await createTempTable ( specialTableName , [
2342
+ {
2343
+ name : 'id' ,
2344
+ type : 'INTEGER' ,
2345
+ values : [ '1' , '2' , '3' ]
2346
+ } ,
2347
+ {
2348
+ name : 'data' ,
2349
+ type : 'VARCHAR' ,
2350
+ values : [ "'A'" , "'B'" , "'C'" ]
2351
+ }
2352
+ ] ) ;
2353
+
2354
+ const uri = vscode . Uri . from ( { scheme : 'duckdb' , path : specialTableName } ) ;
2355
+
2356
+ // Test convert to code with a complex filename
2357
+ const result = await dxExec ( {
2358
+ method : DataExplorerBackendRequest . ConvertToCode ,
2359
+ uri : uri . toString ( ) ,
2360
+ params : {
2361
+ column_filters : [ ] ,
2362
+ row_filters : [ ] ,
2363
+ sort_keys : [ ] ,
2364
+ code_syntax_name : { code_syntax_name : 'SQL' }
2365
+ }
2366
+ } ) ;
2367
+
2368
+ assert . ok ( result , 'Convert to code result should be returned' ) ;
2369
+ assert . ok ( result . converted_code , 'Converted code should be present' ) ;
2370
+ assert . strictEqual ( result . converted_code . length , 2 , 'Should have 2 lines of code' ) ;
2371
+ assert . strictEqual ( result . converted_code [ 0 ] , 'SELECT * ' , 'First line should be SELECT * ' ) ;
2372
+
2373
+ // Verify that the table name is properly quoted in SQL
2374
+ assert . strictEqual ( result . converted_code [ 1 ] , `FROM "${ specialTableName } "` , 'Second line should properly quote the table name' ) ;
2375
+ } ) ;
2120
2376
} ) ;
0 commit comments