Created
March 5, 2009 17:29
-
-
Save sgoguen/74441 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copy and Paste this code into LINQPad and use the Nutshell database | |
void Main() | |
{ | |
var text = @"$Purchase.Customer.Name purchased $Detail on $Purchase.Date for $$$Purchase.Price"; | |
var Hello = new ExpressionTemplate<PurchaseItem>(text); | |
var query = PurchaseItems.Select(Hello.ToExpr()); | |
query.ToString().Dump("SQL"); | |
} | |
class ExpressionTemplate<T> { | |
private string _source; | |
public ExpressionTemplate(string source) { | |
_source = source; | |
} | |
public Expression<Func<T,string>> ToExpr() { | |
var pattern = new Regex("(?<text>\\$\\$)|\\$(?<field>[\\w.]+)|(?<text>[^$]*)"); | |
var parameter = Expression.Parameter(typeof(T), "p"); | |
var matches = from m in pattern.Matches(_source).Cast<Match>() | |
let field = m.Groups["field"].Value | |
let raw_text = m.Groups["text"].Value | |
let text = (raw_text == "$$") ? "$" : raw_text | |
where field.Length > 0 || text.Length > 0 | |
let expr = (field.Length > 0) ? GetProperties(parameter, field) : Expression.Constant(text) | |
select new { field, text, expr }; | |
Expression joined = matches.FirstOrDefault().expr; | |
foreach(var match in matches.Skip(1)) { | |
var concat = typeof(string).GetMethod("Concat", new Type[] { typeof(Object), typeof(Object) }); | |
joined = Expression.Add(joined, match.expr, concat); | |
} | |
return Expression.Lambda<Func<T, string>>(joined, new ParameterExpression[] { parameter }); | |
} | |
public Expression GetProperties(Expression Param, string Name) | |
{ | |
var TypeInfo = Param.Type; | |
try { | |
// Create the accessor function | |
var PropertyNames = Name.Split('.'); | |
Expression Input = Param; | |
var Accessors = from PropertyName in PropertyNames | |
select new { | |
PropertyName, | |
Accessor = (Input = Expression.PropertyOrField(Input, PropertyName)) | |
}; | |
var RAccessors = Accessors.ToArray().Reverse().ToArray(); | |
var DefaultValue = Expression.Constant(""); | |
Expression Last = null; | |
foreach (var Item in RAccessors) { | |
if (Last == null) { | |
Last = MemberExpToString(Item.Accessor, DefaultValue); | |
} | |
else { | |
Last = Expression.Condition(IsNotNothing(Item.Accessor), Last, DefaultValue); | |
} | |
} | |
return Expression.Condition(IsNotNothing(Param), Last, DefaultValue); | |
} | |
catch (Exception ex) { | |
throw new Exception(string.Format("Error compiling: {0} for type {1}", Name, TypeInfo.Name), ex); | |
} | |
} | |
public Expression MemberExpToString(Expression PropGet, Expression DefaultValue) | |
{ | |
var TestNull = IsNotNothing(PropGet); | |
var t = PropGet.Type; | |
if (object.ReferenceEquals(t, typeof(string))) { | |
return Expression.Condition(IsNotNothing(PropGet), PropGet, DefaultValue); | |
} | |
else { | |
var ToStringMethod = PropGet.Type.GetMethod("ToString", new Type[] { }); | |
var ConvGet = Expression.Call(PropGet, ToStringMethod, new Expression[] { }); | |
return Expression.Condition(IsNotNothing(PropGet), ConvGet, DefaultValue); | |
} | |
} | |
public Expression GetProperty(Expression e, string field) | |
{ | |
var DefaultValue = Expression.Constant(""); | |
var PropGet = Expression.PropertyOrField(e, field); | |
var TestNull = IsNotNothing(PropGet); | |
var t = PropertyOrFieldType(e, field); | |
if (object.ReferenceEquals(t, typeof(string))) { | |
return Expression.Condition(IsNotNothing(PropGet), PropGet, DefaultValue); | |
} | |
else { | |
var ToStringMethod = PropGet.Type.GetMethod("ToString", new Type[] { }); | |
var ConvGet = Expression.Call(PropGet, ToStringMethod, new Expression[] { }); | |
return Expression.Condition(IsNotNothing(PropGet), ConvGet, DefaultValue); | |
} | |
} | |
private BinaryExpression IsNotNothing(Expression e) { | |
if(e.Type.IsPrimitive) { | |
return Expression.Equal(Expression.Constant(true), Expression.Constant(true)); | |
} else { | |
return Expression.NotEqual(Expression.Convert(e, typeof(Object)), Expression.Constant(null, typeof(Object))); | |
} | |
} | |
public Type PropertyOrFieldType(Expression expression, string propertyOrFieldName) | |
{ | |
var p = expression.Type.GetProperty(propertyOrFieldName, (BindingFlags.FlattenHierarchy | (BindingFlags.Public | (BindingFlags.Instance | BindingFlags.IgnoreCase)))); | |
if (p != null) { | |
return p.PropertyType; | |
} | |
var f = expression.Type.GetField(propertyOrFieldName, (BindingFlags.FlattenHierarchy | (BindingFlags.Public | (BindingFlags.Instance | BindingFlags.IgnoreCase)))); | |
if (f == null) { | |
p = expression.Type.GetProperty(propertyOrFieldName, (BindingFlags.FlattenHierarchy | (BindingFlags.NonPublic | (BindingFlags.Instance | BindingFlags.IgnoreCase)))); | |
if (p != null) { | |
return p.PropertyType; | |
} | |
f = expression.Type.GetField(propertyOrFieldName, (BindingFlags.FlattenHierarchy | (BindingFlags.NonPublic | (BindingFlags.Instance | BindingFlags.IgnoreCase)))); | |
} | |
if (f != null) return f.FieldType; | |
return null; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment