Pietro Di Leo · Aug 28, 2024 go to post

Recently, I asked the DC-AI where the streams formatted as %GlobalCharacterStream are saved, as since I suspected that these were responsible for a significant disk usage. 

The chatbot answered: <"Streams formatted as %GlobalCharacterStream are typically stored in the global ^CacheStream by default.">. I found out that I wasn't the only one with this problem and asked further information about the CacheStream global and how to clean it up.

The best solution to my issue was to implement a custom purge task, as I found in one of the sources the bot provided me (that provided purging code too):

1.Cleaning up CacheStream Global

2.Default Purge Does Not Delete Streams

3.A beginners guide to Orphaned data- How as a trust we cleaned up 200+gb

My overall experience with the DC-AI has been quite positive. Provided information is still closely tied to the specific answers given on the forum about the argument and could be more generalized, but I believe we're on the right way.
Links to the discussions below:

https://community.intersystems.com/ask-dc-ai?question_id=249111

https://community.intersystems.com/ask-dc-ai?question_id=249126

Pietro Di Leo · Jul 9, 2024 go to post

Wow! I'm so happy :)

Thank you to InterSystems and to the whole Developer Community for this beautiful competition. Congratulations to the other winners and all the participants for the incredible ideas they submitted. I hope these can be implemented in the next future to be useful for all the developers.

Pietro Di Leo · Apr 18, 2024 go to post

Hi Stefano,

Thank you for your response. Unfortunately, as @Enrico Parisi mentioned, OnFailureTimeout() isn't working as expected.

Nevertheless,  I managed to solve this issue by using an existing table which logs information about messages sent from the BO, a Business Service and a Business Process to initiate a parallel process alongside my ongoing transmissions.

Pietro Di Leo · Apr 17, 2024 go to post

Hi Hannah,

Thank you for your response. As you mentioned, the 'arrayref()' function is not available in IRIS 2023.1, as I suspected.

However, I managed to resolve this issue by developing a custom method to convert a Python dictionary into an ObjectScript dynamic object. I believe it works quite effectively.

I'll share the code here for anyone interested:

/// This class provides methods for working with embedded Python in various scenarios
Class Utility.Python Extends %RegisteredObject
{

/// ConvertPyDictToDynamicObject recursively converts a Python dictionary to an ObjectScript DynamicObject
/// 
/// Input:
/// - PythonDictionary: The Python dictionary to be converted
/// 
/// Output:
/// Returns a DynamicObject with similar structure and content of the parsed Python dictionary
ClassMethod ConvertPyDictToDynamicObject(PythonDictionary) [ Language = python ]
{
    import iris

    # This is a recursive function to parse a Python dictionary and convert it into an ObjectScript %DynamicObject
    # The method takes two parameters: 'data', which represents the current dictionary being parsed, and 'depth', which keeps track of the nesting level of the current data
    def parse_dictionary_to_dynamic_object(data, depth=0):
        # Create a new ObjectScript DynamicObject through iris module
        dynamic_object = iris.cls('%DynamicObject')._New()

        # If data is a dictionary, iterate through its key-value pairs
        if isinstance(data, dict):
            for key, value in data.items():
                # Recursively parse the value and set it in the DynamicObject
                parsed_value = parse_dictionary_to_dynamic_object(value, depth + 1)
                dynamic_object._Set(key, parsed_value)
        # If data is a list, create a %DynamicArray and parse each item of the list recursively
        elif isinstance(data, list):
            dynamic_array = iris.cls('%DynamicArray')._New()
            for item in data:
                parsed_item = parse_dictionary_to_dynamic_object(item, depth)
                dynamic_array._Push(parsed_item)
            return dynamic_array
        # If data is neither a dictionary nor a list, return the data itself
        else:
            return data

        return dynamic_object
    
    # Call the recursive parsing function with the input Python dictionary
    dynamic_object = parse_dictionary_to_dynamic_object(PythonDictionary)

    # Return the parsed DynamicObject
    return dynamic_object
}

}

You can easily test this method with complex dictionaries, like the one in the following example:

ClassMethod StartTestPyDictConverter()
{
    set dynObj = ##class(Python.MessageBuilder).TestPyDictConverter()
    w "dynObj tested",!
}

