Eduard Lebedyuk · Aug 7, 2019 go to post

Here's a way without indirection:

Class MyPackage.MyClass
{

ClassMethod MyMethod(p1 = 1, p2 = 2, p3 = 3)
{
    Write p1,"-",p2,"-",p3,!
}

/// do ##class(MyPackage.MyClass).Test()
ClassMethod Test()
{
    Do ..FromJson({})
    Do ..FromJson({"p1":"first value", "p2":"second value"})
    Do ..FromJson({"p1":"first value", "p3":"third value"})
    Do ..FromJson({"p2":"second value"})
}

/// do ##class(MyPackage.MyClass).ArgPosMapping("MyPackage.MyClass", "MyMethod")
ClassMethod ArgPosMapping(class, method, Output map)
{
    kill map
    set formalspec = $$$comMemberKeyGet(class,$$$cCLASSmethod,method,$$$cMETHformalspecparsed)
    for i=1:1:$ll(formalspec) {
        set arg = $lg(formalspec, i)
        set map($lg(arg, 1)) =  i
    }
    
    set map = $ll(formalspec)
}

ClassMethod FromJson(json)
{
    Do ..ArgPosMapping($classname(), "MyMethod", .map)
    Set iterator = json.%GetIterator()
    Set position = 0
    While iterator.%GetNext(.key, .value) {
        Set position = position + 1
        Set arguments(map(key)) = value
    }
    
    Set arguments = map

    Do ..MyMethod(arguments...)
}

}
Eduard Lebedyuk · Aug 6, 2019 go to post

Is it service or operation? Please elaborate on your configuration.

Because you have XML error, I think there are some additional transformation(s) taking place.

Have you tried checking Stream at line 3 offset 120?

Eduard Lebedyuk · Aug 5, 2019 go to post

You need both Package mapping and global mappings.

In package mapping you add package containing your table from routine database for original namespace.

In global mapping you add data, index, stream and id globals from global database for original namespace.

Eduard Lebedyuk · Jul 31, 2019 go to post

Doesn't CORS exist to prevent exactly that?

Check that origin/referer headers in your OnHandleCorsRequest are what you expect them to be and all would be good.

Eduard Lebedyuk · Jul 30, 2019 go to post

E=D should work.

You don't need to throw an exception, just return error %Status from handler method.

Eduard Lebedyuk · Jul 29, 2019 go to post

The problem with JSON_OBJECT is that you need to write each field twice for each query.

It's good for one-off things, but for generalized solution authors approach looks better.

Eduard Lebedyuk · Jul 29, 2019 go to post

I use Pycharm  for complicated projects and debugging and bash for quick scripting.

Also check PythonGateway - it comes with integrated Python interpreter right in your IRIS terminal.

Eduard Lebedyuk · Jul 29, 2019 go to post

If you don't need statistics, this should help

kill ^rINDEXSQL("sqlidx")

or with macros

kill $$$SQLIndexRoot

Untested but should help.

Maybe backup the global just in case.

Eduard Lebedyuk · Jul 27, 2019 go to post

Tip.

Metadata does not change from one row to the other and accessing it takes time, so removing it from the row loop would improve the execution speed:

Class User.Test
{

Query TestQuery() As %SQLQuery
{
SELECT * FROM Sample.Person
}

/// do ##class(User.Test).Test()
ClassMethod Test()
{
    for method = "EveryRow", "Once" {
        set rSet = ..TestQueryFunc()
        
        set start = $zh
        do $classmethod(, method, rSet)
        set end = $zh
        
        write $$$FormatText("Method %1 took %2 sec.", method, end - start), !
    }
}

ClassMethod EveryRow(rSet As %SQL.ISelectResult)
{
    
    set tResults = []
    while rSet.%Next() {
        set tRow = {}
        set tMetadata = rSet.%GetMetadata()
        set tColumnCount = tMetadata.columns.Count()
        for x=1:1:tColumnCount {
            set tColumn = tMetadata.columns.GetAt(x)
            set tColumnName = tColumn.colName
            //do tRow.%Set(tColumnName, rSet.%GetData(x) )
            set $PROPERTY(tRow,tColumnName) = $PROPERTY(rSet,tColumnName)
        }
        do tResults.%Push(tRow)
    }
}

ClassMethod Once(rSet As %SQL.ISelectResult)
{
    set tResults = []
    set tColumns = ""
    
    set tMetadata = rSet.%GetMetadata()
    set tColumnCount = tMetadata.columns.Count()
    for x=1:1:tColumnCount {
        set tColumn = tMetadata.columns.GetAt(x)
        set tColumnName = tColumn.colName
        set tColumns = tColumns _ $lb(tColumnName)
    }

    while rSet.%Next() {
        set tRow = {}
        for x=1:1:tColumnCount {
            do tRow.%Set($lg(tColumns, x), rSet.%GetData(x) )
        }
        do tResults.%Push(tRow)
    }
}

}

Results for me:

>do ##class(User.Test).Test()
Method EveryRow took .017803 sec.
Method Once took .01076 sec.
Eduard Lebedyuk · Jul 25, 2019 go to post

By default Ensemble service is run under System account, which does not have user environment variables.

You can either specify system variables or run Ensemble service from a user account.

Eduard Lebedyuk · Jul 21, 2019 go to post

This really helps when you have several running containers simultaneously and don't know what port of Management Portal relates to a certain terminal.

Wouldn't help, as terminals would report internal container port, which is always 52773.

Eduard Lebedyuk · Jul 18, 2019 go to post

Try

C:\InterSystems\Cache\bin\cache.exe -s C:\InterSystems\Cache\mgr -U %%SYS C:\Users\Zdenda\Desktop\run.script 
Eduard Lebedyuk · Jul 18, 2019 go to post

You need to either escape your command or use a separate file for a script. I recommend a file.

Eduard Lebedyuk · Jul 18, 2019 go to post

I've got minimal security settings

Then you don't need to provide user and password.

  I can use this method right Login(Username As %String, Password As %String)?

No. First line of script - user, second line - password. After that - ObjectScript.

Do $system.OBJ.Load("Installer.xml", "c") I dont know why. 

Try full path. Also this method returns status, check it:

Set sc =  $system.OBJ.Load("/path/to/Installer.xml", "c")
Write:('sc) $System.Status.GetErrorText(sc) 
Eduard Lebedyuk · Jul 18, 2019 go to post

First two lines of your script should probably be user and password, unless you're running a minimal security install or enabled OS authentication.

ObjectScript code after that, yes, sothis looks correct

do ##class(User.Installer).setup()  

Maybe you need to load User.Installer beforehand?

Use $system.OBJ.Load(file, "c") to load and compile class(es) you need.

Eduard Lebedyuk · Jul 18, 2019 go to post

Sure

csession {INSTANCE} -U{NAMESPACE} < {SCRIPT}

Script contains code you want to execute, in your case the call to installer manifest. It could be a file or just the code itself.

Example.

A series of articles about automating CI/CD.

Eduard Lebedyuk · Jul 17, 2019 go to post

Fixed some issues in REST, but you have license problem.

ClassMethod CreateCoffee() As %Status
{

s json = {}.%FromJSON(%request.Data)
s CoffeeProp = ##class(User.PropertyName).%New()
s CoffeeProp.CoffeeName= json.CoffeeName
s CoffeeProp.CoffeeColor=json.CoffeeColor
s CoffeeProp.CoffeePrice= json.CoffeePrice
s Status = CoffeeProp.%Save()
}