public static Term ConvertAppendToTerm(MethodCallExpression methodCall, DefaultExpressionConverterFactory.RecursiveMapDelegate recursiveMap, IDatumConverterFactory datumConverterFactory, IExpressionConverterFactory expressionConverterFactory) { var target = methodCall.Arguments[0]; var appendArray = methodCall.Arguments[1]; if (appendArray.NodeType != ExpressionType.NewArrayInit) throw new NotSupportedException(String.Format("Expected second arg to ReQLExpression.Append to be NewArrayInit, but was: {0}", appendArray.NodeType)); var newArrayExpression = (NewArrayExpression)appendArray; var term = recursiveMap(target); foreach (var datumExpression in newArrayExpression.Expressions) { var newTerm = new Term() { type = Term.TermType.APPEND }; newTerm.args.Add(term); if (datumExpression.NodeType == ExpressionType.MemberInit) { var memberInit = (MemberInitExpression)datumExpression; newTerm.args.Add(recursiveMap(memberInit)); } else throw new NotSupportedException(String.Format("Expected ReQLExpression.Append to contain MemberInit additions, but was: {0}", datumExpression.NodeType)); term = newTerm; } return term; }
private void AssertAddFunctionWithConversion(Term expr, double value, double conversion) { var funcTerm = new Term() { type = Term.TermType.FUNC, args = { new Term() { type = Term.TermType.MAKE_ARRAY, args = { new Term() { type = Term.TermType.DATUM, datum = new Datum() { type = Datum.DatumType.R_NUM, r_num = 2, } } } }, new Term() { type = Term.TermType.ADD, args = { new Term() { type = Term.TermType.VAR, args = { new Term() { type = Term.TermType.DATUM, datum = new Datum() { type = Datum.DatumType.R_NUM, r_num = 2, } } } }, new Term() { type = Term.TermType.MUL, args = { new Term() { type = Term.TermType.DATUM, datum = new Datum() { type = Datum.DatumType.R_NUM, r_num = value, } }, new Term() { type = Term.TermType.DATUM, datum = new Datum() { type = Datum.DatumType.R_NUM, r_num = conversion, } }, } } } }, } }; expr.ShouldBeEquivalentTo(funcTerm); }
private void AssertAddFunction(Term expr, TimeSpan ts) { var funcTerm = new Term() { type = Term.TermType.FUNC, args = { new Term() { type = Term.TermType.MAKE_ARRAY, args = { new Term() { type = Term.TermType.DATUM, datum = new Datum() { type = Datum.DatumType.R_NUM, r_num = 2, } } } }, new Term() { type = Term.TermType.ADD, args = { new Term() { type = Term.TermType.VAR, args = { new Term() { type = Term.TermType.DATUM, datum = new Datum() { type = Datum.DatumType.R_NUM, r_num = 2, } } } }, new Term() { type = Term.TermType.DATUM, datum = new Datum() { type = Datum.DatumType.R_NUM, r_num = ts.TotalSeconds, } }, } }, } }; expr.ShouldBeEquivalentTo(funcTerm); }
public Term GenerateTerm(IDatumConverterFactory datumConverterFactory) { var dbTerm = new Term() { type = Term.TermType.DB_DROP, }; dbTerm.args.Add( new Term() { type = Term.TermType.DATUM, datum = new Datum() { type = Datum.DatumType.R_STR, r_str = db, } } ); return dbTerm; }
public Term GenerateTerm(IDatumConverterFactory datumConverterFactory) { var tableTerm = new Term() { type = Term.TermType.TABLE_DROP, }; tableTerm.args.Add(dbTerm.GenerateTerm(datumConverterFactory)); tableTerm.args.Add( new Term() { type = Term.TermType.DATUM, datum = new Datum() { type = Datum.DatumType.R_STR, r_str = table, } } ); return tableTerm; }
public static Term ConvertEnumerableAnyToTerm(MethodCallExpression methodCall, DefaultExpressionConverterFactory.RecursiveMapDelegate recursiveMap, IDatumConverterFactory datumConverterFactory, IExpressionConverterFactory expressionConverterFactory) { var target = methodCall.Arguments[0]; var predicate = methodCall.Arguments[1]; var filterTerm = new Term() { type = Term.TermType.CONTAINS }; filterTerm.args.Add(recursiveMap(target)); var enumerableElementType = methodCall.Method.GetGenericArguments()[0]; var createFunctionTermMethod = typeof(ExpressionUtils) .GetMethods(BindingFlags.Public | BindingFlags.Static) .Single(m => m.Name == "CreateFunctionTerm" && m.GetGenericArguments().Length == 2); createFunctionTermMethod = createFunctionTermMethod.MakeGenericMethod(enumerableElementType, typeof(bool)); var functionTerm = (Term)createFunctionTermMethod.Invoke(null, new object[] { new QueryConverter(datumConverterFactory, expressionConverterFactory), predicate }); filterTerm.args.Add(functionTerm); return filterTerm; }
private static Term Count(Term term) { return new Term() { type = Term.TermType.COUNT, args = { term } }; }
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; }
private void AssertDateTimeAccessor(Term expr, Term.TermType termType) { expr.ShouldBeEquivalentTo( new Term() { type = Term.TermType.FUNC, args = { new Term() { type = Term.TermType.MAKE_ARRAY, args = { new Term() { type = Term.TermType.DATUM, datum = new Datum() { type = Datum.DatumType.R_NUM, r_num = 2, } } } }, new Term() { type = termType, args = { new Term() { type = Term.TermType.VAR, args = { new Term() { type = Term.TermType.DATUM, datum = new Datum() { type = Datum.DatumType.R_NUM, r_num = 2, } } } } } } } } ); }
private static Term TimeSpanToPlusMinus(Term offset) { return new Term() { type = Term.TermType.BRANCH, args = { Binary(offset, Term.TermType.LT, 0), String("-"), String("+") } }; }
private static Term TimeSpanToOffsetHouts(Term offset) { // (offset - (offset % 3600)) / 3600 var hours = Binary( Binary(offset, Term.TermType.SUB, Binary(offset, Term.TermType.MOD, 3600)), Term.TermType.DIV, 3600); // then ensure hours is positive; TimeSpanToPlusMinus takes care of the minus sign if needed // to make the padding simpler here hours = Branch( Binary(hours, Term.TermType.LT, 0), Binary(hours, Term.TermType.MUL, -1), hours); return Branch( Binary(hours, Term.TermType.LT, 10), Add(String("0"), CoerceTo(hours, "string")), CoerceTo(hours, "string") ); }
private static Term MinutesToSeconds(Term term) { return Binary(term, Term.TermType.MUL, 60); }
private static void WriteDatum(JsonWriter writer, Spec.Datum datum) { switch (datum.type) { case Spec.Datum.DatumType.R_BOOL: writer.WriteBoolean(datum.r_bool); break; case Spec.Datum.DatumType.R_JSON: throw new NotSupportedException(); case Spec.Datum.DatumType.R_NULL: writer.WriteNull(); break; case Spec.Datum.DatumType.R_NUM: writer.WriteNumber(datum.r_num); break; case Spec.Datum.DatumType.R_STR: writer.WriteString(datum.r_str); break; case Spec.Datum.DatumType.R_ARRAY: { var newterm = new Term() { type = Term.TermType.MAKE_ARRAY }; newterm.args.AddRange(datum.r_array.Select(ap => new Term() { type = Term.TermType.DATUM, datum = ap, })); WriteTerm(writer, newterm); } break; case Spec.Datum.DatumType.R_OBJECT: { var newterm = new Term() { type = Term.TermType.MAKE_OBJ }; newterm.optargs.AddRange(datum.r_object.Select(ap => new Term.AssocPair() { key = ap.key, val = new Term() { type = Term.TermType.DATUM, datum = ap.val } })); WriteTerm(writer, newterm); } break; } }
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); } } }
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 static Term HoursToSeconds(Term term) { // seconds per hour return Binary(term, Term.TermType.MUL, 3600); }
private static Term MillisecondsToSeconds(Term term) { return Binary(term, Term.TermType.DIV, 1000); }
public static Term TimeSpanToOffset(Term offset) { // offset will be a number of seconds on the server-side since that's how we've mapped // TimeSpans to ReQL. This is basically: str(floor(offset / 60)) + ":" + (offset % 60), // but, ReQL doesn't support floor, and requires the timezone to be in the exact format // [+-][0-9]{2}:[0-9]{2}. return Add( TimeSpanToPlusMinus(offset), TimeSpanToOffsetHouts(offset), String(":"), TimeSpanToOffsetMinutes(offset) ); }
private static Term TicksToSeconds(Term term) { return Binary(term, Term.TermType.DIV, TimeSpan.TicksPerSecond); }
private static Term Binary(Term leftTerm, Term.TermType type, Term rightTerm) { return new Term() { type = type, args = { leftTerm, rightTerm } }; }
private static Term TimeSpanToOffsetMinutes(Term offset) { // minutes is now the total number of minutes, any second precision has been removed var minutes = Binary( Binary(offset, Term.TermType.SUB, Binary(offset, Term.TermType.MOD, 60)), Term.TermType.DIV, 60); // then take out the hours accounted for in TimeSpanToOffsetHours minutes = Binary(minutes, Term.TermType.MOD, 60); // then ensure minutes is positive; ReSQL -30 % 60 -> -30 minutes = Branch( Binary(minutes, Term.TermType.LT, 0), Binary(minutes, Term.TermType.MUL, -1), minutes); return Branch( Binary(minutes, Term.TermType.LE, 10), Add(String("0"), CoerceTo(minutes, "string")), // leading zero CoerceTo(minutes, "string") ); }
private static Term Binary(Term leftTerm, Term.TermType type, double rightTerm) { return Binary(leftTerm, type, new Term() { type = Term.TermType.DATUM, datum = new Datum() { type = Datum.DatumType.R_NUM, r_num = rightTerm } }); }
public Term GenerateTerm(IDatumConverterFactory datumConverterFactory) { var tableTerm = new Term() { type = Term.TermType.TABLE_CREATE, }; tableTerm.args.Add(dbTerm.GenerateTerm(datumConverterFactory)); tableTerm.args.Add( new Term() { type = Term.TermType.DATUM, datum = new Datum() { type = Datum.DatumType.R_STR, r_str = table, } } ); if (datacenter != null) { tableTerm.optargs.Add(new Term.AssocPair() { key = "datacenter", val = new Term() { type = Term.TermType.DATUM, datum = new Datum() { type = Datum.DatumType.R_STR, r_str = datacenter, } } }); } if (primaryKey != null) { tableTerm.optargs.Add(new Term.AssocPair() { key = "primary_key", val = new Term() { type = Term.TermType.DATUM, datum = new Datum() { type = Datum.DatumType.R_STR, r_str = primaryKey, } } }); } if (cacheSize.HasValue) { tableTerm.optargs.Add(new Term.AssocPair() { key = "cache_size", val = new Term() { type = Term.TermType.DATUM, datum = new Datum() { type = Datum.DatumType.R_NUM, r_num = cacheSize.Value, } } }); } return tableTerm; }
private static Term Branch(Term test, Term ifTrue, Term ifFalse) { return new Term() { type = Term.TermType.BRANCH, args = { test, ifTrue, ifFalse } }; }
public void DateTimeYearMonthDayConstructor() { var expr = ExpressionUtils.CreateFunctionTerm<int, DateTime>(queryConverter, (i) => new DateTime(i, i, i)); var variableRefenceTerm = new Term() { type = Term.TermType.VAR, args = { new Term() { type = Term.TermType.DATUM, datum = new Datum() { type = Datum.DatumType.R_NUM, r_num = 2, } } } }; expr.ShouldBeEquivalentTo( new Term() { type = Term.TermType.FUNC, args = { new Term() { type = Term.TermType.MAKE_ARRAY, args = { new Term() { type = Term.TermType.DATUM, datum = new Datum() { type = Datum.DatumType.R_NUM, r_num = 2, } } } }, new Term() { type = Term.TermType.TIME, args = { variableRefenceTerm, variableRefenceTerm, variableRefenceTerm, new Term() { type = Term.TermType.DATUM, datum = new Datum() { type = Datum.DatumType.R_STR, r_str = "Z", } } } } } } ); }
private static Term CoerceTo(Term term, string type) { return new Term() { type = Term.TermType.COERCE_TO, args = { term, String(type) } }; }
private Term ConvertUnaryExpressionToTerm(UnaryExpression expr, IDatumConverterFactory datumConverterFactory) { DefaultExpressionConverterFactory.ExpressionMappingDelegate<UnaryExpression> unaryExpressionMapping; Term.TermType defaultTermType; if (expressionConverterFactory.TryGetUnaryExpressionMapping(expr.Operand.Type, expr.NodeType, out unaryExpressionMapping)) { return unaryExpressionMapping(expr, RecursiveMap, datumConverterFactory, expressionConverterFactory); } else if (DefaultTermTypes.TryGetValue(expr.NodeType, out defaultTermType)) { var term = new Term() { type = defaultTermType }; term.args.Add(RecursiveMap(expr.Operand)); return term; } else return AttemptClientSideConversion(datumConverterFactory, expr); }
private static Term DaysToSeconds(Term term) { // seconds per day... doesn't account for days with leap seconds, but, close enough return Binary(term, Term.TermType.MUL, 86400); }
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.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); } default: { return AttemptClientSideConversion(datumConverterFactory, expr); } } }
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.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); else 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) } }; } default: { return AttemptClientSideConversion(datumConverterFactory, expr); } } }