ClassMethod TestPyDictConverter() [ Language = python ]
{
    import iris

    data = {
        "person": {
            "name": "John Doe",
            "age": 30,
            "address": {
                "street": "123 Main St",
                "city": "Anytown",
                "zipcode": "12345"
            },
            "emails": ["john@example.com", "doe@example.com"],
            "phone_numbers": [
                {
                    "type": "home",
                    "number": "123-456-7890"
                },
                {
                    "type": "work",
                    "number": "987-654-3210"
                }
            ],
            "friends": [
                {
                    "name": "Alice",
                    "age": 28,
                    "address": {
                        "street": "456 Elm St",
                        "city": "Sometown",
                        "zipcode": "54321"
                    },
                    "emails": ["alice@example.com"],
                    "phone_numbers": [
                        {
                            "type": "mobile",
                            "number": "555-555-5555"
                        }
                    ],
                    "pets": [
                        {
                            "name": "Fluffy",
                            "species": "Cat",
                            "age": 5
                        },
                        {
                            "name": "Spot",
                            "species": "Dog",
                            "age": 3
                        }
                    ]
                },
                {
                    "name": "Bob",
                    "age": 35,
                    "address": {
                        "street": "789 Oak St",
                        "city": "Othertown",
                        "zipcode": "67890"
                    },
                    "emails": ["bob@example.com"],
                    "phone_numbers": [
                        {
                            "type": "mobile",
                            "number": "666-666-6666"
                        }
                    ]
                }
            ]
        },
        "company": {
            "name": "Acme Corporation",
            "address": {
                "street": "456 Business Ave",
                "city": "Bigcity",
                "zipcode": "54321"
            },
            "employees": [
                {
                    "name": "Jane Smith",
                    "position": "Manager",
                    "age": 40,
                    "emails": ["jane@example.com"],
                    "phone_numbers": [
                        {
                            "type": "work",
                            "number": "222-222-2222"
                        }
                    ]
                },
                {
                    "name": "Sam Johnson",
                    "position": "Developer",
                    "age": 35,
                    "emails": ["sam@example.com"],
                    "phone_numbers": [
                        {
                            "type": "work",
                            "number": "333-333-3333"
                        }
                    ]
                }
            ]
        }
    }

    dynObj = iris.cls('Utility.Python').ConvertPyDictToDynamicObject(data)

    return dynObj
}

I've tested it even with more complex dictionaries, like FHIR JSON, and it worked fine.

For example, this is a screenshot from my VSC Debugger: 

Pietro Di Leo · Apr 4, 2024 go to post

Hello, I encountered a similar issue but managed to resolve it.

If you were connected directly to the server-side folders, try the following steps: 
1. Click: View -> Command Palette -> Open Workspace Settings (JSON) 

2. In the "folders" property of the JSON you should see something like: 

"folders": [
	{
		"name": "<server_folder_name>:<namespace>",
		"uri": "isfs://<server_name>:<namespace>/"
	}
]

3. Try replacing the old one with the new one. 

If you were working on a local folder that was connected to a server, you should have a .vscode folder in your VSC workspace.

1. Try editing the settings.json file inside the folder. You should see something similar to: 

"objectscript.conn": {
    "server": "<server name>",
    "ns": "<namespace name>",
    "active": true
}

2. Edit the connection with the name of the server you want to reach

Pietro Di Leo · Mar 13, 2024 go to post

Hi Muhammad, great article! 

Do you know by chance how to switch from an instance to another through the ObjectScript extension? 

I have a local folder where I'm setting up a Docker instance, but the folder is linked to my IRIS local instance and it is not possible to unlink them even by doing Toggle connection or Refresh connection. Of course, I would like to connect to my containerized instance instead. 

Thanks :) 

Pietro Di Leo · Jan 17, 2024 go to post

I would like to export the project as an XML file, as is it possible in Studio

Pietro Di Leo · Nov 17, 2023 go to post

Thank you Brett,

if it's feasible for you, link this article to the one you're writing in order to connect articles on similar subjects. I'll do the same 

Pietro Di Leo · Nov 9, 2023 go to post

Hi, you can try something like this: 

Set sc = $$$OK
// Send a GET request
Set messageStatus = httpRequest.Get()

// Analyze response code
If '($$$ISERR(messageStatus)) {
    If httpRequest.HttpResponse.StatusCode = 200 {
        // If a positive response was received 
        // ...
        // ...
    } ElseIf httpRequest.HttpResponse.StatusCode = 404 {
        // Manage an HTTP status error
        // ...
        // ...
        // If you want a custom error status
        Set ErrorText = "This is a string that contains your custom error text"
        Set sc = $$$ERROR(ErrorCode, ErrorText)
    } Else {
        // You can manage other HTTP codes here
    } 
} Else {
    If '($ISOBJECT(httpRequest.HttpResponse.StatusCode)){
        // Manage an error raised if the endpoint couldn't be reached or if you didn't get a response in time
        // ...
        // ...
        Set ErrorText = "This is a string that contains your custom error text"
        Set sc = $$$ERROR(ErrorCode, ErrorText)
    }
}

Return sc

You can manage any status code in the way you prefer (not just code 200 or 404) 

Pietro Di Leo · Nov 6, 2023 go to post

I know that answering a question and providing your own response may seem unusual, but I won't delete this question as it could be helpful to someone in the future.

The issue was related to the method "jsonFormatter.FormatToStream", which returned "ByRef" a pStream object that, for some reason, Postman and the other client software didn't handle well. 

A solution is to remove the jsonFormatter and to pass directly the OriginalStream to the function:

Set pResponse = ##class(EnsLib.HTTP.GenericMessage).%New(OriginalStream,,tHttpResponse)

