protected virtual string ParseInvoke( DynamicNode.Invoke node, KParameterList pars = null ) { // This is used as an especial syntax to merely concatenate its arguments separated by spaces if needed... // It is used as a way to extend the supported syntax without the need of treating all the possible cases... if( node.Arguments == null ) return string.Empty; if( node.Arguments.Length == 0 ) return string.Empty; StringBuilder sb = new StringBuilder(); bool first = true; foreach( object arg in node.Arguments ) { if( !first ) { bool space = true; if( ( arg is string ) && ( (string)arg ).StartsWith( " " ) ) space = false; if( space ) sb.Append( " " ); } else first = false; if( arg is string ) sb.Append( (string)arg ); else sb.Append( Parse( arg, pars, rawstr: true, nulls: true ) ); } return sb.ToString(); }
protected virtual string ParseConvert( DynamicNode.Convert node, KParameterList pars = null ) { DEBUG.WriteLine( "\n-- PENDING: KParser.ParseConvert() requires an override..." ); string r = Parse( node.SourceNode, pars ); return r; }
protected virtual string ParseBinary( DynamicNode.Binary node, KParameterList pars = null ) { string op = ""; switch( node.Operation ) { case ExpressionType.Add: op = "+"; break; case ExpressionType.Subtract: op = "-"; break; case ExpressionType.Multiply: op = "*"; break; case ExpressionType.Divide: op = "/"; break; case ExpressionType.Modulo: op = "%"; break; case ExpressionType.Power: op = "^"; break; case ExpressionType.And: op = "AND"; break; case ExpressionType.Or: op = "OR"; break; // Treating NULL targets as special cases... case ExpressionType.Equal: op = node.Right == null ? "IS" : "="; break; case ExpressionType.NotEqual: op = node.Right == null ? "IS NOT" : "!="; break; case ExpressionType.GreaterThan: op = ">"; break; case ExpressionType.GreaterThanOrEqual: op = ">="; break; case ExpressionType.LessThan: op = "<"; break; case ExpressionType.LessThanOrEqual: op = "<="; break; default: throw new ArgumentException( "Not supported operator: '" + node.Operation + "'." ); } string left = Parse( node.Left, pars ); // Not nulls: left is assumed to be an object string right = Parse( node.Right, pars, nulls: true ); return string.Format( "( {0} {1} {2} )", left, op, right ); }
protected virtual string ParseMethod( DynamicNode.Method node, KParameterList pars = null ) { string parent = Parse( node.Host, pars ); string method = node.Name.ToUpper(); string item = null; // ROOT-LEVEL... if( parent == null ) { switch( method ) { case "NOT": if( node.Arguments == null || node.Arguments.Length != 1 ) throw new ArgumentException( "NOT operator expects one argument." ); item = Parse( node.Arguments[0], pars ); return string.Format( "( NOT {0} )", item ); } } // COLUMN-LEVEL... else { switch( method ) { case "IN": if( node.Arguments == null || node.Arguments.Length != 1 ) throw new ArgumentException( "IN operator expects one argument." ); item = Parse( node.Arguments[0], pars ); return string.Format( "{0} IN ( {1} )", parent, item ); case "AS": if( node.Arguments == null || node.Arguments.Length != 1 ) throw new ArgumentException( "AS operator expects one argument." ); item = Parse( node.Arguments[0], null, rawstr: true ); // pars=null to avoid parametrize aliases item = item.Validated( "Alias", invalidChars: TypeHelper.InvalidNameChars ); return string.Format( "{0} AS {1}", parent, item ); } } // DEFAULT-CASE... method = parent == null ? node.Name : string.Format( "{0}.{1}", parent, node.Name ); StringBuilder sb = new StringBuilder(); sb.AppendFormat( "{0}(", method ); if( node.Arguments != null && node.Arguments.Length != 0 ) { sb.Append( " " ); bool first = true; foreach( object argument in node.Arguments ) { if( !first ) sb.Append( ", " ); else first = false; sb.Append( Parse( argument, pars, nulls: true ) ); // We don't accept raw strings here!!! } sb.Append( " " ); } sb.Append( ")" ); return sb.ToString(); }
protected virtual string ParseSetMember( DynamicNode.SetMember node, KParameterList pars = null ) { string parent = Parse( node.Host, pars ); string name = parent == null ? node.Name : string.Format( "{0}.{1}", parent, node.Name ); string value = Parse( node.Value, pars, nulls: true ); return string.Format( "{0} = ( {1} )", name, value ); }
protected virtual string ParseUnary( DynamicNode.Unary node, KParameterList pars = null ) { switch( node.Operation ) { // Artifacts from the DynamicParser class that are not usefull here... case ExpressionType.IsFalse: case ExpressionType.IsTrue: return Parse( node.Target, pars ); // Unary supported operations... case ExpressionType.Not: return string.Format( "( NOT {0} )", Parse( node.Target, pars ) ); case ExpressionType.Negate: return string.Format( "!( {0} )", Parse( node.Target, pars ) ); } throw new ArgumentException( "Not supported unary operation: " + node ); }
protected virtual string ParseCommand( IKCommand node, KParameterList pars = null ) { // Getting the command's text... string str = node.CommandText( iterable: false ); // Avoiding spurious "OUTPUT XXX" statements // If there are parameters to transform, but cannot store them, it is an error if( node.Parameters.Count != 0 && pars == null ) throw new InvalidOperationException( "Cannot parse IKCommand because the receiving parameters collection is null." ); // Transforming the parameters using names compatible with this command string and context foreach( var parameter in node.Parameters ) { KParameter neo = pars.Insert( parameter.Value ); str = str.Replace( parameter.Name, neo.Name ); } return str; }
protected virtual string ParseGetMember( DynamicNode.GetMember node, KParameterList pars = null ) { string parent = Parse( node.Host, pars ); string name = parent == null ? node.Name : string.Format( "{0}.{1}", parent, node.Name ); return name; }
string Dispatch( object node, KParameterList pars = null ) { if( node != null ) { // Flag to indicate the root of a dynamic argument... if( node.GetType() == typeof( DynamicNode.Argument ) ) return null; // Other node types and elements to parse... else if( node is IKCommand ) return ParseCommand( (IKCommand)node, pars ); else if( node is DynamicNode.GetMember ) return ParseGetMember( (DynamicNode.GetMember)node, pars ); else if( node is DynamicNode.SetMember ) return ParseSetMember( (DynamicNode.SetMember)node, pars ); else if( node is DynamicNode.Unary ) return ParseUnary( (DynamicNode.Unary)node, pars ); else if( node is DynamicNode.Binary ) return ParseBinary( (DynamicNode.Binary)node, pars ); else if( node is DynamicNode.Method ) return ParseMethod( (DynamicNode.Method)node, pars ); else if( node is DynamicNode.Invoke ) return ParseInvoke( (DynamicNode.Invoke)node, pars ); else if( node is DynamicNode.Convert ) return ParseConvert( (DynamicNode.Convert)node, pars ); } // All other cases are considered constant parameters... return ParseConstant( node, pars ); }
protected virtual string ParseConstant( object node, KParameterList pars = null ) { if( node == null ) return ParseNull(); if( pars != null ) { // If we have a list of parameters to store it, let's parametrize it var par = pars.Insert( node ); return par.Name; } return node.ToString(); // Last resort case }
/// <summary> /// Parsers the given node and returns a string with its contents translated. /// <para>The node is typically a dynamic lambda expression, but can also be any valid C# object.</para> /// <para>In this case, typically a new parameter is created to contain its value, who is stored in the parameter /// list given (if it is not null), and the parameter's name is placed into the returned string.</para> /// </summary> /// <param name="node">The object to parse.</param> /// <param name="pars">The parameters list where to store the parameters created.</param> /// <param name="rawstr">If raw strings are considered valid, or not acceptable.</param> /// <param name="nulls">If null nodes are considered valid, or not acceptable.</param> /// <returns>The parsed string.</returns> public virtual string Parse( object node, KParameterList pars = null, bool rawstr = false, bool nulls = false ) { // Null nodes are accepted or not depending upon the "nulls" flag... if( node == null ) { if( !nulls ) throw new ArgumentNullException( "node", "Null nodes are not accepted." ); return Dispatch( node, pars ); } // Nodes that are strings are parametrized or not depending the "rawstr" flag... if( node is string ) { if( rawstr ) return (string)node; else return Dispatch( node, pars ); } // If node is a delegate, parse it to create the logical tree... if( node is Delegate ) { node = DynamicParser.Parse( (Delegate)node ).Result; return Parse( node, pars, rawstr ); // Intercept containers as in (x => "string") } return Dispatch( node, pars ); }
protected virtual void Dispose( bool disposing ) { DEBUG.IndentLine( "\n-- KCommand.Dispose( Disposing={0} ) - This={1}", disposing, this ); if( _Parameters != null ) { _Parameters.Dispose(); _Parameters = null; } if( _Parser != null ) { _Parser.Dispose(); _Parser = null; } _Link = null; DEBUG.Unindent(); }
/// <summary> /// Creates a new <see cref="KCommand"/> associated with the given link. /// </summary> /// <param name="link">The link this command is associated with.</param> protected KCommand( IKLink link ) { DEBUG.IndentLine( "\n-- KCommand( Link={0} )", link == null ? "null" : link.ToString() ); if( ( _Link = link ) == null ) throw new ArgumentNullException( "link", "Link cannot be null." ); if( ( _Parameters = _Link.Factory.CreateParameterList() ) == null ) throw new InvalidOperationException( "Cannot create a List of Parameters." ); if( ( _Parser = _Link.Factory.CreateParser() ) == null ) throw new InvalidOperationException( "Cannot create a Parser." ); DEBUG.Unindent(); }
/// <summary> /// Creates a new executor for the command specified by its text and parameters. /// </summary> /// <param name="text">The text of the non-query command.</param> /// <param name="pars">The arguments of the command.</param> /// <returns>The unique Guid identifying the new created executor.</returns> public virtual Guid ExecutorCreate( string text, KParameterList pars ) { DEBUG.IndentLine( "\n-- [{0}] KServerWCF.ExecutorCreate( {1}{2} )", _ProxyId.TagString(), text ?? "<null>", pars == null ? "" : string.Format( " - {0}", pars ) ); try { if( _Link == null ) throw new InvalidOperationException( "WCF Server is not yet connected." ); text = text.Validated( "Command Text" ); IKCommandExecutable cmd = _Link.Raw( text ); if( pars != null ) foreach( var par in pars ) cmd.Parameters.Add( par.Clone() ); IKExecutor executor = cmd.GetExecutor(); if( executor == null ) throw new InvalidOperationException( "Cannot create Executor for command: " + cmd.TraceString() ); Guid uid = Guid.NewGuid(); _Elements.Add( uid, executor ); DEBUG.WriteLine( "\n-- Executor created with UID = {0}", uid.TagString() ); return uid; } catch( Exception e ) { DEBUG.PrintException( e ); throw; } finally { DEBUG.Unindent(); } }
protected override string ParseMethod( DynamicNode.Method node, KParameterList pars ) { string host = Parse( node.Host, pars ); string name = node.Name.ToUpper(); string item = null; string alias = null; string extra = null; // ROOT-LEVEL... if( host == null ) { switch( name ) { case "CAST": if( node.Arguments == null || node.Arguments.Length != 2 ) throw new ArgumentException( "CAST operator expects two arguments." ); item = Parse( node.Arguments[0], pars ); // No raw strings alias = Parse( node.Arguments[1], null, rawstr: true ); // pars=null to avoid parametrize aliases alias = alias.Validated( "Alias", invalidChars: TypeHelper.InvalidNameChars ); return string.Format( "CAST( {0} AS {1} )", item, alias ); } } // COLUMN-LEVEL... else { switch( name ) { case "LEFT": if( node.Arguments == null || node.Arguments.Length != 1 ) throw new ArgumentException( "LEFT operator expects one argument." ); item = Parse( node.Arguments[0], pars ); return string.Format( "LEFT( {0}, {1} )", host, item ); case "RIGHT": if( node.Arguments == null || node.Arguments.Length != 1 ) throw new ArgumentException( "RIGHT operator expects one argument." ); item = Parse( node.Arguments[0], pars ); return string.Format( "RIGHT( {0}, {1} )", host, item ); case "LEN": if( node.Arguments != null && node.Arguments.Length != 0 ) throw new ArgumentException( "LEN operator does not expect any arguments." ); return string.Format( "LEN( {0} )", host ); case "LOWER": if( node.Arguments != null && node.Arguments.Length != 0 ) throw new ArgumentException( "LOWER operator does not expect any arguments." ); return string.Format( "LOWER( {0} )", host ); case "UPPER": if( node.Arguments != null && node.Arguments.Length != 0 ) throw new ArgumentException( "UPPER operator does not expect any arguments." ); return string.Format( "UPPER( {0} )", host ); case "YEAR": if( node.Arguments != null && node.Arguments.Length != 0 ) throw new ArgumentException( "YEAR operator does not expect any arguments." ); return string.Format( "DATEPART( YEAR, {0} )", host ); case "MONTH": if( node.Arguments != null && node.Arguments.Length != 0 ) throw new ArgumentException( "MONTH operator does not expect any arguments." ); return string.Format( "DATEPART( MONTH, {0} )", host ); case "DAY": if( node.Arguments != null && node.Arguments.Length != 0 ) throw new ArgumentException( "DAY operator does not expect any arguments." ); return string.Format( "DATEPART( DAY, {0} )", host ); case "HOUR": if( node.Arguments != null && node.Arguments.Length != 0 ) throw new ArgumentException( "HOUR operator does not expect any arguments." ); return string.Format( "DATEPART( HOUR, {0} )", host ); case "MINUTE": if( node.Arguments != null && node.Arguments.Length != 0 ) throw new ArgumentException( "MINUTE operator does not expect any arguments." ); return string.Format( "DATEPART( MINUTE, {0} )", host ); case "SECOND": if( node.Arguments != null && node.Arguments.Length != 0 ) throw new ArgumentException( "SECOND operator does not expect any arguments." ); return string.Format( "DATEPART( SECOND, {0} )", host ); case "MILLISECOND": if( node.Arguments != null && node.Arguments.Length != 0 ) throw new ArgumentException( "MILLISECOND operator does not expect any arguments." ); return string.Format( "DATEPART( MILLISECOND, {0} )", host ); case "OFFSET": if( node.Arguments != null && node.Arguments.Length != 0 ) throw new ArgumentException( "OFFSET operator does not expect any arguments." ); return string.Format( "DATEPART( TZ, {0} )", host ); case "LIKE": if( node.Arguments == null || node.Arguments.Length != 1 ) throw new ArgumentException( "LIKE operator expects one argument." ); item = Parse( node.Arguments[0], pars ); return string.Format( "( {0} LIKE {1} )", host, item ); case "NOTLIKE": if( node.Arguments == null || node.Arguments.Length != 1 ) throw new ArgumentException( "NOT LIKE operator expects one argument." ); item = Parse( node.Arguments[0], pars ); return string.Format( "( {0} NOT LIKE {1} )", host, item ); case "CONTAINS": if( node.Arguments == null || node.Arguments.Length != 1 ) throw new ArgumentException( "CONTAINS operator expects one argument." ); item = Parse( node.Arguments[0], pars ); return string.Format( "CONTAINS( {0}, {1} )", host, item ); case "PATINDEX": if( node.Arguments == null || node.Arguments.Length != 1 ) throw new ArgumentException( "PATINDEX operator expects one argument." ); item = Parse( node.Arguments[0], pars ); return string.Format( "PATINDEX( {1}, {0} )", host, item ); // Note {0} and {1} are reversed case "SUBSTRING": if( node.Arguments == null || node.Arguments.Length != 2 ) throw new ArgumentException( "SUBSTRING operator expects two arguments." ); item = Parse( node.Arguments[0], pars ); extra = Parse( node.Arguments[1], pars ); return string.Format( "SUBSTRING( {0}, {1}, {2} )", host, item, extra ); case "LTRIM": if( node.Arguments != null && node.Arguments.Length != 0 ) throw new ArgumentException( "LTRIM operator does not expect any arguments." ); return string.Format( "LTRIM( {0} )", host ); case "RTRIM": if( node.Arguments != null && node.Arguments.Length != 0 ) throw new ArgumentException( "RTRIM operator does not expect any arguments." ); return string.Format( "RTRIM( {0} )", host ); case "TRIM": if( node.Arguments != null && node.Arguments.Length != 0 ) throw new ArgumentException( "TRIM operator does not expect any arguments." ); return string.Format( "LTRIM( RTRIM( {0} ) )", host ); } } // DEFAULT case... return base.ParseMethod( node, pars ); }