Timothy Leavitt · Feb 10, 2023 go to post

I agree on most of this. A few comments:

"Triple slash - Great idea. TestCoverage - Great tool. Why are they not in a single "powerful" package?"

These tools solve different, distinct problems (although both are related to unit testing). Tools that solve different, distinct problems should be separate packages. If you want to write a single "powerful" package that depends on both of them and maybe adds some glue between them, feel free!

Dependencies:

Packages should use semantic versioning, and dependencies in IPM can be declared in a way that adheres to the semantic versioning contract. It's the responsibility of the dependency repo owner to follow this, and if you don't trust them you can just lock down to the version you tested with.

Also, I'm hoping to get around to reviewing your TestCoverage PR soon - just trying to deal with some CI infrastructure issues, and my day job keeps interfering. smiley

Timothy Leavitt · Feb 6, 2023 go to post

Here's a quick example. In short:

  • View Other
  • Click in the document
  • Click the thing that shows up in the bottom status bar
  • Enter routine + offset (e.g., copy/paste from error message) and hit enter.

It would be nice if this was available via quick pick based on the isfs context (including the routine, not just the tag+offset).

Timothy Leavitt · Feb 1, 2023 go to post

@Kari Vatjus-Anttila I'm just seeing this now. I'm a bit mystified - currently I'm using the same flags with latest-enough IRIS and the latest package manager, and it's fine.

It's possible that the mocking framework is causing issues. It looks like it has its own unit test manager; how does that play alongside the custom TestCoverage unit test manager? Have you made further changes to TestCoverage.Manager?

Timothy Leavitt · Jan 24, 2023 go to post

Also - git-source-control 2.1.0 fixes issues with import of its own export format. You should try it out. ;)

Timothy Leavitt · Jan 24, 2023 go to post

@Evgeny Shvarov as we've covered in GitHub issues, the business rule issue is a product-level issue (in the new Angular rule editor only, not the old Zen rule editor). I clarified https://github.com/intersystems/git-source-control/issues/225 re: the importable format.

The non-"wrapped" XML export format is importable by git-source-control and, I believe, IPM itself, although not by $System.OBJ.Load. It's just a matter of preference/readability. In a package manager context being loadable by $System.OBJ.Load isn't as important, and while the enclosing <Export> and <Document> tags aren't as annoying for XML files as for XML-exported classes/routines/etc., they're still annoying and distract from the true content of the document.

Timothy Leavitt · Jan 4, 2023 go to post

@Dmitry Maslennikov it's not actually a REST service, I just want a web application where I have full control over behavior of URLs under the application root in ObjectScript. %CSP.REST is the easiest (maybe only?) way to do that.

I ended up implementing Login as follows (which at least mostly works):

/// Called for a REST page in the event of a login being required
ClassMethod Login(skipheader As %Boolean = 1) As %Status [ ProcedureBlock = 0 ]
{
    // Support including logo image (most of the time...)
    Set brokerApp = "/csp/broker/"
    Set brokerName = $Replace(%request.URL,$Piece(%request.URL,"/portal",1),brokerApp)
    If (brokerName '= brokerApp) {
        Set filename = $System.CSP.GetFileName(brokerName)
        If ##class(%Library.File).Exists(filename) {
            Set %response.ServerSideRedirect = brokerName
            Quit $$$OK
        }
    }

    // Redirect with trailing slash (supports above)
    If ($Extract(%request.CgiEnvs("REQUEST_URI"),*) '= "/") && (%request.URL = %request.Application) {
        Set %response.Redirect = %request.Application
        Do %response.WriteHTTPHeader()
        Quit $$$OK
    }

    // Suppress "Access Denied" error message
    If %request.Method = "GET" {
        Set %request.Data("Error:ErrorCode",1) = $$$ERROR($$$RequireAuthentication)
    }

    Quit ##class(%CSP.Login).Page()
}
Timothy Leavitt · Nov 30, 2022 go to post

