Question
Eduard Lebedyuk · Feb 1, 2017

How can I override the getter for serial property?

I want to override getter for a serial property as a whole, because getter code depends on a class in which a property is defined.

Let's say I have CS.Serial as a serial class:

Class CS.Serial Extends %SerialObject
{
Property Year As %Integer;

Property Month As %Integer;
}

And CS.Persistent as a persistent class:

Class CS.Persistent Extends %Persistent
{

Property data As CS.Serial [ SqlComputeCode = {set {*} = ##class(CS.Persistent).dataGetStatic()}, SqlComputed, Transient ];

/// data getter method in object context
Method dataGet() As CS.Serial
{
    return ..data2GetStatic()
}

/// data getter method in SQL context
ClassMethod dataGetStatic() As CS.Serial
{
    return $lb($lb("2017","01"),"CS.Serial")
}
}

But compiling it gives me an error:

ERROR #5502: Error compiling SQL Table: CS.Persistent
Table CS.Persistent has the following unmapped (not defined on the data map) fields:  data_Month, data_Year
%msg:  Table CS.Persistent has the following unmapped (not defined on the data map) fields:  data_Month, data_Year [CompileTable+36^%ocsSQLRTDict:TIME]
  > ERROR #5030: An error occurred while compiling class 'CS.Persistent' [CreateTable+7^%occCompile:TIME]

Is there  way to override getter for a serial property?

Code.

0
0 455
Discussion (7)0
Log in or sign up to continue

I'm pretty sure you need to return an oref to get this working.  Here's one that I was able to get working:

Class Sample.SerialGet Extends %Persistent {
Property Address as Sample.Address [calculated];

Method AddressGet() as Sample.Address {  
    set a=##class(Sample.Address).%New()  
    set a.City="Cambridge"  
    set a.State="MA"  
    set a.Zip="02142"  
    set a.Street="1 Memorial Drive"  
    quit a
}
}

Terminal:

SAMPLES>s reader=##class(%XML.Reader).%New()

SAMPLES>w reader.OpenFile("/users/kbaxter/downloads/testopensinglequote.xml")

1

SAMPLES>s x=##class(Sample.SerialGet).%New()

SAMPLES>w x.Address

5@Sample.Address

SAMPLES>w x.Address.Street

1 Memorial Drive

Thank you.

How can I make  it work from SQL context too?

It all depends on what you wish to achieve.
For example:

Class CS.Serial Extends %SerialObject
{
Property Year As %Integer;
Property Month As %Integer;

Method %MyGetSerial() As %List [ ServerOnly = 1 ]
{
  q $lb(i%Year,i%Month)
}
}

Class CS.Persistent Extends %Persistent
{
/// Property is triggered computed
Property data1 As CS.Serial [ SqlComputeCode = {set {*} = ..dataGetStatic()}, SqlComputed ];
/// Property is always computed
Property data2 As %List [ SqlComputeCode = {set {*} = ##class(CS.Persistent).dataGetStatic()}, SqlComputed, Transient ];

/// data getter method in SQL context
ClassMethod dataGetStatic() As %List
{
  s s=##class(CS.Serial).%New(), s.Month=1, s.Year=2017
  q s.%MyGetSerial()
  ; or
  q $lb(2017,1)
}
}

---------

select ID,data1,data2,data1_Month,data1_Year from CS.Persistent

ID  data1   data2   data1_Month  data1_Year
1   2017,1  2017,1  1            2017
2   2017,1  2017,1  1            2017
3   2017,1  2017,1  1            2017

Thank you!

I copied your example, but SQL returns results saved on disk, which is expected as the data property is triggered computed

Class CS.Persistent Extends %Persistent
{

Property data As CS.Serial [ SqlComputeCode = {set {*} = ##class(CS.Persistent).dataGetStatic()}, SqlComputed ];

/// data getter method in SQL context
ClassMethod dataGetStatic() As %List
{
    quit $lb(2017,1)
}

/// do ##class(CS.Persistent).test()
ClassMethod test()
{
    do ..%KillExtent()
    do $system.SQL.PurgeForTable($classname())
    set obj = ##class(CS.Persistent).%New()
    set obj.data.Month=-1
    set obj.data.Year=0
    set sc = obj.%Save()
    write !,"Save: ",$s($$$ISOK(sc):"OK", 1:$System.Status.GetErrorText(sc)),!
    zw ^CS.PersistentD
    do ##class(%SQL.Statement).%ExecDirect(,"select * from "_$classname()).%Display()
}
}

I execute in a terminal:

do ##class(CS.Persistent).test()

And I receive the following output:

Save: OK
^CS.PersistentD=1
^CS.PersistentD(1)=$lb("",$lb(0,-1))
ID      data_Month      data_Year
1       -1              0

Can I make a serial class always computed?

I want to receive the following output:

Save: OK
^CS.PersistentD=1
^CS.PersistentD(1)=$lb("",$lb(0,-1))
ID      data_Month      data_Year
1       1               2017

> Can I make a serial class always computed?
Yes, of course.

Class CS.Serial Extends %SerialObject [ NoExtent ]
{
Property Year As %Integer;
Property Month As %Integer;
}

Class CS.Persistent Extends %Persistent
{

Property data As CS.Serial [ SqlComputeCode = {set {*} = ##class(CS.Persistent).dataGetStatic()}, SqlComputed, Transient ];

ClassMethod dataGetStatic() As %List
{
  quit $lb(2017,1)
}
}

Output:
^CS.PersistentD=1
^CS.PersistentD(1)=$lb("")
ID      data
1       $lb(2017,1)
 
1 Rows(s) Affected

That is almost what I started this topic with. I get a compilation error with this code. And fields data_Year and data_Month are not getting created it seems.

It seems to me that in this case is not well suited %SerialObject.
Will be easier to use %List.