TDL - FieldExist?

Posts   
 
    
jshallard
User
Posts: 62
Joined: 23-Mar-2005
# Posted on: 05-Sep-2005 11:24:40   

Is there an easy way of using the Template Definition Language (TDL) to generate Entity code based on whether or not a particular field exists in an table?

For example, if a field with the name "Deleted" exists in a particular table, i would like to generate Entity code to handle the retrieval differently than if it does exist.

Perhaps there is some TDL statement along the line of?:

<[If Not HasField]>
text
<[EndIf]>

Any help / suggestions much appreciated.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 05-Sep-2005 12:11:49   

Use a <ForEach EntityField ]> loop with inside a <[If StringValueEquals EntityFieldName "Deleted"]> your code here <[EndIf]>

Frans Bouma | Lead developer LLBLGen Pro
jshallard
User
Posts: 62
Joined: 23-Mar-2005
# Posted on: 05-Sep-2005 15:11:14   

Thanks for the reply.

I had thought about using the <ForEach EntityField ]> syntax. However, what i need to do is to output one code block IF the fields exists, else output an alternative code block If Not. With the ForEach method, there is no obvious way to output code if a field does not exist (as it only checks one field at a time).

Is there perhaps a way to loop through and set a TDL variable if it does exist, and then do an IF-ELSE based on the variable?

Thanks for any help

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 06-Sep-2005 10:40:11   

Hmm, that's indeed a problem disappointed

TDL is not a general purpose language, so it's not flexible in some areas. Is this an include template or a template which generates a new file? If it's the latter, you could try to write a .lpt template, which can access every element in the project file.

Frans Bouma | Lead developer LLBLGen Pro
jshallard
User
Posts: 62
Joined: 23-Mar-2005
# Posted on: 06-Sep-2005 11:55:41   

As a way forward with this issue, I am attempting to extend the TDL to create an "IF" tag called "HasEntityField", which will take the following format:

<[If HasEntityField Deleted ]> (Text)<[ EndIf ]>

Could you let me know if this is even feasible, or if i am going about it the wrong way (I have not currently got it working):

I have added the following code in the Interpreter.cs class

        private void HandleIfHasEntityFieldStart()
        {
            // if there is no current entity, this if statement is not executed.
            if(_currentEntity==null)
            {
                return;
            }

            NonTerminal current = (NonTerminal)_parseTree[_nonTerminalIndex];

            // negate the expression if a NOT is present.
            bool negate = (((Token)((IToken)current.Tokens[2]).TokenID)==Token.Not);

            //get field name to search for
            int index=3;
            if(negate)
            {
                // not present, relationtype token is at index 4:
                // 0  1  2   3         4
                // <[ If Not HasEntityField FieldName ]>
                index=4;
            }

            IToken fieldToken = (IToken)current.Tokens[index];
            string fieldName = fieldToken.LiteralMatchedTokenText;
            
            bool executeIfBody = ((_currentEntity.Fields[fieldName] != null)^negate);

            if(executeIfBody)
            {
                // execute if statement
                _nonTerminalIndex++;
                InnerIfHandler();
            }
            else
            {
                // move current index to corresponding EndIf statement.
                _nonTerminalIndex = current.CorrespondingEndNTIndex;
            }
        }

And added the following code to the Parser.cs


private void CreateTokenDefinitions()
        {
...

// 'HasEntityField'
            _tokenDefinitions.Add(new TDLTokenDefinition((int)Token.HasEntityField, @"HasEntityField", RegexOptions.Compiled | RegexOptions.IgnoreCase));

...

}

private NonTerminal HandleIfStart(ref ArrayList tokensInStatement)
        {
...

// HasRelationStart and RelationTypeStart have an argument: relation type
            if(toReturn.Type==NonTerminalType.IfHasEntityFieldStart)
            {
                // peek for token.
                currentToken = (IToken)_tokenStream.Peek();
                if(((Token)currentToken.TokenID==Token.NoCursors)||((Token)currentToken.TokenID==Token.InputParameter))
                {
                    // valid argument. Pop it.
                    tokensInStatement.Add(_tokenStream.Dequeue());
                    StripWhiteSpace();
                }
            }
...

} 

In addition, I have updated the EnumConstants.cs with the appropriate (i think) enums.

Any help or input is much appreciated.

Thanks

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 06-Sep-2005 12:22:29   

