How to determine that a package exists?
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?
ClassMethod PackageExists(package) As %Boolean { Set prefix = package_"." Set firstClass = $Order(^oddCOM(prefix)) Quit prefix = $Extract(firstClass,1,$Length(prefix)) }
Thank you, Timothy!
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:
UPD:
Take another look at the %Dictionary.PackageDefinitionQuery:SubPackage/FlatPackage, %ZEN.Utils:EnumeratePackages
Thanks!
I have just had to do something similar, but needed it to be Case Sensitive.
The only solution that I could find that would be Case Sensitive was the SQL solution.
The PackageDefinition class contains only packages where we need to keep metadata about a package. Most packages do not have any extra metadata.
The SQL solution is the correct solution IMO. If I were a developer on the Object team I would advocate for a method in $system.OBJ - PackageExists(<package_name>) perhaps. :)