public void TestFixtureSetUp() { datumConverterFactory = Substitute.For<IDatumConverterFactory>(); var stringDatum = new Datum() { type = Datum.DatumType.R_STR, r_str = "Jackpot!", }; var stringDatumConverter = Substitute.For<IDatumConverter<string>>(); stringDatumConverter .ConvertObject("Jackpot!") .Returns(stringDatum); stringDatumConverter .ConvertDatum(Arg.Is<Datum>(d => d.type == stringDatum.type && d.r_str == stringDatum.r_str)) .Returns("Jackpot!"); IDatumConverter<string> value; datumConverterFactory .TryGet<string>(datumConverterFactory, out value) .Returns(args => { args[1] = stringDatumConverter; return true; }); IDatumConverter value2; datumConverterFactory .TryGet(typeof(string), datumConverterFactory, out value2) .Returns(args => { args[2] = stringDatumConverter; return true; }); }
public void TestFixtureSetUp() { datumConverterFactory = Substitute.For <IDatumConverterFactory>(); int[] ints = { 1, 2, 3 }; var intDatumConverter = Substitute.For <IDatumConverter>(); foreach (int i in ints) { var dtm = i.ToDatum(); intDatumConverter .ConvertObject(i) .Returns(dtm); intDatumConverter .ConvertDatum(Arg.Is <Datum>(d => d.type == dtm.type && d.r_num == dtm.r_num)) .Returns(i); } string[] strs = { "one", "two", "three" }; var stringDatumConverter = Substitute.For <IDatumConverter>(); foreach (var i in strs) { var dtm = i.ToDatum(); stringDatumConverter .ConvertObject(i) .Returns(dtm); stringDatumConverter .ConvertDatum(Arg.Is <Datum>(d => d.type == dtm.type && d.r_str == dtm.r_str)) .Returns(i); } IDatumConverter value; datumConverterFactory .TryGet(typeof(int), datumConverterFactory, out value) .Returns(args => { args[2] = intDatumConverter; return(true); }); datumConverterFactory .TryGet(typeof(string), datumConverterFactory, out value) .Returns(args => { args[2] = stringDatumConverter; return(true); }); }
public void TestFixtureSetUp() { datumConverterFactory = Substitute.For<IDatumConverterFactory>(); int[] ints = {1, 2, 3}; var intDatumConverter = Substitute.For<IDatumConverter>(); foreach(int i in ints) { var dtm = i.ToDatum(); intDatumConverter .ConvertObject(i) .Returns(dtm); intDatumConverter .ConvertDatum(Arg.Is<Datum>(d => d.type == dtm.type && d.r_num == dtm.r_num)) .Returns(i); } string[] strs = { "one", "two", "three" }; var stringDatumConverter = Substitute.For<IDatumConverter>(); foreach (var i in strs) { var dtm = i.ToDatum(); stringDatumConverter .ConvertObject(i) .Returns(dtm); stringDatumConverter .ConvertDatum(Arg.Is<Datum>(d => d.type == dtm.type && d.r_str == dtm.r_str)) .Returns(i); } IDatumConverter value; datumConverterFactory .TryGet(typeof(int), datumConverterFactory, out value) .Returns(args => { args[2] = intDatumConverter; return true; }); datumConverterFactory .TryGet(typeof(string), datumConverterFactory, out value) .Returns(args => { args[2] = stringDatumConverter; return true; }); }
public static Tuple <bool, IDatumConverter> TryGet(IDatumConverterFactory target, IDatumConverterFactory rootDatumConverterFactory) { IDatumConverter <T> datumConverter; bool success = target.TryGet <T>(rootDatumConverterFactory, out datumConverter); return(new Tuple <bool, IDatumConverter>(success, datumConverter)); }
public void TestFixtureSetUp() { datumConverterFactory = Substitute.For <IDatumConverterFactory>(); queryConverter = new QueryConverter(datumConverterFactory, expressionConverterFactory); var stringDatum = new Datum() { type = Datum.DatumType.R_STR, r_str = "Jackpot!", }; var stringDatumConverter = Substitute.For <IDatumConverter <string> >(); stringDatumConverter .ConvertObject("Jackpot!") .Returns(stringDatum); stringDatumConverter .ConvertDatum(Arg.Is <Datum>(d => d.type == stringDatum.type && d.r_str == stringDatum.r_str)) .Returns("Jackpot!"); IDatumConverter <string> value; datumConverterFactory .TryGet <string>(queryConverter, out value) .Returns(args => { args[1] = stringDatumConverter; return(true); }); }
public void TestFixtureSetUp() { datumConverterFactory = Substitute.For <IDatumConverterFactory>(); var intDatumConverter = Substitute.For <IDatumConverter>(); intDatumConverter.ConvertDatum(Arg.Any <Datum>()).Returns(args => (int)((Datum)args[0]).r_num); intDatumConverter.ConvertObject(Arg.Any <object>()).Returns(args => new Datum() { type = Datum.DatumType.R_NUM, r_num = (int)args [0] }); IDatumConverter value; datumConverterFactory .TryGet(typeof(int), datumConverterFactory, out value) .Returns(args => { args[2] = intDatumConverter; return(true); }); datumConverterFactory.GetBestNativeTypeForDatum(Arg.Any <Datum>()).Returns(typeof(int)); }
private bool ServerSideMemberAccess(IDatumConverterFactory datumConverterFactory, MemberExpression memberExpression, out Term term) { term = null; if (memberExpression.Expression == null) { // static member access; can't do that server-side, wouldn't want to either. return(false); } if (memberExpression.Expression.NodeType == ExpressionType.Constant) { // Accessing a constant; client-side conversion will be more efficient since we won't be round-tripping the object return(false); } IDatumConverter datumConverter; if (!datumConverterFactory.TryGet(memberExpression.Expression.Type, out datumConverter)) { // No datum converter for this type. return(false); } var fieldConverter = datumConverter as IObjectDatumConverter; if (fieldConverter == null) { // doesn't implement IObjectDatumConverter, so we don't know how to map the MemberInfo to the field name return(false); } var datumFieldName = fieldConverter.GetDatumFieldName(memberExpression.Member); if (string.IsNullOrEmpty(datumFieldName)) { // At this point we're not returning false because we're expecting this should work; throwing an error instead. throw new NotSupportedException(String.Format("Member {0} on type {1} could not be mapped to a datum field", memberExpression.Member.Name, memberExpression.Type)); } var getAttrTerm = new Term() { type = Term.TermType.GET_FIELD }; getAttrTerm.args.Add(RecursiveMap(memberExpression.Expression)); getAttrTerm.args.Add(new Term() { type = Term.TermType.DATUM, datum = new Datum() { type = Datum.DatumType.R_STR, r_str = datumFieldName } }); term = getAttrTerm; return(true); }
public void TestFixtureSetUp() { var stringDatum = new Datum() { type = Datum.DatumType.R_STR, r_str = "Jackpot!", }; var stringDatumConverter = Substitute.For <IDatumConverter <string> >(); stringDatumConverter .ConvertObject("Jackpot!") .Returns(stringDatum); stringDatumConverter .ConvertDatum(Arg.Is <Datum>(d => d.type == stringDatum.type && d.r_str == stringDatum.r_str)) .Returns("Jackpot!"); ((IDatumConverter)stringDatumConverter) .ConvertObject("Jackpot!") .Returns(stringDatum); ((IDatumConverter)stringDatumConverter) .ConvertDatum(Arg.Is <Datum>(d => d.type == stringDatum.type && d.r_str == stringDatum.r_str)) .Returns("Jackpot!"); rootDatumConverterFactory = Substitute.For <IDatumConverterFactory>(); IDatumConverter <string> _dcs; rootDatumConverterFactory .TryGet <string>(rootDatumConverterFactory, out _dcs) .Returns(args => { Console.WriteLine("TryGet<string>"); args[1] = stringDatumConverter; return(true); }); IDatumConverter _dc; rootDatumConverterFactory .TryGet(typeof(String), rootDatumConverterFactory, out _dc) .Returns(args => { args[2] = stringDatumConverter; return(true); }); }
public void TestFixtureSetUp() { var stringDatum = new Datum() { type = Datum.DatumType.R_STR, r_str = "Jackpot!", }; var stringDatumConverter = Substitute.For<IDatumConverter<string>>(); stringDatumConverter .ConvertObject("Jackpot!") .Returns(stringDatum); stringDatumConverter .ConvertDatum(Arg.Is<Datum>(d => d.type == stringDatum.type && d.r_str == stringDatum.r_str)) .Returns("Jackpot!"); ((IDatumConverter)stringDatumConverter) .ConvertObject("Jackpot!") .Returns(stringDatum); ((IDatumConverter)stringDatumConverter) .ConvertDatum(Arg.Is<Datum>(d => d.type == stringDatum.type && d.r_str == stringDatum.r_str)) .Returns("Jackpot!"); rootDatumConverterFactory = Substitute.For<IDatumConverterFactory>(); IDatumConverter<string> _dcs; rootDatumConverterFactory .TryGet<string>(rootDatumConverterFactory, out _dcs) .Returns(args => { Console.WriteLine("TryGet<string>"); args[1] = stringDatumConverter; return true; }); IDatumConverter _dc; rootDatumConverterFactory .TryGet(typeof(String), rootDatumConverterFactory, out _dc) .Returns(args => { args[2] = stringDatumConverter; return true; }); }
public static IDatumConverter Get(this IDatumConverterFactory datumConverterFactory, Type datumType, IDatumConverterFactory rootDatumConverterFactory) { if (datumConverterFactory == null) { throw new ArgumentNullException("datumConverterFactory"); } if (rootDatumConverterFactory == null) { throw new ArgumentNullException("rootDatumConverterFactory"); } IDatumConverter retval; if (datumConverterFactory.TryGet(datumType, rootDatumConverterFactory, out retval)) { return(retval); } else { throw new NotSupportedException(String.Format("Datum converter is not available for type {0}", datumType)); } }
private bool ServerSideMemberAccess(IDatumConverterFactory datumConverterFactory, MemberExpression memberExpression, out Term term) { term = null; if (memberExpression.Expression == null) // static member access; can't do that server-side, wouldn't want to either. return false; if (memberExpression.Expression.NodeType == ExpressionType.Constant) // Accessing a constant; client-side conversion will be more efficient since we won't be round-tripping the object return false; IDatumConverter datumConverter; if (!datumConverterFactory.TryGet(memberExpression.Expression.Type, out datumConverter)) // No datum converter for this type. return false; var fieldConverter = datumConverter as IObjectDatumConverter; if (fieldConverter == null) // doesn't implement IObjectDatumConverter, so we don't know how to map the MemberInfo to the field name return false; var datumFieldName = fieldConverter.GetDatumFieldName(memberExpression.Member); if (string.IsNullOrEmpty(datumFieldName)) { // At this point we're not returning false because we're expecting this should work; throwing an error instead. // We're expecting this to work, but, returning false will give us a chance to try client-side evaluation instead and // maintain compatibility with the pre-PR #209 behaviour. (issue #220). return false; } var getAttrTerm = new Term() { type = Term.TermType.GET_FIELD }; getAttrTerm.args.Add(RecursiveMap(memberExpression.Expression)); getAttrTerm.args.Add(new Term() { type = Term.TermType.DATUM, datum = new Datum() { type = Datum.DatumType.R_STR, r_str = datumFieldName } }); term = getAttrTerm; return true; }
private bool ServerSideMemberAccess(IDatumConverterFactory datumConverterFactory, MemberExpression memberExpression, out Term term) { term = null; if (memberExpression.Expression == null) // static member access; can't do that server-side, wouldn't want to either. return false; if (memberExpression.Expression.NodeType == ExpressionType.Constant) // Accessing a constant; client-side conversion will be more efficient since we won't be round-tripping the object return false; IDatumConverter datumConverter; if (!datumConverterFactory.TryGet(memberExpression.Expression.Type, out datumConverter)) // No datum converter for this type. return false; var fieldConverter = datumConverter as IObjectDatumConverter; if (fieldConverter == null) // doesn't implement IObjectDatumConverter, so we don't know how to map the MemberInfo to the field name return false; var datumFieldName = fieldConverter.GetDatumFieldName(memberExpression.Member); if (string.IsNullOrEmpty(datumFieldName)) // At this point we're not returning false because we're expecting this should work; throwing an error instead. throw new NotSupportedException(String.Format("Member {0} on type {1} could not be mapped to a datum field", memberExpression.Member.Name, memberExpression.Type)); var getAttrTerm = new Term() { type = Term.TermType.GET_FIELD }; getAttrTerm.args.Add(RecursiveMap(memberExpression.Expression)); getAttrTerm.args.Add(new Term() { type = Term.TermType.DATUM, datum = new Datum() { type = Datum.DatumType.R_STR, r_str = datumFieldName } }); term = getAttrTerm; return true; }
protected Term SimpleMap(IDatumConverterFactory datumConverterFactory, Expression expr) { switch (expr.NodeType) { case ExpressionType.Constant: { var constantExpression = (ConstantExpression)expr; var datumConverter = datumConverterFactory.Get(constantExpression.Type); var datum = datumConverter.ConvertObject(constantExpression.Value); return(new Term() { type = Term.TermType.DATUM, datum = datum }); } case ExpressionType.Add: case ExpressionType.Modulo: case ExpressionType.Divide: case ExpressionType.Multiply: case ExpressionType.Subtract: case ExpressionType.Equal: case ExpressionType.LessThan: case ExpressionType.LessThanOrEqual: case ExpressionType.GreaterThan: case ExpressionType.GreaterThanOrEqual: case ExpressionType.AndAlso: case ExpressionType.OrElse: case ExpressionType.NotEqual: case ExpressionType.ArrayIndex: return(ConvertBinaryExpressionToTerm((BinaryExpression)expr, datumConverterFactory)); case ExpressionType.Not: case ExpressionType.ArrayLength: return(ConvertUnaryExpressionToTerm((UnaryExpression)expr, datumConverterFactory)); case ExpressionType.New: { var newExpression = (NewExpression)expr; if (AnonymousTypeDatumConverterFactory.Instance.IsTypeSupported(newExpression.Type)) { var retval = new Term() { type = Term.TermType.MAKE_OBJ, }; foreach (var property in newExpression.Type.GetProperties().Select((p, i) => new { Property = p, Index = i })) { var key = property.Property.Name; var value = RecursiveMap(newExpression.Arguments[property.Index]); retval.optargs.Add(new Term.AssocPair() { key = key, val = value }); } return(retval); } DefaultExpressionConverterFactory.ExpressionMappingDelegate <NewExpression> newExpressionMapping; if (expressionConverterFactory.TryGetNewExpressionMapping(newExpression.Constructor, out newExpressionMapping)) { return(newExpressionMapping(newExpression, RecursiveMap, datumConverterFactory, expressionConverterFactory)); } return(AttemptClientSideConversion(datumConverterFactory, expr)); } case ExpressionType.NewArrayInit: var arrayExpression = (NewArrayExpression)expr; var array = new Term { type = Term.TermType.MAKE_ARRAY }; foreach (var expression in arrayExpression.Expressions) { array.args.Add(RecursiveMap(expression)); } return(array); case ExpressionType.Call: { var callExpression = (MethodCallExpression)expr; var method = callExpression.Method; DefaultExpressionConverterFactory.ExpressionMappingDelegate <MethodCallExpression> methodCallMapping; if (expressionConverterFactory.TryGetMethodCallMapping(method, out methodCallMapping)) { return(methodCallMapping(callExpression, RecursiveMap, datumConverterFactory, expressionConverterFactory)); } else { return(AttemptClientSideConversion(datumConverterFactory, expr)); } } case ExpressionType.MemberAccess: { var memberExpression = (MemberExpression)expr; var member = memberExpression.Member; DefaultExpressionConverterFactory.ExpressionMappingDelegate <MemberExpression> memberAccessMapping; if (expressionConverterFactory.TryGetMemberAccessMapping(member, out memberAccessMapping)) { return(memberAccessMapping(memberExpression, RecursiveMap, datumConverterFactory, expressionConverterFactory)); } Term serverSideTerm; if (ServerSideMemberAccess(datumConverterFactory, memberExpression, out serverSideTerm)) { return(serverSideTerm); } return(AttemptClientSideConversion(datumConverterFactory, expr)); } case ExpressionType.Conditional: { var conditionalExpression = (ConditionalExpression)expr; return(new Term() { type = Term.TermType.BRANCH, args = { RecursiveMap(conditionalExpression.Test), RecursiveMap(conditionalExpression.IfTrue), RecursiveMap(conditionalExpression.IfFalse) } }); } case ExpressionType.Convert: { // The use-case for this right now is automatic boxing that occurs when setting a Dictionary<string,object>'s value // to a primitive. In that particular case, we don't actually need to generate any ReQL for the conversion, so we're // just ignoring the Convert and mapping the expression inside. Might need other behavior here in the future... return(RecursiveMap(((UnaryExpression)expr).Operand)); } case ExpressionType.MemberInit: { var memberInit = (MemberInitExpression)expr; var memberType = memberInit.Type; IDatumConverter datumConverter; if (!datumConverterFactory.TryGet(memberType, out datumConverter)) { return(AttemptClientSideConversion(datumConverterFactory, expr)); } var fieldConverter = datumConverter as IObjectDatumConverter; if (fieldConverter == null) { return(AttemptClientSideConversion(datumConverterFactory, expr)); } var makeObjTerm = new Term() { type = Term.TermType.MAKE_OBJ, }; foreach (var binding in memberInit.Bindings) { switch (binding.BindingType) { case MemberBindingType.Assignment: { var memberAssignment = (MemberAssignment)binding; var pair = new Term.AssocPair(); pair.key = fieldConverter.GetDatumFieldName(memberAssignment.Member); pair.val = RecursiveMap(memberAssignment.Expression); if (pair.key == null) { throw new NotSupportedException("Cannot map member assignments into ReQL without implementing IObjectDatumConverter"); } makeObjTerm.optargs.Add(pair); break; } case MemberBindingType.ListBinding: case MemberBindingType.MemberBinding: throw new NotSupportedException("Binding type not currently supported"); } } return(makeObjTerm); } default: { return(AttemptClientSideConversion(datumConverterFactory, expr)); } } }
public void TestFixtureSetUp() { datumConverterFactory = Substitute.For<IDatumConverterFactory>(); var intDatumConverter = Substitute.For<IDatumConverter>(); intDatumConverter.ConvertDatum(Arg.Any<Datum>()).Returns(args => (int)((Datum)args[0]).r_num); intDatumConverter.ConvertObject(Arg.Any<object>()).Returns(args => new Datum() { type = Datum.DatumType.R_NUM, r_num = (int)args [0] }); IDatumConverter value; datumConverterFactory .TryGet(typeof(int), datumConverterFactory, out value) .Returns(args => { args[2] = intDatumConverter; return true; }); datumConverterFactory.GetBestNativeTypeForDatum(Arg.Any<Datum>()).Returns(typeof(int)); }
public static bool TryGet <T>(this IDatumConverterFactory datumConverterFactory, out IDatumConverter <T> datumConverter) { return(datumConverterFactory.TryGet <T>(datumConverterFactory, out datumConverter)); }
public static bool TryGet(this IDatumConverterFactory datumConverterFactory, Type datumType, out IDatumConverter datumConverter) { return(datumConverterFactory.TryGet(datumType, datumConverterFactory, out datumConverter)); }
protected Term SimpleMap(IDatumConverterFactory datumConverterFactory, Expression expr) { switch (expr.NodeType) { case ExpressionType.Constant: { var constantExpression = (ConstantExpression)expr; var datumConverter = datumConverterFactory.Get(constantExpression.Type); var datum = datumConverter.ConvertObject(constantExpression.Value); return new Term() { type = Term.TermType.DATUM, datum = datum }; } case ExpressionType.Add: case ExpressionType.Modulo: case ExpressionType.Divide: case ExpressionType.Multiply: case ExpressionType.Subtract: case ExpressionType.Equal: case ExpressionType.LessThan: case ExpressionType.LessThanOrEqual: case ExpressionType.GreaterThan: case ExpressionType.GreaterThanOrEqual: case ExpressionType.AndAlso: case ExpressionType.OrElse: case ExpressionType.NotEqual: case ExpressionType.ArrayIndex: return ConvertBinaryExpressionToTerm((BinaryExpression)expr, datumConverterFactory); case ExpressionType.Not: case ExpressionType.ArrayLength: return ConvertUnaryExpressionToTerm((UnaryExpression)expr, datumConverterFactory); case ExpressionType.New: { var newExpression = (NewExpression)expr; if (AnonymousTypeDatumConverterFactory.Instance.IsTypeSupported(newExpression.Type)) { var retval = new Term() { type = Term.TermType.MAKE_OBJ, }; foreach (var property in newExpression.Type.GetProperties().Select((p, i) => new { Property = p, Index = i })) { var key = property.Property.Name; var value = RecursiveMap(newExpression.Arguments[property.Index]); retval.optargs.Add(new Term.AssocPair() { key = key, val = value }); } return retval; } DefaultExpressionConverterFactory.ExpressionMappingDelegate<NewExpression> newExpressionMapping; if (expressionConverterFactory.TryGetNewExpressionMapping(newExpression.Constructor, out newExpressionMapping)) return newExpressionMapping(newExpression, RecursiveMap, datumConverterFactory, expressionConverterFactory); return AttemptClientSideConversion(datumConverterFactory, expr); } case ExpressionType.NewArrayInit: var arrayExpression = (NewArrayExpression)expr; var array = new Term {type = Term.TermType.MAKE_ARRAY}; foreach (var expression in arrayExpression.Expressions) { array.args.Add(RecursiveMap(expression)); } return array; case ExpressionType.Call: { var callExpression = (MethodCallExpression)expr; var method = callExpression.Method; DefaultExpressionConverterFactory.ExpressionMappingDelegate<MethodCallExpression> methodCallMapping; if (expressionConverterFactory.TryGetMethodCallMapping(method, out methodCallMapping)) return methodCallMapping(callExpression, RecursiveMap, datumConverterFactory, expressionConverterFactory); else return AttemptClientSideConversion(datumConverterFactory, expr); } case ExpressionType.MemberAccess: { var memberExpression = (MemberExpression)expr; var member = memberExpression.Member; DefaultExpressionConverterFactory.ExpressionMappingDelegate<MemberExpression> memberAccessMapping; if (expressionConverterFactory.TryGetMemberAccessMapping(member, out memberAccessMapping)) return memberAccessMapping(memberExpression, RecursiveMap, datumConverterFactory, expressionConverterFactory); Term serverSideTerm; if (ServerSideMemberAccess(datumConverterFactory, memberExpression, out serverSideTerm)) return serverSideTerm; return AttemptClientSideConversion(datumConverterFactory, expr); } case ExpressionType.Conditional: { var conditionalExpression = (ConditionalExpression)expr; return new Term() { type = Term.TermType.BRANCH, args = { RecursiveMap(conditionalExpression.Test), RecursiveMap(conditionalExpression.IfTrue), RecursiveMap(conditionalExpression.IfFalse) } }; } case ExpressionType.Convert: { // The use-case for this right now is automatic boxing that occurs when setting a Dictionary<string,object>'s value // to a primitive. In that particular case, we don't actually need to generate any ReQL for the conversion, so we're // just ignoring the Convert and mapping the expression inside. Might need other behavior here in the future... return RecursiveMap(((UnaryExpression)expr).Operand); } case ExpressionType.MemberInit: { var memberInit = (MemberInitExpression)expr; var memberType = memberInit.Type; IDatumConverter datumConverter; if (!datumConverterFactory.TryGet(memberType, out datumConverter)) return AttemptClientSideConversion(datumConverterFactory, expr); var fieldConverter = datumConverter as IObjectDatumConverter; if (fieldConverter == null) return AttemptClientSideConversion(datumConverterFactory, expr); var makeObjTerm = new Term() { type = Term.TermType.MAKE_OBJ, }; foreach (var binding in memberInit.Bindings) { switch (binding.BindingType) { case MemberBindingType.Assignment: { var memberAssignment = (MemberAssignment)binding; var pair = new Term.AssocPair(); pair.key = fieldConverter.GetDatumFieldName(memberAssignment.Member); pair.val = RecursiveMap(memberAssignment.Expression); if (pair.key == null) throw new NotSupportedException("Cannot map member assignments into ReQL without implementing IObjectDatumConverter"); makeObjTerm.optargs.Add(pair); break; } case MemberBindingType.ListBinding: case MemberBindingType.MemberBinding: throw new NotSupportedException("Binding type not currently supported"); } } return makeObjTerm; } default: { return AttemptClientSideConversion(datumConverterFactory, expr); } } }
public bool TryGet(Type datumType, IDatumConverterFactory rootDatumConverterFactory, out IDatumConverter datumConverter) { return(delegatedDatumConverterFactory.TryGet(datumType, rootDatumConverterFactory, out datumConverter)); }
private bool ServerSideMemberAccess(IDatumConverterFactory datumConverterFactory, MemberExpression memberExpression, out Term term) { term = null; if (memberExpression.Expression == null) { // static member access; can't do that server-side, wouldn't want to either. return(false); } if (memberExpression.Expression.NodeType == ExpressionType.Constant) { // Accessing a constant; client-side conversion will be more efficient since we won't be round-tripping the object return(false); } IDatumConverter datumConverter; if (!datumConverterFactory.TryGet(memberExpression.Expression.Type, out datumConverter)) { // No datum converter for this type. return(false); } var fieldConverter = datumConverter as IObjectDatumConverter; if (fieldConverter == null) { // doesn't implement IObjectDatumConverter, so we don't know how to map the MemberInfo to the field name return(false); } var datumFieldName = fieldConverter.GetDatumFieldName(memberExpression.Member); if (string.IsNullOrEmpty(datumFieldName)) { // At this point we're not returning false because we're expecting this should work; throwing an error instead. // We're expecting this to work, but, returning false will give us a chance to try client-side evaluation instead and // maintain compatibility with the pre-PR #209 behaviour. (issue #220). return(false); } var getAttrTerm = new Term() { type = Term.TermType.GET_FIELD }; getAttrTerm.args.Add(RecursiveMap(memberExpression.Expression)); getAttrTerm.args.Add(new Term() { type = Term.TermType.DATUM, datum = new Datum() { type = Datum.DatumType.R_STR, r_str = datumFieldName } }); term = getAttrTerm; return(true); }