Add 2 case NonTerminalType.IfHasEntityFieldStart lines: 1 to the routine Interpreter.InnerIfHandler 1 to the routine Interpreter.HandleNonterminal

the last one should call your if statement handler.

Use for naming schemes If<tokennames>Start.

Your code seems to be copied from another piece of code wink .

What's the syntax exactly? So I can add it to the 1.0.2005.1 TDL parser/interpreter.

Frans Bouma | Lead developer LLBLGen Pro
jshallard
User
Posts: 62
Joined: 23-Mar-2005
# Posted on: 07-Sep-2005 00:59:08   

__Bingo!

I think that this TDL tag may be very useful to other developers too, as it opens up the possibility of writing custom template code based on the presence of various standard fields (such as "Deleted").

Here are the ammends to the TDL related code - and yes, it is all copied and borrowed from what is already there wink

Otis - if you would like me to email you the files with these changes, let me know.

Thanks for your help.

Interpreter.cs: Line 200:


                    case NonTerminalType.IfHasEntityFieldStart:

Line 369:


case NonTerminalType.IfHasEntityFieldStart:
                    HandleIfHasEntityFieldStart();
                    break;

_ Line 3117:_


        /// <summary>
        /// Handles an if start of type 'HandleIfHasEntityField'. Will walk the statements between the start and IfEnd statement, if
        /// the expression resolves to true, otherwise all statements are skipped. Will keep track of nested ifs when skipping the
        /// inner if body.
        /// </summary>
        private void HandleIfHasEntityFieldStart()
        {
            // if there is no current entity, this if statement is not executed.
            if(_currentEntity==null)
            {
                return;
            }

            NonTerminal current = (NonTerminal)_parseTree[_nonTerminalIndex];

            // negate the expression if a NOT is present.
            bool negate = (((Token)((IToken)current.Tokens[2]).TokenID)==Token.Not);

            //get field name to search for
            int index=3;
            if(negate)
            {
                // not present, relationtype token is at index 4:
                // 0  1  2   3         4
                // <[ If Not HasEntityField FieldName ]>
                index=4;
            }

            IToken fieldToken = (IToken)current.Tokens[index];
            string fieldName = fieldToken.LiteralMatchedTokenText;
            
            bool executeIfBody = ((_currentEntity.Fields[fieldName] != null)^negate);

            if(executeIfBody)
            {
                // execute if statement
                _nonTerminalIndex++;
                InnerIfHandler();
            }
            else
            {
                // move current index to corresponding EndIf statement.
                _nonTerminalIndex = current.CorrespondingEndNTIndex;
            }
        }

EnumConstants.cs Line 90:


    HasEntityField,

_ Line 245:_


        IfHasEntityFieldStart,

** Parser.cs** _ Line 940L_


case Token.HasEntityField:
                    tokensInStatement.Add(_tokenStream.Dequeue());
                    toReturn = new NonTerminal(NonTerminalType.IfHasEntityFieldStart);
                    break;

_ Line 1096:_


            // HasRelationStart and RelationTypeStart have an argument: relation type
            if(toReturn.Type==NonTerminalType.IfHasEntityFieldStart)
            {
                // peek for token.
                currentToken = (IToken)_tokenStream.Peek();
                if(((Token)currentToken.LiteralMatchedTokenText.Length > 0))
                {
                    // valid argument. Pop it.
                    tokensInStatement.Add(_tokenStream.Dequeue());
                    StripWhiteSpace();
                }
            }

_ Line 1840:_


// 'HasEntityField'
            _tokenDefinitions.Add(new TDLTokenDefinition((int)Token.HasEntityField, @"HasEntityField", RegexOptions.Compiled | RegexOptions.IgnoreCase));

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 07-Sep-2005 10:34:36   

Cool, I'll add it to the TDL in 1.0.2005.1. Syntax: If HasEntityField name where name is the name of the field (case sensitive).

Adding these statements is a piece of cake, so no big deal simple_smile .

Frans Bouma | Lead developer LLBLGen Pro
jshallard
User
Posts: 62
Joined: 23-Mar-2005
# Posted on: 07-Sep-2005 11:06:48   

Great!

Here is an example of the tag checking for and EntityField with the name "Deleted":

<[If HasEntityField Deleted ]> True <[ EndIf ]>
<[If not HasEntityField Deleted ]> False <[ EndIf ]>

Thanks