@@ -213,24 +213,161 @@ func outputRestOperation(w io.Writer, op *model.RestClientOperation) {
213213// createRestClient handles CREATE REST CLIENT statement.
214214func (e * Executor ) createRestClient (stmt * ast.CreateRestClientStmt ) error {
215215 if e .writer == nil {
216- return fmt .Errorf ("project not open for writing " )
216+ return fmt .Errorf ("not connected to a project (read-only mode) " )
217217 }
218218
219- // For now, just validate the statement was parsed correctly
220- fmt .Fprintf (e .output , "Parsed REST client: %s.%s with %d operations\n " ,
221- stmt .Name .Module , stmt .Name .Name , len (stmt .Operations ))
222- fmt .Fprintln (e .output , "Note: BSON writing not yet implemented for consumed REST services" )
219+ moduleName := stmt .Name .Module
220+ module , err := e .findModule (moduleName )
221+ if err != nil {
222+ return fmt .Errorf ("module not found: %s" , moduleName )
223+ }
224+
225+ // Check for existing service with same name
226+ existingServices , _ := e .reader .ListConsumedRestServices ()
227+ h , err := e .getHierarchy ()
228+ if err != nil {
229+ return fmt .Errorf ("failed to build hierarchy: %w" , err )
230+ }
223231
232+ for _ , existing := range existingServices {
233+ existModID := h .FindModuleID (existing .ContainerID )
234+ existModName := h .GetModuleName (existModID )
235+ if strings .EqualFold (existModName , moduleName ) && strings .EqualFold (existing .Name , stmt .Name .Name ) {
236+ if stmt .CreateOrModify {
237+ // Delete existing and recreate
238+ if err := e .writer .DeleteConsumedRestService (existing .ID ); err != nil {
239+ return fmt .Errorf ("failed to delete existing REST client: %w" , err )
240+ }
241+ } else {
242+ return fmt .Errorf ("REST client already exists: %s.%s (use CREATE OR MODIFY to overwrite)" , moduleName , stmt .Name .Name )
243+ }
244+ }
245+ }
246+
247+ // Resolve folder if specified
248+ containerID := module .ID
249+ if stmt .Folder != "" {
250+ folderID , err := e .resolveFolder (module .ID , stmt .Folder )
251+ if err != nil {
252+ return fmt .Errorf ("failed to resolve folder '%s': %w" , stmt .Folder , err )
253+ }
254+ containerID = folderID
255+ }
256+
257+ // Build the model from AST
258+ svc := & model.ConsumedRestService {
259+ ContainerID : containerID ,
260+ Name : stmt .Name .Name ,
261+ Documentation : stmt .Documentation ,
262+ BaseUrl : stmt .BaseUrl ,
263+ }
264+
265+ // Authentication
266+ if stmt .Authentication != nil {
267+ svc .Authentication = & model.RestAuthentication {
268+ Scheme : stmt .Authentication .Scheme ,
269+ Username : stmt .Authentication .Username ,
270+ Password : stmt .Authentication .Password ,
271+ }
272+ }
273+
274+ // Operations
275+ for _ , opDef := range stmt .Operations {
276+ op := buildRestClientOperation (opDef )
277+ svc .Operations = append (svc .Operations , op )
278+ }
279+
280+ // Write to project
281+ if err := e .writer .CreateConsumedRestService (svc ); err != nil {
282+ return fmt .Errorf ("failed to create REST client: %w" , err )
283+ }
284+
285+ fmt .Fprintf (e .output , "Created REST client: %s.%s (%d operations)\n " , moduleName , stmt .Name .Name , len (svc .Operations ))
224286 return nil
225287}
226288
289+ // buildRestClientOperation converts an AST RestOperationDef to a model RestClientOperation.
290+ func buildRestClientOperation (opDef * ast.RestOperationDef ) * model.RestClientOperation {
291+ op := & model.RestClientOperation {
292+ Name : opDef .Name ,
293+ Documentation : opDef .Documentation ,
294+ HttpMethod : opDef .Method ,
295+ Path : opDef .Path ,
296+ BodyType : opDef .BodyType ,
297+ BodyVariable : opDef .BodyVariable ,
298+ ResponseType : opDef .ResponseType ,
299+ ResponseVariable : opDef .ResponseVariable ,
300+ Timeout : opDef .Timeout ,
301+ }
302+
303+ // Path parameters
304+ for _ , p := range opDef .Parameters {
305+ name := strings .TrimPrefix (p .Name , "$" )
306+ op .Parameters = append (op .Parameters , & model.RestClientParameter {
307+ Name : name ,
308+ DataType : p .DataType ,
309+ })
310+ }
311+
312+ // Query parameters
313+ for _ , q := range opDef .QueryParameters {
314+ name := strings .TrimPrefix (q .Name , "$" )
315+ op .QueryParameters = append (op .QueryParameters , & model.RestClientParameter {
316+ Name : name ,
317+ DataType : q .DataType ,
318+ })
319+ }
320+
321+ // Headers
322+ for _ , h := range opDef .Headers {
323+ header := & model.RestClientHeader {
324+ Name : h .Name ,
325+ }
326+ if h .Variable != "" {
327+ // Dynamic header: 'prefix' + $Var or just $Var
328+ if h .Prefix != "" {
329+ header .Value = h .Prefix + "{1}"
330+ } else {
331+ header .Value = "{1}"
332+ }
333+ } else {
334+ header .Value = h .Value
335+ }
336+ op .Headers = append (op .Headers , header )
337+ }
338+
339+ return op
340+ }
341+
227342// dropRestClient handles DROP REST CLIENT statement.
228343func (e * Executor ) dropRestClient (stmt * ast.DropRestClientStmt ) error {
229344 if e .writer == nil {
230- return fmt .Errorf ("project not open for writing" )
345+ return fmt .Errorf ("not connected to a project (read-only mode)" )
346+ }
347+
348+ services , err := e .reader .ListConsumedRestServices ()
349+ if err != nil {
350+ return fmt .Errorf ("failed to list consumed REST services: %w" , err )
351+ }
352+
353+ h , err := e .getHierarchy ()
354+ if err != nil {
355+ return fmt .Errorf ("failed to build hierarchy: %w" , err )
356+ }
357+
358+ for _ , svc := range services {
359+ modID := h .FindModuleID (svc .ContainerID )
360+ moduleName := h .GetModuleName (modID )
361+ if strings .EqualFold (moduleName , stmt .Name .Module ) && strings .EqualFold (svc .Name , stmt .Name .Name ) {
362+ if err := e .writer .DeleteConsumedRestService (svc .ID ); err != nil {
363+ return fmt .Errorf ("failed to delete REST client: %w" , err )
364+ }
365+ fmt .Fprintf (e .output , "Dropped REST client: %s.%s\n " , moduleName , svc .Name )
366+ return nil
367+ }
231368 }
232369
233- return fmt .Errorf ("DROP REST CLIENT not yet implemented" )
370+ return fmt .Errorf ("REST client not found: %s" , stmt . Name )
234371}
235372
236373// formatRestAuthValue formats an authentication value for MDL output.
0 commit comments