Changing class definition at compilation time
Hi everyone
Is there any way to change a class definition (especifically a query definition during the compilation time)?
The idea is:
I have an abstract class with a parameter where I will define the ROWSPEC of a query and some methods to populate e temporary table
The implementation class will override the parameter, specifying the ROWSPEC of this implementation, and the methods will populate the rows in the same format as the ROWSPEC.
I want to change the ROWSPEC of the inherit query according to the implementation of the overriden parameter.
What I've already tried to change the parameter definition (of the query):
- Create a macro, thinking about the possibility of running it before the compilation
- Override the ClassMethod CreateProjection from the class %Projection.AbstractProjection
- Run a method in a objectgenerator
It seems that Caché compiles the queries before compiling the classes, because in all these cases, the query compiled code only generated the ROWSPEC as expected in the second compilation (where the class definition were changed and saved by the first compilation)
Any ideas if this is possible to be done without having to compile twice?
Basically I "just" need to have something executed before the compilation, but right after the beggining of the compile process
Another question (this would be the simplest solution):
Is it possible to execute some callback whenever a class definition is saved?
Thanks
One option could be to generate a sibling class that implements the generated code.
You could use the abstract create projection event to create the sibling implementation class and then tie the two together using the base class methods.
Alternatively, if you wanted to trigger code on a save event then create a class that extends %Studio.Extension.Base and override its OnAfterSave method. You will then need to enable that class in management portal > system admin > config > additional settings > source control.
Hi Eduard.
Thanks for your reply. It worked perfectly!!
When you define a query:
Or
That means that this query implements an interface provided by %Library.Query or %Library.SQLQuery respectively. They define method generators for Fetch/Execute/Func methods (more on them). Each method of the interface class gets called during compilation
You can subclass %Library.Query or %Library.SQLQuery to define your own methods. Here's custom query interface that does 2 things:
Class Utils.MyQuery Extends %SQLQuery { /// This method would be ran before others and changes ROWSPEC to "Id123:%String" ClassMethod %ChangeRowspec() [ CodeMode = objectgenerator, ServerOnly = 1 ] { // quit if we're not compiling a query if %mode="method" quit $$$OK set class = %class.Name set query = %compiledmethod.parent.Name set rowspec = "Id123:%String" // Modify query definition $$$defSubMemberSet(class,$$$cCLASSquery,query,$$$cQUERYparameter,"ROWSPEC",rowspec) // Modify
compiled
query definition $$$comSubMemberSet(class,$$$cCLASSquery,query,$$$cQUERYparameter,"ROWSPEC",rowspec) // Update compile-time parameter value set %parameter("ROWSPEC") = rowspec // Update class definition do UpdClsDef^%occLibrary(class) quit $$$OK } /// GetText is a method that is used to get query text as a %String ClassMethod GetText() As %String [ CodeMode = objectgenerator, ServerOnly = 1 ] { if %mode="method" quit $$$OK $$$comMemberKeyGetLvar(query,%classname,$$$cCLASSquery,%property,$$$cQUERYsqlquery) do %code.WriteLine(" quit " _ $$$quote(query)) quit $$$OK } }
And here's a test class with our new query:
After Utils.MyQueryTest is compiled it looks like this:
You can modify this interface to get any behavior you want.
Code is available on GitHub.
Hi, Thiago!
If you like the answer, would you please mark it as "Accepted"? Details.
Thank you in advance!