go to post Mike Henderson · Mar 18 FWIW I was able to pull this successfully on Apple M2 macOS 14.4 docker engine 25.0.3.
go to post Mike Henderson · Aug 23, 2022 A word of caution - you can exhaust RAM when correlating a object with a collection like this. The pattern I use for collections of unknown size is to correlate the collection tag and loop over the items. If the collection parent (eg Envelope here) is also needed you can use XSL to reorganize the XML nodes to make it easier for the XML reader to iterate.
go to post Mike Henderson · Jan 24, 2022 The mapped port is 52773, not 52772. Run this: docker run --name test-iris -d -p 52773:52773 store/intersystems/iris-community:2021.1.0.215.3 Then open http://localhost:52773/csp/sys/UtilHome.csp
go to post Mike Henderson · May 24, 2016 I've worked around this by creating a comprehensive work-space with Atelier projects for all the databases I need to search. Then I can just drop into shell and use grep/ack. Definitely not as good as Find-in-Files but good enough until Atelier 1.1 and definitely better than firing up a windows VM.Warning - there is a large storage overhead - mostly in the Atelier/Eclipse .metadata cache especially for large codebases. However operations such as synchronizing and autocomplete perform well.
go to post Mike Henderson · May 13, 2016 Open enough tabs to get the >> chevron icon on the far right of tab bar. Clicking it will list all the tabs including the hidden ones.
go to post Mike Henderson · Apr 20, 2016 Agreed - GetErrorCodes() is the right thing to do from an I18N perspective.
go to post Mike Henderson · Apr 20, 2016 Thanks for pointing out the toolbar button. It would be nice if this was also a menu-item (preferably with hotkey) for those of us that don't use toolbars.
go to post Mike Henderson · Apr 18, 2016 What do you do when you need to cleanup things like locks? Put the unlock code both in the Catch and before the Quit?
go to post Mike Henderson · Apr 18, 2016 Most of my methods look like this: Method MyMethod() As %Status { // Initialization - note locking and transactions only when needed Set sc = $$$OK Lock +^SomeGlobal:5 If '$TEST Quit $$$ERROR($$$GeneralError,"Failed to obtain lock") Try { TSTART // When error is significant $$$ThrowOnError(..SomeMethod()) // When error can be ignored Do ..SomeMethod() // When only certain errors apply Set sc = ..SomeMethod() If $$$ISERR(sc),$SYSTEM.Status.GetErrorText(sc)["Something" $$$ThrowStatus(sc) TCOMMIT } Catch e { TROLLBACK Set sc = e.AsStatus() } Lock -^SomeGlobal Quit sc }
go to post Mike Henderson · Apr 17, 2016 I agree with both Nic and Rich.The issue with e.Log() is that it clutters up the error log with repetitive entries, each subsequent one with less detail than the prior. The same thing happens in Ensemble when errors bubble through the host jobs.The trick here is knowing when to log an error verses when to just bubble it up. Using Nic's method we lose the context of the stack since the log isn't written until the entry method with the Try/Catch. Using your method we get noise in the logs, but at least the first one has the detail we'll need.I believe the root problem here is re-throwing the status. An exception should represent something fatal and usually out of the applications control (e.g. FILEFULL) while a %Status is a call success indicator. To that end your code could be refactored to just Quit on an error instead of throwing it. That way a single log is generated in the method that triggered the exception and the stack is accurate.However this doesn't work well in nested loops. In that case a Return would work unless there is a cleanup chore (e.g. releasing locks, closing transactions, etc). I haven't come up with a pattern for nested loops that doesn't clutter up the source with a bunch of extra $$$ISERR checks that are easily missed and lead to subtle bugs.Personally I use your style without logging because:Every method uses the same control structureWorks with nested loops without extra thoughtCan ignore errors by simply invoking with Do instead of $$$TOE/$$$ThrowOnErrorCleanup code is easy to find or insertUsing ByRef/Output parameters makes it trivial to refactor to return more than one valueI do lose the ability to see an accurate stack trace but most of the time the line reference in the error is enough for me to quickly debug an issue so it is an acceptable trade-off. Only in the most trivial methods is the Try/Catch skipped.All that said Nic's style is a solid approach too. By removing a bunch of boilerplate Try/Catch code it lets the programmer focus on the logic and makes the codebase much easier on the eyes.
go to post Mike Henderson · Apr 17, 2016 Low priority (since we can compile from a csession) but it would be nice if on P4 revert the class (and dependents) were recompiled.
go to post Mike Henderson · Apr 17, 2016 Here you go - this will compile in USER namespace Class User.SQLForSome Extends %Persistent { Property Name As %String; Property Domains As list Of %String; Index Domains On Domains(ELEMENTS) [ Type = bitmap ]; Query TestQuery(Favorites As %List) As %SQLQuery(ROWSPEC = "Name:%String") { SELECT Name FROM SQLForSome WHERE FOR SOME %ELEMENT(Domains)(%VALUE %INLIST :Favorites) } // Broken when table alias used. Still will save/compile though Query TestQueryBroken(Favorites As %List) As %SQLQuery(ROWSPEC = "Name:%String") { SELECT foo.Name FROM SQLForSome foo WHERE FOR SOME %ELEMENT(foo.Domains)(%VALUE %INLIST :Favorites) } Storage Default { <Data name="SQLForSomeDefaultData"> <Value name="1"> <Value>%%CLASSNAME</Value> </Value> <Value name="2"> <Value>Domains</Value> </Value> <Value name="3"> <Value>Name</Value> </Value> </Data> <DataLocation>^User.SQLForSomeD</DataLocation> <DefaultData>SQLForSomeDefaultData</DefaultData> <IdLocation>^User.SQLForSomeD</IdLocation> <IndexLocation>^User.SQLForSomeI</IndexLocation> <StreamLocation>^User.SQLForSomeS</StreamLocation> <Type>%Library.CacheStorage</Type> } }
go to post Mike Henderson · Apr 12, 2016 Two issues:First in 2016.2 (Cache for UNIX (Apple Mac OS X for x86-64) 2016.2 (Build 618U) Wed Mar 16 2016 19:23:28 EDT) two processes are created and both call the Server method. Looks like CSP is invoking %CSP.WebSocket:Page multiple times during the initial connection. The following seems to fix the issue:Method Server() As %Status{ Quit:$D(^CacheTemp.Chat.WebSockets(..WebSocketID,"$J")) Set ^CacheTemp.Chat.WebSockets(..WebSocketID,"$J")=$J // ... Second in WebKit browsers (Safari, Chrome) if the page is refreshed the WebSocket will open but no ..StatusUpdate is received and at least one process starts spinning in an infinite loop. Sometimes it may take more than one refresh, other times multiple processes start spinning. This may be due to a long-standing bug in chromium where WebSocket close is not called on refresh/close like Firefox does (IE not tested). Adding an addition listener to init() solved the issue and seems to work cross browser:window.addEventListener("beforeunload", function (event) { if (ws) { ws.close(); ws = null }});