Discussion
· Nov 9, 2020

%session.Data with unlimited amount of indexes

Let's imagine you have to implement a method with a definition

/// Set value to %session.Data
ClassMethod setValue(params...) As %Status
{
}

How it should work

do ..setValue("key1", "val")

is equal to

set %session.Data("key1") = "val"

and 

do ..setValue("key1", "key2", "key3", "key4", "val")

is equal to 

set %session.Data("key1", "key2", "key3", "key4") = "val"

so, quite simple, any amount of arguments, while the latest one is a value, and any previous is an index, should accept at least 2 arguments.

 

How would you implement this method?

Discussion (15)0
Log in or sign up to continue

I'm not sure about what you mean with "unlimited amount of indexes"...

first, there is a limit of 255 for the parameters, this means you can have 

do ..setValue(key1,key2,...key254,value)

but you can't have 

 do ..setValue(key1,key2,...key254,key255,value)

second, if you meant to have many-many values (in sense of, we have to much data)

  do ..setValue(key1,value1)
  do ..setValue(key2,value2)
  // etc.

then, at some point you will reach the and of the available RAM (incl. swap/paging space.  Usually swap/paging space is much less then the space for the real data).

thirdly, if you meant variable number of indexes (in sense of variable number of parameters) then I can just refine Robert's solution to

ClassMethod setValue(params...) As %Status
{
   set base=$name(%session.Data)
   for i=1:1:params-1 { set base=$name(@base@(params(i)))
   set @base=params(params)
   quit 1
}

In case, you have both, variable number of indices and too much data then you could use a mix of the above with data placed in a temp file.

Somewhere, at the program start, let you point %sessionData to a temp file

   set %sessionData=$nam(^||SessionTemp)

and then consider this in the setValue method

ClassMethod setValue(params...) As %Status
{
   set bas=%sessionData
   ...
}

Of course, in your application, you have to change only those %session.Data(...) to  @%sessionData@(...)  which uses the "variable-big-data" part of %session.Data(). All other (the standard ones) stay unchanged.

I'd mimic %DispatchSetMultidimProperty signature. Shame local cannot be casted into a multi-argument call. Wrap in $g if values can be skipped.

/// do ##class().Test()
ClassMethod Test()
{
    kill ^data
    do ..setValue("val", "key1")
    do ..setValue("val", "key1", "key2", "key3", "key4")
    zw ^data
}

ClassMethod setValue(val, args...)
{
    if args=1 {
        set ^data(args(1)) = val
    } elseif args=2 {
        set ^data(args(1), args(2)) = val
    } elseif args=3 {
        set ^data(args(1), args(2), args(3)) = val
    } elseif args=4 {
        set ^data(args(1), args(2), args(3), args(4)) = val
    }
}

Another option just for the fun:

Include %SYS.PTools.Stats

Class dc.test Abstract ]
{

ClassMethod setValue(args...) As %Status
{
  
quit:args<2 $$$ERROR($$$DataMissing)

  $$$convertArrayToList(args,list)
  
quit:$listlength(list)'=args $$$ERROR($$$RequiredArgumentMissing)
  
  
set $list(list,*,*)="",
         
var=##class(%Utility).FormatString(list),
         
$extract(var,1,3)=$name(%sessionData), ##; or $name(%session.Data)
         
@var=args(args)
  
quit $$$OK
}

/// do ##class(dc.test).Test()
ClassMethod 
Test()
{
  
new %sessionData

  try{

    do $system.OBJ.DisplayError(..setValue("key1""val1")),
          
$system.OBJ.DisplayError(..setValue("key1""key2""key3""key4""val2")),
          
$system.OBJ.DisplayError(..setValue("key1""key2", , "key4""val3")),
          
$system.OBJ.DisplayError(..setValue())
    
    
write !
    
zwrite %sessionData
  
}
  
catch(ex){
    
write ex.DisplayString(),!
  
}
}

}