How to determine that a package exists?

Primary tabs

I need to know if given package exists or not.

Currently found two solution - one doesn't work, another works but I don't like it.

 

Solution 1.

I started, of course, with %Dictionary package - it has PackageDefinition class after all.

However, %ExistsId returned 0 on packages that clearly do exist, so I went to %LoadData, it uses this macro to determine if the package exist:

#define PACKAGE(%package)             ^oddPKG($zcvt(%package,"u"))

And zw ^oddPKG showed the root cause - ^oddPKG global only contains data for packages with tables (or something along these lines).

 

Solution 2.

Using sql to find first class that starts with package name. Seems like an overhead to me.

Query PackageExists(package) As %SQLQuery
{
SELECT TOP 1 1 As "Exists"
FROM %Dictionary.ClassDefinition
WHERE ID %STARTSWITH :package
}

/// write ##class().GetPackageExists("isc")
ClassMethod GetPackageExists(class)
{
    #dim exists As %Boolean
    if class = "" {
        set exists = $$$YES
    } else {
        set package = $case($l(class, "."), 1: class, : $p(class, ".", 1, *-1))
        set rs = ..PackageExistsFunc(package)
        do rs.%Next()
        set exists = (rs.Exists = $$$YES)
    }    
    quit exists
}

Ideas?

Answers

How about (swapping in ^oddDEF if you don't care if it's been compiled):

ClassMethod PackageExists(package) As %Boolean
{
    Set prefix = package_"."
    Set firstClass = $Order(^oddCOM(prefix))
    Quit prefix = $Extract(firstClass,1,$Length(prefix))
}

 

The simple (and documented) answer is something like this:

 

set name="Test.Package"

if ##class(%Dictionary.PackageDefinition).GetPackageList().Find($zconvert(name,"u")) { w "Yes" } else { w "No" }

@Timothy

using ^oddDEF and/or ^oddCOM works today, we hope, it will work tomorrow too, but there is no garantie

 

%Dictionary.PackageDefinition does not contain all packages, only ones with immediate tables (see Solution 1).

If it did, calling %ExistsId   would be enough.

In the class definition one can create  persistent-, serial-, registered-, abstract- and data-classes.

All of the above classes are contained in ##class(%Dictionary.PackageDefinition).GetPackageList(). Do you have a example for an class, which is not contained in the above method?

Or there is just a misunderstanding?

Create this class:

Class ABC.Try
{

/// w ##class(ABC.Try).PackageExists()
ClassMethod PackageExists(package = "ABC") As %Boolean [ CodeMode = expression ]
{
##class(%Dictionary.PackageDefinition).%ExistsId(package)
}

}

Test:

>w ##class(ABC.Try).PackageExists()
0

It also won't be available in GetPackageList

ABC.Try can also extend registered or persistent to the same effect.

Ok, I started my Studio (2018.1.1) --> New Class --> ABC.Try --> Finish.

Then removed the Extends... and I left over with

Class ABC.Try
{

}

Then saved (but no compile) and my test in a terminal:

USER>s aa=##class(%Dictionary.PackageDefinition).GetPackageList()

USER>w aa.Find("ABC")
523
USER>

Thanks!

Turns out PackageDefinition Queries are not based on PackageDefinition class.

@Julius Kavay got a point.

I will offer two more options:


Class ABC.Try
{

/// d ##class(ABC.Try).PackageExists()
ClassMethod PackageExists(package "ABC")
{
  ; option by Julius Kavay
  list=##class(%Dictionary.PackageDefinition).GetPackageList()
  ''list.Find($zcvt(package,"U")),!
  
  ; option 2
  ##class(%Library.RoutineMgr).Exists($zcvt(package,"U")_".PKG"),!
  
  ; option 3
  list
  d $system.OBJ.GetPackageList(.list,package)
  ''$d(list),!
}

}

USER>##class(ABC.Try).PackageExists("ab")
0
0
0
 
USER>##class(ABC.Try).PackageExists("abc")
1
1
1

UPD:
Take another look at the %Dictionary.PackageDefinitionQuery:SubPackage/FlatPackage, %ZEN.Utils:EnumeratePackages