go to post Sean Connelly · Oct 9, 2018 Try using the GetValues() method instead of the GetValuesLen() method
go to post Sean Connelly · Oct 8, 2018 Hi Evgeny,Community and Express licensing for InterSystems IRIS sounds very interesting. Do you have any more information on this?Sean.
go to post Sean Connelly · Oct 5, 2018 Hi Tuan,1. I'm not sure if you are asking for timed execution or benchmarking execution, so here is an answer to both.For timed execution use the task manager...https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GSA_manage_taskmgrFor benchmarking a loop you will want to use $zh, its the most granular time function in COS, the docs here show it being used for benchmarking the execution of code...https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_vzhorolog2. You will need to wrap your outer method call in a try catch block so that it will continue to repeat itself even if an error is thrown, something along the lines of...ClassMethod Start(){ While 1 { try { do ..YourMainMethod() } catch err { //log error here } }}More information can be found here...https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCOS_errors#GCOS_errors_ttcSean.
go to post Sean Connelly · Oct 4, 2018 No, the internal code will call AKISet when you assign a value to the AKI property. I bashed this out as a registered object, probably had a singleton pattern going on in my mind. On reflection it would be a really bad idea to mix this with a persistent object.If you really want to wrap legacy data with persistent objects then do it the right way...https://community.intersystems.com/post/art-mapping-globals-classes-1-3You can set up ^CODE("TNO","BIO",{BIOID},"AKI") as the storage structure for the AKI property value. For any new objects, it doesn't matter if you assign "1", "0" or "" to that property, it will always create the storage location with one of those three values. The state will never be broken.There is no point moving to persistent objects if there is legacy code that is bypassing it. It would be an all or nothing solution, everything uses the persistent object or not at all. In which case, when you come to deploy the object and legacy updates, you just need to run a small utility that will add in missing "AKI" nodes with an empty string value.This would be a much more maintainable approach in the long run, and you will get all the benefits of SQL as well.
go to post Sean Connelly · Oct 4, 2018 >s x=##class(Foo.Bananas).%New() >s x.BIOID=291 >zw ^CODE >s x.AKI=1 >zw ^CODE ^CODE("TNO","BIO",291,"AKI")=1 >s x.AKI="" >zw ^CODE >s x.AKI=0 >zw ^CODE ^CODE("TNO","BIO",291,"AKI")=0
go to post Sean Connelly · Oct 4, 2018 How about something along these lines... Property AKI As %Boolean; Property BIOID As %String; Method AKIGet() As %Boolean [ ServerOnly = 1 ] { If '$Data(^CODE("TNO")) Quit "" If '$Data(^CODE("TNO","BIO")) Quit "" If '$Data(^CODE("TNO","BIO",..BIOID)) Quit "" Quit $Get(^CODE("TNO","BIO",..BIOID,"AKI")) } Method AKISet(Arg As %Boolean) As %Status [ ServerOnly = 1 ] { If Arg="" { Kill ^CODE("TNO","BIO",..BIOID,"AKI") } Else { Set ^CODE("TNO","BIO",..BIOID,"AKI")=Arg } Quit $$$OK } I'm passing in your BIO number as another property, I guess you could use a public variable list. I've tried to make the getter a little defensive. You could argue that you might also need to check if ..BIOID is empty, because this can cause subscript errors, but then again, maybe you want these to fail anyway so they can be handled upstream. Sean.
go to post Sean Connelly · Oct 4, 2018 Hi,Studio will run under Wine on Linux. I've not tried it myself, but others have reported it working ok. Just make sure you are using the latest version of Wine. I seem to remember there being one issue reported here, not sure if it was ever resolved...https://community.intersystems.com/post/cache-studio-20172Alternatively you could use Atelier, Serenji or Visual Studio Code.I've also listed some other editors on this page...https://github.com/SeanConnelly/Public-Cache-ProjectsSean.
go to post Sean Connelly · Oct 4, 2018 Hi Rosti,I suspect the problem is on both the desktop and on the iphone, if you squeeze down the size of the desktop browser you will probably also see the table expanding beyond the width of the visible viewport.You might want to take a look at using table layout fixed, and allow text to overflow, take a look at the codepen examples listed on this page...https://css-tricks.com/fixing-tables-long-strings/You don't have many columns so this type of fix would be just about ok with users, any more information and I would suggest going for a card layout on the mobile device.Sean.
go to post Sean Connelly · Oct 4, 2018 Hi Hieu,This is a very common problem that will trip you up the first few times you work with persistent strings.The primary issue is that persistent strings have a default max length of 50, and in your example your are trying to save 164 characters.When you call %Save(), the internal code will first check the object is valid, if it is not then it will return an error.This is where you need a little more defensive code to catch these errors and bubble them up to your error handling code.The %Save() method returns what we call a status code, it is either a 1 or a 0, if its a 0 then it was also include a status code error text.So in your code you might do something like this Set sc=docObj.%Save() If $$$ISERR(sc) Write !,##class(%SYSTEM.Status).GetOneErrorText(sc) I've assigned the status code returned by %Save() to a variable called sc. It's fairly common to see developers use the naming convention for a status code variable of sc or tSC, but you can of course call it anything your wish within reason. If you just Write sc it will look a little garbled and would probably make out the line it failed which you spotted in your debugger. In my example I have used a macro called $$$ISERR(sc) which checks to see if the status code passed or failed, if it fails then it will use the %SYSTEM.Status class which has several helpful method to write out a more friendly display of the error. This will have something like "length longer than MAXLEN allowed of 50", which will then point you to the validation failure. OK, so lets fix the problem by increasing the %String size. You can do this two ways, the first would be to use the code inspector, if your in studio its a tab on the side panel, click on it and select Property from the top left drop down box. You will then see the property listed, click on this and you will see a list of all the settings you can apply to this property. You will see MAXLEN, you can click on its value and increase it to say 10000. You will notice this will change the code to this... Property jsonStorer As %String(MAXLEN = 10000); The second way is to just manually type this setting to the property yourself. When you now save the JSON it will pass validation and appear in your persistent store. There are a couple more things to consider. What you probably want to do is bubble up these validation errors either via return values, or by throwing an error. So you might do... Quit docObj.%Save() You can then call your saveJson() method like so.. Set sc=##class(DEMO.TestDocSource).saveJson() and then deal with the sc status code in your outer calling code. For instance if you were writing an HTML form to submit the JSON, you might return your own error response that would then be handled with an HTML form error message about exceeding the length. You should also consider that there is a limitation to how long strings can be, in older versions of Caché without long string support enabled the limitation is around 32K, modern version with long string support is around 3.6MB, take a look here... https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCOS_types_strings_long In general you will want to consider using streams instead of strings for properties that are larger than this. The other consideration is that generating JSON by hand is going to trip you up in many ways. My guess is your are just testing out an idea here, but you will want to use a built in function to produce and correctly escape the JSON for you. If you search for JSON here on the DC site then you will see lots of different ways to achieve this safely. On a final note you might want to go through the documentation a few times on Caché objects as this will explain some of these points in more detail, you will want to look at this section... https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GOBJ Good luck and welcome to the world of Caché persistence, it might seem a little quirky at first but you will learn to love it!! Sean.
go to post Sean Connelly · Oct 3, 2018 You can output the list to a file using this command... ccontrol list nodisplay > mylist.txt You could then create a class method to return the contents as a string, something along these lines using $ZF to run the command... Class Foo.Ccontrol Extends %RegisteredObject { Parameter FOLDER = "C:\InterSystems\Cache2017\bin\"; Parameter FILE = "mylist.txt"; ClassMethod GetList() { do $ZF(-1,..#FOLDER_"ccontrol list nodisplay > "_..#FILE) set stream=##class(%Stream.FileCharacter).%New() set sc=stream.LinkToFile(..#FOLDER_..#FILE) quit stream.Read() } }
go to post Sean Connelly · Sep 12, 2018 Thanks Evgeny, probably sounds about right.I would hazard a guess then that upwards of 0.1% of developers worldwide use Caché in one shape or form.It's interesting to compare that to the last stackoverflow survey...https://insights.stackoverflow.com/survey/2018/#technology-databasesespecially since some of those at the bottom of the list are developed on top of Hadoop, opens up some ideas for what could be possible on top of the IRIS Hadoop platform.On a side note, how about an annual DC survey? Would give some fascinating insights.
go to post Sean Connelly · Jul 9, 2018 Hi Wouter,I'm not looking at any HL7 documentation at the moment, but I think \X0D\ is the valid escape sequence. The X denotes that this is one or more hex characters and the 0D is hex for carriage return. The value 00D would not be a valid hex value.
go to post Sean Connelly · Jun 4, 2018 Right, probably because the settings are not in the reg to read.In which case, the OP question asked for the registry path, which would be... Computer\HKEY_USERS\(your HKEY user value here)\Software\InterSystems\Cache Studio\Settings\EditorSet the value of "Hover" to Hex 0.
go to post Sean Connelly · Jun 4, 2018 Hi Hendri,Have you tried disabling hover tips from within Studio itself, you can find it under the top menu...Tools > Options > Editor > Syntax Check and Assist > Hover TipsWell done getting Studio to run under Wine, never tried it, would be interesting to read a "how to" post on it if things turn out stable / usable for you.Sean.
go to post Sean Connelly · May 31, 2018 Hi Julian,Take a look at the documentation here...http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=EGDV_prog#EGDV_prog_settingsEssentially, when you define a setting in the SETTINGS parameter you can assign a category name to the settings value, e.g.Parameter SETTINGS = "Sheds:Foobar"Which will result in---------------------------Foobar SettingsSheds[ 5 ]---------------------------
go to post Sean Connelly · May 30, 2018 Ahh, just re-read your question, I think your asking how to change the settings label?You will need to change the language lookup value, take a look at...^CacheMsg("EnsColumns","en")
go to post Sean Connelly · May 30, 2018 Hi Larry,Have you added the property into the SETTINGS parameter, e.g.Parameter SETTINGS = "Foobar";Property Foobar As %String;If its not in the SETTINGS then it won't appear on the config UI settings.Sean.
go to post Sean Connelly · May 17, 2018 It's not a bad question, but the short answer is not in a single line of code.Take a look at this post, it might give you a few ideas if you just wanted a Dynamic Object...https://community.intersystems.com/post/xml-json-conversion
go to post Sean Connelly · May 16, 2018 Hi Laura, I find it simpler to write an XSD (even if you don't have one) and then use the XML code generator wizard. A good place to start is by using an online tool that will auto generate an XSD from XML for you, such at the one you can find here... https://www.liquid-technologies.com/online-xml-to-xsd-converter Sometimes you will need to massage the XML a little first, for instance add a second instance of an element when you only have one in your example and you know there will be many. So you would end up with an XSD that looks like this... <?xml version="1.0" encoding="utf-8"?> <!-- Created with Liquid Technologies Online Tools 1.0 (https://www.liquid-technologies.com) --> <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="Envelope"> <xs:complexType> <xs:sequence> <xs:element name="Body"> <xs:complexType> <xs:sequence> <xs:element name="RESULT"> <xs:complexType> <xs:sequence> <xs:element name="SUCCESS" type="xs:string" /> <xs:element maxOccurs="unbounded" name="LIST"> <xs:complexType> <xs:sequence> <xs:element name="ID" type="xs:unsignedShort" /> <xs:element name="NAME" type="xs:string" /> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema> Save this to a file and from studio select "Tools" from the main menu, then "add-ins" and then "XML Schema Wizard" which might be visible or you might need to click "add-ins" again to bring it into focus. Select the file, click next, de-select the "Create Persistent Classes" option and type in a package name, click next and select "Serial" for each of the classes, click next and the classes will be generated. You might need to go and compile them before they can be used. The generated code looks like this... Class Spuds.Envelope Extends (%SerialObject, %XML.Adaptor) [ ProcedureBlock ] { Parameter XMLNAME = "Envelope"; Parameter XMLSEQUENCE = 1; Property Body As Spuds.RESULT(XMLNAME = "Body", XMLPROJECTION = "WRAPPED") [ Required ]; } Class Spuds.RESULT Extends (%SerialObject, %XML.Adaptor) [ ProcedureBlock ] { Parameter XMLNAME = "RESULT"; Parameter XMLSEQUENCE = 1; Property SUCCESS As %String(MAXLEN = "", XMLNAME = "SUCCESS") [ Required ]; Property LIST As list Of Spuds.LIST(XMLNAME = "LIST", XMLPROJECTION = "ELEMENT") [ Required ]; } Class Spuds.LIST Extends (%SerialObject, %XML.Adaptor) [ ProcedureBlock ] { Parameter XMLNAME = "LIST"; Parameter XMLSEQUENCE = 1; Property ID As %xsd.unsignedShort(XMLNAME = "ID") [ Required ]; Property NAME As %String(MAXLEN = "", XMLNAME = "NAME") [ Required ]; } And here is the solution in action... TEST>s xml="<Envelope><Body><RESULT><SUCCESS>TRUE</SUCCESS><LIST><ID>11111</ID><NAME>one</NAME></LIST><LIST><ID>22222</ID><NAME>two</NAME></LIST></RESULT></Body></Envelope>" TEST>set reader=##class(%XML.Reader).%New() TEST>set sc=reader.OpenString(xml) TEST>do reader.Correlate("Envelope","Spuds.Envelope") TEST>do reader.Next(.envelope,.sc) TEST>w envelope.Body.SUCCESS TRUE TEST>w envelope.Body.LIST.GetAt(1).ID 11111 TEST>w envelope.Body.LIST.GetAt(1).NAME one