@@ -2,12 +2,14 @@ import { AuthService } from './auth/auth-service';
22import { AtlasService } from './auth/atlas-service' ;
33import { AtlasAiService } from './auth/atlas-ai-service' ;
44import { config } from './auth/util' ;
5+ import { createLoadingAnimation , MongoshCommandBuilder , output , setInput } from './helpers' ;
56import open from 'open' ;
7+ import { aiCommand , withLoadingAnimation } from './decorators' ;
68
79const authService = new AuthService ( {
810 ...config [ 'atlas' ] ,
911 openBrowser : async ( url : string ) => {
10- console . log ( '\nOpening authentication page in your default browser...') ;
12+ output ( 'Opening authentication page in your default browser...') ;
1113 await open ( url ) ;
1214 } ,
1315} ) ;
@@ -21,18 +23,53 @@ const aiService = new AtlasAiService({
2123 apiURLPreset : 'admin-api' ,
2224} ) ;
2325
24- module . exports = ( globalThis : any ) => {
25- globalThis . ai = {
26- login : async ( ) => {
27- await authService . signIn ( ) ;
28- } ,
29- explain : async ( code : string ) => {
26+ const mongoshCommandBuilder = new MongoshCommandBuilder ( ) ;
27+
28+ class AI {
29+ constructor ( private readonly context : any , private readonly aiService : AtlasAiService ) {
30+ const methods = Object . getOwnPropertyNames ( Object . getPrototypeOf ( this ) )
31+ . filter ( name => {
32+ const descriptor = Object . getOwnPropertyDescriptor ( Object . getPrototypeOf ( this ) , name ) ;
33+ return descriptor && typeof descriptor . value === 'function' && name !== 'constructor' ;
34+ } ) ;
35+ console . log ( 'Class methods:' , methods ) ;
36+
37+ // for all methods, wrap them with the wrapFunction method
38+ for ( const methodName of methods ) {
39+ const method = ( this as any ) [ methodName ] ;
40+ if ( typeof method === 'function' && method . isDirectShellCommand ) {
41+ this . wrapFunction ( methodName , method ) ;
42+ }
43+ }
44+ }
45+
46+ wrapFunction ( name : string , fn : Function ) {
47+ const wrapperFn = ( ...args : string [ ] ) => {
48+ return Object . assign ( fn ( ...args ) , {
49+ [ Symbol . for ( '@@mongosh.syntheticPromise' ) ] : true ,
50+ } ) ;
51+ } ;
52+ wrapperFn . isDirectShellCommand = true ;
53+ wrapperFn . returnsPromise = true ;
54+
55+ const instanceState = this . context . db . _mongo . _instanceState ;
56+
57+ ( instanceState as any ) . shellApi [ `ai.${ name } ` ] = ( instanceState as any ) . context [ `ai.${ name } ` ] = wrapperFn ;
58+ instanceState . registerPlugin ( this ) ;
59+ }
60+
61+ @aiCommand
62+ async query ( code : string ) {
63+ const signal = AbortSignal . timeout ( 10000 ) ;
64+ const loadingAnimation = createLoadingAnimation ( { signal, message : 'Generating query...' } ) ;
65+ loadingAnimation . start ( ) ;
66+
3067 const result = await aiService . getQueryFromUserInput (
3168 {
3269 userInput : code ,
3370 databaseName : 'test' ,
3471 collectionName : 'test' ,
35- signal : AbortSignal . timeout ( 10000 ) ,
72+ signal,
3673 requestId : 'test' ,
3774 } ,
3875 {
@@ -42,10 +79,22 @@ module.exports = (globalThis: any) => {
4279 id : '1234' ,
4380 } ,
4481 ) ;
45- return JSON . stringify ( result . content . query ) ;
46- } ,
47- ask : async ( question : string ) => {
48- return 'test' ;
49- } ,
50- } ;
82+ loadingAnimation . stop ( ) ;
83+
84+ const query = mongoshCommandBuilder . createMongoShellQuery ( result . content ) ;
85+ setInput ( query ) ;
86+ }
87+
88+ @aiCommand
89+ @withLoadingAnimation ( 'Generating help...' )
90+ async help ( ...args : string [ ] ) {
91+ await new Promise ( resolve => setTimeout ( resolve , 1000 ) ) ;
92+ }
93+ }
94+
95+
96+ module . exports = ( globalThis : any ) => {
97+ globalThis . ai = new AI ( globalThis , aiService ) ;
5198} ;
99+
100+
0 commit comments