· 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"


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)

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

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


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