If you prefer to keep the JSONFormatter, just declare the pStream as an object of %Stream.FileCharacter class before using the FormatToStream method:

// Format the newJson with the correct indentation
Set jsonFormatter = ##class(%JSON.Formatter).%New()
// Declare a new stream object
Set pStream = ##class(%Stream.FileCharacter).%New()
Set sc = jsonFormatter.FormatToStream(jsonACK, .pStream)

Now everything works fine.

Pietro Di Leo · Oct 19, 2023 go to post

Thanks, Julius! That was part of the problem. I'm still facing some issue but now I'm able to reach a web service deployed with another program (in the next days I will retry with Render).

Pietro Di Leo · Oct 15, 2023 go to post

The Gateway is very interesting, but could it work on 2021.1?

Edit. I think so, as on Github it says IRIS supports the Gateway from version 2020.3. I will try it, thanks!

Pietro Di Leo · Oct 13, 2023 go to post

Ok, probably that's the problem. I was looking for this information but I couldn't find it before. I'm not sure if I can upgrade the remote server. Is there an alternative?

Pietro Di Leo · Oct 3, 2023 go to post

I don't know if this can help, but in objectscript the command to extract some elements from a list is the following: 

SELECT * FROM <tableName> WHERE FOR SOME %ELEMENT (<listName>) (%VALUE = '<value>')
For example, if you have a persistent class like this: 

Class User.SQLtable Extends %Persistent
{
    Property propertyList As list Of %String(MAXLEN = 100) [ Required ];
    Index ListIdx On List(ELEMENTS);
}

You can extract information using: 
SELECT * FROM User.SQLtable WHERE FOR SOME %ELEMENT (propertyList) (%VALUE = '67')

In this way you can retrieve the row that contains the specific data value of interest with dynamic or static SQL and subsequently extract the list as a property of the SQL result object

Pietro Di Leo · Oct 2, 2023 go to post

Hi Enrico,

Thank you for the response. I've tried both adding an OnFailureTimeout method in my custom BO and directly modifying the OnFailureTimeout method inside the Ens.BusinessOperation. However, in the first case, nothing happens, while in the second case, the error "ERROR #5883: Item 'Ens.BusinessOperation' is mapped from a database that you do not have write permission on" occurs

Pietro Di Leo · Sep 25, 2023 go to post

 

Hi Ashok,

Thank you for your response. As I said to Ian, maybe I expressed wrong and I apologize for any confusion, but I did not intend to start a new line within the log that is printed in the Visual Trace. Instead, I wanted to start a new line within VSC in order to avoid writing long one-line logs in the visual interface of VSC.

For example, I am looking for a way to transform this line of code:

$$$LOGINFO("this is the first line "_$c(13,10)_"this is second line"_$c(13,10)_" this is third line")

 Into something like that, to improve code readability: 

$$$LOGINFO("this is the first line "
            _$c(13,10)_"this is second line"
            _$c(13,10)_" this is third line")
Pietro Di Leo · Sep 25, 2023 go to post

Hi Ian,

Thank you for your response. Maybe I expressed wrong and I apologize for any confusion, but I did not intend to start a new line within the log that is printed in the Visual Trace. Instead, I wanted to start a new line within VSC in order to avoid writing long one-line logs in the visual interface of VSC.

For example, I am looking for a way to transform this line of code:

$$$LOGINFO("this is the first line "_$c(13,10)_"this is second line"_$c(13,10)_" this is third line")

 Into something like that, to improve code readability: 

$$$LOGINFO("this is the first line "
            _$c(13,10)_"this is second line"
            _$c(13,10)_" this is third line")
Pietro Di Leo · Sep 13, 2023 go to post

No, I don't have any HTML-type formatting. This is the message displayed through the trace: 

object: 'No response or error was received in reply to the previous message, attempting to resend the message.',
retryCount: '3'
ResponseTimeout: '5'

To display this message in the visual trace, I used the following code:

$$$TRACE("object: 'No response or error was received in reply to the previous message, attempting to resend the message.', "_$CHAR(10)_"retryCount: '"_..RetryCount_"'"_$CHAR(10)_"ResponseTimeout: '"_httpRequest.Timeout_"'")

I used $CHAR(10) to insert a new line since the $$$TRACE command isn't affected by syntax like "\n." 

Pietro Di Leo · Sep 12, 2023 go to post

Hi Pravin, 

You can use the syntax ./folderName in the files to include camp from the Search panel. 

Example

This is my workspace

I have 3 folders: 2 on a remote server and one in local.

If I would like to restrict the research only to a remote folder I can type: ./npri_server_fhir:OMR

As shown in the following picture:

Make sure you have followed the procedure outlined at this page (InterSystems ObjectScript extension for VS Code), under Enable proposed APIs, to enable the search across all folders.

Pietro Di Leo · Sep 12, 2023 go to post

Thank you Alex, how can I modify the OnFailureTimeout method for my purpose? I can find only a little documentation