The jsonProvider code may also be invoked from a non-Zen context by calling one of the following APIs:

  • %WriteJSONFromArray
  • %WriteJSONFromObject
  • %WriteJSONStreamFromArray
  • %WriteJSONStreamFromObject
  • %ConvertJSONToObject

proof

Example:

##class(%ZEN.Auxiliary.jsonProvider).%WriteJSONStreamFromObject(.stream,..%OpenId(1),,,1,"aelqoc")
"<- json = ",stream.Read(),!

If you know how to work with ActiveX from MS Excel VBA, then there is no problem.

E.g. (demo.vbs):

Set f = CreateObject("CacheActiveX.Factory")
Set rs = CreateObject("CacheActiveX.ResultSet")
If Not f.IsConnected() Then

  f.Connect("cn_iptcp:127.0.0.1[1972]:SAMPLES:_SYSTEM:SYS")

  Set rs=f.DynamicSQL("select TOP 3 * from Sample.Person")
  rs.Execute()
  while rs.Next
    WScript.Echo rs.Get("SSN"'print of field SSN for first three rows from the table Sample.Person
  wend

  rs.Close()
  Set person = f.Static("Sample.Person")
  age=person.CurrentAge(45678) 'call of method of class Sample.Person

  WScript.Echo age
End If

Running a Query in Visual Basic

Indeed, thank you:

Class demo.B Extends %Persistent Final ]
{

Parameter MANAGEDEXTENT As INTEGER [ Constraint "0,1"Flags = ENUM ] = 0;

Parameter READONLY = 1;

Property P2;

Storage Default
{
<Data name="BDefaultData">
  <Value name="3">
    <Value>P2</Value>
  </Value>
</Data>
<DataLocation>^demo.AD</DataLocation>
<DefaultData>BDefaultData</DefaultData>
<IdLocation>^demo.AD</IdLocation>
<IndexLocation>^demo.AI</IndexLocation>
<StreamLocation>^demo.AS</StreamLocation>
<Type>%Library.CacheStorage</Type>
}

}

Is there any way to "generate" compatible storage? And why SQLStorage? Why not default CachéStorage, but copy-pasted from Class A?

Unfortunately, to use %CacheStorage will not work, since at compile occurs the error:

ERROR #5564: Storage reference: '^demo.AD' used in 'demo.B.cls' is already registered for use by 'demo.A.cls'
  > ERROR #5030: An error occurred while compiling class 'demo.B'

If you only need SQL access, then will be easier to create a view (CREATE VIEW), if need both, then - %CacheSQLStorage, e.g.:

Class demo.A Extends %Persistent
{

Property P1;

Property P2;

ClassMethod Fill()
{
  ..%KillExtent()
  
  i=1:1:3 {
    t=..%New()
    t.P1="P1_"_i
    t.P2="P2_"_i
    t.%Save()
  }
}

Storage Default
{
<Data name="ADefaultData">
  <Value name="1">
    <Value>%%CLASSNAME</Value>
  </Value>
  <Value name="2">
    <Value>P1</Value>
  </Value>
  <Value name="3">
    <Value>P2</Value>
  </Value>
</Data>
<DataLocation>^demo.AD</DataLocation>
<DefaultData>ADefaultData</DefaultData>
<IdLocation>^demo.AD</IdLocation>
<IndexLocation>^demo.AI</IndexLocation>
<StreamLocation>^demo.AS</StreamLocation>
<Type>%Library.CacheStorage</Type>
}

}

Class demo.B Extends %Persistent FinalStorageStrategy = Default ]
{

Parameter READONLY = 1;

Property P2;

Storage Default
{
<SQLMap name="BDefaultData">
  <Data name="P2">
    <Piece>3</Piece>
  </Data>
  <Global>^demo.AD</Global>
  <RowIdSpec name="1">
    <Expression>{L1}</Expression>
    <Field>ID</Field>
  </RowIdSpec>
  <Subscript name="1">
    <Expression>{ID}</Expression>
  </Subscript>
  <Type>data</Type>
</SQLMap>
<StreamLocation>^demo.AS</StreamLocation>
<Type>%CacheSQLStorage</Type>
}

}

Result:

USER>##class(demo.A).Fill()
 
