diff --git a/.github/workflows/build-app-pro-beta.yaml b/.github/workflows/build-app-pro-beta.yaml index 0379a00fc..733dc36dd 100644 --- a/.github/workflows/build-app-pro-beta.yaml +++ b/.github/workflows/build-app-pro-beta.yaml @@ -39,7 +39,7 @@ jobs: repository: dbgate/dbgate-pro token: '${{ secrets.GH_TOKEN }}' path: dbgate-pro - ref: a770b7e7a4d0ced5f1ade7cba4ba516220765648 + ref: a2f824dc711b510a5e8235d3faf4aafab1965184 - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-app-pro.yaml b/.github/workflows/build-app-pro.yaml index bf7615383..3ab892a19 100644 --- a/.github/workflows/build-app-pro.yaml +++ b/.github/workflows/build-app-pro.yaml @@ -39,7 +39,7 @@ jobs: repository: dbgate/dbgate-pro token: '${{ secrets.GH_TOKEN }}' path: dbgate-pro - ref: a770b7e7a4d0ced5f1ade7cba4ba516220765648 + ref: a2f824dc711b510a5e8235d3faf4aafab1965184 - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-aws-pro.yaml b/.github/workflows/build-aws-pro.yaml index cecc55926..52fa8f321 100644 --- a/.github/workflows/build-aws-pro.yaml +++ b/.github/workflows/build-aws-pro.yaml @@ -36,7 +36,7 @@ jobs: repository: dbgate/dbgate-pro token: '${{ secrets.GH_TOKEN }}' path: dbgate-pro - ref: a770b7e7a4d0ced5f1ade7cba4ba516220765648 + ref: a2f824dc711b510a5e8235d3faf4aafab1965184 - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-docker-pro.yaml b/.github/workflows/build-docker-pro.yaml index b650bde46..1da09a70a 100644 --- a/.github/workflows/build-docker-pro.yaml +++ b/.github/workflows/build-docker-pro.yaml @@ -44,7 +44,7 @@ jobs: repository: dbgate/dbgate-pro token: '${{ secrets.GH_TOKEN }}' path: dbgate-pro - ref: a770b7e7a4d0ced5f1ade7cba4ba516220765648 + ref: a2f824dc711b510a5e8235d3faf4aafab1965184 - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-npm-pro.yaml b/.github/workflows/build-npm-pro.yaml index cb378c1d1..fc876f443 100644 --- a/.github/workflows/build-npm-pro.yaml +++ b/.github/workflows/build-npm-pro.yaml @@ -32,7 +32,7 @@ jobs: repository: dbgate/dbgate-pro token: '${{ secrets.GH_TOKEN }}' path: dbgate-pro - ref: a770b7e7a4d0ced5f1ade7cba4ba516220765648 + ref: a2f824dc711b510a5e8235d3faf4aafab1965184 - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/e2e-pro.yaml b/.github/workflows/e2e-pro.yaml index 0edb18b8b..9e3378751 100644 --- a/.github/workflows/e2e-pro.yaml +++ b/.github/workflows/e2e-pro.yaml @@ -26,7 +26,7 @@ jobs: repository: dbgate/dbgate-pro token: '${{ secrets.GH_TOKEN }}' path: dbgate-pro - ref: a770b7e7a4d0ced5f1ade7cba4ba516220765648 + ref: a2f824dc711b510a5e8235d3faf4aafab1965184 - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/e2e-tests/cypress/e2e/browse-data.cy.js b/e2e-tests/cypress/e2e/browse-data.cy.js index 51a0127cb..b1dd797ef 100644 --- a/e2e-tests/cypress/e2e/browse-data.cy.js +++ b/e2e-tests/cypress/e2e/browse-data.cy.js @@ -349,4 +349,17 @@ describe('Data browser data', () => { cy.testid('CompareModelTab_tabOperations').click(); cy.themeshot('comparesettings'); }); + + it.only('Query editor - AI assistant', () => { + cy.contains('MySql-connection').click(); + cy.contains('MyChinook').click(); + cy.testid('TabsPanel_buttonNewQuery').click(); + cy.testid('QueryTab_switchAiAssistantButton').click(); + cy.testid('QueryAiAssistant_promptInput').type('album names'); + cy.testid('QueryAiAssistant_queryFromQuestionButton').click(); + cy.contains('Use this').click(); + cy.testid('QueryTab_executeButton').click(); + cy.contains('Balls to the Wall'); + cy.themeshot('aiassistant'); + }); }); diff --git a/packages/api/src/controllers/databaseConnections.js b/packages/api/src/controllers/databaseConnections.js index fd51b5b32..57b794c11 100644 --- a/packages/api/src/controllers/databaseConnections.js +++ b/packages/api/src/controllers/databaseConnections.js @@ -34,6 +34,8 @@ const pipeForkLogs = require('../utility/pipeForkLogs'); const crypto = require('crypto'); const loadModelTransform = require('../utility/loadModelTransform'); const exportDbModelSql = require('../utility/exportDbModelSql'); +const axios = require('axios'); +const { callTextToSqlApi, callCompleteOnCursorApi, callRefactorSqlQueryApi } = require('../utility/authProxy'); const logger = getLogger('databaseConnections'); @@ -562,4 +564,47 @@ module.exports = { return true; }, + + textToSql_meta: true, + async textToSql({ conid, database, text, dialect }) { + const existing = this.opened.find(x => x.conid == conid && x.database == database); + const { structure } = existing || {}; + if (!structure) return { errorMessage: 'No database structure' }; + + const res = await callTextToSqlApi(text, structure, dialect); + + if (!res?.sql) { + return { errorMessage: 'No SQL generated' }; + } + + return res; + }, + + completeOnCursor_meta: true, + async completeOnCursor({ conid, database, text, dialect, line }) { + const existing = this.opened.find(x => x.conid == conid && x.database == database); + const { structure } = existing || {}; + if (!structure) return { errorMessage: 'No database structure' }; + const res = await callCompleteOnCursorApi(text, structure, dialect, line); + + if (!res?.variants) { + return { errorMessage: 'No SQL generated' }; + } + + return res; + }, + + refactorSqlQuery_meta: true, + async refactorSqlQuery({ conid, database, query, task, dialect }) { + const existing = this.opened.find(x => x.conid == conid && x.database == database); + const { structure } = existing || {}; + if (!structure) return { errorMessage: 'No database structure' }; + const res = await callRefactorSqlQueryApi(query, task, structure, dialect); + + if (!res?.sql) { + return { errorMessage: 'No SQL generated' }; + } + + return res; + }, }; diff --git a/packages/api/src/utility/authProxy.js b/packages/api/src/utility/authProxy.js index f8bec4025..0d998fec2 100644 --- a/packages/api/src/utility/authProxy.js +++ b/packages/api/src/utility/authProxy.js @@ -24,6 +24,18 @@ async function getAwsIamToken(params) { return null; } +async function callTextToSqlApi(text, structure, dialect) { + return null; +} + +async function callCompleteOnCursorApi(cursorId, query, position, dialect) { + return null; +} + +async function callRefactorSqlQueryApi(query, task, structure, dialect) { + return null; +} + module.exports = { isAuthProxySupported, authProxyGetRedirectUrl, @@ -32,4 +44,7 @@ module.exports = { getAuthProxyUrl, supportsAwsIam, getAwsIamToken, + callTextToSqlApi, + callCompleteOnCursorApi, + callRefactorSqlQueryApi, }; diff --git a/packages/types/dbinfo.d.ts b/packages/types/dbinfo.d.ts index 75012dbab..0f5a0b99f 100644 --- a/packages/types/dbinfo.d.ts +++ b/packages/types/dbinfo.d.ts @@ -189,3 +189,34 @@ export interface DatabaseInfoObjects { export interface DatabaseInfo extends DatabaseInfoObjects { engine?: string; } + +export interface ColumnReferenceTiny { + n: string; // name + r?: string; // ref name +} + +export interface PrimaryKeyInfoTiny { + c: ColumnReferenceTiny[]; // columns +} + +export interface ForeignKeyInfoTiny { + c: ColumnReferenceTiny[]; // columns + r: string; // reference table name +} + +export interface ColumnInfoTiny { + n: string; // name + t: string; // type +} + +export interface TableInfoTiny { + n: string; //name + o: string; // comment + c: ColumnInfoTiny[]; // columns + p?: PrimaryKeyInfoTiny; // primary key + f?: ForeignKeyInfoTiny[]; // foreign keys +} + +export interface DatabaseInfoTiny { + t: TableInfoTiny[]; // tables +} diff --git a/packages/web/public/bulma.css b/packages/web/public/bulma.css index 6492cd0c3..471553f74 100644 --- a/packages/web/public/bulma.css +++ b/packages/web/public/bulma.css @@ -2,6 +2,30 @@ margin: 0 !important; } +.m-1 { + margin: 0.25rem !important; +} + +.m-2 { + margin: 0.5rem !important; +} + +.m-3 { + margin: 0.75rem !important; +} + +.m-4 { + margin: 1rem !important; +} + +.m-5 { + margin: 1.5rem !important; +} + +.m-6 { + margin: 3rem !important; +} + .mt-0 { margin-top: 0 !important; } @@ -28,10 +52,6 @@ margin-bottom: 0 !important; } -.m-1 { - margin: 0.25rem !important; -} - .mt-1 { margin-top: 0.25rem !important; } @@ -58,10 +78,6 @@ margin-bottom: 0.25rem !important; } -.m-2 { - margin: 0.5rem !important; -} - .mt-2 { margin-top: 0.5rem !important; } @@ -88,10 +104,6 @@ margin-bottom: 0.5rem !important; } -.m-3 { - margin: 0.75rem !important; -} - .mt-3 { margin-top: 0.75rem !important; } @@ -118,10 +130,6 @@ margin-bottom: 0.75rem !important; } -.m-4 { - margin: 1rem !important; -} - .mt-4 { margin-top: 1rem !important; } @@ -148,10 +156,6 @@ margin-bottom: 1rem !important; } -.m-5 { - margin: 1.5rem !important; -} - .mt-5 { margin-top: 1.5rem !important; } @@ -178,10 +182,6 @@ margin-bottom: 1.5rem !important; } -.m-6 { - margin: 3rem !important; -} - .mt-6 { margin-top: 3rem !important; } diff --git a/packages/web/src/buttons/ToolStripCommandSplitButton.svelte b/packages/web/src/buttons/ToolStripCommandSplitButton.svelte index 933b5fe51..0373bb8cc 100644 --- a/packages/web/src/buttons/ToolStripCommandSplitButton.svelte +++ b/packages/web/src/buttons/ToolStripCommandSplitButton.svelte @@ -17,4 +17,5 @@ {menu} {hideDisabled} {buttonLabel} + {...$$restProps} /> diff --git a/packages/web/src/buttons/ToolStripSplitButton.svelte b/packages/web/src/buttons/ToolStripSplitButton.svelte index 007ca44cd..a21253c85 100644 --- a/packages/web/src/buttons/ToolStripSplitButton.svelte +++ b/packages/web/src/buttons/ToolStripSplitButton.svelte @@ -21,7 +21,7 @@