go to post Julius Kavay · Feb 19 There arises two questions. First, why do you use a class where the documentation starts with "This class is used internally to hold property/field values needed for computed fields"?Another word for classes which are marked as "used internally" is, that this classes can be changed (altered in its behavior) without any notice or documentation in one of the next versions. That's definitelly not what you want. Second, what is your real problem (where you think, it's only solvable by using that %Library.PropertyHelper class)? Can you post (and describe) your real problem?
go to post Julius Kavay · Jan 31 You have right, I overlooked the [ character, sorry (usually one posts a piece of code and not a piece of picture!). So the above line would be if jsonobj, jsonobj.statusCode = 200 { for i=0:1:jsonobj.value.labReports.%Size()-1 { set pdf(i)=jsonobj.value.labReports.%Get(i).%Get("pdf",,"stream<base64") } ... // do something with pfd(i) streams }
go to post Julius Kavay · Jan 30 Two notes to your (above) code - first, if you use the iterator method on an object which can contain long strings (longer what IRIS can handle) then you must specify the thrid argument to the %GetNext() method too, i.e. while iterator.%GetNext(.key, .value, "stream") { ... } - second, if you know the name and location of a stream property in an JSON object, like in your case, then just grab the data without using an iterator: try { set jsonobj = {}.%FromJSON(httprequest.HttpResponse.Data) } catch { jsonobj=0 } if jsonobj, jsonobj.statusCode = 200 { set pdf=jsonobj.value.labReport.%Get("pdf",,"stream<base64") // according to the picture you provided ... // do something with the pdf-stream } For another example, how to work with long strings see this thread.
go to post Julius Kavay · Jan 26 You have right, do {code} and do {code} while expr are mutually exclusive. I thought more something like this do {{code}} (no spaces between curly braces) or, as you suggested, a new keyword like WRAP {...}, of course, BLOCK {...} and SCOPE {...} are also acceptable. By the way, we already have an alternative for argumentless DOdo {code} while 0It looks ugly and confusing and- does not preseve $T- does not establich a new stack levelbut one can get over both easily respective do a work-around.
go to post Julius Kavay · Jan 25 I hope someone is already working on that extension and it's scheduled for the upcoming release
go to post Julius Kavay · Jan 21 Oh, I see, at the very first use of a (new) private global, the storage is decremented (on my machine) by 768 bytes. I think, that bytes will hold some management data for each provate global (name). Instance: cindy:ICINDY Version : IRIS for UNIX (Ubuntu Server LTS for x86-64) 2021.2 (Build 649U) Thu Jan 20 2022 08:49:51 EST Username: kav Password: ****** USER>s x=$storage USER>set x=$storage, ^myKav=123 write x-$storage 768 USER>set x=$storage, ^myKav2=123 write x-$storage 768 USER>set x=$storage, ^myKav3=123 write x-$storage 768 USER>set x=$storage, ^myKav3=123 write x-$storage 0 USER>set x=$storage, ^myKav2=123 write x-$storage 0 USER>set x=$storage, ^myKav=123 write x-$storage 0 USER>
go to post Julius Kavay · Jan 21 I don't see any difference USER>write $storage,! set ^myTest=123 write $storage 2199022714000 2199022714000 USER>write $zv IRIS for UNIX (Ubuntu Server LTS for x86-64) 2021.2 (Build 649U) Thu Jan 20 2022 08:49:51 EST USER> Try the above line. Maybe you have issued one or more "set variable=..." commands between the two "write $storage" statements in your tests...
go to post Julius Kavay · Jan 11 In general, $extract() and $zstrip() are your friends.If you want to strip ONLY the LAST character, then use this set data="abc,," set $extract(data,*)="" write data --> abc, If you want to strip ALL (same) trailing characters, use this set remove="," set data1="abc," set data2="abc,,," set data3="abc,,-,," set data1=$zstrip(data1,">",remove) set data2=$zstrip(data2,">",remove) set data3=$zstrip(data3,">",remove) write data1 --> abc write data2 --> abc write data3 --> abc,,-
go to post Julius Kavay · Jan 9 Just a curious question, do you talk about a form with encoding? Something like this <form method="post" enctype="multipart/form-data" ...> ... </form> If yes, I think WRC will be your friend. In any case, I have never worked with such type of encoding. Maybe someone else?
go to post Julius Kavay · Jan 8 Maybe you didn't read it carefully enough... /// the documentation say clearly: /// /// %request.Data(itemName, itemIndex) /// set vProfile1 = $Get(%request.Data("profile",1)) // the first value set vProfile2 = $Get(%request.Data("profile",2)) // the second value /// etc. /// or you use a loop /// kill value ser value=0 set idx=$order(%request.Data("profile",idx)) while idx]"" { set value($increment(value))=%request.Data("profile",idx) set idx=$order(%request.Data("profile",idx) } /// value = item count /// value(i) = i-th value
go to post Julius Kavay · Dec 21, 2023 If you know which record is locked (i.e. ^My.Global(123) ) then you can identify the locking process (and therefore the user) in a simple method Class DC.Lock Extends %RegisteredObject { /// For a given (global) reference /// return the (exclusive) locking processID and username /// /// ref: a global reference, for example: $name(^My.Global(1,2,3)) /// /// For other lock types (shared, remote) /// use the infos obtained by info_types OWNER, MODE, FLAGS and COUNTS, see /// https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_slock /// ClassMethod Who(ref) { if ^$LOCK(ref,"MODE")="X" { set pid=^$LOCK(ref,"OWNER") if pid { set job=##class(%SYS.ProcessQuery).%OpenId(pid) quit {"pid":(pid), "usr":($s(job:job.UserName,1:""))} } } else { quit {} } } } For example: set ref=$name(^My.Global(123)) lock +@ref:1 if '$test { // in case, the node is locked, // check up, by who is the node locked set who=##class(DC.Lock).Who(ref) write who.%ToJSON() --> {"pid":"2396","usr":"kav"} }
go to post Julius Kavay · Dec 15, 2023 A few lines of code and you have your own object cloner Class DC.ObjCloner [ Abstract ] { /// obj: Cache/IRIS or a Dynamic(JSON) Object /// /// For simplicity, JSON-Types null, true, false, etc. are ignored ClassMethod Clone(obj) { if $isobject(obj) { if obj.%IsA("%DynamicAbstractObject") { if obj.%IsA("%DynamicObject") { set new={},arr=0 } else { set new=[], arr=1 } set iter=obj.%GetIterator() while iter.%GetNext(.key,.val) { set:$isobject(val) val=..Clone(val) do $case(arr, 1:new.%Push(val), :new.%Set(key,val)) } quit new } else { quit obj.%ConstructClone(1) } } else { quit "" } } }
go to post Julius Kavay · Dec 13, 2023 Class DC.Import Extends (%Persistent, %JSON.Adaptor) { Property thingone As %String; Property thingtwo As %String; ClassMethod Test() { // create a test stream set myStream=##class(%Stream.TmpCharacter).%New() do myStream.Write("[{""thingone"":""Red"",""thingtwo"":""Green""},{""thingone"":""Blue"",""thingtwo"":""Yellow""}]") // convert input (JSON) stream into a JSON object set data={}.%FromJSON(myStream) // loop over the JSON-Array and import each array element into your database for i=0:1:data.%Size()-1 { set obj=..%New() set sts=obj.%JSONImport(data.%Get(i)) if sts set sts=obj.%Save() if sts continue write "Error: i=",i,", reason=",$system.Status.GetOneErrorText(sts),! } } Of course, instead of "myStream" you should use your REST-input stream. do ##class(DC.Import).Test() zwrite ^DC.ImportD ^DC.ImportD=2 ^DC.ImportD(1)=$lb("","Red","Green") ^DC.ImportD(2)=$lb("","Blue","Yellow")
go to post Julius Kavay · Dec 12, 2023 Shouldn't be a problem, $ZTZ isn't the only thing you can change. Whatever value or setting you change, $namespace, $zeof, $horolog, etc. you have to consider a simple rule, if you change things (which can be used by subsequent routines, methods, etc.) for your own use, then after using them, you have to restore them to their original value. That's all. YouRESTorWHATEVERmethod() { set oldZTZ=$ztz set $ztz=<your preferred value> ... set $ztz=oldZTZ return }
go to post Julius Kavay · Dec 11, 2023 You can change the Timezone system variable // for example EST (Eastern Standard Time, 5 hours behind UTC) set $ztz = 300 // you can even consider daylight saving // for example CET (Central European Time, 1 hour ahead of UTC) #define DSTOFFSET -60 #; -60=CET, 300=EST #define LOCALZONE -60 set $ztz = $$$LOCALZONE+$s($system.Util.IsDST():$$$DSTOFFSET,1:0) Setting $ZTZ affects the current job only (the job, which sets $ztz), so there is no danger for other processes.
go to post Julius Kavay · Nov 29, 2023 If you want, for whatever reason, to compute the CRC of a Stream then write an short method like this (or use this): /// Input : str - a sting or a stream /// typ - CRC-Type (0..7, See ISC documentation) /// /// Output: crc-value /// ClassMethod CRC(str, typ = 7) { i $isobject(str),str.%IsA("%Stream.Object") { d str.Rewind() s crc=0 while 'str.AtEnd { s crc=$zcrc(str.Read(32000),typ,crc) } ret crc } else { ret $zcrc(str,typ) } } Where is the problem?
go to post Julius Kavay · Nov 29, 2023 Just a short update, the problem is fixed in IRIS 2022.1 and later versions.
go to post Julius Kavay · Nov 23, 2023 I already have a database (named APPLIB) where such classes, routines and (some) data are stored and mapped to %ALL. By the way, I use %APP since it was introduced.Nevertheless, mapping the above mentioned class (Py.Utility) to APPLIB has the same effect: it works, if I'm in %SYS but does not work for in other (for example USER) namespace.I thought, it's simpler to explain the problem if I use a percent-class (%Zpy.Utility). USER> USER>w ##class(Py.Utility).Info() set val = ..internal(arg) ^ <OBJECT DISPATCH>zInfo+1^Py.Utility.1 *python object not found USER 2e1>q USER> USER>w ##class(%SYS.Namespace).GetPackageDest(,"Py") ^/opt/isc/icindy/db/applib/ USER> USER>zn "%SYS" %SYS>w ##class(Py.Utility).Info() def %SYS>