My first thought for "there should be results but there aren't" is an index that hasn't been built. Try calling %BuildIndices(,1,1) on the local table and see if that makes a difference. (Note - that purges existing indices and locks the extent, so use with caution if there are transactional updates happening to the table.)

Timothy Leavitt · Nov 30, 2022 go to post

@Eduard Lebedyuk - I just found this while looking to do the same thing. You say that adding a favorite is the easiest way - are there other approaches as well short of editing code you shouldn't edit?

Timothy Leavitt · Nov 3, 2022 go to post

This is a good point. Fortunately, dictionary version updates are few and far between these days. (They used to happen all the time.)

Timothy Leavitt · Oct 26, 2022 go to post

You could do something truly horrible and disgusting with the storage definition, like:

<IndexLocation>@$Select($D(%SuppressIndexFile,0):"foo",1:"^DC.Demo.SuppressIndexFileI")</IndexLocation>

But that would be truly horrible and disgusting. (Echoing Robert Cemper's comment, knowing why would help!)

Timothy Leavitt · Oct 20, 2022 go to post

I've added two more questions at a colleague's suggestion:

What has made an upgrade fail?

When have you had to roll-back?

Timothy Leavitt · Oct 19, 2022 go to post

@Julian.Matthews7786 thanks for the super quick reply!

A follow-up question - do you tend to do maintenance release updates or just jump major versions?

Timothy Leavitt · Oct 17, 2022 go to post

Not sure if this is what you're getting at, but one of the most exciting and unique things about ObjectScript is how natural it is to do metaprogramming (in the sense of writing ObjectScript that treats other ObjectScript code as data). Because all of your code is in the database, you can work with it from an object or relational perspective - see the %Dictionary package.

There are to main ways of doing this: generators and projections. A generator produces the actual code that will run for a method or trigger in a class at compile time, typically based on the class definition. A projection adds side effects of compiling/recompiling/deleting the class (e.g., updating a global with metadata about the class, creating + queueing compilation of other classes).

isc.rest has a lots of examples of both of these; here's a representative sample:

%pkg.isc.rest.handlerProjection does a bunch of SQL/object updates to data after compilation

%pkg.isc.rest.handler (which uses that projection) has a CodeMode = objectgenerator method that fails compilation of subclasses if certain methods are not overridden.

%pkg.isc.rest.model.action.projection creates a separate class with dependencies on other classes properly declared and queues it to be compiled. The class created extends %pkg.isc.rest.model.action.handler which defines some methods with CodeMode = objectgenerator, though a separate class does the actual work of code generation.

Timothy Leavitt · Oct 6, 2022 go to post

Glad this was the first Google result for "docker required linux capability is missing" smiley

Timothy Leavitt · Oct 5, 2022 go to post

@Eduard Lebedyuk if you say zpm "install packagename" and you already have the latest version installed, it'll just reinstall the same package (rather than doing nothing, which is what Ron wants).

Timothy Leavitt · Oct 5, 2022 go to post

@sween this seems like a good use case to define your own package with dependencies for the things you want to "install if not already installed" - installing your package will install those dependencies only if they haven't been installed. (And if the versions update, they'll be updated.)

Alternatively, you could do something like:
 

if '##class(%ZPM.PackageManager.Developer.Module).NameExists(packagename) { zpm "install "_packagename }
Timothy Leavitt · Sep 19, 2022 go to post

Hard for any language to beat:

ClassMethod makeComplement(d As %String) As %String
{
 q $tr(d,"ATGC","TACG")
}
Timothy Leavitt · Sep 13, 2022 go to post

Not great around edge cases, but this passes the tests at least (and might beat a $find-based approach since it avoids set commands):

ClassMethod findShort(s) As %Integer
{
 f i=1:1 ret:$locate(s,"(^| )\w{"_i_"}( |$)") i
}
Timothy Leavitt · Sep 7, 2022 go to post

If the thing you're working with is actually some sort of configuration data then this is probably a good approach. If not then building your own integration to transmit the data is probably better.