go to post Julius Kavay · Jul 15, 2023 Indirection is your friend, which of course, works for globals, locals and other things too. set ^myglobal="This is the root node" set ^myglobal(12)="A node on level 1" set ^myglobal(17)="More level 1 node" set ^myglobal(17,1)="Data on the second level" set ^myglobal(19,3)="More data on the second level" ; now start to play indirection set someVariable="^myglobal" // the better way were: set someVariable=$name(^myglobal) ; and get the content of the above global write @someVariable // --> This is the root node write @someVariable@(12) // --> A node on level 1 write @someVariable@(17,1) // --> Data on the second level ; the same as above set myVariable="^myglobal(17)" // Better: set myVariable=$name(^myglobal(17)) write @myVariable // --> More level 1 node write @myVariable@(1) // Data on second level ; a bit overcomplicated set string1="^" set string2="myglobal" write @(string1_string2_"("_(15+4_","_(1+2))_")") // --> More data on second level So just (re)read the docu about indirection...
go to post Julius Kavay · Jul 7, 2023 The error message <METHOD NOT SUPPORTED> says everything. USER>s obj={"name":"john", "value":65} USER>w obj.%ToJSON() // --> {"name":"john","value":65} USER>s obj={"name":"john", "value":65, "dynObj":{"info":"something"} } USER>w obj.%ToJSON() // --> {"name":"john","value":65,"dynObj":{"info":"something"}} USER>s obj={"name":"john", "value":65, "dynObj":{"info":"something"}, "cosObj":(##class(%Net.HttpRequest).%New()) } USER>w obj.%ToJSON() // --> <METHOD NOT SUPPORTED> *%ToJSON,%Net.HttpRequest So the problem is, you try to "stringify" (JS-speech) a dynamic object, where one of the properties contains a non-dynamic object (%Net.HttpRequest in the above example).
go to post Julius Kavay · Jun 30, 2023 I have absolutely nothing to do with health and HL7 etc. except I know, they exists but the $length(string,delimiterstring) function will you always tell, how many subfields a string has for a given delimiter string. write $l("","-") --> 1 write $l("abc-def","-") --> 2 write $l("abc-","-") --> 2 write $l("abc-def-ghi","-") --> 3 etc.
go to post Julius Kavay · Jun 9, 2023 Correct.But (in case of need) there is a workaround (assuming, args is an JSON-array of arguments): kill tmp set tmp=args.%Size() for i=1:1:tmp set tmp(i)=args.%Get(i-1) set resultSet = ##class(%SQL.Statement).%ExecDirect( , sql_whereClause, tmp...)
go to post Julius Kavay · May 15, 2023 Class DC.Samples Extends %RegisteredObject { /// partition an array into two subarrays /// return [[even], [odd]] ClassMethod Task1a(x As %DynamicArray) As %DynamicArray { set t(0)=[],t(1)=[] for i=0:1:x.%Size()-1 do t(x.%Get(i)#2).%Push(x.%Get(i)) quit [(t(0)),(t(1))] } /// partition an array into two subarrays /// return [[even], [odd]] ClassMethod Task1b(x As %DynamicArray) As %DynamicArray { set t(0)=[], t(1)=[], i=x.%GetIterator() while i.%GetNext(,.v) { do t(v#2).%Push(v) } quit [(t(0)),(t(1))] } /// hamming distance of two strings ClassMethod Task2(x As %String, y As %String) As %Integer { if $l(x)-$l(y) quit "<Error>" // strings have to be the same length set r=0 for i=1:1:$l(x) set r=$e(x,i)'=$e(y,i)+r quit r } /// encrypt an string ClassMethod Task3(x As %String) As %String { quit $tr($re(x),"aeiou","01223")_"aca" } /// check a string for identical chars ClassMethod Task4(x As %String) As %Boolean { quit $tr(x,$e(x))="" } /// double chars ClassMethod Task5(x As %String) As %String { f i=$l(x):-1:1 s $e(x,i)=$e(x,i)_$e(x,i) q x } }
go to post Julius Kavay · May 4, 2023 Suppose, you have a class my.test with two methods: check1 and check2 then after running the above methode: do ##class(your.class).Transfer("my.test", "check1,check2") creates two new classes my.test.parts.check1 and my.test.parts.check.2 so what do you mean with "give the destination package a different name, maybe the original class name" ?
go to post Julius Kavay · May 3, 2023 For a handful of methods the manual method is likely the fastest... in case, you have a real big bunch of methods to copy put this "short" method into a class and let it run... /// Transfer all or selected methods from a class into /// individual classes /// cls : the donor class /// list: list of methods to be transfered: "method1,method2,..." /// or empty to transfer all methods ClassMethod Transfer(cls, list = "") { s old=##class(%Dictionary.ClassDefinition).%OpenId(cls) s:list]"" list=$lfs(list) i old { f i=old.Methods.Count():-1:1 { s met=old.Methods.GetAt(i) // grab the next method i list]"",'$lf(list,met.Name) continue // skip if not to copy s new=old.%ConstructClone() // duplicate old class s tmp=old.Name // grab the old classname s $p(tmp,".",*)="Parts."_met.Name // create a new classname s new.Name=tmp s new.Abstract=1 // make the class abstract s new.Super="" // remove all superclasses s dup=met.%ConstructClone() // duplicate the old method s dup.Name=met.Name // but keep the old name d new.Properties.Clear() // remove all properties d new.Parameters.Clear() // remove all parameters d new.Methods.Clear() // remove all methods d new.Methods.Insert(dup) // insert the copied method only d old.Methods.RemoveAt(i) // Remove this method from old class i old.Super="" { s d="" } else { s d="," } s old.Super=old.Super_d_new.Name // add the new class to extends-list s st=new.%Save() // save the new class w new.Name,"-->",$s(st:"OK",1:$system.Status.GetOneErrorText(st)),! // Possibly compile the class: do $system.OBJ.Compile(...) } s st=old.%Save() // save the old class w old.Name,"-->",$s(st:"OK",1:$system.Status.GetOneErrorText(st)),! // Possibly compile... }
go to post Julius Kavay · Jan 23, 2023 do res.HttpResponse.Data.Rewind() set dynObj = {}.%FromJSON(res.HttpResponse.Data) // now, you can use the JSON-Data write dynObj.propName // if it's a dynObject write dynObj.%Get(0) // if it's a dynArray
go to post Julius Kavay · Dec 22, 2022 If you want to reorder JSON properties (alphabetically or just put some of them at the beginning) then use a utility method, like this, especially if you have several object(types) to reorder Class DC.Utility Extends %RegisteredObject { /// Reorder a JSON Object or Array /// /// obj: JSON-Object /// ord: prop1, prop2, ... Desired order for (some) properties /// (Properties not listed are copied in the order in which they were created) /// If ord not present, properties will be reordered in aplphabetical order /// /// obj: JSON-Array /// ord: pos1, pos2, ... Desired order for (some) array items /// (Items not listed are copied in ascending order) /// ClassMethod ReOrder(obj As %DynamicAbstractObject, ord... As %String) { i obj.%Extends("%DynamicObject") { s new={}, itr=obj.%GetIterator() i '$g(ord) { while itr.%GetNext(.k) { s done(k)=0 } s k="" f s k=$o(done(k)) q:k="" d new.%Set(k,obj.%Get(k)) } else { f i=1:1:$g(ord) { s k=ord(i),done(k)=1 d:$e(obj.%GetTypeOf(k),1,2)'="un" new.%Set(k,obj.%Get(k)) } while itr.%GetNext(.k,.v) { d:'$d(done(k)) new.%Set(k,v) } } } elseif obj.%Extends("%DynamicArray") { s new=[], itr=obj.%GetIterator(), max=obj.%Size(), done="" f i=1:1:$g(ord) { s k=ord(i) i k,k<=max d new.%Push(obj.%Get(k-1)) s $bit(done,k)=1 } while itr.%GetNext(.k,.v) { d:'$bit(done,k+1) new.%Push(v) } } else { s new=obj } q new } } Some examples s car={"color":"red", "fuel":"diesel", "maxspeed":150, "maker":"Audi", "model":"Quattro Q5", "power":300, "available":true, "rating":8, "allWheel":true } s car1=##class(DC.Utility).ReOrder(car) // order all props alphabetically s car2=##class(DC.Utility).ReOrder(car,"maker","model","available") // start with maker, model, etc. w car.%ToJSON(),!,car1.%ToJSON(),!,car2.%ToJSON() ---> {"color":"red","fuel":"diesel","maxspeed":150,"maker":"Audi","model":"Quattro Q5","power":300,"available":true,"rating":8,"allWheel":true} {"allWheel":"1","available":"1","color":"red","fuel":"diesel","maker":"Audi","maxspeed":150,"model":"Quattro Q5","power":300,"rating":8} {"maker":"Audi","model":"Quattro Q5","available":"1","color":"red","fuel":"diesel","maxspeed":150,"power":300,"rating":8,"allWheel":"1"}
go to post Julius Kavay · Dec 16, 2022 Is NOT the same. You can it prove by adding a label to the line with the read command and a new line at the end // DOT VERSION // Use fic old Read *R:20 Else Do Quit ;;;; comando else aplicado a read. . Use 0 Write !!!,"Expired time." If $c(R)="a" d . Use 0 Write !!!,"A letter a has been read." . Quit write !,"If there are more lines, they will be executed",! quit // LITTLE BIT MODERN VERSION // Use fic new Read *R:20 If $Test { Use 0 Write !!!,"One character read" Quit } Else { Use 0 Write !!!,"Expired time." } write !,"If there are more lines, they will be executed",! quit now let run both of them... do old // let the timeout occur do old // now with some input do new // let the timeout occur do new // now with some input Do you see the difference? If there are more lines (at end) they will be executed in opposite cases (timeout/notimeout)
go to post Julius Kavay · Dec 15, 2022 Things are not so easy as they seem, you have to consider scopes too. Take the above class (DC.LineNumber) and add three more methods: ClassMethod CaseA(x) { if x goto zTest quit "A0" zTest quit "A1" } ClassMethod CaseB(x) { if x goto Test quit "B0" Test quit "B1" } ClassMethod Test() { write ..CaseA(0),..CaseA(1) set linenumber=..SrcLineNumberFromStack(.routine,.label,.offset,.src) do prt write ..CaseB(1),..CaseB(0) set linenumber=..SrcLineNumberFromStack(.routine,.label,.offset,.src) do prt quit // debug prt write !,"routine: ",routine write !,"label: ",label write !,"offset: ",offset write !,"linenumber: ",linenumber write !,"src:",src,!! } and now do the test: do ##class(DC.LineNumber).Test() and check the output... OK, I know, this is a (very) constructed case and shouldn't coincide with an everyday development style, but who knows, what a mad programer sometimes produces...
go to post Julius Kavay · Nov 16, 2022 If your serial class is named Data.Serial (as in your example code) then you should use the same name for the serial property too Class Data.Persistent Extends %Persistent { Property MPID as %Integer; Property Name as Data.Serial; <--- !!!!! } The correct way to set the values Set Obj=##Class(Data.Persistent).%New() Set Obj.MPID=MPID Set Obj.Name.FirstName=FirstName ; <---- Set Obj.Name.LastName=LastName ; <---- Set tSC=Obj.%Save()
go to post Julius Kavay · Nov 14, 2022 I think, I have a solution for you ClassMethod GetImage() { s req=##class(%Net.HttpRequest).%New() s req.Server="www.distrelec.de" s req.SSLConfiguration="SSL" s req.ReadRawMode=1 // <<---- this is your solution d req.Get("/Web/WebShopImages/landscape_medium/_t/if/sortimentsboxen-1.jpg") q req.HttpResponse } To get the image s rsp=##class(Some.Class).GetImage() i rsp.StatusCode=200 { s file="c:\temp\imageName.jpg" o file:"nwu":0 i $t u file d rsp.Data.Rewind(),rsp.Data.OutputToDevice() c file } That's all...
go to post Julius Kavay · Nov 7, 2022 License counting depends on how you access Cache/IRIS (i.e. Web interface or some kind of client).
go to post Julius Kavay · Nov 4, 2022 One of the problems could be the Bas64 encoding. This function inserts after each 76th byte a CRLF which possibly confuses the other party. Try with Set EncryptedBase64=$SYSTEM.Encryption.Base64Encode(encrypted, 1) The parameter 1 says, do not insert CRLFs. Also, the text you encrypt must be an ANSI (8bit) text. If you are on a unicode system, you should call Set encrypted=$SYSTEM.Encryption.AESCBCEncrypt($zcvt(text,"O","UTF8"),key,iv)
go to post Julius Kavay · Nov 2, 2022 You are just one letter away from solution... set db=##Class(SYS.Database).%OpenId("/trak/base/tc/db/ct",,.sc) //................................^^^ Id, not ID!
go to post Julius Kavay · Oct 20, 2022 I do not use Ensemble, but I would try using the JSON-Adaptor, something like this Class MessageB Extends (Ens.Request, %JSON.Adaptor) { Property ClientId As %String(MAXLEN = ""); Property message As %Stream.TmpBinary; } For example s r=##class(MessageB).%New() s r.ClientId=12345 d r.message.Write("part1") d r.message.Write("part2") w r.%JSONExportToStream(.s) d s.Rewind() w s.Read(s.Size) --> {"ClientId":"12345","message":"cGFydDFwYXJ0Mg=="}
go to post Julius Kavay · Oct 19, 2022 Your solution is nearly perfect, here my quick (untested) version. ClassMethod Encode() { // You read N bytes (which MUST be divisible by 3) and write N*4/3 encoded bytes // 3 * 8190 = 24570; 24570 * 4 / 3 = 32760; 32760 < 32768; to avoid (slow) long strings set CHUNK=24570 set NOCR=1 // don't insert CRLF after each 72 written bytes set encodedData=##class(%Stream.TmpBinary).%New() // adapt this to your needs: %Stream.Whatever... set request=##class(%Net.HttpRequest).%New() set request.Server="..." do request.Get("/...") if request.HttpResponse.StatusCode = 200 { while 'request.HttpResponse.Data.AtEnd { do encodedData.Write($system.Encryption.Base64Encode(request.HttpResponse.Data.Read(CHUNK),1)) } } QUIT encodedData // as an alternative, you could return a string or a streamobject set YOURMAXSTRING = 32767 // or 3641144 if encodedData.Size <= YOURMAXSTRING { do encodedData.Rewind() quit encodedData.Read(encodedData.Size) } else { quit encodedData } }
go to post Julius Kavay · Oct 10, 2022 You are mixing two different things... Property Data1 As list of %String; Property Data2 As %List; are two very different things. The first (Data1, equates to your DataObj.Services) is an object while the second one (Data2) is a simple scalar value (in this case a string which in its structure casually matches the inner structure of a $list() respective $listbuild() function). write $listvalid(oref.Data1) ==> 0 // NOT a list write $listvalid(oref.Data2) ==> 1 // a VALID list write $isobject(oref.Data1) ==> 1 // a valid (list)object write $isobject(oref.Data2) ==> 0 // not a valid (list)object $listnext() does NOT work on objects (your DataObj.Services) is an object
go to post Julius Kavay · Oct 8, 2022 For a string like "hallo" Cache will use 5+2 = 7 bytes. If that "hallo..." is longer then 253 bytes then length_of_string + 4 bytes will be used and if your "hallo..." is longer then 65535 bytes then length_of_string + 6 bytes will be used. But there is one more thing, you should know: the sum of the lengths of ALL properties, except the array(like) properties, can't be greater then that famous 3641144 magic number (if you use the standard Cache Storage). Array-like properties are those, which are stored in own nodes.