go to post Julius Kavay · Oct 14, 2021 You have a problem with the scoping! Indirection has a global scoping, you have to put things with indirection in a global scope: ClassMethod testvalidator(class As %String, value As %String) As %Status [ PublicList = (validator, sc) ] { new validator, sc set validator = "sc = ##class("_class_").IsValid("""_value_""")" write validator,! set @validator write sc,! quit sc } set result = ##class(...).testvalidator("%Library.Numeric","BLABLA") do $system.OBJ.DisplayError(result) --> ERROR #7207: Datatype value 'BLABLA' is not a valid number
go to post Julius Kavay · Oct 11, 2021 According to the task, "...You will receive an integer number and you will return a new number..." set s=9999999999999999999 write s --> 10000000000000000000 write AddWater(s) --> 1 // which is the expected result The above method works also for cases, where s contains a string of digits set a="9999999999999999999" write a --> 9999999999999999999 set res=AddWater(s) write res ---> 999...<165 more nines>...999 write $length(s) --> 19 write $length(res) --> 171 // 19 * 9 = 171 So why do you show those devils?
go to post Julius Kavay · Oct 8, 2021 Oh, I see right now, we can save one byte... ClassMethod AddWater(s) { f i=$l(s):-1:1 s t=$e(s,i),$e(s,i)=10**t-1/9*t q $tr(s,0) }
go to post Julius Kavay · Oct 8, 2021 Check this one... ClassMethod AddWater(s) { f i=$l(s):-1:1 s t=$e(s,i),$e(s,i)="1E"_t-1/9*t q $tr(s,0) }
go to post Julius Kavay · Oct 7, 2021 %FromJSON is not a class, it's a method of %DynamicObject and is available in IRIS and for Cache version 2016.2 and later.
go to post Julius Kavay · Oct 2, 2021 There is one thing you should check, than this could trigger effects observed by you.Objects are tracked by reference counts, as long as an objects reference count is greater then one, locks won't be released and the object isn't deleted. set obj = ##class(Some.Class).%OpenId(id, 4) // the obj's ref count is one ... // more commands // now, the application does something like this set tmp = obj // obj's ref count is now two! ... // more commands set obj = "" // the application intents to close the object // but the object still exists due to the fact that the ref count is one // (the object is still referenced by <tmp>) There are methods to detect such a situation:- $system.OBJ.ShowObjects(), lists all objects with reference counts- $system.OBJ.ShowReferences(obj), list all variables which contains a reference to <obj> A quick and dirty approach: set filename = "...some file name" open filename:"nw":0 if $t { use filename do $system.ShowObjects() do $system.ShowReferences(obj) close filename } set obj = "" Give it a try, maybe your object has multiple references which cause the problem
go to post Julius Kavay · Sep 28, 2021 I don't know exactly what you mean, maybe you have a example for us? Something like: DateFrom: 2021-09-27 DateThru: 2021-09-28 Expected time range: from ???? thru ????
go to post Julius Kavay · Sep 28, 2021 The %SYS.Namespace class contains the methods, you are looking for. write ##class(%SYS.Namespace).GetGlobalDest( [namspace], "global") --> DB where the global lies write ##class(%SYS.Namespace).GetRoutineDest( [namspace], "routine") --> DB where the routine lies write ##class(%SYS.Namespace).GetPackageDest( [namspace], "package") --> DB where the package lies
go to post Julius Kavay · Sep 27, 2021 If you create a class, you can it declare as a hidden class, see https://docs.intersystems.com/iris20211/csp/docbook/DocBook.UI.Page.cls?... Class My.Class Extends What.Ever [ Hidden ] { } will be a hidden class. For your own classes you can adjust this class keyword as you like but for the system classes - there is no chance, they lie somwhere on ISC servers (and, but this is my very own opinion, not very wise. First, I would like to read the documentation for the version I have installed (and not always the latest version) and second, I would like to read the doc everywhere! For example, I have a 10 hour flight, and want to work. And in case, a server only has a local LAN access, then you have no docu!).
go to post Julius Kavay · Sep 26, 2021 set old = ##class(%Stream.TmpCharacter).%New() do old.Write("This is my text") So, now you have an old stream, "This is my text" but want to have a new stream as "This is my NEW text". set new = ##class(%Stream.TmpCharacter).%New() do old.Rewind() set pos = 10 // This is my do new.Write(old.Read(pos)), new.Write(" NEW"), new.Write(old.Read(old.Size-pos)) And now, check the resulty do new.Rewind() write new.Read(new.Size) --> This is my NEW text
go to post Julius Kavay · Sep 24, 2021 assuming, the variable jsonStr contains the response from the API, then write jsonStr ---> {"code":200,"status":"OK","data":... set object={}.%FromJSON( jsonStr ) write object.data.hijri.date That's all.
go to post Julius Kavay · Sep 22, 2021 you wrote in your original message, I quote "...But if I add one additional column such as below the query fails:" and now, see above, you talk about "batch term session". I'm confused.
go to post Julius Kavay · Sep 21, 2021 I'm not sure, if I understand your problem correctly... but if your problem is the terminal width, then you can change the default terminal width from 80 to 132 (Edit --> Window Size) or simply, you use for example PuTTY. Sometimes my PuTTY starts on the left monitor and goes over to the second monitor, so I can see long lines in its entirety.
go to post Julius Kavay · Sep 20, 2021 Of course, my loop is a little bit too short ;-( the correct one is ClassMethod Merge(obj...) { set res=obj(1) do res.%Remove("NextCursor") for i=2:1:obj { for j=0:1:obj(i).OptOuts.%Size()-1 do res.OptOuts.%Push(obj(i).OptOuts.%Get(j)) } quit res } Sorry, it seems, a telephone call and writing does not go together.
go to post Julius Kavay · Sep 20, 2021 If I understand you correctly, all you have to do is a short loop: ClassMethod Merge(obj...) { set res=obj(1) do res.%Remove("NextCursor") for i=2:1:obj do res.OptOuts.%Push(obj(i).OptOuts) quit res } do Merge(json1, json2, json3, ...)
go to post Julius Kavay · Sep 18, 2021 Sorry to say, but your comparsion has some sore points: a) The very first mistake is, you are comparing programing languages!This is a disputable attempt because each programing language was created with a specific aim (i.e. use case) in mind. So there are very few languages which can be compared to each other. ObjecStript was created as an Operating-System-and-Database-and-Programing-Language. Nowdays, it's a Database-and-Programming-Language. Python is just a programming language! b) The second mistake is, comparing methods with the same name (one may think, they do the same thing) but they have different internal behaviour. Your Python code reads one line from the file (i.e. characters until the next LF): line = file.readline() but your ObjecScript code: set strBuffer = FileReader.ReadLine(.len, .tSC, .eol) reads a chunk of data from a stream and tries to extract a line from this chunk (take a look at the source code!). Here you loose (probably) most of the time. The more comparable statement should have been: read strBuffer assuming, the file was opened as open filename:"R":0 c) Apart from OS, CPU and Disk (HDD, SSD), where there is no information, did you made both runs under the same buffer state (cold or warm)? In my opinion you're comparing apples with oranges.
go to post Julius Kavay · Sep 16, 2021 <Nitpicking ON> For the LAST() function you can also use just an expression: LAST(y,m) QUIT $ZDATEH(m=12+y*100+(m#12)+1*100+1,8)-1 <Nitpicking OFF> By the way, if you are just interested, how many days a month in a given year has, there is a simple formula: LastDay(y,m) quit $s(m-2:m\8+m#2+30, 1:y#4=0+28) In the above formula, it's OK to use short leap year calculation (y#4=0) for contemporary dates (date from 1901 until 2099) else case you have to stick to the long format: (y#4=0)-(y#100=0)+(y#400=0)
go to post Julius Kavay · Sep 6, 2021 As we know, an email can contain one or more attached email(s), which in turn can contain other attached mails ... so we have to work recursively until the end. The following program excerpt should show the concept: ClassMethod GetMails(popAddr, popUser, popPass) { set pop=##class(%Net.POP3).%New(), cnt=0 if pop.Connect(popAddr, popUser, popPass) { if pop.GetMailBoxStatus(.cnt,.siz) { for id=1:1:cnt { if pop.Fetch(id,.msg,0) do ..getParts(pop,msg,id,0) } } } } ClassMethod getParts(pop, msg, id, lev) { for i=1:1:msg.Parts.Count() { set part=msg.Parts.GetAt(i) set typ=$zcvt(part.CntentType,"l") set dsp=part.Headers.GetAt("content-disposition") if typ["message/rfc822" { // this is another email, we step one level deeper if pop.GetAttachedEmail(msg.Parts.GetAt(i), .new) do ..getParts(pop, new, id, lev+1) } elseif dsp["attachment" { // attachments if typ["application/pdf" { } elseif typ["image" { } elseif ... { } } elseif typ["text" { } elseif ... { } } }
go to post Julius Kavay · Sep 1, 2021 You could start with select * from %SYS.Task and look at the TaskClass column, this gives you the entry point for a given task.
go to post Julius Kavay · Aug 31, 2021 You could create an abstract class, which adds all the information you need to your class(es), see the example below.Then include this class into the class(es) where you need this kind of information: Class Your.Class Extends (%Persistent, DC.ClassInfo) { ... } Class Your.OtherClass Extends (%Persistent, DC.ClassInfo) { ... } and use it as follows: set allProps = ##class(Your.Class).PropertyInfo() write allProps.%ToJSON() --> [prop1, prop2, ...] // here you get the names of all properties set oneProp = ##class(Your.Class).PropertyInfo("aPropertyName") --> {"Type":"%String"} // Info about one property The same goes for the methods too. Class definition for the (example) DC.ClassInfo class: Class DC.ClassInfo [ Abstract ] { /// Return information about properties /// /// 1) return list of all properties /// obj.PropertyInfo() --> [Propertynam1, Propertyname2, Propertyname3, ...] /// /// 2) return info for a specific property /// obj.PropertyInfo(propertyname) --> {"Type":type, "MaxLen":nn, "Scale":n, ...} /// ClassMethod PropertyInfo(name = "") As %DynamicObject [ CodeMode = objectgenerator ] { set prp=%compiledclass.Properties, all={} for i=1:1:prp.Count() { set p=prp.GetAt(i), inf={} // Add all the infos you need... set inf.Type=p.Type set x=p.Parameters.GetAt("MAXLEN") set:x]"" inf.MaxLen=x set x=p.Parameters.GetAt("SCALE") set:x]"" inf.Scale=x do all.%Set(p.Name,inf) } do %code.WriteLine($c(9)_"set prp="_all.%ToJSON()) do %code.WriteLine($c(9)_"if name]"""" quit prp.%Get(name)") do %code.WriteLine($c(9)_"set itr=prp.%GetIterator(), names=[]") do %code.WriteLine($c(9)_"while itr.%GetNext(.k) { do names.%Push(k) }") do %code.WriteLine($c(9)_"quit names") quit $$$OK } /// Return information about properties /// /// 1) return list of all properties /// obj.PropertyInfo() --> [Propertynam1, Propertyname2, Propertyname3, ...] /// /// 2) return info for a specific property /// obj.PropertyInfo(propertyname) --> {"Type":type, "MaxLen":nn, "Scale":n, ...} /// ClassMethod MethodInfo(name = "") As %DynamicObject [ CodeMode = objectgenerator ] { set mth=%compiledclass.Methods, all={} for i=1:1:mth.Count() { set m=mth.GetAt(i) // Add all the infos you need... set inf={}, spc=m.FormalSpecParsed set inf.SqlProc=m.SqlProc set inf.ClassMethod=m.ClassMethod set inf.ReturnType=m.ReturnType set inf.Args=[] for j=1:1:$ll(spc) { set arg={}, itm=$li(spc,j), arg.Name=$li(itm), arg.Type=$li(itm,2) set arg.ByRef=$li(itm,3)="&", arg.DefValue=$li(itm,4) do inf.Args.%Push(arg) } do all.%Set(m.Name,inf) } do %code.WriteLine($c(9)_"set mth="_all.%ToJSON()) do %code.WriteLine($c(9)_"if name]"""" quit mth.%Get(name)") do %code.WriteLine($c(9)_"set itr=mth.%GetIterator(), names=[]") do %code.WriteLine($c(9)_"while itr.%GetNext(.k) { do names.%Push(k) }") do %code.WriteLine($c(9)_"quit names") quit $$$OK } } The class should work, but it's only partially tested. Also, you may want to omit all the inherited properties and methods set p=prp.GetAt(i) continue:p.Origin '= %class.Name // skip inherited propps set m=mth.GetAt(i) continue:m.Origin '= %class.Name // skip inherited methods it's up to you. Also you can add other informations, depending on your needs, see the respective classes (%Dictionary.CompiledClass, %Dictionary.CompiledProperties and %Dictionary.CompiledMethods)