USER>d $SYSTEM.SQL.Shell()
SQL Command Line Shell
----------------------------------------------------
 
The command prefix is currently set to: >.
Enter q to quit, ? for help.
USER>>select * from demo.A
1.      select * from demo.A
 
ID      P1      P2
1       P1_1    P2_1
2       P1_2    P2_2
3       P1_3    P2_3
 
3 Rows(s) Affected
statement prepare time(s)/globals/lines/disk: 0.1426s/46110/260143/45ms
          execute time(s)/globals/lines/disk: 0.0004s/16/809/0ms
                          cached query class: %sqlcq.USER.cls12
---------------------------------------------------------------------------
USER>>select * from demo.B
2.      select * from demo.B
 
ID      P2
1       P2_1
2       P2_2
3       P2_3
 
3 Rows(s) Affected
statement prepare time(s)/globals/lines/disk: 0.0696s/44550/243602/0ms
          execute time(s)/globals/lines/disk: 0.0002s/4/619/0ms
                          cached query class: %sqlcq.USER.cls13
---------------------------------------------------------------------------
USER>>quit
 
USER>##class(demo.B).%OpenId(3).P2
P2_3

Ok, exclusively for fun.

I made some improvements and now my score is 9, but if you try very hard, even - 0!
Who less ? ;)

Here is the code:

Class ITPlanet.Task2 Abstract ]
{

Parameter p = {$zwbunpack("㤸㜶㔴㌲㄰")};

ClassMethod main() As %String
{
 ..#p
}

}

Class ITPlanet.Test Abstract ]
{

ClassMethod length(
  class = {$classname()},
  method "main"As %Integer CodeMode = expression ]
{
##class(%Dictionary.MethodDefinition).IDKEYOpen(classmethod).Implementation.Size
}

ClassMethod test(makeDeploy = {$$$NO})
{
  ;do ##class(ITPlanet.Test).test()

  set classname="ITPlanet.Task2"
  set check=9876543210
  do:makeDeploy $system.OBJ.MakeClassDeployed(classname)
  set result=$classmethod(classname,"main")
  write !,result,!,check,
        !,"correct: ",$select(result=check:"yes",1:"no"),
        !,"length: ",..length(classname)
}

}
USER>do ##class(ITPlanet.Test).test()
 
9876543210
9876543210
correct: yes
length: 9
USER>do ##class(ITPlanet.Test).test(1)
 
9876543210
9876543210
correct: yes
length: 0

You can use the class %ZEN.proxyObject, e.g.:

Class demo.Customer Extends %RegisteredObject
{

Property p1 As %String;

Property p2 As %String;

Property list As %Collection.ListOfDT;

/// d ##class(demo.Customer).Test()
ClassMethod Test()
{
  customer=##class(demo.Customer).%New()
  customer.p1="p1"
  customer.p2="p2"
  customer.list=##class(%ListOfDataTypes).%New()
  customer.list.InsertList($lb(1,"two",,"four"))
  
  appointment=##class(%ZEN.proxyObject).%New()
  appointment.a1="a1"
  appointment.a2="a2"
  appointment.list=##class(%ListOfDataTypes).%New()
  appointment.list.InsertList($lb(2,3,"test",8))
  
  ; Cancellation
  response=##class(%ZEN.proxyObject).%New()
  response.Code="Cancellation"
  response.Info="Info_Cancellation"
  response.Code,":",! response.%ToJSON(,"2aelow")
  
  response.%Clear()

  ; Customer
  response.Code="Customer"
  response.Info=customer
  
  !!,response.Code,":",! response.%ToJSON(,"2aelow")

  response.%Clear()

  ; Appointment
  response.Code="Appointment"
  response.Info=appointment
  
  !!,response.Code,":",! response.%ToJSON(,"2aelow")
}

}
USER>##class(demo.Customer).Test()
Cancellation:
{
  "Code":"Cancellation",
  "Info":"Info_Cancellation"
}
 
Customer:
{
  "Code":"Customer",
  "Info"{
    "p1":"p1",
    "p2":"p2",
    "list":["1","two","","four"]
  }
}
 
Appointment:
{
  "Code":"Appointment",
  "Info"{
    "a1":"a1",
    "a2":"a2",
    "list":[2,3,"test",8
    ]
  }
}