[stringtemplate-interest] Why an == operator is sometimes necessary, and how to implement it (ST3/C#)
Harald Mueller
harald_m_mueller at gmx.de
Fri Mar 12 11:15:22 PST 2010
Hi -
as we all know, ST does not have any expression operators in its language, and that is almost always a good thing. However, in a well-worn code generator we use to create triggers in an SQL database, we finally got to the point where we needed an equals operator in $if(...)$. Here is why; and how we implemented it.
The problem is as follows: Input to the generation is (a) a list of SQL tables; (b) the FROM part of an SQL statement, which is a tree of join nodes; each join node points to a table (and of course has information about the joined columns and inner/outer etc., but that's not important); and (c) a replacement string (typically "INSERTED" or "DELETED"; but there are more).
The job to do is to write a trigger for each table in the join tree, such that the table itself is replaced with the replacement string.
A small example:
(a) T1, T2
(b) ... FROM T1 INNER JOIN T2 INNER JOIN T3
(c) "INSERTED"
Result:
... FROM INSERTED INNER JOIN T2 INNER JOIN T3
... FROM T1 INNER JOIN INSERTED INNER JOIN T3
The example below is a simplified version of the above, however, its ST template marks nodes in a tree with an arrow (<--) if the node's "table name" is equal to the "replacement table".
Here is the model, together with the "equals operator":
public class Table {
public string Name;
}
public class Join {
public readonly string Name;
public readonly Table JoinedTable;
public readonly List<Join> Children;
public Join(string name, Table joinedTable, params Join[] children) {
Name = name;
JoinedTable = joinedTable;
Children = new List<Join>(children);
}
}
Here are the templates - first the Main template, then the recursive one for printing the tree.
Main(Target, Tables) ::= <<
$Tables:PrintTreeReplacingTable(Target=Target,Replace=it)$
>>
PrintTreeReplacingTable(Target,Replace) ::= <<
$Target.Name$ $if(Target.NameIsReplace.(Replace.Name))$ <-- $endif$
$Target.Children:PrintTreeReplacingTable(Target=it,Replace=Replace)$
>>
The important idea here is the expression
Target.NameIsReplace.(Replace.Name)
where .NameEquals is a property that returns an IDictionary. The (Replacement.Name) then passes in a value which is in effect the parameter of a single-arg function which implements "Target.Name == Replace.Name" - that's the whole trick.
So we extend Join with the following additional property
public IDictionary NameEquals {
get {
return new Equals(JoinedTable.Name);
}
}
and the class Equals, which is implemented as follows:
class Equals : DictionaryBase, IDictionary {
private readonly string _tn;
public Equals(string tn) {
_tn = tn;
}
bool IDictionary.Contains(object key) {
return key.ToString() == _tn;
}
object IDictionary.this[object key] {
get {
return key.ToString() == _tn;
}
set { throw new NotImplementedException(); }
}
}
That's it. Maybe it helps someone.
And maybe someone's got an idea how this works without that IDictionary trick - but we didn't see how!
Regards
Harald M.
--
GRATIS für alle GMX-Mitglieder: Die maxdome Movie-FLAT!
Jetzt freischalten unter http://portal.gmx.net/de/go/maxdome01
More information about the stringtemplate-interest
mailing list