go to post Julius Kavay · Aug 5, 2023 also, you could try the $SCONVERT(s,format,endian,position) function (Format: F4)
go to post Julius Kavay · Aug 4, 2023 set name = $name(^A) for i=1:1:10 { set name = $name(@name@("TEST"_i)) } set @name=""
go to post Julius Kavay · Aug 3, 2023 Two more bytes and the problem is solved: Property refDate As %Date [InitialExpression = {$piece($horolog,",",1)}]; //.............................................^......................^
go to post Julius Kavay · Jul 27, 2023 Caution, backward $order() is always slower than forward $order(). If you need the last (hopefully few) entries, than it's OK to use a backward-$O() but running (counting) from the bottom to the top over several millions of nodes is definitely not an effective run.
go to post Julius Kavay · Jul 26, 2023 As others already wrote, write $order(^$GLOBAL("")) gives you the first global name accessible from a given namespace. Usually, this will be a percent-global (^%...) but if you want to get the first (or all) global, which resides in a given database, the do the same as above but with extended global access set dir = "^^c:\databases\mydb\" // "^^" and "the path to your CACHE/IRIS.dat file" write $order(^$|dir|GLOBAL(""))
go to post Julius Kavay · Jul 24, 2023 There are several possibilities, using WinSCP from Windows, Linux and Samba, etc. But if "using Cache codes" (Objectscript) is a requirement, then the simplest way is: open a TCP-(server)port on the one end and a TCP-(client)port on the other end, write and read the data, close the connections. Voila. The job is done. I do not see any problem there. OK, maybe you need to open those ports. And do not forget, USB-Sticks exists too ;-))
go to post Julius Kavay · Jul 18, 2023 I'm not aware of any $ISJSON() or similar named function but you can easily make your own ClassMethod IsJSON(str) { try { ret:{}.%FromJSON(str) 1 } catch e { ret:e.Code=3 0 throw e } } set a="{name:""John Doe"" " set b="{""name"":""John Doe"" }" write ##class(some.class).IsJSON(a) --> 0 write ##class(some.class).IsJSON(b) --> 1 write ##class(some.class).IsJSON() --> <UNDEFINED>zIsJSON+1^... *str
go to post Julius Kavay · Jul 15, 2023 As an addition to the above possibilities, you can ALWAYS use (assumed, you have the rights to access the database where the global lives - this is true for both of the above too) extended global access. Just one remark, this kind of access is possible but not the recommended way for creating regular classes (databases) rather to occasionally (on demand) access data from other namespace and/or namespaces. set nsp = "USER" set myvar = ^|nsp|MyGlobal(1,2,3) If there is no namespace associated with the database (where the global lives) just use the implicit namespace set dir = "^^C:\mydatabases\myfolder\" // win-world, "^^pathToTheDatabase" set dir = "^^/opt/mydatabases/myfolder/" // unix-world, write ^|dir|myglobal(1,2,3) // and, of course all other commands and functions kill ^|dir|myglobal(1) write $order(^|dir|myglobal(1,2)) set isDef = $data(^|dir|myglobal)
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()