go to post Ken Earl · Aug 18, 2022 Seems like a pointless exercise to me. A question to ask is what is the objective for this? There is a quick way to do this but it depends on how accurate you want the count to be. In the Management Portal, under System Explorer, Classes there is the option to export classes to an external XML file; there is also the option to include/exclude system classes and select individual or all classes. This will export the classes into an XML file which you can open in a text file editor to get the number of lines. Note though, the XML export adds additional lines for tags to differentiate the code sections so the count will be greater than the actual lines shown when actually editing the code in the usual editor. But it could be an option for you.
go to post Ken Earl · Jun 24, 2022 You need to understand the difference between $order and $query; they both handle globals/arrays differently for different purposes.$order is the more straightforward to use (and more commonly used); it scans down a particular node of a global/array. For example for your example: `set n="" for{ set n=$order(^TestGlobal("Not Configured",n)) quit:n="" ; do something with n } ` $query is more useful if the global structure is unknown or less structured. It starts at the top of the global and returns the entire subscript string at a given level. So again for your example, the first $query would return ("Not Configured","Value 1"). You could then use $QL to get the number of subscripts at that level (2 in this case), and $qs(subscripts,position) to get the value of the subscript. set gbl="TestGlobal" set node=$q(@gbl@("")) w node ; this would return TestGlobal("Not Configured","Value 1") w $ql(node) ; this would return 2 w $qs(node,1) ; this would return "not configured" w $qs(node,2) ; this would return "Value 1" w @node ; returns the data at that node; in this example null $order is the more commonly used. You need to understand how to use globals and arrays to efficiently store data, and how to traverse them using $order. Globals and arrays are handled the same except globals are store on disk (persistant/permanent) and arrays are stored in memory (volatile/temporary). Hope this helps.
go to post Ken Earl · Mar 28, 2022 I have also looked into installing the db onto a NAS drive (but not using Docker). From my understanding, you cannot do this with the free community version of Iris/Cache, I believe a licenced version would enable this functionality. I haven't purchased a licence to prove this as I can't justify buying a personal licence for myself.Professionally though, where the company I work for have purchased licences, a local installation of Iris/Cache can access different db's on remote servers. I hope that helps.
go to post Ken Earl · Dec 22, 2021 Interesting article, thanks Rob. Have you written any documents (or aware of any documentation) that details how the globals work in the background? I know when I started coding Mumps in the early 90's, I assumed that every time you referred to a global in the code the data was being accessed directly from the disk. However I know that isn't the case and have a vague understanding that the global data is stored in data blocks stored in a b-tree structure but I would like a deeper understanding of how globals are actually stored and managed.
go to post Ken Earl · Oct 11, 2021 I don't fully understand the Cache licences as they are managed by someone else in our company but my understanding is that whenever a task is 'JOB'bed on a database the licence count is increased. For that reason we avoid JOB's unless absolutely necessary. Hope that helps in some way.
go to post Ken Earl · Jun 17, 2021 This is how I would do it. Use the following query to insert the data (note the colons before the variable names); &sql( insert into tableX (firstname,middleName,surname) values (:firstname,:middleName,:surname) ) I don't know how you have your data stored, but assuming that the data is on an array, try something along these lines: set idx=""for { set idx=$order(personArray(idx)) quit:idx="" set firstname=personArray(idx,"firstName") set middleName=personArray(idx,"middleName") set surname=personArray(idx,"surname") &sql( insert into tableX (firstname,middleName,surname) values (:firstname,:middleName,:surname) )} Hope this is useful.
go to post Ken Earl · Jul 29, 2020 Thanks again for the code, it does exactly what I am looking for. However, I have amended the code to list all of the abstract methods required to be implemented for the subclass in the error message. Class User.Abstract.AbstractChecker { ClassMethod Check() As %Status [ CodeMode = objectgenerator, ForceGenerate ] { k absCheck #Dim sc As %Status = $$$OK // Get class name from %compiledclass object which is an instance of a currently compiled class Set class = %compiledclass.Name ; get the abstract methods set methodCnt=..FindAbstractMethods(class,.methods) ; check whether the abstract methods have been implemented set methodCnt=$order(methods(""),-1) for i=1:1:methodCnt { set method=methods(i) set origin = $$$comMemberKeyGet(class, $$$cCLASSmethod, method, $$$cMETHorigin) set errtext=$$$FormatText("%1 [abstract] (origin %2)", method,origin) ; build array of error messages set absCheck("AbsNotImp",$order(absCheck("AbsNotImp",""),-1)+1)=errtext } ; if there are error messages build the error string set str="" if $data(absCheck("AbsNotImp")) { set ind="",ind=$order(absCheck("AbsNotImp",ind)) while ind { set $piece(str,", ",ind)="("_ind_") "_$get(absCheck("AbsNotImp",ind)) set ind=$order(absCheck("AbsNotImp",ind)) } set str="In class '"_class_"' the following "_$order(absCheck("AbsNotImp",""),-1)_" abstract classes are to be implemented: "_str set sc=$$$ERROR($$$GeneralError,str) } quit $get(sc) } ClassMethod FindAbstractMethods(class As %String, ByRef methods As %String) As %Integer { kill methods // Iterate over class methods. // You can also use %class object to iterate Set method=$$$comMemberNext(class, $$$cCLASSmethod, "") While method'="" { // Get method abstract state Set abstract = $$$comMemberKeyGet(class, $$$cCLASSmethod, method, $$$cMETHabstract) if abstract{ set methods($order(methods(""),-1)+1)=method } Set method=$$$comMemberNext(class, $$$cCLASSmethod, method) } quit +$order(methods(""),-1) } }
go to post Ken Earl · Jul 27, 2020 Eduard, Many thanks for the code it does what I am looking for. Do you know if there are plans for the compiler to check for the implementation of abstract methods instead of having to inherit code to do this? A couple of things I have noticed: If the method is inherited in a Persistent class, it won't compile. It looks as though it checks for the name of the abstract method but not the number of parameters the method requires. But otherwise that is what I am looking for, I just have to remember to add the AbstractChecker to the inheritance list. Thanks again.
go to post Ken Earl · Jul 26, 2020 Hi Jenna, Thanks for your response. Fully understand your response but unless I am doing something wrong, Cache does not seem to throw an error/warning if the subclass does not implement the abstract methods defined in the superclass. My understanding is that inherited abstract methods in subclasses must be implemented (even if the implemented method is empty) to standardise class interfaces but in my code this does not seem to be being enforced. Thanks again, Ken
go to post Ken Earl · May 6, 2020 Thanks Robert,How do I ensure that the USER database is part of the durable environment? I am attempting this just locally on my pc (not using any external servers so I am expecting the DB to be stored locally), so do I have to add/change anything to the Docker Run command below? docker run --detach --publish 52773:52773 --volume /data/dur:/dur --env ISC_DATA_DIRECTORY=/dur/iconfig --name iris22 store/intersystems/iris-community:2020.1.0.199.0 Many thanks
go to post Ken Earl · Mar 16, 2020 I think you're overthinking this, either method is fine. If you are passing a key value and not searching each time then this is nothing to worry about. Sometimes doing something in 2 steps can be easier to read than a compound instruction.
go to post Ken Earl · Mar 16, 2020 Use $QUERY, $QL and $QS to traverse the array ClassMethod Array(){; Note: $query only works on globals or ; public variables ; not local array in an object set ^tmp(1,2,3)="Joe"set ^tmp(1,2,3,4,1)="Paul"set ^tmp(1,2,3,4,2)="Paula"set ^tmp(1,2,3,5,6)="Tom" ; use indirection to traverse the global ; get the data nodesset sub="^tmp"set sub=$query(@sub)while sub]""{ write !,sub,"=",@sub ; use $QL to get the number of subscripts for the data node set subCnt=$ql(sub) w !,"Number of subscripts = ",subCnt ; use $QS to get the subscript value for i=1:1:subCnt w !,"subscript ",i,"=",$qs(sub,i) ; get the next data node set sub=$query(@sub)} Hope this helps.
go to post Ken Earl · Mar 16, 2020 Interesting question and one I hadn't considered. If it helps, you need to think about the type of data you are referencing as they work on different data structures: $GET works on variables, arrays and global references but does not refer to object data. GetAt is a specific object function. I cannot see any need to combine both in the same instruction, both return null if the item does not exist. Hope this helps.
go to post Ken Earl · Feb 10, 2020 As we don't have source control, I have been experimenting with Tortoise SVN to create a local source control on my own PC.This involves exporting the source files from Cache in .xml format to my source control folders and managing the commits via the Tortoise SVN file controls Its not ideal but it has worked for me as an experiment to have personal control for my work.
go to post Ken Earl · Jul 16, 2019 To call the method from the terminal use the following code (note that you have to initialise the variable and indicate that you are passing the value by reference by using the '.' before the relevant parameter):set var="" do ##class(classname).DoMyWork(.var, 0) write varTherefore in your method, the value you assign to pWorkCount will be returned to var. You don't need to return the variable, it will be automatically returned as the variable has been passed by reference.The dot before variable name (.var) in the method call indicates that the variable is being passed by reference (by default values are passed by value), therefore I believe the "Output" keyword is optional (but it does make it clear in the method signature how the value is being passed).I hope this makes sense; this depends on understanding the difference between passing by reference and value.